Files
TypstDrive/server/src/db/sqlite.rs
T
2026-05-14 18:40:27 -04:00

102 lines
4.1 KiB
Rust

use sqlx::AnyPool;
pub async fn init_schema(pool: &AnyPool) {
sqlx::query("PRAGMA foreign_keys = ON")
.execute(pool)
.await
.expect("Failed to enable SQLite foreign keys");
let statements = [
"CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
email TEXT UNIQUE,
password_hash TEXT NOT NULL,
is_admin INTEGER NOT NULL DEFAULT 0,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))
)",
"CREATE TABLE IF NOT EXISTS folders (
id TEXT PRIMARY KEY,
owner_id TEXT NOT NULL REFERENCES users(id),
parent_id TEXT REFERENCES folders(id),
name TEXT NOT NULL,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))
)",
"CREATE TABLE IF NOT EXISTS documents (
id TEXT PRIMARY KEY,
owner_id TEXT NOT NULL REFERENCES users(id),
folder_id TEXT REFERENCES folders(id),
title TEXT NOT NULL,
content BLOB,
thumbnail_svg TEXT,
public_role TEXT DEFAULT NULL,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now')),
updated_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))
)",
"CREATE TABLE IF NOT EXISTS files (
id TEXT PRIMARY KEY,
owner_id TEXT NOT NULL REFERENCES users(id),
document_id TEXT REFERENCES documents(id),
folder_id TEXT REFERENCES folders(id),
name TEXT NOT NULL,
mime_type TEXT NOT NULL,
data BLOB NOT NULL,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))
)",
"CREATE TABLE IF NOT EXISTS collaborators (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role TEXT NOT NULL,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now')),
UNIQUE(document_id, user_id)
)",
"CREATE TABLE IF NOT EXISTS invitations (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
role TEXT NOT NULL,
token TEXT NOT NULL UNIQUE,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now')),
expires_at TEXT
)",
"CREATE TABLE IF NOT EXISTS comments (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
resolved INTEGER DEFAULT 0,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))
)",
"CREATE TABLE IF NOT EXISTS document_history (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
content BLOB NOT NULL,
created_by TEXT NOT NULL REFERENCES users(id) ON DELETE SET NULL,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))
)",
"CREATE TABLE IF NOT EXISTS document_versions (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))
)",
];
for stmt in &statements {
sqlx::query(stmt)
.execute(pool)
.await
.expect("Failed to execute SQLite schema");
}
// Idempotent migrations for existing databases
let migrations = [
"ALTER TABLE users ADD COLUMN is_admin INTEGER NOT NULL DEFAULT 0",
"ALTER TABLE users ADD COLUMN created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now'))",
];
for stmt in &migrations {
let _ = sqlx::query(stmt).execute(pool).await;
}
}