78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
import sqlite3
|
|
import contextlib
|
|
from typing import Generator
|
|
from app import config
|
|
|
|
def get_db_connection() -> sqlite3.Connection:
|
|
conn = sqlite3.connect(
|
|
config.DB_PATH,
|
|
timeout=15.0
|
|
)
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute("PRAGMA journal_mode=WAL;")
|
|
conn.execute("PRAGMA synchronous=NORMAL;")
|
|
conn.execute("PRAGMA foreign_keys=ON;")
|
|
return conn
|
|
|
|
@contextlib.contextmanager
|
|
def get_db() -> Generator[sqlite3.Connection, None, None]:
|
|
conn = get_db_connection()
|
|
try:
|
|
yield conn
|
|
conn.commit()
|
|
except Exception:
|
|
conn.rollback()
|
|
raise
|
|
finally:
|
|
conn.close()
|
|
|
|
def init_db():
|
|
config.DB_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
with get_db() as conn:
|
|
conn.executescript("""
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username TEXT UNIQUE NOT NULL COLLATE NOCASE,
|
|
password_hash TEXT NOT NULL,
|
|
salt TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
token TEXT PRIMARY KEY,
|
|
user_id INTEGER NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
user_agent TEXT,
|
|
ip TEXT,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS vocabulary_cards (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
term TEXT NOT NULL,
|
|
translation TEXT NOT NULL,
|
|
context_sentence TEXT,
|
|
phonetic TEXT,
|
|
audio_url TEXT,
|
|
part_of_speech TEXT,
|
|
definition_en TEXT,
|
|
tags TEXT,
|
|
notes TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_vocab_user ON vocabulary_cards(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_vocab_term ON vocabulary_cards(term);
|
|
CREATE INDEX IF NOT EXISTS idx_vocab_created ON vocabulary_cards(created_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS dictionary_cache (
|
|
query TEXT PRIMARY KEY COLLATE NOCASE,
|
|
response_json TEXT NOT NULL,
|
|
cached_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
""")
|