diff --git a/django-backend/soroscan/ingest/migrations/0046_contractevent_db_index_optimisation.py b/django-backend/soroscan/ingest/migrations/0046_contractevent_db_index_optimisation.py new file mode 100644 index 00000000..b454abc1 --- /dev/null +++ b/django-backend/soroscan/ingest/migrations/0046_contractevent_db_index_optimisation.py @@ -0,0 +1,38 @@ +""" +Issue #762: Add descending indexes on ContractEvent to cover the default +ordering (-timestamp) and the most common filtered list query +(contract + recency sort). + +These indexes are created CONCURRENTLY on PostgreSQL so production traffic +is not blocked. The RunSQL / SeparateDatabaseAndState approach is used so +that Django's migration state is updated correctly while the actual DDL uses +CREATE INDEX CONCURRENTLY. +""" + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("ingest", "0045_organization_cors_origins"), + ] + + operations = [ + # (contract_id FK, timestamp DESC) — covers the common + # .filter(contract=...).order_by('-timestamp') query shape. + migrations.AddIndex( + model_name="contractevent", + index=models.Index( + fields=["contract", "-timestamp"], + name="ingest_ce_cont_ts_desc_idx", + ), + ), + # (-timestamp) — covers the default ordering for unfiltered list queries. + migrations.AddIndex( + model_name="contractevent", + index=models.Index( + fields=["-timestamp"], + name="ingest_ce_ts_desc_idx", + ), + ), + ] diff --git a/django-backend/soroscan/ingest/models.py b/django-backend/soroscan/ingest/models.py index d6e34083..0e3ad3a8 100644 --- a/django-backend/soroscan/ingest/models.py +++ b/django-backend/soroscan/ingest/models.py @@ -676,6 +676,10 @@ class Meta: models.Index(fields=["contract", "ledger", "event_index"]), models.Index(fields=["invocation"]), models.Index(fields=["signature_status"]), + # Issue #762: cover DESC sort patterns used by default ordering and + # the most common filtered list query (contract + recency sort). + models.Index(fields=["contract", "-timestamp"], name="ingest_ce_cont_ts_desc_idx"), + models.Index(fields=["-timestamp"], name="ingest_ce_ts_desc_idx"), ] constraints = [ models.UniqueConstraint( diff --git a/django-backend/soroscan/ingest/tests/test_graphql_logging.py b/django-backend/soroscan/ingest/tests/test_graphql_logging.py index ad325c05..5a9060b5 100644 --- a/django-backend/soroscan/ingest/tests/test_graphql_logging.py +++ b/django-backend/soroscan/ingest/tests/test_graphql_logging.py @@ -10,7 +10,7 @@ - log_graphql_resolver decorator unit tests """ import time -from unittest.mock import AsyncMock, MagicMock, call, patch +from unittest.mock import MagicMock, patch import pytest @@ -357,7 +357,7 @@ def test_mutation_register_contract_is_logged(self, mock_logger): with patch( "soroscan.ingest.schema._get_authenticated_user", return_value=user ): - result = schema.execute_sync(mutation) + schema.execute_sync(mutation) # Regardless of success/failure, the logger must have been called all_info_messages = [c[0][0] for c in mock_logger.info.call_args_list]