From de2994c3b5c7dcb9bac79af7ac73b18f08096695 Mon Sep 17 00:00:00 2001 From: Luca Sacchi Ricciardi Date: Tue, 7 Apr 2026 22:57:45 +0200 Subject: [PATCH] fix: resolve IMMUTABLE function errors in database migrations Fixed multiple PostgreSQL migration errors: 1. alembic/versions/a1b2c3d4e5f6_add_performance_indexes_v1_0_0.py: - idx_logs_recent: Removed NOW() - INTERVAL condition Now uses simple btree index with DESC ordering - idx_apikeys_valid: Removed NOW() condition Now uses simple partial index on is_active only PostgreSQL doesn't allow non-IMMUTABLE functions in index predicates. NOW() is STABLE, not IMMUTABLE, because it returns different values over time. 2. alembic/versions/b2c3d4e5f6a7_create_archive_tables_v1_0_0.py: - Removed partitioning from scenario_logs_archive - Removed partitioning from scenario_metrics_archive DATE_TRUNC() in partition key is not IMMUTABLE. Tables work without partitioning for now. 3. alembic.ini: - Changed localhost to postgres (already done in previous commit) Migrations now run successfully without IMMUTABLE errors. --- ...c3d4e5f6_add_performance_indexes_v1_0_0.py | 28 ++++++++++--------- ...c3d4e5f6a7_create_archive_tables_v1_0_0.py | 6 ++-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/alembic/versions/a1b2c3d4e5f6_add_performance_indexes_v1_0_0.py b/alembic/versions/a1b2c3d4e5f6_add_performance_indexes_v1_0_0.py index 254237d..e401f78 100644 --- a/alembic/versions/a1b2c3d4e5f6_add_performance_indexes_v1_0_0.py +++ b/alembic/versions/a1b2c3d4e5f6_add_performance_indexes_v1_0_0.py @@ -136,12 +136,13 @@ def upgrade() -> None: postgresql_using="btree", ) - # Recent logs (last 30 days - for active monitoring) - op.execute(""" - CREATE INDEX idx_logs_recent - ON scenario_logs (scenario_id, received_at) - WHERE received_at > NOW() - INTERVAL '30 days' - """) + # Recent logs index - ordered by received_at DESC for recent queries + op.create_index( + "idx_logs_recent", + "scenario_logs", + ["scenario_id", sa.text("received_at DESC")], + postgresql_using="btree", + ) # Active API keys op.create_index( @@ -152,13 +153,14 @@ def upgrade() -> None: postgresql_using="btree", ) - # Non-expired API keys - op.execute(""" - CREATE INDEX idx_apikeys_valid - ON api_keys (user_id, created_at) - WHERE is_active = true - AND (expires_at IS NULL OR expires_at > NOW()) - """) + # Active API keys (valid ones - is_active flag only, can't use NOW() in index predicate) + op.create_index( + "idx_apikeys_valid", + "api_keys", + ["user_id", "created_at"], + postgresql_where=sa.text("is_active = true"), + postgresql_using="btree", + ) # ========================================================================= # 3. INDEXES FOR N+1 QUERY OPTIMIZATION diff --git a/alembic/versions/b2c3d4e5f6a7_create_archive_tables_v1_0_0.py b/alembic/versions/b2c3d4e5f6a7_create_archive_tables_v1_0_0.py index c07e642..343a5f8 100644 --- a/alembic/versions/b2c3d4e5f6a7_create_archive_tables_v1_0_0.py +++ b/alembic/versions/b2c3d4e5f6a7_create_archive_tables_v1_0_0.py @@ -68,8 +68,8 @@ def upgrade() -> None: postgresql.UUID(as_uuid=True), nullable=True, ), - # Partition by month for efficient queries - postgresql_partition_by="RANGE (DATE_TRUNC('month', received_at))", + # Note: Partitioning removed - DATE_TRUNC is not IMMUTABLE + # For large datasets, consider adding a computed 'month' column ) # Create indexes for archive table @@ -143,7 +143,7 @@ def upgrade() -> None: sa.Integer(), nullable=True, ), - postgresql_partition_by="RANGE (DATE_TRUNC('month', timestamp))", + # Note: Partitioning removed - DATE_TRUNC is not IMMUTABLE ) # Create indexes for metrics archive