"""市場情報平台種子資料寫入 dry-run 規劃。 本模組只建立 upsert preview 與 schema smoke 結果,不執行資料庫寫入。 """ import json from database.manager import Base MARKET_PLATFORM_REQUIRED_COLUMNS = ( "code", "name", "base_url", "enabled", "crawl_policy_json", ) def build_schema_smoke(expected_tables, metadata=None): """檢查 ORM metadata 是否具備 market_* 表與 platform upsert 必要欄位。""" metadata = metadata or Base.metadata metadata_tables = metadata.tables table_names = set(metadata_tables) missing_tables = [ table_name for table_name in expected_tables if table_name not in table_names ] market_platform = metadata_tables.get("market_platforms") platform_columns = ( set(market_platform.columns.keys()) if market_platform is not None else set() ) missing_platform_columns = [ column_name for column_name in MARKET_PLATFORM_REQUIRED_COLUMNS if column_name not in platform_columns ] return { "passed": not missing_tables and not missing_platform_columns, "expected_table_count": len(expected_tables), "metadata_table_count": len(table_names), "missing_tables": missing_tables, "market_platform_required_columns": list(MARKET_PLATFORM_REQUIRED_COLUMNS), "missing_market_platform_columns": missing_platform_columns, } def build_platform_seed_writer_plan(seed_plan, write_guard, schema_smoke): """建立 market_platforms upsert dry-run plan,不建立 session、不 commit。""" operations = [] for seed in seed_plan.get("seeds", []): operations.append( { "operation": "upsert", "table": "market_platforms", "lookup": {"code": seed["code"]}, "values": { "code": seed["code"], "name": seed["name"], "base_url": seed["base_url"], "enabled": False, "crawl_policy_json": json.dumps( seed["crawl_policy_json"], ensure_ascii=False, sort_keys=True, ), }, "sql_shape": ( "INSERT INTO market_platforms (...) VALUES (...) " "ON CONFLICT(code) DO UPDATE SET ..." ), "write_status": "blocked_dry_run_only", } ) return { "mode": "dry_run", "operation_count": len(operations), "operations": operations, "schema_smoke": schema_smoke, "ready_to_write": False, "writes_executed": False, "would_write_database": False, "database_write_allowed": bool(write_guard.get("database_write_allowed")), "blocked_reasons": write_guard.get("blocked_reasons", []), "write_action": "preview_only_no_session_no_commit", }