"""SQLite 数据库结构和迁移定义。 每个版本对应一组按顺序执行的 SQL。新增数据库版本时,只能在 ``MIGRATIONS`` 末尾增加版本,不能修改已经发布的迁移。 """ SCHEMA_VERSION = 5 MIGRATION_1 = ( """ CREATE TABLE pdd_tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, remote_task_id TEXT NOT NULL UNIQUE, task_type TEXT NOT NULL CHECK (task_type IN ('collect', 'purchase')), goods_id TEXT, goods_url TEXT NOT NULL, title TEXT, target_color TEXT, target_size TEXT, price_cent INTEGER CHECK (price_cent IS NULL OR price_cent >= 0), quantity INTEGER CHECK (quantity IS NULL OR quantity > 0), status TEXT NOT NULL DEFAULT 'claimed' CHECK (status IN ( 'claimed', 'running', 'result_pending', 'retry_wait', 'manual_review', 'succeeded', 'failed', 'cancelled' )), current_step TEXT, priority INTEGER NOT NULL DEFAULT 0, version INTEGER NOT NULL DEFAULT 1 CHECK (version > 0), admin_payload TEXT NOT NULL DEFAULT '{}', pdd_data TEXT, retry_count INTEGER NOT NULL DEFAULT 0 CHECK (retry_count >= 0), last_error_code TEXT, last_error_message TEXT, received_at TEXT NOT NULL, started_at TEXT, finished_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ) """, """ CREATE INDEX idx_pdd_tasks_list ON pdd_tasks(updated_at DESC, id DESC) """, """ CREATE INDEX idx_pdd_tasks_status_type ON pdd_tasks(status, task_type) """, """ CREATE INDEX idx_pdd_tasks_goods_id ON pdd_tasks(goods_id) """, """ CREATE TABLE task_runs ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL, attempt_id TEXT NOT NULL UNIQUE, attempt_no INTEGER NOT NULL CHECK (attempt_no > 0), device_address TEXT NOT NULL, run_status TEXT NOT NULL CHECK (run_status IN ( 'running', 'succeeded', 'failed', 'cancelled', 'manual_review' )), current_step TEXT, started_at TEXT NOT NULL, finished_at TEXT, irreversible_action_at TEXT, order_submitted_at TEXT, error_code TEXT, error_message TEXT, diagnostics_json TEXT, artifact_directory TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (task_id) REFERENCES pdd_tasks(id) ON DELETE CASCADE, UNIQUE (task_id, attempt_no) ) """, """ CREATE INDEX idx_task_runs_task ON task_runs(task_id, attempt_no DESC) """, """ CREATE TABLE outbox_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL, event_type TEXT NOT NULL CHECK (event_type IN ( 'collect_result', 'purchase_result', 'task_failure' )), idempotency_key TEXT NOT NULL UNIQUE, payload_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ( 'pending', 'sending', 'sent', 'failed' )), attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0), next_retry_at TEXT, last_error TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, sent_at TEXT, FOREIGN KEY (task_id) REFERENCES pdd_tasks(id) ON DELETE CASCADE ) """, """ CREATE INDEX idx_outbox_pending ON outbox_events(status, next_retry_at, id) """, """ CREATE TABLE app_settings ( setting_key TEXT PRIMARY KEY, value_json TEXT NOT NULL, updated_at TEXT NOT NULL ) """, ) MIGRATION_2 = ( """ ALTER TABLE task_runs ADD COLUMN result_data TEXT """, ) MIGRATION_3 = ( """ ALTER TABLE pdd_tasks ADD COLUMN execution_mode TEXT NOT NULL DEFAULT 'dry_run' CHECK (execution_mode IN ('dry_run', 'live')) """, ) MIGRATION_4 = ( """ ALTER TABLE pdd_tasks ADD COLUMN removed_at TEXT """, """ CREATE INDEX idx_pdd_tasks_visible_list ON pdd_tasks(removed_at, updated_at DESC, id DESC) """, ) MIGRATION_5 = ( "ALTER TABLE pdd_tasks ADD COLUMN shop_name TEXT", """ UPDATE pdd_tasks SET shop_name = TRIM(json_extract(pdd_data, '$.shop_name')) WHERE pdd_data IS NOT NULL AND json_valid(pdd_data) AND json_type(pdd_data, '$.shop_name') = 'text' AND TRIM(json_extract(pdd_data, '$.shop_name')) <> '' """, ) MIGRATIONS = { 1: MIGRATION_1, 2: MIGRATION_2, 3: MIGRATION_3, 4: MIGRATION_4, 5: MIGRATION_5, }