pub(crate) const VERSION: i64 = 16;
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,
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; NULL when
-- unknown (pre-v9 rows backfill lazily)
);
CREATE INDEX idx_symbols_name_lower ON symbols(name_lower);
CREATE INDEX idx_symbols_file ON symbols(file_id);
CREATE INDEX idx_symbols_repo_name ON symbols(repository_id, name_lower);
-- fuzzy candidate narrowing: trigram FTS over symbol names. detail=none drops
-- positions, which an OR of single trigrams never reads; a MATCH on a longer
-- substring is a phrase query, and fails.
CREATE VIRTUAL TABLE symbols_fts USING fts5(
name,
content='symbols',
content_rowid='id',
tokenize='trigram',
detail=none
);
-- keep the external-content FTS index in sync with symbols
-- (the AFTER INSERT trigger is FTS_INSERT_TRIGGER, defined once below)
CREATE TRIGGER symbols_ad AFTER DELETE ON symbols BEGIN
INSERT INTO symbols_fts(symbols_fts, rowid, name) VALUES ('delete', old.id, old.name);
END;
CREATE TRIGGER symbols_au AFTER UPDATE ON symbols BEGIN
INSERT INTO symbols_fts(symbols_fts, rowid, name) VALUES ('delete', old.id, old.name);
INSERT INTO symbols_fts(rowid, name) VALUES (new.id, new.name);
END;
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)
);
-- 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) enum Step {
Sql(&'static str),
AddColumn {
table: &'static str,
column: &'static str,
decl: &'static str,
},
}
pub(crate) const MIGRATIONS: [(i64, Step); 15] = [
(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),
];
pub(crate) const FTS_INSERT_TRIGGER: &str = r#"
CREATE TRIGGER IF NOT EXISTS symbols_ai AFTER INSERT ON symbols BEGIN
INSERT INTO symbols_fts(rowid, name) VALUES (new.id, new.name);
END;
"#;