Add idempotent additive schema upgrader

This commit is contained in:
jessikitty committed 2026-09-25 00:44:00 +10:00
1 parent 8d5cccc4e3
commit 19a2d7ad9e
1 file changed
+58
+58
View File
@@ -0,0 +1,58 @@
"""
Lightweight, idempotent schema top-ups.
`db.create_all()` creates missing tables but never alters existing ones, so a
new column on an existing table needs help. This adds only what's missing and
is safe to run on every boot, on both SQLite and Postgres.
It is not a replacement for real migrations — it handles additive column
changes, which is all LIM has needed so far.
Created by: Jess Rogerson (yelling commands at Claude.AI)
"""
from sqlalchemy import inspect, text
from app import db
# table -> column -> DDL fragment used in ALTER TABLE ... ADD COLUMN
ADDITIVE_COLUMNS = {
'sets': {
# Existing rows keep the behaviour they had before visibility existed:
# everyone could see every set, so they become 'public' rather than
# silently vanishing from other users' libraries. New sets use the
# site default instead.
'visibility': "VARCHAR(10) NOT NULL DEFAULT 'public'",
},
}
def ensure_schema(app):
"""Add any missing columns. Returns a list of changes made."""
applied = []
with app.app_context():
try:
inspector = inspect(db.engine)
existing_tables = set(inspector.get_table_names())
except Exception as exc: # database not reachable yet
app.logger.warning('Schema check skipped: %s', exc)
return applied
for table, columns in ADDITIVE_COLUMNS.items():
if table not in existing_tables:
continue # create_all() will build it with everything present
present = {c['name'] for c in inspector.get_columns(table)}
for column, ddl in columns.items():
if column in present:
continue
statement = f'ALTER TABLE {table} ADD COLUMN {column} {ddl}'
try:
with db.engine.begin() as conn:
conn.execute(text(statement))
applied.append(f'{table}.{column}')
app.logger.info('Schema upgrade: added %s.%s', table, column)
except Exception as exc:
app.logger.error('Schema upgrade failed for %s.%s: %s',
table, column, exc)
return applied