frappe_pg/
├── frappe_pg/ # Main application package
│ ├── __init__.py # App initialization, auto-applies patches
│ ├── hooks.py # Frappe hooks configuration
│ │
│ ├── postgres/ # Core PostgreSQL compatibility
│ │ ├── __init__.py
│ │ ├── database_patches.py # Monkey patches for PostgresDatabase class
│ │ ├── query_transformers.py # SQL transformation functions
│ │ └── db_functions.py # PostgreSQL function creation/management
│ │
│ ├── utils/ # Utility modules
│ │ ├── __init__.py
│ │ └── regex_patterns.py # SQL pattern matching (IF, FORCE INDEX, etc.)
│ │
│ ├── patches/ # Versioned patches
│ │ ├── __init__.py
│ │ ├── v1/ # Version 1 patches
│ │ │ ├── __init__.py
│ │ │ ├── apply_postgres_compatibility.py # Main compatibility patch
│ │ │ └── fix_erpnext_trends.py # ERPNext GROUP BY fixes
│ │ ├── erpnext_trends_fix.py # Legacy (kept for backwards compat)
│ │ └── postgres_fix.py # Legacy (kept for backwards compat)
│ │
│ ├── api/ # API endpoints
│ │ ├── __init__.py
│ │ └── patches.py # Patch management API
│ │
│ ├── config/ # Frappe configuration
│ │ └── __init__.py
│ │
│ ├── docs/ # Documentation
│ │ ├── README.md
│ │ ├── installation.md
│ │ ├── architecture.md
│ │ └── troubleshooting.md
│ │
│ ├── templates/ # Frappe templates
│ │ ├── __init__.py
│ │ └── pages/
│ │
│ └── public/ # Static assets
│ ├── css/
│ └── js/
│
├── STRUCTURE.md # This file
├── README.md # Main README
├── license.txt # MIT License
└── pyproject.toml # Python project configuration
- Monkey-patches
PostgresDatabase.sql()method - Applies query transformations before execution
- Handles transaction errors with auto-rollback
- Provides retry mechanism (up to 3 attempts)
- Functions:
patched_sql(): Enhanced SQL executionapply_postgres_fixes(): Apply all patchescheck_patches_status(): Verify patch status
- Contains all SQL transformation logic
- Functions:
convert_if_to_case(): IF() → CASE WHEN (handles 100+ nested calls)remove_index_hints(): Remove FORCE/USE/IGNORE INDEXconvert_ifnull_to_coalesce(): IFNULL() → COALESCE()convert_date_format(): DATE_FORMAT() → TO_CHAR()apply_all_query_transformations(): Main transformation pipelinesplit_by_comma(): Helper for parsing function arguments
- Creates PostgreSQL compatibility functions
- Functions:
create_missing_functions(): Install all functionsverify_db_functions(): Test function installationdrop_all_functions(): Clean uninstallation
- Database functions created:
GROUP_CONCAT(text): String aggregationunix_timestamp(): Unix timestamp conversiontimestampdiff(): Time difference calculation
- Compiled regex patterns for SQL matching
- Patterns:
FORCE_INDEX_PATTERN,USE_INDEX_PATTERN,IGNORE_INDEX_PATTERNIF_FUNCTION_PATTERN,IFNULL_PATTERNDATE_FORMAT_PATTERN,NOW_PATTERN
- Helper functions for pattern matching
- Frappe patch: applies all PostgreSQL fixes
- Called during migration
- Functions:
execute(): Run the patchvalidate(): Verify patch success
- Frappe patch: fixes ERPNext trends.py GROUP BY issues
- Patches
based_wise_columns_query()function - Fixes:
- Item reports: adds
item_name - Customer reports: adds
customer_name,territory - Supplier reports: adds
supplier_name - Project reports: adds
project_name - Universal: adds
default_currencyto all reports
- Item reports: adds
- Whitelisted API endpoints for patch management
- Endpoints:
check_patches_status(): Get patch statusverify_patches(): Run verification testsreinstall_patches(): Reinstall all patchesget_patch_info(): Get patch documentation
File: hooks.py
after_install = "frappe_pg.postgres.database_patches.apply_postgres_fixes"
after_migrate = "frappe_pg.postgres.database_patches.after_migrate"
on_session_creation = "frappe_pg.postgres.database_patches.on_session_creation"These hooks ensure patches are applied:
- After installation: Initial patch application
- After migration: Reapply patches + create DB functions
- On session creation: Keep patches active after restarts
-
App Import (
__init__.py):from frappe_pg.postgres.database_patches import apply_postgres_fixes from frappe_pg.patches.v1.fix_erpnext_trends import apply_trends_patch apply_postgres_fixes() # Apply database patches apply_trends_patch() # Apply ERPNext trends fix
-
Database Patches Applied:
PostgresDatabase.sql→patched_sqlPostgresDatabase.commit→patched_commitPostgresDatabase.rollback→patched_rollback
-
Query Execution Flow:
User Query ↓ patched_sql() ↓ apply_all_query_transformations() ├→ remove_index_hints() ├→ convert_if_to_case() ├→ convert_ifnull_to_coalesce() └→ convert_date_format() ↓ Frappe's modify_query() ↓ PostgreSQL Database
These files are kept for backwards compatibility but not used in new structure:
patches/postgres_fix.py- Original monolithic patch filepatches/erpnext_trends_fix.py- Original trends fix
Migration: Old imports still work but point to new modules internally.
Run verification tests:
bench --site site1.local console
# Check patch status
>>> from frappe_pg.api import check_patches_status, verify_patches
>>> check_patches_status()
>>> verify_patches()
# Test individual components
>>> from frappe_pg.postgres.db_functions import verify_db_functions
>>> verify_db_functions()- Current Version: 1.0.0
- Patch Version: v1
- License: MIT