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.
393 lines
25 KiB
Python
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 ###
|