Files
ss-tools/backend/alembic/versions/ed310b33f02c_multi_language_translation_tables.py
busya 4205618ee6 chore: eliminate all deprecation warnings from tests and linter
Warnings fixed:
- datetime.utcnow() → datetime.now(UTC) across 48+ files (src/ + tests/)
- datetime.utcnow (callback ref) → lambda: datetime.now(UTC) in model fields (18 files)
- Pydantic class Config → model_config = ConfigDict(...) (16 files)
- Pydantic .dict() → .model_dump() (8 files)
- ConfigDict(allow_population_by_field_name=True) → validate_by_name=True
- SQLAlchemy declarative_base() import path updated
- FastAPI on_event → lifespan context manager (app.py)
- Import sorting (ruff I001) auto-fixed across all files
- Fixed broken re-export chains that ruff F401 cleanup broke:
  _validate_bcp47: service.py now imports from dictionary_validation directly
  job_to_response: _job_routes.py and test imports from service_utils directly
  fetch_datasource_metadata: restored re-export in service.py
- Added missing TranslateJobService import in _job_routes.py (was deleted by F401)
- Added ConfigDict(protected_namespaces=()) for DashboardDatasetItem schema field
- pytest.ini: replaced deprecated importmode with asyncio_mode

All 440 tests pass with zero deprecation warnings.
2026-05-26 19:18:28 +03:00

393 lines
25 KiB
Python

"""multi-language translation tables
Revision ID: ed310b33f02c
Revises:
Create Date: 2026-05-14 15:35:03.167031
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = 'ed310b33f02c'
down_revision: str | Sequence[str] | None = None
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('environments',
sa.Column('id', sa.String(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('url', sa.String(), nullable=False),
sa.Column('credentials_id', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('terminology_dictionaries',
sa.Column('id', sa.String(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('source_dialect', sa.String(), nullable=False),
sa.Column('target_dialect', sa.String(), nullable=False),
sa.Column('source_language', sa.String(), nullable=True, comment='[DEPRECATED: use per-entry source_language]'),
sa.Column('target_language', sa.String(), nullable=True, comment='[DEPRECATED: use per-entry target_language]'),
sa.Column('is_active', sa.Boolean(), nullable=True),
sa.Column('created_by', sa.String(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('translation_jobs',
sa.Column('id', sa.String(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('source_dialect', sa.String(), nullable=False),
sa.Column('target_dialect', sa.String(), nullable=False),
sa.Column('database_dialect', sa.String(), nullable=True, comment='Detected dialect from Superset connection at save time'),
sa.Column('status', sa.String(), nullable=False),
sa.Column('source_datasource_id', sa.String(), nullable=True, comment='Superset datasource ID'),
sa.Column('source_table', sa.String(), nullable=True, comment='Source table name resolved from datasource'),
sa.Column('target_schema', sa.String(), nullable=True, comment='Target table schema'),
sa.Column('target_table', sa.String(), nullable=True, comment='Target table name'),
sa.Column('source_key_cols', sa.JSON(), nullable=True, comment='Source key column names for composite key'),
sa.Column('target_key_cols', sa.JSON(), nullable=True, comment='Target key column names for composite key'),
sa.Column('translation_column', sa.String(), nullable=True, comment='Source column whose values will be translated'),
sa.Column('target_column', sa.String(), nullable=True, comment='Target column for translated output (defaults to translation_column)'),
sa.Column('context_columns', sa.JSON(), nullable=True, comment='Context column names included in LLM prompt'),
sa.Column('target_language', sa.String(), nullable=True, comment='Target language code (e.g. en, ru) [DEPRECATED: use target_languages]'),
sa.Column('source_language', sa.String(), nullable=True, comment='Fallback source language hint [DEPRECATED: auto-detected per row]'),
sa.Column('target_languages', sa.JSON(), nullable=True, comment='List of BCP-47 target language codes (multi-language support)'),
sa.Column('provider_id', sa.String(), nullable=True, comment='LLM provider ID'),
sa.Column('batch_size', sa.Integer(), nullable=False, comment='Records per batch'),
sa.Column('upsert_strategy', sa.String(), nullable=False, comment='MERGE, INSERT, UPDATE'),
sa.Column('environment_id', sa.String(), nullable=True, comment='Superset environment ID for datasource access'),
sa.Column('target_database_id', sa.String(), nullable=True, comment='Superset database ID for SQL Lab insert target'),
sa.Column('created_by', sa.String(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('database_mappings',
sa.Column('id', sa.String(), nullable=False),
sa.Column('source_env_id', sa.String(), nullable=False),
sa.Column('target_env_id', sa.String(), nullable=False),
sa.Column('source_db_uuid', sa.String(), nullable=False),
sa.Column('target_db_uuid', sa.String(), nullable=False),
sa.Column('source_db_name', sa.String(), nullable=False),
sa.Column('target_db_name', sa.String(), nullable=False),
sa.Column('engine', sa.String(), nullable=True),
sa.ForeignKeyConstraint(['source_env_id'], ['environments.id'], ),
sa.ForeignKeyConstraint(['target_env_id'], ['environments.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('dictionary_entries',
sa.Column('id', sa.String(), nullable=False),
sa.Column('dictionary_id', sa.String(), nullable=False),
sa.Column('source_term', sa.String(), nullable=False),
sa.Column('source_term_normalized', sa.String(), nullable=False),
sa.Column('target_term', sa.String(), nullable=False),
sa.Column('source_language', sa.String(), nullable=False, comment='BCP-47 source language code'),
sa.Column('target_language', sa.String(), nullable=False, comment='BCP-47 target language code'),
sa.Column('context_notes', sa.Text(), nullable=True),
sa.Column('context_data', sa.JSON(), nullable=True, comment='Structured context for term usage'),
sa.Column('usage_notes', sa.Text(), nullable=True, comment='Usage guidance for the term mapping'),
sa.Column('has_context', sa.Boolean(), nullable=True, comment='Whether context_data is populated'),
sa.Column('context_source', sa.String(), nullable=True, comment='auto|auto_with_edits|manual|bulk'),
sa.Column('origin_source_language', sa.String(), nullable=True, comment='Original source language of the term'),
sa.Column('origin_run_id', sa.String(), nullable=True, comment='Run ID from which this correction originated'),
sa.Column('origin_row_key', sa.String(), nullable=True, comment='Row key within the run that triggered this correction'),
sa.Column('origin_user_id', sa.String(), nullable=True, comment='User who submitted the correction'),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['dictionary_id'], ['terminology_dictionaries.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('dictionary_id', 'source_term_normalized', 'source_language', 'target_language', name='uq_dict_source_term_lang')
)
op.create_index('idx_dict_entry_lang', 'dictionary_entries', ['source_language', 'target_language'], unique=False)
op.create_index('idx_dict_has_context', 'dictionary_entries', ['has_context'], unique=False)
op.create_index(op.f('ix_dictionary_entries_dictionary_id'), 'dictionary_entries', ['dictionary_id'], unique=False)
op.create_table('migration_jobs',
sa.Column('id', sa.String(), nullable=False),
sa.Column('source_env_id', sa.String(), nullable=False),
sa.Column('target_env_id', sa.String(), nullable=False),
sa.Column('status', sa.Enum('PENDING', 'RUNNING', 'COMPLETED', 'FAILED', 'AWAITING_MAPPING', name='migrationstatus'), nullable=True),
sa.Column('replace_db', sa.Boolean(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
sa.ForeignKeyConstraint(['source_env_id'], ['environments.id'], ),
sa.ForeignKeyConstraint(['target_env_id'], ['environments.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('resource_mappings',
sa.Column('id', sa.String(), nullable=False),
sa.Column('environment_id', sa.String(), nullable=False),
sa.Column('resource_type', sa.Enum('CHART', 'DATASET', 'DASHBOARD', name='resourcetype'), nullable=False),
sa.Column('uuid', sa.String(), nullable=False),
sa.Column('remote_integer_id', sa.String(), nullable=False),
sa.Column('resource_name', sa.String(), nullable=True),
sa.Column('last_synced_at', sa.DateTime(timezone=True), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
sa.ForeignKeyConstraint(['environment_id'], ['environments.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('translation_job_dictionaries',
sa.Column('id', sa.String(), nullable=False),
sa.Column('job_id', sa.String(), nullable=False),
sa.Column('dictionary_id', sa.String(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['dictionary_id'], ['terminology_dictionaries.id'], ),
sa.ForeignKeyConstraint(['job_id'], ['translation_jobs.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('job_id', 'dictionary_id', name='uq_job_dictionary')
)
op.create_index(op.f('ix_translation_job_dictionaries_dictionary_id'), 'translation_job_dictionaries', ['dictionary_id'], unique=False)
op.create_index(op.f('ix_translation_job_dictionaries_job_id'), 'translation_job_dictionaries', ['job_id'], unique=False)
op.create_table('translation_runs',
sa.Column('id', sa.String(), nullable=False),
sa.Column('job_id', sa.String(), nullable=False),
sa.Column('status', sa.String(), nullable=False),
sa.Column('trigger_type', sa.String(), nullable=True, comment='manual, scheduled, retry, baseline_expired'),
sa.Column('started_at', sa.DateTime(), nullable=True),
sa.Column('completed_at', sa.DateTime(), nullable=True),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('total_records', sa.Integer(), nullable=True),
sa.Column('successful_records', sa.Integer(), nullable=True),
sa.Column('failed_records', sa.Integer(), nullable=True),
sa.Column('skipped_records', sa.Integer(), nullable=True),
sa.Column('insert_status', sa.String(), nullable=True, comment='Status of the Superset insert/update operation'),
sa.Column('superset_execution_id', sa.String(), nullable=True, comment='Superset execution/task ID'),
sa.Column('superset_execution_log', sa.JSON(), nullable=True, comment='Superset execution log output'),
sa.Column('config_snapshot', sa.JSON(), nullable=True, comment='Snapshot of job config at run creation time'),
sa.Column('key_hash', sa.String(), nullable=True, comment='Hash of source key fields for dedup'),
sa.Column('config_hash', sa.String(), nullable=True, comment='Hash of translation configuration state'),
sa.Column('dict_snapshot_hash', sa.String(), nullable=True, comment='Hash of dictionary state at run time'),
sa.Column('created_by', sa.String(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['job_id'], ['translation_jobs.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_translation_runs_job_id'), 'translation_runs', ['job_id'], unique=False)
op.create_table('translation_schedules',
sa.Column('id', sa.String(), nullable=False),
sa.Column('job_id', sa.String(), nullable=False),
sa.Column('cron_expression', sa.String(), nullable=False),
sa.Column('timezone', sa.String(), nullable=False),
sa.Column('is_active', sa.Boolean(), nullable=True),
sa.Column('last_run_at', sa.DateTime(), nullable=True),
sa.Column('next_run_at', sa.DateTime(), nullable=True),
sa.Column('execution_mode', sa.String(), nullable=False, comment='full, new_key_only'),
sa.Column('created_by', sa.String(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['job_id'], ['translation_jobs.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_translation_schedules_job_id'), 'translation_schedules', ['job_id'], unique=False)
op.create_table('translation_batches',
sa.Column('id', sa.String(), nullable=False),
sa.Column('run_id', sa.String(), nullable=False),
sa.Column('batch_index', sa.Integer(), nullable=False),
sa.Column('status', sa.String(), nullable=False),
sa.Column('total_records', sa.Integer(), nullable=True),
sa.Column('successful_records', sa.Integer(), nullable=True),
sa.Column('failed_records', sa.Integer(), nullable=True),
sa.Column('started_at', sa.DateTime(), nullable=True),
sa.Column('completed_at', sa.DateTime(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['run_id'], ['translation_runs.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_translation_batches_run_id'), 'translation_batches', ['run_id'], unique=False)
op.create_table('translation_events',
sa.Column('id', sa.String(), nullable=False),
sa.Column('job_id', sa.String(), nullable=False),
sa.Column('run_id', sa.String(), nullable=True),
sa.Column('event_type', sa.String(), nullable=False),
sa.Column('event_data', sa.JSON(), nullable=True),
sa.Column('created_by', sa.String(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['job_id'], ['translation_jobs.id'], ),
sa.ForeignKeyConstraint(['run_id'], ['translation_runs.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_translation_events_job_id'), 'translation_events', ['job_id'], unique=False)
op.create_index(op.f('ix_translation_events_run_id'), 'translation_events', ['run_id'], unique=False)
op.create_table('translation_metric_snapshots',
sa.Column('id', sa.String(), nullable=False),
sa.Column('job_id', sa.String(), nullable=False),
sa.Column('run_id', sa.String(), nullable=True),
sa.Column('key_hash', sa.String(), nullable=False, comment='Hash of dimension key fields for aggregation'),
sa.Column('config_hash', sa.String(), nullable=True, comment='Hash of translation configuration state'),
sa.Column('dict_snapshot_hash', sa.String(), nullable=True, comment='Hash of dictionary state at capture time'),
sa.Column('covers_events_before', sa.DateTime(), nullable=True, comment='Indicates snapshot covers events before this timestamp'),
sa.Column('total_jobs', sa.Integer(), nullable=True),
sa.Column('total_runs', sa.Integer(), nullable=True),
sa.Column('total_records', sa.Integer(), nullable=True),
sa.Column('successful_records', sa.Integer(), nullable=True),
sa.Column('failed_records', sa.Integer(), nullable=True),
sa.Column('skipped_records', sa.Integer(), nullable=True),
sa.Column('avg_duration_ms', sa.Integer(), nullable=True),
sa.Column('p50_duration_ms', sa.Integer(), nullable=True),
sa.Column('p95_duration_ms', sa.Integer(), nullable=True),
sa.Column('p99_duration_ms', sa.Integer(), nullable=True),
sa.Column('snapshot_date', sa.DateTime(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['job_id'], ['translation_jobs.id'], ),
sa.ForeignKeyConstraint(['run_id'], ['translation_runs.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_metric_snapshots_job_date', 'translation_metric_snapshots', ['job_id', 'snapshot_date'], unique=False)
op.create_index(op.f('ix_translation_metric_snapshots_job_id'), 'translation_metric_snapshots', ['job_id'], unique=False)
op.create_index(op.f('ix_translation_metric_snapshots_run_id'), 'translation_metric_snapshots', ['run_id'], unique=False)
op.create_table('translation_preview_sessions',
sa.Column('id', sa.String(), nullable=False),
sa.Column('job_id', sa.String(), nullable=False),
sa.Column('run_id', sa.String(), nullable=True),
sa.Column('status', sa.String(), nullable=False),
sa.Column('created_by', sa.String(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('expires_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['job_id'], ['translation_jobs.id'], ),
sa.ForeignKeyConstraint(['run_id'], ['translation_runs.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_translation_preview_sessions_job_id'), 'translation_preview_sessions', ['job_id'], unique=False)
op.create_table('translation_run_language_stats',
sa.Column('id', sa.String(), nullable=False),
sa.Column('run_id', sa.String(), nullable=False),
sa.Column('language_code', sa.String(), nullable=False, comment='BCP-47 language code'),
sa.Column('total_rows', sa.Integer(), nullable=True),
sa.Column('translated_rows', sa.Integer(), nullable=True),
sa.Column('failed_rows', sa.Integer(), nullable=True),
sa.Column('skipped_rows', sa.Integer(), nullable=True),
sa.Column('token_count', sa.Integer(), nullable=True),
sa.Column('estimated_cost', sa.Float(), nullable=True),
sa.ForeignKeyConstraint(['run_id'], ['translation_runs.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('run_id', 'language_code', name='uq_run_language')
)
op.create_index('idx_rls_run', 'translation_run_language_stats', ['run_id'], unique=False)
op.create_table('translation_preview_records',
sa.Column('id', sa.String(), nullable=False),
sa.Column('session_id', sa.String(), nullable=False),
sa.Column('source_sql', sa.Text(), nullable=True),
sa.Column('target_sql', sa.Text(), nullable=True),
sa.Column('source_object_type', sa.String(), nullable=True),
sa.Column('source_object_id', sa.String(), nullable=True),
sa.Column('source_object_name', sa.String(), nullable=True),
sa.Column('source_data', sa.JSON(), nullable=True, comment='Original source row key columns for upsert matching'),
sa.Column('status', sa.String(), nullable=False),
sa.Column('feedback', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['session_id'], ['translation_preview_sessions.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_translation_preview_records_session_id'), 'translation_preview_records', ['session_id'], unique=False)
op.create_table('translation_records',
sa.Column('id', sa.String(), nullable=False),
sa.Column('batch_id', sa.String(), nullable=False),
sa.Column('run_id', sa.String(), nullable=False),
sa.Column('source_sql', sa.Text(), nullable=True),
sa.Column('target_sql', sa.Text(), nullable=True),
sa.Column('source_object_type', sa.String(), nullable=True),
sa.Column('source_object_id', sa.String(), nullable=True),
sa.Column('source_object_name', sa.String(), nullable=True),
sa.Column('source_data', sa.JSON(), nullable=True, comment='Original source row key columns for upsert matching'),
sa.Column('status', sa.String(), nullable=False),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('token_count_input', sa.Integer(), nullable=True),
sa.Column('token_count_output', sa.Integer(), nullable=True),
sa.Column('translation_duration_ms', sa.Integer(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('llm_translation', sa.Text(), nullable=True, comment='[DEPRECATED: use TranslationLanguage]'),
sa.Column('user_edit', sa.Text(), nullable=True, comment='[DEPRECATED: use TranslationLanguage]'),
sa.Column('final_value', sa.Text(), nullable=True, comment='[DEPRECATED: use TranslationLanguage]'),
sa.ForeignKeyConstraint(['batch_id'], ['translation_batches.id'], ),
sa.ForeignKeyConstraint(['run_id'], ['translation_runs.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_translation_records_batch_id'), 'translation_records', ['batch_id'], unique=False)
op.create_index(op.f('ix_translation_records_run_id'), 'translation_records', ['run_id'], unique=False)
op.create_index('ix_translation_records_run_status', 'translation_records', ['run_id', 'status'], unique=False)
op.create_table('translation_languages',
sa.Column('id', sa.String(), nullable=False),
sa.Column('record_id', sa.String(), nullable=False),
sa.Column('language_code', sa.String(), nullable=False, comment='BCP-47 language code'),
sa.Column('source_language_detected', sa.String(), nullable=True, comment="BCP-47 or 'und' for undetermined"),
sa.Column('translated_value', sa.Text(), nullable=True, comment='LLM-generated translation'),
sa.Column('user_edit', sa.Text(), nullable=True, comment='User-edited translation'),
sa.Column('final_value', sa.Text(), nullable=True, comment='Final resolved value (translated or user edit)'),
sa.Column('status', sa.String(), nullable=True, comment='pending|translated|approved|edited|rejected|failed|skipped'),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['record_id'], ['translation_records.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('record_id', 'language_code', name='uq_record_language')
)
op.create_index('idx_tl_language', 'translation_languages', ['language_code'], unique=False)
op.create_index('idx_tl_record_lang', 'translation_languages', ['record_id', 'language_code'], unique=False)
op.create_table('translation_preview_languages',
sa.Column('id', sa.String(), nullable=False),
sa.Column('preview_record_id', sa.String(), nullable=False),
sa.Column('language_code', sa.String(), nullable=False, comment='BCP-47 language code'),
sa.Column('source_language_detected', sa.String(), nullable=True, comment="BCP-47 or 'und'"),
sa.Column('translated_value', sa.Text(), nullable=True),
sa.Column('user_edit', sa.Text(), nullable=True),
sa.Column('final_value', sa.Text(), nullable=True),
sa.Column('status', sa.String(), nullable=True, comment='pending|approved|edited|rejected'),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['preview_record_id'], ['translation_preview_records.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('preview_record_id', 'language_code', name='uq_preview_record_language')
)
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('translation_preview_languages')
op.drop_index('idx_tl_record_lang', table_name='translation_languages')
op.drop_index('idx_tl_language', table_name='translation_languages')
op.drop_table('translation_languages')
op.drop_index('ix_translation_records_run_status', table_name='translation_records')
op.drop_index(op.f('ix_translation_records_run_id'), table_name='translation_records')
op.drop_index(op.f('ix_translation_records_batch_id'), table_name='translation_records')
op.drop_table('translation_records')
op.drop_index(op.f('ix_translation_preview_records_session_id'), table_name='translation_preview_records')
op.drop_table('translation_preview_records')
op.drop_index('idx_rls_run', table_name='translation_run_language_stats')
op.drop_table('translation_run_language_stats')
op.drop_index(op.f('ix_translation_preview_sessions_job_id'), table_name='translation_preview_sessions')
op.drop_table('translation_preview_sessions')
op.drop_index(op.f('ix_translation_metric_snapshots_run_id'), table_name='translation_metric_snapshots')
op.drop_index(op.f('ix_translation_metric_snapshots_job_id'), table_name='translation_metric_snapshots')
op.drop_index('ix_metric_snapshots_job_date', table_name='translation_metric_snapshots')
op.drop_table('translation_metric_snapshots')
op.drop_index(op.f('ix_translation_events_run_id'), table_name='translation_events')
op.drop_index(op.f('ix_translation_events_job_id'), table_name='translation_events')
op.drop_table('translation_events')
op.drop_index(op.f('ix_translation_batches_run_id'), table_name='translation_batches')
op.drop_table('translation_batches')
op.drop_index(op.f('ix_translation_schedules_job_id'), table_name='translation_schedules')
op.drop_table('translation_schedules')
op.drop_index(op.f('ix_translation_runs_job_id'), table_name='translation_runs')
op.drop_table('translation_runs')
op.drop_index(op.f('ix_translation_job_dictionaries_job_id'), table_name='translation_job_dictionaries')
op.drop_index(op.f('ix_translation_job_dictionaries_dictionary_id'), table_name='translation_job_dictionaries')
op.drop_table('translation_job_dictionaries')
op.drop_table('resource_mappings')
op.drop_table('migration_jobs')
op.drop_index(op.f('ix_dictionary_entries_dictionary_id'), table_name='dictionary_entries')
op.drop_index('idx_dict_has_context', table_name='dictionary_entries')
op.drop_index('idx_dict_entry_lang', table_name='dictionary_entries')
op.drop_table('dictionary_entries')
op.drop_table('database_mappings')
op.drop_table('translation_jobs')
op.drop_table('terminology_dictionaries')
op.drop_table('environments')
# ### end Alembic commands ###