132 lines
3.9 KiB
Python
132 lines
3.9 KiB
Python
"""
|
|
i18n JSONB Migration Script (Phase 1)
|
|
Migrates old name_hu/name_en columns to name_i18n JSONB format.
|
|
Run INSIDE the sf_api container:
|
|
docker exec sf_api python3 /app/backend/app/scripts/migrate_i18n_jsonb.py
|
|
|
|
IMPORTANT: Run this AFTER the new JSONB columns have been added by sync_engine.
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
from sqlalchemy import text
|
|
from app.db.session import AsyncSessionLocal
|
|
|
|
TABLES = [
|
|
{
|
|
"schema": "marketplace",
|
|
"table": "expertise_tags",
|
|
"name_cols": ["name_hu", "name_en"],
|
|
"name_translations_col": "name_translations",
|
|
"desc_cols": ["description"],
|
|
"target_name_col": "name_i18n",
|
|
"target_desc_col": "description_i18n",
|
|
},
|
|
{
|
|
"schema": "vehicle",
|
|
"table": "dict_body_types",
|
|
"name_cols": ["name_hu"],
|
|
"name_translations_col": None,
|
|
"desc_cols": [],
|
|
"target_name_col": "name_i18n",
|
|
"target_desc_col": None,
|
|
},
|
|
{
|
|
"schema": "system",
|
|
"table": "service_catalog",
|
|
"name_cols": ["name"],
|
|
"name_translations_col": None,
|
|
"desc_cols": ["description"],
|
|
"target_name_col": "name_i18n",
|
|
"target_desc_col": "description_i18n",
|
|
},
|
|
]
|
|
|
|
|
|
async def migrate_table(config: dict):
|
|
schema = config["schema"]
|
|
table = config["table"]
|
|
target_name = config["target_name_col"]
|
|
target_desc = config["target_desc_col"]
|
|
name_cols = config["name_cols"]
|
|
desc_cols = config["desc_cols"]
|
|
trans_col = config["name_translations_col"]
|
|
|
|
print(f"\n{'='*60}")
|
|
print(f" Migrating: {schema}.{table}")
|
|
print(f"{'='*60}")
|
|
|
|
async with AsyncSessionLocal() as db:
|
|
select_cols = ["id"] + name_cols + desc_cols
|
|
if trans_col:
|
|
select_cols.append(trans_col)
|
|
|
|
stmt = text(
|
|
f"SELECT {', '.join(select_cols)} FROM {schema}.{table} "
|
|
f"WHERE {target_name} IS NULL OR {target_name} = '{{\"hu\": \"\"}}'::jsonb"
|
|
)
|
|
result = await db.execute(stmt)
|
|
rows = result.fetchall()
|
|
|
|
if not rows:
|
|
print(f" ✅ No rows need migration in {schema}.{table}")
|
|
return
|
|
|
|
updated = 0
|
|
for row in rows:
|
|
row_dict = row._mapping
|
|
|
|
# Build name_i18n
|
|
name_i18n = {}
|
|
if len(name_cols) >= 1 and row_dict.get(name_cols[0]):
|
|
name_i18n["hu"] = row_dict[name_cols[0]]
|
|
if len(name_cols) >= 2 and row_dict.get(name_cols[1]):
|
|
name_i18n["en"] = row_dict[name_cols[1]]
|
|
|
|
# Merge with existing name_translations
|
|
if trans_col and row_dict.get(trans_col):
|
|
if isinstance(row_dict[trans_col], dict):
|
|
name_i18n.update(row_dict[trans_col])
|
|
|
|
# Build description_i18n
|
|
desc_i18n = None
|
|
if desc_cols and row_dict.get(desc_cols[0]):
|
|
desc_i18n = {"hu": row_dict[desc_cols[0]]}
|
|
|
|
# Update
|
|
update_cols = [f"{target_name} = :name_val"]
|
|
params = {"name_val": json.dumps(name_i18n), "row_id": row_dict["id"]}
|
|
|
|
if target_desc and desc_i18n:
|
|
update_cols.append(f"{target_desc} = :desc_val")
|
|
params["desc_val"] = json.dumps(desc_i18n)
|
|
|
|
update_sql = f"UPDATE {schema}.{table} SET {', '.join(update_cols)} WHERE id = :row_id"
|
|
await db.execute(text(update_sql), params)
|
|
updated += 1
|
|
|
|
await db.commit()
|
|
print(f" ✅ Migrated {updated} rows in {schema}.{table}")
|
|
|
|
|
|
async def main():
|
|
print("=" * 70)
|
|
print(" i18n JSONB Migration Script (Phase 1)")
|
|
print("=" * 70)
|
|
|
|
for table_config in TABLES:
|
|
await migrate_table(table_config)
|
|
|
|
print("\n" + "=" * 70)
|
|
print(" ✅ Migration complete!")
|
|
print("=" * 70)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|