e76fa586f1
Ship dual-track learning (daily accumulation vs textbook),沪教/商务词书 APIs and UI, native iOS wrapper with bundled H5, and production book import on deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
3.5 KiB
Python
87 lines
3.5 KiB
Python
"""启动时补齐新增列(已有库无需手工迁移)。"""
|
|
|
|
from sqlalchemy import inspect, text
|
|
|
|
from database import engine
|
|
|
|
|
|
def run_migrations() -> None:
|
|
insp = inspect(engine)
|
|
with engine.begin() as conn:
|
|
if insp.has_table("words"):
|
|
cols = {c["name"] for c in insp.get_columns("words")}
|
|
if "total_train_seconds" not in cols:
|
|
conn.execute(
|
|
text(
|
|
"ALTER TABLE words ADD COLUMN total_train_seconds "
|
|
"INTEGER NOT NULL DEFAULT 0"
|
|
)
|
|
)
|
|
if "train_count" not in cols:
|
|
conn.execute(
|
|
text("ALTER TABLE words ADD COLUMN train_count INTEGER NOT NULL DEFAULT 0")
|
|
)
|
|
|
|
if insp.has_table("quiz_records"):
|
|
cols = {c["name"] for c in insp.get_columns("quiz_records")}
|
|
if "duration_seconds" not in cols:
|
|
conn.execute(
|
|
text(
|
|
"ALTER TABLE quiz_records ADD COLUMN duration_seconds "
|
|
"INTEGER NOT NULL DEFAULT 0"
|
|
)
|
|
)
|
|
|
|
if insp.has_table("user_settings"):
|
|
cols = {c["name"] for c in insp.get_columns("user_settings")}
|
|
if "active_book_id" not in cols:
|
|
conn.execute(text("ALTER TABLE user_settings ADD COLUMN active_book_id INTEGER"))
|
|
|
|
if not insp.has_table("user_book_settings"):
|
|
conn.execute(
|
|
text(
|
|
"""
|
|
CREATE TABLE user_book_settings (
|
|
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
book_id INTEGER NOT NULL,
|
|
daily_target INTEGER NOT NULL DEFAULT 12,
|
|
master_required_count INTEGER NOT NULL DEFAULT 3,
|
|
weak_wrong_threshold INTEGER NOT NULL DEFAULT 2,
|
|
CONSTRAINT uq_user_book_settings UNIQUE (user_id, book_id),
|
|
FOREIGN KEY(user_id) REFERENCES users (id),
|
|
FOREIGN KEY(book_id) REFERENCES word_books (id)
|
|
)
|
|
"""
|
|
)
|
|
)
|
|
|
|
if insp.has_table("words"):
|
|
cols = {c["name"] for c in insp.get_columns("words")}
|
|
if "book_id" not in cols:
|
|
conn.execute(
|
|
text("ALTER TABLE words ADD COLUMN book_id INTEGER NOT NULL DEFAULT 0")
|
|
)
|
|
conn.execute(text("CREATE INDEX ix_words_book_id ON words (book_id)"))
|
|
if "book_entry_id" not in cols:
|
|
conn.execute(text("ALTER TABLE words ADD COLUMN book_entry_id INTEGER"))
|
|
|
|
if insp.has_table("words") and insp.has_table("quiz_records"):
|
|
conn.execute(
|
|
text(
|
|
"""
|
|
UPDATE words w SET
|
|
train_count = (
|
|
SELECT COUNT(*) FROM quiz_records q WHERE q.word_id = w.id
|
|
),
|
|
total_train_seconds = (
|
|
SELECT COALESCE(SUM(duration_seconds), 0)
|
|
FROM quiz_records q WHERE q.word_id = w.id
|
|
)
|
|
WHERE train_count = 0 AND EXISTS (
|
|
SELECT 1 FROM quiz_records q WHERE q.word_id = w.id
|
|
)
|
|
"""
|
|
)
|
|
)
|