fix(db): make migrations and glossary index SQLite-compatible
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m57s

This commit is contained in:
2026-06-14 19:01:07 +02:00
parent cb8ce697d2
commit adc3583358
6 changed files with 93 additions and 35 deletions

View File

@@ -21,11 +21,14 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.add_column("users", sa.Column("reset_token", sa.String(length=255), nullable=True))
op.add_column("users", sa.Column("reset_token_expires", sa.DateTime(), nullable=True))
# Make legacy password_hash column nullable (ORM uses hashed_password now)
op.alter_column("users", "password_hash", nullable=True)
# Make legacy password_hash column nullable (ORM uses hashed_password now).
# Use batch_alter_table for SQLite compatibility.
with op.batch_alter_table("users") as batch_op:
batch_op.alter_column("password_hash", nullable=True)
def downgrade() -> None:
op.drop_column("users", "reset_token_expires")
op.drop_column("users", "reset_token")
op.alter_column("users", "password_hash", nullable=False)
with op.batch_alter_table("users") as batch_op:
batch_op.drop_column("reset_token_expires")
batch_op.drop_column("reset_token")
batch_op.alter_column("password_hash", nullable=False)

View File

@@ -12,9 +12,18 @@ depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE users DROP CONSTRAINT IF EXISTS ck_users_tier"
conn = op.get_bind()
dialect = conn.dialect.name
if dialect == "sqlite":
# Migration 002 skipped the CHECK constraint on SQLite; just create it now.
with op.batch_alter_table("users") as batch_op:
batch_op.create_check_constraint(
"ck_users_tier",
"tier IN ('free', 'starter', 'pro', 'business', 'enterprise')",
)
else:
op.execute("ALTER TABLE users DROP CONSTRAINT IF EXISTS ck_users_tier")
op.execute(
"ALTER TABLE users ADD CONSTRAINT ck_users_tier "
"CHECK (tier IN ('free', 'starter', 'pro', 'business', 'enterprise'))"
@@ -22,9 +31,18 @@ def upgrade() -> None:
def downgrade() -> None:
op.execute(
"ALTER TABLE users DROP CONSTRAINT IF EXISTS ck_users_tier"
conn = op.get_bind()
dialect = conn.dialect.name
if dialect == "sqlite":
with op.batch_alter_table("users") as batch_op:
batch_op.drop_constraint("ck_users_tier", type_="check")
batch_op.create_check_constraint(
"ck_users_tier",
"tier IN ('free', 'pro')",
)
else:
op.execute("ALTER TABLE users DROP CONSTRAINT IF EXISTS ck_users_tier")
op.execute(
"ALTER TABLE users ADD CONSTRAINT ck_users_tier "
"CHECK (tier IN ('free', 'pro'))"

View File

@@ -26,8 +26,29 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
conn = op.get_bind()
dialect = conn.dialect.name
# Glossaries with terms containing 5+ translation keys are multilingual templates
# (enriched glossaries have 11 translations: de, es, it, pt, nl, ru, ja, ko, zh, ar, fa)
if dialect == "sqlite":
# SQLite does not have jsonb_object_keys. Use json_each for compatibility.
op.execute("""
UPDATE glossaries
SET target_language = 'multi'
WHERE id IN (
SELECT DISTINCT g.id
FROM glossaries g
JOIN glossary_terms gt ON gt.glossary_id = g.id
WHERE gt.translations IS NOT NULL
AND json_type(gt.translations, '$') = 'object'
AND (
SELECT count(*)
FROM json_each(gt.translations)
) >= 5
)
""")
else:
op.execute("""
UPDATE glossaries
SET target_language = 'multi'

View File

@@ -22,6 +22,14 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
conn = op.get_bind()
dialect = conn.dialect.name
if dialect == "sqlite":
# SQLite test databases are created fresh and have no legacy glossaries to clean up.
# The PostgreSQL-specific jsonb_object_keys logic is not needed here.
return
# 1. Delete old FR→EN glossaries that don't have multilingual translations
# (imported before enrichment, they are stale duplicates)
op.execute("""

View File

@@ -21,10 +21,18 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
conn = op.get_bind()
dialect = conn.dialect.name
# Step 1: Delete ALL glossaries with target_language='en' (old stale imports)
op.execute("DELETE FROM glossary_terms WHERE glossary_id IN (SELECT id FROM glossaries WHERE target_language = 'en')")
op.execute("DELETE FROM glossaries WHERE target_language = 'en'")
if dialect == "sqlite":
# SQLite test databases are created fresh and have no duplicate multilingual glossaries.
# The PostgreSQL-specific DISTINCT ON logic is not needed here.
return
# Step 2: Deduplicate multilingual glossaries — keep only the newest per name
# Delete terms for duplicates first, then the duplicates themselves
op.execute("""

View File

@@ -334,7 +334,7 @@ class Glossary(Base):
name = Column(String(255), nullable=False)
source_language = Column(String(10), nullable=False, default="fr")
target_language = Column(String(10), nullable=True, default="en")
template_id = Column(String(50), nullable=True, index=True)
template_id = Column(String(50), nullable=True)
created_at = Column(DateTime, default=_utcnow)
updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow)