pub(crate) const VERSION: i64 = 20;
pub(crate) const SCHEMA: &str = r#"
CREATE TABLE repositories (
id INTEGER PRIMARY KEY,
identity TEXT UNIQUE NOT NULL,
default_branch TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE checkouts (
id INTEGER PRIMARY KEY,
repository_id INTEGER NOT NULL REFERENCES repositories(id),
root_path TEXT NOT NULL UNIQUE,
current_branch TEXT
);
CREATE TABLE files (
id INTEGER PRIMARY KEY,
repository_id INTEGER NOT NULL REFERENCES repositories(id),
path TEXT NOT NULL,
language TEXT,
mtime INTEGER, -- last-modified time, unix *nanoseconds*
-- (git-style racy-edit protection)
git_ts INTEGER, -- last git commit time touching this file
content_hash TEXT,
indexed_at INTEGER,
generated INTEGER NOT NULL DEFAULT 0, -- declares itself generated (a header marker)
UNIQUE(repository_id, path)
);
CREATE TABLE symbols (
id INTEGER PRIMARY KEY,
repository_id INTEGER NOT NULL REFERENCES repositories(id),
file_id INTEGER NOT NULL REFERENCES files(id),
name TEXT NOT NULL,
name_lower TEXT NOT NULL,
kind TEXT NOT NULL,
language TEXT NOT NULL,
line INTEGER NOT NULL,
end_line INTEGER, -- 1-based last line of the definition body
parent TEXT,
visibility TEXT -- public|crate|private|protected|local;
-- NULL when unknown (pre-v9 rows
-- backfill lazily)
);
CREATE INDEX idx_symbols_file ON symbols(file_id);
CREATE INDEX idx_symbols_repo_name ON symbols(repository_id, name_lower);
CREATE TABLE coverage (
id INTEGER PRIMARY KEY,
repository_id INTEGER NOT NULL REFERENCES repositories(id),
scope TEXT NOT NULL DEFAULT 'full',
files_seen INTEGER,
files_indexed INTEGER,
status TEXT NOT NULL,
last_indexed_at INTEGER,
UNIQUE(repository_id, scope)
);
-- usage counters, one row per (day, caller, flag set), incremented on write.
-- The only record of how rq is actually used. Read by `--usage`, never by
-- ranking.
CREATE TABLE usage_daily (
day TEXT NOT NULL, -- local date, YYYY-MM-DD
source TEXT NOT NULL,
flags TEXT NOT NULL,
searches INTEGER NOT NULL,
misses INTEGER NOT NULL, -- answered nothing, against a ready index
warming INTEGER NOT NULL, -- answered nothing because it wasn't ready
on_complete INTEGER NOT NULL, -- ran against a fully indexed repo
live INTEGER NOT NULL DEFAULT 0, -- answered from a live scan, not the index
PRIMARY KEY (day, source, flags)
);
-- the name index (docs/NAME_INDEX.md): each repo's distinct symbol names and
-- file paths as fixed-size signatures, in append-order chunks. `keys` is each
-- key's end offset (u32), then the keys' bytes.
CREATE TABLE name_sigs (
repository_id INTEGER NOT NULL,
kind INTEGER NOT NULL, -- 0 symbol names, 1 file paths (by stem)
chunk INTEGER NOT NULL,
n INTEGER NOT NULL,
sigs BLOB NOT NULL,
keys BLOB NOT NULL,
PRIMARY KEY (repository_id, kind, chunk)
);
-- a repo's index is read only while it's current: built under this format,
-- and maintained since; -1 while a cold pass suspends it. `built` is how many
-- names the last rebuild wrote.
CREATE TABLE name_index (
repository_id INTEGER PRIMARY KEY,
format INTEGER NOT NULL,
built INTEGER NOT NULL
);
-- small key/value store (indexed HEAD, warm lock, branch-file cache)
CREATE TABLE meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
"#;
pub(crate) const MIGRATION_V2: &str = r#"
DROP TABLE IF EXISTS selection_stats;
DROP TABLE IF EXISTS events;
CREATE TABLE events (
id INTEGER PRIMARY KEY,
type TEXT NOT NULL,
query TEXT,
repository_id INTEGER,
path TEXT,
line INTEGER,
branch TEXT,
ts INTEGER NOT NULL
);
CREATE TABLE selection_stats (
repository_id INTEGER NOT NULL,
query_norm TEXT NOT NULL,
file TEXT NOT NULL,
name TEXT NOT NULL,
selections INTEGER NOT NULL,
last_selected_at INTEGER,
PRIMARY KEY (repository_id, query_norm, file, name)
);
CREATE TABLE IF NOT EXISTS meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
"#;
pub(crate) const MIGRATION_V3: &str = r#"
ALTER TABLE files ADD COLUMN git_ts INTEGER;
"#;
pub(crate) const MIGRATION_V4: &str = r#"
ALTER TABLE symbols ADD COLUMN end_line INTEGER;
"#;
pub(crate) const MIGRATION_V5: &str = r#"
CREATE INDEX IF NOT EXISTS idx_symbols_repo ON symbols(repository_id);
CREATE INDEX IF NOT EXISTS idx_events_repo ON events(repository_id, id);
"#;
pub(crate) const MIGRATION_V6: &str = r#"
UPDATE files SET mtime = mtime * 1000000000
WHERE mtime IS NOT NULL AND mtime < 100000000000;
"#;
pub(crate) const MIGRATION_V7: &str = r#"
ALTER TABLE repositories DROP COLUMN display_name;
"#;
pub(crate) const MIGRATION_V8: &str = r#"
UPDATE coverage SET status = 'warming' WHERE status = 'partial';
"#;
pub(crate) const MIGRATION_V9: &str = r#"
ALTER TABLE symbols ADD COLUMN visibility TEXT;
"#;
pub(crate) const MIGRATION_V10: &str = r#"
ALTER TABLE events ADD COLUMN source TEXT;
ALTER TABLE events ADD COLUMN results INTEGER;
ALTER TABLE events ADD COLUMN flags TEXT;
CREATE TABLE IF NOT EXISTS usage_daily (
day TEXT NOT NULL,
source TEXT NOT NULL,
flags TEXT NOT NULL,
searches INTEGER NOT NULL,
misses INTEGER NOT NULL,
PRIMARY KEY (day, source, flags)
);
"#;
pub(crate) const MIGRATION_V11: &str = r#"
ALTER TABLE events ADD COLUMN status TEXT;
ALTER TABLE events ADD COLUMN coverage TEXT;
ALTER TABLE usage_daily ADD COLUMN warming INTEGER NOT NULL DEFAULT 0;
ALTER TABLE usage_daily ADD COLUMN on_complete INTEGER NOT NULL DEFAULT 0;
"#;
pub(crate) const MIGRATION_V12: &str = r#"
CREATE INDEX IF NOT EXISTS idx_symbols_repo_name ON symbols(repository_id, name_lower);
DROP INDEX IF EXISTS idx_symbols_repo;
"#;
pub(crate) const MIGRATION_V13: &str = r#"
DROP TABLE IF EXISTS selection_stats;
DROP TABLE IF EXISTS events;
DELETE FROM meta WHERE key = 'events_hwm';
"#;
pub(crate) const MIGRATION_V14: &str = r#"
UPDATE coverage SET status = 'warming'
WHERE scope = 'full' AND status = 'complete'
AND repository_id IN (
SELECT repository_id FROM files
WHERE language IN ('go', 'python', 'typescript', 'javascript'));
UPDATE files SET mtime = NULL, content_hash = ''
WHERE language IN ('go', 'python', 'typescript', 'javascript');
"#;
pub(crate) const MIGRATION_V15: &str = r#"
DROP TABLE IF EXISTS symbols_fts;
CREATE VIRTUAL TABLE symbols_fts USING fts5(
name,
content='symbols',
content_rowid='id',
tokenize='trigram',
detail=none
);
INSERT INTO symbols_fts(symbols_fts) VALUES ('rebuild');
"#;
const MIGRATION_V16: Step = Step::AddColumn {
table: "usage_daily",
column: "live",
decl: "INTEGER NOT NULL DEFAULT 0",
};
pub(crate) const MIGRATION_V17: &str = r#"
CREATE TABLE IF NOT EXISTS name_sigs (
repository_id INTEGER NOT NULL,
kind INTEGER NOT NULL,
chunk INTEGER NOT NULL,
n INTEGER NOT NULL,
sigs BLOB NOT NULL,
keys BLOB NOT NULL,
PRIMARY KEY (repository_id, kind, chunk)
);
CREATE TABLE IF NOT EXISTS name_index (
repository_id INTEGER PRIMARY KEY,
format INTEGER NOT NULL,
built INTEGER NOT NULL
);
"#;
pub(crate) const MIGRATION_V18: &str = r#"
DROP TRIGGER IF EXISTS symbols_ai;
DROP TRIGGER IF EXISTS symbols_ad;
DROP TRIGGER IF EXISTS symbols_au;
DROP TABLE IF EXISTS symbols_fts;
DROP INDEX IF EXISTS idx_symbols_name_lower;
"#;
const MIGRATION_V19: Step = Step::AddColumn {
table: "files",
column: "generated",
decl: "INTEGER NOT NULL DEFAULT 0",
};
pub(crate) const MIGRATION_V19_REQUEUE: &str = r#"
UPDATE coverage SET status = 'warming' WHERE scope = 'full' AND status = 'complete';
UPDATE files SET mtime = NULL, content_hash = '';
"#;
pub(crate) const MIGRATION_V20: &str = MIGRATION_V14;
pub(crate) enum Step {
Sql(&'static str),
AddColumn {
table: &'static str,
column: &'static str,
decl: &'static str,
},
}
pub(crate) const MIGRATIONS: [(i64, Step); 20] = [
(2, Step::Sql(MIGRATION_V2)),
(3, Step::Sql(MIGRATION_V3)),
(4, Step::Sql(MIGRATION_V4)),
(5, Step::Sql(MIGRATION_V5)),
(6, Step::Sql(MIGRATION_V6)),
(7, Step::Sql(MIGRATION_V7)),
(8, Step::Sql(MIGRATION_V8)),
(9, Step::Sql(MIGRATION_V9)),
(10, Step::Sql(MIGRATION_V10)),
(11, Step::Sql(MIGRATION_V11)),
(12, Step::Sql(MIGRATION_V12)),
(13, Step::Sql(MIGRATION_V13)),
(14, Step::Sql(MIGRATION_V14)),
(15, Step::Sql(MIGRATION_V15)),
(16, MIGRATION_V16),
(17, Step::Sql(MIGRATION_V17)),
(18, Step::Sql(MIGRATION_V18)),
(19, MIGRATION_V19),
(19, Step::Sql(MIGRATION_V19_REQUEUE)),
(20, Step::Sql(MIGRATION_V20)),
];