grapha 0.4.0

Blazingly fast code intelligence CLI and MCP server for Swift and Rust
Documentation
use rusqlite::{Connection, OptionalExtension, Transaction};

use grapha_core::graph::Graph;

pub(super) const STORE_SCHEMA_VERSION: &str = "7";
pub(super) const BINARY_PROVENANCE_SCHEMA_VERSION: &str = "5";

pub(super) fn create_tables(conn: &Connection) -> anyhow::Result<()> {
    conn.execute_batch(
        "CREATE TABLE IF NOT EXISTS meta (
            key   TEXT PRIMARY KEY,
            value TEXT NOT NULL
        );
        CREATE TABLE IF NOT EXISTS nodes (
            id         TEXT PRIMARY KEY,
            kind       TEXT NOT NULL,
            name       TEXT NOT NULL,
            file       TEXT NOT NULL,
            span_start_line   INTEGER NOT NULL,
            span_start_col    INTEGER NOT NULL,
            span_end_line     INTEGER NOT NULL,
            span_end_col      INTEGER NOT NULL,
            visibility TEXT NOT NULL,
            metadata   TEXT NOT NULL,
            role       TEXT,
            signature  TEXT,
            doc_comment TEXT,
            module     TEXT,
            snippet    TEXT,
            repo       TEXT
        );
        CREATE TABLE IF NOT EXISTS edges (
            edge_id    TEXT PRIMARY KEY,
            source     TEXT NOT NULL,
            target     TEXT NOT NULL,
            kind       TEXT NOT NULL,
            confidence REAL NOT NULL,
            direction  TEXT,
            operation  TEXT,
            condition  TEXT,
            async_boundary INTEGER,
            provenance BLOB NOT NULL,
            repo       TEXT
        );",
    )?;
    Ok(())
}

pub(super) fn schema_version(conn: &Connection) -> anyhow::Result<Option<String>> {
    let has_meta = conn
        .query_row(
            "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'meta'",
            [],
            |_| Ok(()),
        )
        .optional()?
        .is_some();
    if !has_meta {
        return Ok(None);
    }

    Ok(conn
        .query_row(
            "SELECT value FROM meta WHERE key = 'store_schema_version'",
            [],
            |row| row.get(0),
        )
        .optional()?)
}

pub(super) fn write_meta(tx: &Transaction<'_>, graph: &Graph) -> anyhow::Result<()> {
    tx.execute(
        "INSERT INTO meta (key, value) VALUES ('version', ?1)
         ON CONFLICT(key) DO UPDATE SET value = excluded.value",
        [&graph.version],
    )?;
    tx.execute(
        "INSERT INTO meta (key, value) VALUES ('store_schema_version', ?1)
         ON CONFLICT(key) DO UPDATE SET value = excluded.value",
        [STORE_SCHEMA_VERSION],
    )?;
    Ok(())
}

pub(super) fn drop_tables(conn: &Connection) -> anyhow::Result<()> {
    conn.execute_batch(
        "DROP TABLE IF EXISTS edges;
         DROP TABLE IF EXISTS nodes;
         DROP TABLE IF EXISTS meta;",
    )?;
    Ok(())
}

pub(super) fn create_bulk_load_tables(conn: &Connection) -> anyhow::Result<()> {
    conn.execute_batch(
        "CREATE TABLE meta (
            key   TEXT PRIMARY KEY,
            value TEXT NOT NULL
        );
        CREATE TABLE nodes (
            id         TEXT NOT NULL,
            kind       TEXT NOT NULL,
            name       TEXT NOT NULL,
            file       TEXT NOT NULL,
            span_start_line   INTEGER NOT NULL,
            span_start_col    INTEGER NOT NULL,
            span_end_line     INTEGER NOT NULL,
            span_end_col      INTEGER NOT NULL,
            visibility TEXT NOT NULL,
            metadata   TEXT NOT NULL,
            role       TEXT,
            signature  TEXT,
            doc_comment TEXT,
            module     TEXT,
            snippet    TEXT,
            repo       TEXT
        );
        CREATE TABLE edges (
            edge_id    TEXT NOT NULL,
            source     TEXT NOT NULL,
            target     TEXT NOT NULL,
            kind       TEXT NOT NULL,
            confidence REAL NOT NULL,
            direction  TEXT,
            operation  TEXT,
            condition  TEXT,
            async_boundary INTEGER,
            provenance BLOB NOT NULL,
            repo       TEXT
        );",
    )?;
    Ok(())
}

pub(super) fn create_bulk_load_indexes(conn: &Connection) -> anyhow::Result<()> {
    conn.execute_batch(
        "CREATE UNIQUE INDEX idx_nodes_id ON nodes(id);
         CREATE UNIQUE INDEX idx_edges_id ON edges(edge_id);",
    )?;
    Ok(())
}