Files
memory-gateway/core/db.py

146 lines
3.6 KiB
Python

from __future__ import annotations
import sqlite3
from pathlib import Path
SCHEMA = """
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
user_key TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);
CREATE TABLE IF NOT EXISTS user_resources (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
app_id TEXT NOT NULL DEFAULT 'default',
project_id TEXT NOT NULL DEFAULT 'default',
session_id TEXT NOT NULL,
original_filename TEXT,
mime_type TEXT,
content_type TEXT NOT NULL,
uri TEXT NOT NULL,
uri_public BOOLEAN NOT NULL DEFAULT FALSE,
sha256 TEXT,
size_bytes INTEGER,
title TEXT,
description TEXT,
status TEXT NOT NULL DEFAULT 'pending',
error_message TEXT,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
deleted_at TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_user_resources_user_scope
ON user_resources (user_id, app_id, project_id, status, deleted_at);
CREATE INDEX IF NOT EXISTS idx_user_resources_session_id
ON user_resources (session_id);
CREATE INDEX IF NOT EXISTS idx_user_resources_user_id
ON user_resources (user_id);
CREATE TABLE IF NOT EXISTS memory_attachments (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
app_id TEXT NOT NULL DEFAULT 'default',
project_id TEXT NOT NULL DEFAULT 'default',
session_id TEXT NOT NULL,
resource_id TEXT,
content_type TEXT NOT NULL,
name TEXT NOT NULL,
internal_uri TEXT NOT NULL,
source TEXT NOT NULL,
sha256 TEXT,
created_at TIMESTAMP NOT NULL,
deleted_at TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_attachments_unique_uri
ON memory_attachments (user_id, session_id, internal_uri);
CREATE INDEX IF NOT EXISTS idx_memory_attachments_user_session
ON memory_attachments (user_id, session_id, deleted_at);
CREATE INDEX IF NOT EXISTS idx_memory_attachments_resource
ON memory_attachments (resource_id, deleted_at);
INSERT OR IGNORE INTO memory_attachments (
id,
user_id,
app_id,
project_id,
session_id,
resource_id,
content_type,
name,
internal_uri,
source,
sha256,
created_at,
deleted_at
)
SELECT
'a_resource_' || id,
user_id,
app_id,
project_id,
session_id,
id,
content_type,
COALESCE(original_filename, id),
uri,
'resource_upload',
sha256,
created_at,
deleted_at
FROM user_resources;
CREATE TABLE IF NOT EXISTS memory_tombstones (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
memory_id TEXT,
session_id TEXT,
reason TEXT,
created_at TIMESTAMP NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_memory_tombstones_user_memory
ON memory_tombstones (user_id, memory_id);
CREATE INDEX IF NOT EXISTS idx_memory_tombstones_user_session
ON memory_tombstones (user_id, session_id);
CREATE TABLE IF NOT EXISTS memory_overrides (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
memory_id TEXT,
session_id TEXT,
override_text TEXT NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_memory_overrides_user_memory_active
ON memory_overrides (user_id, memory_id, is_active);
"""
def connect(db_path: Path) -> sqlite3.Connection:
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA journal_mode=WAL")
conn.execute("PRAGMA foreign_keys=ON")
conn.execute("PRAGMA busy_timeout=5000")
return conn
def init_db(db_path: Path) -> None:
db_path.parent.mkdir(parents=True, exist_ok=True)
with connect(db_path) as conn:
conn.executescript(SCHEMA)