This commit is contained in:
team3
2026-06-29 00:09:24 +02:00
parent 07b6736ced
commit bf7ebe045b
8 changed files with 483 additions and 40 deletions

View File

@@ -86,6 +86,7 @@ CREATE TABLE IF NOT EXISTS bausteine (
nennungen INTEGER NOT NULL DEFAULT 1,
status TEXT NOT NULL DEFAULT 'kandidat',
quellen TEXT NOT NULL DEFAULT '[]',
reader TEXT NOT NULL DEFAULT '[]',
updated_at TEXT NOT NULL,
PRIMARY KEY (topic, titel_norm)
)
@@ -266,6 +267,10 @@ async def init_db():
await db.execute("ALTER TABLE subbausteine ADD COLUMN fakten TEXT NOT NULL DEFAULT ''") # DEFAULT '' nötig für NOT NULL beim ADD COLUMN
except aiosqlite.OperationalError:
pass
try: # Migration: bausteine.reader (Reader-Set je Kandidat, JSON) — exakte Konsens-Zählung (≥2 Reader)
await db.execute("ALTER TABLE bausteine ADD COLUMN reader TEXT NOT NULL DEFAULT '[]'")
except aiosqlite.OperationalError:
pass
# Migration: alte vertiefungen-Tabelle → baustein_texte (Bestand = lange Form, art 'deepdive')
cursor = await db.execute("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'vertiefungen'")
if await cursor.fetchone():
@@ -714,15 +719,31 @@ async def delete_baustein_daten(topic: str) -> None:
# --- Bausteine-Pipeline-Inhalt: Inventar / Subbausteine / Frage-Muster / Coverage / State / Quelle ---
async def upsert_baustein(topic: str, titel_norm: str, titel: str, beschreibung: str = "", quellen: list | None = None) -> None:
"""Kandidat einfügen oder Nennungszähler erhöhen. Erst-Beschreibung bleibt erhalten."""
async def upsert_baustein(topic: str, titel_norm: str, titel: str, beschreibung: str = "",
quellen: list | None = None, reader: str | None = None) -> None:
"""Kandidat einfügen oder Reader-Set vereinigen. Erst-Beschreibung bleibt erhalten.
`reader` = ID des Recherche-Readers (z.B. "a5-1"). Die Vereinigung läuft race-frei in
EINEM Statement (json1), weil mehrere Reader-Coroutinen nebenläufig upserten — ein
read-modify-write über `await` würde Mitglieder verlieren. `nennungen` bleibt synchron
zu `len(reader)`. `reader=None` (z.B. aus `_set_inventar`) lässt das Set unverändert."""
db = await get_db()
rid = reader if isinstance(reader, str) and reader else None
await db.execute(
"""INSERT INTO bausteine (topic, titel_norm, titel, beschreibung, nennungen, status, quellen, updated_at)
VALUES (?, ?, ?, ?, 1, 'kandidat', ?, ?)
"""INSERT INTO bausteine (topic, titel_norm, titel, beschreibung, nennungen, status, quellen, reader, updated_at)
VALUES (?, ?, ?, ?, 1, 'kandidat', ?, ?, ?)
ON CONFLICT(topic, titel_norm) DO UPDATE SET
nennungen = nennungen + 1, quellen = excluded.quellen, updated_at = excluded.updated_at""",
(topic, titel_norm, titel, beschreibung, json.dumps(quellen or [], ensure_ascii=False), _now()),
reader = (SELECT json_group_array(v) FROM (
SELECT value AS v FROM json_each(bausteine.reader)
UNION SELECT ? WHERE ? IS NOT NULL)),
nennungen = (SELECT count(*) FROM (
SELECT value AS v FROM json_each(bausteine.reader)
UNION SELECT ? WHERE ? IS NOT NULL)),
quellen = excluded.quellen, updated_at = excluded.updated_at""",
(topic, titel_norm, titel, beschreibung,
json.dumps(quellen or [], ensure_ascii=False),
json.dumps([rid] if rid else [], ensure_ascii=False), _now(),
rid, rid, rid, rid),
)
await db.commit()
@@ -738,6 +759,7 @@ async def list_bausteine(topic: str, status: str | None = None) -> list[dict]:
for row in rows:
d = _row_to_dict(row, cursor)
d["quellen"] = json.loads(d.get("quellen") or "[]")
d["reader"] = json.loads(d.get("reader") or "[]")
out.append(d)
return out