import argparse import os import sqlite3 from typing import Dict, Any, List, Optional def find_col(columns: List[str], candidates: List[str]) -> Optional[str]: lowered = {c.lower(): c for c in columns} for name in candidates: if name.lower() in lowered: return lowered[name.lower()] return None def main() -> None: parser = argparse.ArgumentParser(description="Import fault codes into local data.db from external SQLite table") parser.add_argument("--src-db", default="fault_codes.db", help="source sqlite file path") parser.add_argument("--src-table", default="fault_code_list", help="source table name") parser.add_argument("--manufacturer", default="woojin", help="manufacturer slug (woojin|rotem)") parser.add_argument("--default-section", default="fault", help="default section if missing (fault|tcms|emergency)") parser.add_argument("--truncate", action="store_true", help="delete existing faults for manufacturer before import") args = parser.parse_args() # destination DB (our app) try: from app import DATABASE_PATH # type: ignore except Exception: DATABASE_PATH = os.path.join(os.path.dirname(__file__), "..", "data.db") dest_path = os.path.abspath(DATABASE_PATH) src_path = os.path.abspath(args.src_db) if not os.path.exists(src_path): raise SystemExit(f"Source DB not found: {src_path}") src = sqlite3.connect(src_path) src.row_factory = sqlite3.Row dst = sqlite3.connect(dest_path) dst.row_factory = sqlite3.Row dst.execute("PRAGMA foreign_keys = ON") cur = src.execute(f"SELECT * FROM {args.src_table}") rows = cur.fetchall() if not rows: print("No rows in source table.") return columns = rows[0].keys() code_col = find_col(columns, ["code", "Code", "fault_code", "고장코드", "CODE"]) or "code" title_col = find_col(columns, ["title", "name", "f.Name", "f_name", "고장명", "fName"]) or None details_col = find_col(columns, ["details", "detail", "고장상세", "desc", "설명"]) # optional action_col = find_col(columns, ["action", "조치", "응급조치", "response", "반응"]) # optional cond_col = find_col(columns, ["condition", "검지조건", "조건"]) # optional category_col = find_col(columns, ["category", "cat", "장치분류", "system", "type"]) # optional section_col = find_col(columns, ["section", "섹션", "tab", "kind"]) # optional print("Column mapping:") print(" code ->", code_col) print(" title ->", title_col) print(" details ->", details_col) print(" action ->", action_col) print(" condition ->", cond_col) print(" category ->", category_col) print(" section ->", section_col, f"(default={args.default_section})") # manufacturer ensure m = dst.execute("SELECT id FROM manufacturer WHERE slug=?", (args.manufacturer.lower(),)).fetchone() if not m: name = "우진" if args.manufacturer.lower() == "woojin" else "로템" dst.execute("INSERT INTO manufacturer (slug, name) VALUES (?, ?)", (args.manufacturer.lower(), name)) m_id = dst.execute("SELECT last_insert_rowid() AS id").fetchone()[0] else: m_id = m["id"] if args.truncate: dst.execute("DELETE FROM fault WHERE manufacturer_id=?", (m_id,)) dst.execute("DELETE FROM category WHERE manufacturer_id=?", (m_id,)) # existing categories map cat_map: Dict[str, int] = {} for r in dst.execute("SELECT id, name FROM category WHERE manufacturer_id=?", (m_id,)): cat_map[r["name"]] = r["id"] def ensure_category(name: Optional[str]) -> Optional[int]: if not name: return None name = str(name).strip() if name == "": return None if name in cat_map: return cat_map[name] dst.execute("INSERT INTO category (manufacturer_id, name) VALUES (?, ?)", (m_id, name)) cid = dst.execute("SELECT last_insert_rowid() AS id").fetchone()[0] cat_map[name] = cid return cid def get_value(r: sqlite3.Row, key: Optional[str]): if not key: return None for k in r.keys(): if k.lower() == key.lower(): return r[k] return None batch: List[tuple] = [] for row in rows: code = str(get_value(row, code_col) or "").strip() title = str(get_value(row, title_col) or "").strip() details = str(get_value(row, details_col) or "").strip() action = str(get_value(row, action_col) or "").strip() cond = str(get_value(row, cond_col) or "").strip() category_val = get_value(row, category_col) category_val = (str(category_val).strip() if category_val is not None else None) section_val = get_value(row, section_col) section = (str(section_val).strip().lower() if section_val is not None else args.default_section) if section not in ("fault", "tcms", "emergency"): section = args.default_section cat_id = ensure_category(category_val) batch.append((m_id, cat_id, section, code, title, details, action, cond)) dst.executemany( "INSERT INTO fault (manufacturer_id, category_id, section, code, title, details, action, condition) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", batch, ) # bump meta version dst.execute("UPDATE meta SET version = version + 1, updated_at = datetime('now') WHERE id = 1") if dst.total_changes == 0: dst.execute("INSERT OR REPLACE INTO meta (id, version, updated_at) VALUES (1, 1, datetime('now'))") dst.commit() src.close() dst.close() print(f"Imported {len(batch)} rows into {dest_path} for manufacturer '{args.manufacturer.lower()}'.") if __name__ == "__main__": main()