"""P0-03: Prediction 幂等指纹——移除旧唯一约束,改为 partial unique on input_hash input_hash 非空时唯一(同指纹返回已有行,不 UPDATE/INSERT); 兼容旧数据 NULL input_hash(不强制回填)。 Revision ID: 0024_prediction_idempotent_fingerprint Revises: 0023_standings_append_only Create Date: 2026-09-22 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa revision: str = '0024_prediction_idempotent_fingerprint' down_revision: Union[str, None] = '0023_standings_append_only' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # 移除旧唯一约束(match, provider, model, mode, run_type) op.drop_constraint( 'uq_predictions_match_provider_model_mode_run_type', 'predictions', type_unique=True, ) # P0-03: partial unique on input_hash(非空时唯一) op.create_index( 'ix_predictions_input_hash_unique', 'predictions', ['input_hash'], unique=True, postgresql_where=sa.text('input_hash IS NOT NULL'), ) def downgrade() -> None: op.drop_index('ix_predictions_input_hash_unique', table_name='predictions') op.create_unique_constraint( 'uq_predictions_match_provider_model_mode_run_type', 'predictions', ['match_id', 'provider', 'model', 'mode', 'run_type'], )