feat: prevent duplicate cards, merge contexts, and display star badge when word is in library

This commit is contained in:
2026-10-05 15:15:06 +03:00
parent f52820fff6
commit a73bdc29fd
7 changed files with 355 additions and 24 deletions
+69
View File
@@ -83,6 +83,75 @@ def _migrate(conn: sqlite3.Connection):
""")
conn.execute("CREATE INDEX IF NOT EXISTS idx_books_user ON books(user_id);")
# --- Deduplicate vocabulary_cards (case-insensitive) and enforce UNIQUE index ---
dup_rows = conn.execute("""
SELECT user_id, lower(trim(term)) as clean_term, COUNT(*) as cnt
FROM vocabulary_cards
GROUP BY user_id, lower(trim(term))
HAVING cnt > 1
""").fetchall()
for d in dup_rows:
u_id = d["user_id"]
c_term = d["clean_term"]
cards = conn.execute(
"SELECT * FROM vocabulary_cards WHERE user_id = ? AND lower(trim(term)) = ? ORDER BY id ASC",
(u_id, c_term),
).fetchall()
if not cards:
continue
primary = cards[0]
primary_id = primary["id"]
merged_contexts = [primary["context_sentence"]] if primary["context_sentence"] else []
merged_tags = set([t.strip() for t in (primary["tags"] or "").split(",") if t.strip()])
max_reps = primary["srs_reps"] or 0
max_interval = primary["srs_interval"] or 0
max_ease = primary["srs_ease"] or 2.5
latest_review = primary["srs_last_review"]
srs_state = primary["srs_state"]
for dup in cards[1:]:
dup_id = dup["id"]
if dup["context_sentence"] and dup["context_sentence"] not in merged_contexts:
merged_contexts.append(dup["context_sentence"])
for t in (dup["tags"] or "").split(","):
if t.strip():
merged_tags.add(t.strip())
if (dup["srs_reps"] or 0) > max_reps:
max_reps = dup["srs_reps"]
max_interval = dup["srs_interval"]
max_ease = dup["srs_ease"]
latest_review = dup["srs_last_review"]
srs_state = dup["srs_state"]
# Reassign SRS logs to primary card
conn.execute("UPDATE srs_logs SET card_id = ? WHERE card_id = ?", (primary_id, dup_id))
# Delete duplicate row
conn.execute("DELETE FROM vocabulary_cards WHERE id = ?", (dup_id,))
# Update primary card with merged data
conn.execute(
"""
UPDATE vocabulary_cards
SET context_sentence = ?, tags = ?, srs_reps = ?, srs_interval = ?, srs_ease = ?,
srs_last_review = ?, srs_state = ?
WHERE id = ?
""",
(
"\n\n".join(merged_contexts),
", ".join(sorted(merged_tags)),
max_reps,
max_interval,
max_ease,
latest_review,
srs_state,
primary_id,
),
)
conn.execute(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_vocab_user_term_nocase ON vocabulary_cards(user_id, term COLLATE NOCASE);"
)
def init_db():
config.DB_PATH.parent.mkdir(parents=True, exist_ok=True)