Files
creator/backend/database.py
2026-06-06 16:07:04 +02:00

166 lines
4.4 KiB
Python

import aiosqlite
from config import DB_PATH
CREATE_GUIDES = """
CREATE TABLE IF NOT EXISTS guides (
id TEXT PRIMARY KEY,
topic TEXT NOT NULL,
format TEXT NOT NULL,
instructions TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'queued',
progress TEXT,
error_msg TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)
"""
CREATE_PROGRESS = """
CREATE TABLE IF NOT EXISTS guide_progress (
guide_id TEXT NOT NULL,
chapter TEXT NOT NULL,
created_at TEXT NOT NULL,
PRIMARY KEY (guide_id, chapter)
)
"""
CREATE_TOPICS = """
CREATE TABLE IF NOT EXISTS topics (
name TEXT PRIMARY KEY,
created_at TEXT NOT NULL
)
"""
_db: aiosqlite.Connection | None = None
async def get_db() -> aiosqlite.Connection:
global _db
if _db is None:
_db = await aiosqlite.connect(DB_PATH)
_db.row_factory = None
return _db
async def init_db():
db = await get_db()
await db.execute(CREATE_GUIDES)
await db.execute(CREATE_PROGRESS)
await db.execute(CREATE_TOPICS)
await db.execute(
"UPDATE guides SET status = 'error', progress = NULL, error_msg = 'Server-Neustart' "
"WHERE status IN ('queued', 'generating')"
)
await db.commit()
async def close_db():
global _db
if _db is not None:
await _db.close()
_db = None
def _row_to_dict(row, cursor):
columns = [d[0] for d in cursor.description]
return dict(zip(columns, row))
async def create_guide(guide: dict) -> dict:
db = await get_db()
await db.execute(
"""INSERT INTO guides (id, topic, format, instructions, status, progress, created_at, updated_at)
VALUES (:id, :topic, :format, :instructions, :status, :progress, :created_at, :updated_at)""",
guide,
)
await db.commit()
return guide
async def get_guide(guide_id: str) -> dict | None:
db = await get_db()
cursor = await db.execute("SELECT * FROM guides WHERE id = ?", (guide_id,))
row = await cursor.fetchone()
if row is None:
return None
return _row_to_dict(row, cursor)
async def list_guides() -> list[dict]:
db = await get_db()
cursor = await db.execute("SELECT * FROM guides ORDER BY created_at DESC")
rows = await cursor.fetchall()
return [_row_to_dict(row, cursor) for row in rows]
async def update_guide(guide_id: str, **fields) -> None:
sets = ", ".join(f"{k} = :{k}" for k in fields)
fields["id"] = guide_id
db = await get_db()
await db.execute(f"UPDATE guides SET {sets} WHERE id = :id", fields)
await db.commit()
async def delete_guide(guide_id: str) -> bool:
db = await get_db()
cursor = await db.execute("DELETE FROM guides WHERE id = ?", (guide_id,))
await db.commit()
return cursor.rowcount > 0
# --- Themen ---
async def create_topic(name: str) -> None:
from datetime import datetime, timezone
db = await get_db()
await db.execute(
"INSERT OR IGNORE INTO topics (name, created_at) VALUES (?, ?)",
(name, datetime.now(timezone.utc).isoformat()),
)
await db.commit()
async def list_topics() -> list[str]:
db = await get_db()
cursor = await db.execute("SELECT name FROM topics ORDER BY created_at DESC")
rows = await cursor.fetchall()
return [row[0] for row in rows]
async def delete_topic(name: str) -> None:
db = await get_db()
await db.execute("DELETE FROM topics WHERE name = ?", (name,))
await db.commit()
# --- Kapitel-Fortschritt ---
async def list_progress(guide_id: str) -> list[str]:
db = await get_db()
cursor = await db.execute(
"SELECT chapter FROM guide_progress WHERE guide_id = ?", (guide_id,)
)
rows = await cursor.fetchall()
return [row[0] for row in rows]
async def set_progress(guide_id: str, chapter: str, done: bool) -> None:
from datetime import datetime, timezone
db = await get_db()
if done:
await db.execute(
"INSERT OR IGNORE INTO guide_progress (guide_id, chapter, created_at) VALUES (?, ?, ?)",
(guide_id, chapter, datetime.now(timezone.utc).isoformat()),
)
else:
await db.execute(
"DELETE FROM guide_progress WHERE guide_id = ? AND chapter = ?", (guide_id, chapter)
)
await db.commit()
async def delete_progress(guide_id: str) -> None:
db = await get_db()
await db.execute("DELETE FROM guide_progress WHERE guide_id = ?", (guide_id,))
await db.commit()