"""Add created_at indexes for performance on large tables. Order by created_at DESC is the slowest query at 68ms with 100k rows. This migration adds indexes on created_at for all tenant-scoped tables that are commonly sorted by created_at. Revision ID: 0099 Revises: 0098 """ from __future__ import annotations from alembic import op revision = "0099" down_revision = "0098" branch_labels = None depends_on = None # Tables that are commonly sorted by created_at DESC TABLES = [ "contacts", "audit_log", "calendar_entries", "comm_messages", "files", "mails", "tasks", "automation_runs", "ai_chat_messages", "ai_chat_sessions", "entity_history", "notifications", "event_outbox", "outbox_deliveries", "entity_attachments", "contact_merge_history", "webhooks", "tags", "contact_folder_permissions", "entity_permissions", "entity_policies", "guest_users", "guest_invitations", "user_groups", "saved_filters", "saved_views", "workspaces", "workspace_modules", "workspace_users", "workspace_widgets", "api_tokens", "sessions", "password_reset_tokens", "custom_field_definitions", "system_settings", "plugin_migrations", "tenant_plugin_activation", "plugin_allowlist", "permissions", "permission_templates", "permission_delegations", "currencies", "tax_rates", "sequences", "addresses", "bank_accounts", "contactpersons", "contact_folders", "user_preferences", "deletion_log", "backups", "consumer_inbox", "folders", "calendars", "calendar_entry_links", "calendar_shares", "user_calendar_visibility", "subtasks", "resources", "resource_bookings", "entity_links", "forgejo_reported_errors", "comm_conversations", "comm_participants", "comm_message_blocks", "comm_message_attachments", "comm_message_reactions", "comm_message_reads", "comm_conversation_pins", "comm_conversation_mutes", "mail_accounts", "mail_folders", "mail_labels", "mail_label_assignments", "mail_attachments", "mail_signatures", "mail_templates", "mail_rules", "mail_sync_queue", "mail_seen_by", "mail_account_delegates", "mail_account_send_permissions", "pgp_keys", "contact_pgp_keys", "ai_providers", "ai_models", "ai_presets", "ai_agents", "ai_chat_folders", "ai_chat_attachments", "ai_proactive_suggestions", "ai_proactive_context_log", "ai_proactive_settings", "automation_agent_definitions", "automation_agent_versions", "automation_definitions", "automation_versions", "automation_cron_jobs", "automation_agent_runs", "unified_search_index_log", "unified_search_providers", "report_templates", "report_instances", "mcp_server_configs", "share_links", "tag_assignments", "plugin_test_data", "vacation_sent_log", ] def upgrade() -> None: # Add created_at index only if the column exists for table in TABLES: op.execute( "DO $do$ BEGIN " "IF EXISTS (SELECT 1 FROM information_schema.columns " f"WHERE table_name = '{table}' AND column_name = 'created_at') THEN " f"CREATE INDEX IF NOT EXISTS ix_{table}_created_at " f"ON {table} (created_at DESC); " "END IF; " "END $do$;" ) def downgrade() -> None: for table in TABLES: op.execute(f"DROP INDEX IF EXISTS ix_{table}_created_at")