o2o-site-AEO/solution/backend/scripts/migrate.py
Mina Choi 11d30bb3d1 [chore] solution,admin,ontology: 코드 주석을 한 줄로 — 히스토리 주석 삭제
여러 줄 주석이 설명보다 경위(예전·실측·지적)를 적고 있어 읽는 사람이 결론을 찾기 어려웠다.

- ts·tsx·js·mjs·css·py 478개: 여러 줄 주석은 첫 문장 한 줄로, 과거형·날짜 문장은 삭제
- 주석 위치는 TypeScript 파서·파이썬 tokenize/ast 로 찾는다 — 문자열 안의 # · /* 는 건드리지 않는다
- eslint·ts·noqa·type: ignore 같은 지시 주석은 그대로 둔다

파이썬 275개 정리 전후 AST 동일, TS 298개 주석 뺀 토큰 동일(빈 JSX 주석 10곳만 차이).
site·frontend·admin tsc, site vitest 105 passed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 16:05:19 +09:00

87 lines
3.2 KiB
Python

"""스키마 마이그레이션 — 이미 만들어진 DB 를 init.sql 최신으로 끌어올린다."""
import argparse
import asyncio
import os
import sys
from pathlib import Path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.environ.setdefault("APP_ENV", "local")
from sqlalchemy import text # noqa: E402
from common.database.db_session_manager import DB_SESSION_MNG # noqa: E402
from common.enums import DBWRType # noqa: E402
from common.database.model.models import places # noqa: E402
# parents[3] = 레포 루트 (scripts → backend → solution → 루트).
MIGRATIONS_DIR = Path(__file__).resolve().parents[3] / "postgres-init" / "migrations"
_LEDGER_DDL = """
CREATE TABLE IF NOT EXISTS public.schema_migrations (
version VARCHAR(255) PRIMARY KEY,
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
)
"""
def pending(applied: set[str]) -> list[Path]:
"""아직 안 돌린 파일."""
files = sorted(p for p in MIGRATIONS_DIR.glob("*.sql"))
return [p for p in files if p.stem not in applied]
async def main(dry_run: bool) -> int:
if not MIGRATIONS_DIR.is_dir():
print(f"마이그레이션 폴더가 없습니다: {MIGRATIONS_DIR}")
return 1
db = await DB_SESSION_MNG.start_session(places.DBType(), DBWRType.DB_WRITE.value)
try:
await db.execute(text(_LEDGER_DDL))
await db.commit()
rows = await db.execute(text("SELECT version FROM public.schema_migrations"))
applied = {r[0] for r in rows}
todo = pending(applied)
if not todo:
print(f"적용할 마이그레이션이 없습니다 (적용됨 {len(applied)}건)")
return 0
print(f"적용 대상 {len(todo)}건:")
for path in todo:
print(f" {path.stem}")
if dry_run:
print("\n--dry-run — 아무것도 적용하지 않았습니다.")
return 0
for path in todo:
sql = path.read_text(encoding="utf-8")
print(f"\n▶ {path.stem}")
try:
# 파일 하나를 한 트랜잭션으로 돌린다 — 중간에 실패하면 그 파일은 통째로 되돌아간다.
raw = await (await db.connection()).get_raw_connection()
await raw.driver_connection.execute(sql)
await db.execute(
text("INSERT INTO public.schema_migrations (version) VALUES (:v)"),
{"v": path.stem},
)
await db.commit()
print(" 적용됨")
except Exception as ex:
await db.rollback()
print(f" 실패 — {ex}")
print(" ★ 여기서 멈춥니다. 뒤 파일은 돌리지 않습니다(순서가 뜻을 갖는다).")
return 1
print(f"\n완료 — {len(todo)}건 적용")
return 0
finally:
await DB_SESSION_MNG.end_session(places.DBType(), DBWRType.DB_WRITE.value)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--dry-run", action="store_true", help="적용하지 않고 대상만 출력")
args = parser.parse_args()
raise SystemExit(asyncio.run(main(args.dry_run)))