fix: resolve IMMUTABLE function errors in database migrations
Some checks failed
CI/CD - Build & Test / Backend Tests (push) Has been cancelled
CI/CD - Build & Test / Frontend Tests (push) Has been cancelled
CI/CD - Build & Test / Security Scans (push) Has been cancelled
CI/CD - Build & Test / Docker Build Test (push) Has been cancelled
CI/CD - Build & Test / Terraform Validate (push) Has been cancelled
Deploy to Production / Build & Test (push) Has been cancelled
Deploy to Production / Security Scan (push) Has been cancelled
Deploy to Production / Build Docker Images (push) Has been cancelled
Deploy to Production / Deploy to Staging (push) Has been cancelled
Deploy to Production / E2E Tests (push) Has been cancelled
Deploy to Production / Deploy to Production (push) Has been cancelled

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.
This commit is contained in:
Luca Sacchi Ricciardi
2026-04-07 22:57:45 +02:00
parent e88050c2e4
commit de2994c3b5
2 changed files with 18 additions and 16 deletions

View File

@@ -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

View File

@@ -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