feat(pos): add tenant migration runner
This commit is contained in:
98
pos/migrations/runner.py
Executable file
98
pos/migrations/runner.py
Executable file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
# /home/Autopartes/pos/migrations/runner.py
|
||||
"""Apply schema migrations to all tenant databases."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from tenant_db import get_master_conn, get_tenant_conn_by_dbname
|
||||
|
||||
MIGRATIONS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Migration registry: version -> filename
|
||||
MIGRATIONS = {
|
||||
'v1.0': 'v1.0_initial.sql',
|
||||
# Future: 'v1.1': 'v1.1_add_xyz.sql',
|
||||
}
|
||||
|
||||
|
||||
def get_all_tenants():
|
||||
"""Get all tenants with their current schema version."""
|
||||
conn = get_master_conn()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT t.id, t.db_name, t.name, COALESCE(v.version, 'v0.0') as version
|
||||
FROM tenants t
|
||||
LEFT JOIN tenant_schema_version v ON t.id = v.tenant_id
|
||||
WHERE t.is_active = true
|
||||
""")
|
||||
tenants = cur.fetchall()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return tenants
|
||||
|
||||
|
||||
def apply_migration(db_name, version):
|
||||
"""Apply a single migration to a tenant DB."""
|
||||
filename = MIGRATIONS[version]
|
||||
filepath = os.path.join(MIGRATIONS_DIR, filename)
|
||||
|
||||
if not os.path.exists(filepath):
|
||||
print(f" ERROR: Migration file not found: {filepath}")
|
||||
return False
|
||||
|
||||
conn = get_tenant_conn_by_dbname(db_name)
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
with open(filepath) as f:
|
||||
cur.execute(f.read())
|
||||
conn.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
print(f" ERROR: {e}")
|
||||
return False
|
||||
finally:
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
|
||||
def run_migrations():
|
||||
"""Apply pending migrations to all tenants."""
|
||||
tenants = get_all_tenants()
|
||||
sorted_versions = sorted(MIGRATIONS.keys())
|
||||
|
||||
print(f"Found {len(tenants)} active tenants")
|
||||
print(f"Available migrations: {sorted_versions}")
|
||||
|
||||
for tenant_id, db_name, name, current_version in tenants:
|
||||
print(f"\n[{name}] (db={db_name}, current={current_version})")
|
||||
|
||||
for version in sorted_versions:
|
||||
if version <= current_version:
|
||||
continue
|
||||
|
||||
print(f" Applying {version}...", end=' ')
|
||||
if apply_migration(db_name, version):
|
||||
# Update version in master
|
||||
master_conn = get_master_conn()
|
||||
master_cur = master_conn.cursor()
|
||||
master_cur.execute("""
|
||||
INSERT INTO tenant_schema_version (tenant_id, version)
|
||||
VALUES (%s, %s)
|
||||
ON CONFLICT (tenant_id) DO UPDATE SET version = %s, updated_at = NOW()
|
||||
""", (tenant_id, version, version))
|
||||
master_conn.commit()
|
||||
master_cur.close()
|
||||
master_conn.close()
|
||||
print("OK")
|
||||
else:
|
||||
print("FAILED — stopping migrations for this tenant")
|
||||
break
|
||||
|
||||
print("\nDone.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_migrations()
|
||||
Reference in New Issue
Block a user