feat: prevent duplicate cards, merge contexts, and display star badge when word is in library
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user