branch: main
schema.rs
7134 bytesRaw
use worker::SqlStorage;
/// Initialize all tables and indexes. Called once from DurableObject::new.
/// Uses IF NOT EXISTS throughout so it's safe to call on every instantiation.
pub fn init(sql: &SqlStorage) {
sql.exec(
"CREATE TABLE IF NOT EXISTS refs (
name TEXT PRIMARY KEY,
commit_hash TEXT NOT NULL
)",
None,
)
.expect("create refs");
sql.exec(
"CREATE TABLE IF NOT EXISTS commits (
hash TEXT PRIMARY KEY,
tree_hash TEXT NOT NULL,
author TEXT NOT NULL,
author_email TEXT NOT NULL,
author_time INTEGER NOT NULL,
committer TEXT NOT NULL,
committer_email TEXT NOT NULL,
commit_time INTEGER NOT NULL,
message TEXT NOT NULL
)",
None,
)
.expect("create commits");
sql.exec(
"CREATE TABLE IF NOT EXISTS commit_parents (
commit_hash TEXT NOT NULL,
parent_hash TEXT NOT NULL,
ordinal INTEGER NOT NULL,
PRIMARY KEY (commit_hash, ordinal)
)",
None,
)
.expect("create commit_parents");
sql.exec(
"CREATE TABLE IF NOT EXISTS commit_graph (
commit_hash TEXT NOT NULL,
level INTEGER NOT NULL,
ancestor_hash TEXT NOT NULL,
PRIMARY KEY (commit_hash, level)
)",
None,
)
.expect("create commit_graph");
sql.exec(
"CREATE TABLE IF NOT EXISTS trees (
tree_hash TEXT NOT NULL,
name TEXT NOT NULL,
mode INTEGER NOT NULL,
entry_hash TEXT NOT NULL,
PRIMARY KEY (tree_hash, name)
)",
None,
)
.expect("create trees");
sql.exec(
"CREATE TABLE IF NOT EXISTS blob_groups (
group_id INTEGER PRIMARY KEY AUTOINCREMENT,
path_hint TEXT,
latest_version INTEGER NOT NULL DEFAULT 0
)",
None,
)
.expect("create blob_groups");
sql.exec(
"CREATE TABLE IF NOT EXISTS blobs (
blob_hash TEXT PRIMARY KEY,
group_id INTEGER NOT NULL REFERENCES blob_groups(group_id),
version_in_group INTEGER NOT NULL,
is_keyframe INTEGER NOT NULL DEFAULT 0,
data BLOB NOT NULL,
raw_size INTEGER NOT NULL,
stored_size INTEGER NOT NULL DEFAULT 0,
UNIQUE (group_id, version_in_group)
)",
None,
)
.expect("create blobs");
// Overflow table for blobs whose compressed data exceeds the 2 MB
// per-row SQLite limit in Cloudflare DOs. The blobs table stores an
// empty sentinel for the data column; actual bytes live here in chunks.
sql.exec(
"CREATE TABLE IF NOT EXISTS blob_chunks (
group_id INTEGER NOT NULL,
version_in_group INTEGER NOT NULL,
chunk_index INTEGER NOT NULL,
data BLOB NOT NULL,
PRIMARY KEY (group_id, version_in_group, chunk_index)
)",
None,
)
.expect("create blob_chunks");
// Raw object bytes for commits and trees. Stored verbatim so we can
// return them byte-for-byte identical during fetch (preserving timezone,
// entry order, etc. that the parsed tables lose).
// Blobs are NOT stored here — they're reconstructed from xpatch chains.
sql.exec(
"CREATE TABLE IF NOT EXISTS raw_objects (
hash TEXT PRIMARY KEY,
data BLOB NOT NULL
)",
None,
)
.expect("create raw_objects");
// -- Indexes --
sql.exec(
"CREATE INDEX IF NOT EXISTS idx_commits_time
ON commits(commit_time DESC)",
None,
)
.expect("create idx_commits_time");
sql.exec(
"CREATE INDEX IF NOT EXISTS idx_commit_parents_parent
ON commit_parents(parent_hash)",
None,
)
.expect("create idx_commit_parents_parent");
sql.exec(
"CREATE INDEX IF NOT EXISTS idx_trees_entry
ON trees(entry_hash)",
None,
)
.expect("create idx_trees_entry");
sql.exec(
"CREATE INDEX IF NOT EXISTS idx_blobs_group
ON blobs(group_id, version_in_group)",
None,
)
.expect("create idx_blobs_group");
sql.exec(
"CREATE INDEX IF NOT EXISTS idx_blob_groups_path
ON blob_groups(path_hint)",
None,
)
.expect("create idx_blob_groups_path");
// -- Config --
sql.exec(
"CREATE TABLE IF NOT EXISTS config (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)",
None,
)
.expect("create config");
// -- FTS5 --
// FTS5 virtual tables don't support IF NOT EXISTS in all SQLite builds.
// Wrap in a check against sqlite_master to be safe.
sql.exec(
"CREATE VIRTUAL TABLE IF NOT EXISTS fts_head USING fts5(path, content)",
None,
)
.expect("create fts_head");
// FTS5 for commit message search
sql.exec(
"CREATE VIRTUAL TABLE IF NOT EXISTS fts_commits USING fts5(hash UNINDEXED, message, author)",
None,
)
.expect("create fts_commits");
// -- Issues and pull requests --
sql.exec(
"CREATE TABLE IF NOT EXISTS issues (
id INTEGER PRIMARY KEY AUTOINCREMENT,
number INTEGER NOT NULL,
kind TEXT NOT NULL DEFAULT 'issue',
title TEXT NOT NULL,
body TEXT NOT NULL DEFAULT '',
author_id TEXT NOT NULL,
author_name TEXT NOT NULL,
state TEXT NOT NULL DEFAULT 'open',
source_branch TEXT,
target_branch TEXT,
source_hash TEXT,
merge_commit_hash TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)",
None,
)
.expect("create issues");
sql.exec(
"CREATE TABLE IF NOT EXISTS issue_comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
issue_id INTEGER NOT NULL,
author_id TEXT NOT NULL,
author_name TEXT NOT NULL,
body TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)",
None,
)
.expect("create issue_comments");
sql.exec(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_issues_number ON issues(number)",
None,
)
.expect("create idx_issues_number");
sql.exec(
"CREATE INDEX IF NOT EXISTS idx_issues_kind_state ON issues(kind, state)",
None,
)
.expect("create idx_issues_kind_state");
sql.exec(
"CREATE INDEX IF NOT EXISTS idx_issue_comments_issue ON issue_comments(issue_id)",
None,
)
.expect("create idx_issue_comments_issue");
}