relay-knowledge 1.1.8

Graph-database-based knowledge graph project.
Documentation
use std::{
    fs,
    path::{Path, PathBuf},
    time::{SystemTime, UNIX_EPOCH},
};

use relay_knowledge::{
    domain::{
        CodeIndexBatch, CodeIndexMode, CodeIndexResourceBudget, CodeIndexSession,
        CodeIndexSnapshot, CodeParseStatus, CodeQueryKind, CodeRepositoryRegistration,
        CodeRepositorySelector, CodeRetrievalRequest, FreshnessPolicy, RepositoryCodeChunkRecord,
        RepositoryCodeFileRecord, RepositoryCodeRange, SoftwareGlobalKind, SoftwareGlobalRequest,
    },
    env::{EnvironmentConfig, PlatformKind},
    paths::RuntimePaths,
    storage::CodeIndexTaskSeed,
};
use rusqlite::Connection;

pub(super) fn runtime_paths() -> RuntimePaths {
    runtime_paths_for_root(&unique_temp_dir("partitioned-sqlite"))
}

pub(super) fn runtime_paths_for_root(root: &Path) -> RuntimePaths {
    let environment = EnvironmentConfig::from_pairs(
        PlatformKind::current(),
        [(
            "RELAY_KNOWLEDGE_HOME",
            root.to_str().expect("temp path should be UTF-8"),
        )],
    )
    .expect("environment should parse");

    RuntimePaths::resolve(&environment.platform, &environment.paths).expect("paths resolve")
}

pub(super) fn unique_temp_dir(name: &str) -> PathBuf {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("clock should be after epoch")
        .as_nanos();
    let path = std::env::temp_dir().join(format!(
        "relay-knowledge-{name}-{}-{nanos}",
        std::process::id()
    ));
    let _ = fs::remove_dir_all(&path);
    path
}

pub(super) fn registration(repository_id: &str, alias: &str) -> CodeRepositoryRegistration {
    CodeRepositoryRegistration::new(
        repository_id,
        alias,
        format!("/tmp/{alias}"),
        Vec::new(),
        Vec::new(),
    )
    .expect("registration validates")
}

pub(super) fn snapshot(
    repository_id: &str,
    source_scope: &str,
    content: &str,
) -> CodeIndexSnapshot {
    let file = RepositoryCodeFileRecord {
        repository_id: repository_id.to_owned(),
        source_scope: source_scope.to_owned(),
        file_id: format!("{repository_id}:src/lib.rs"),
        path: "src/lib.rs".to_owned(),
        language_id: "rust".to_owned(),
        blob_hash: format!("sha256:{repository_id}"),
        byte_len: content.len(),
        line_count: 1,
        parse_status: CodeParseStatus::Parsed,
        degraded_reason: None,
    };
    let chunk = RepositoryCodeChunkRecord {
        repository_id: repository_id.to_owned(),
        source_scope: source_scope.to_owned(),
        chunk_id: format!("{repository_id}:chunk"),
        file_id: file.file_id.clone(),
        path: file.path.clone(),
        language_id: file.language_id.clone(),
        content: content.to_owned(),
        byte_range: range(0, content.len()),
        line_range: range(1, 1),
        symbol_snapshot_id: None,
    };

    CodeIndexSnapshot {
        repository_id: repository_id.to_owned(),
        source_scope: source_scope.to_owned(),
        base_resolved_commit_sha: None,
        resolved_commit_sha: format!("{repository_id}-commit"),
        tree_hash: format!("{repository_id}-tree"),
        path_filters: Vec::new(),
        language_filters: Vec::new(),
        full_replace: true,
        changed_path_count: 1,
        skipped_unchanged_count: 0,
        deleted_paths: Vec::new(),
        tombstones: Vec::new(),
        files: vec![file],
        symbols: Vec::new(),
        references: Vec::new(),
        imports: Vec::new(),
        calls: Vec::new(),
        dependencies: Vec::new(),
        feature_flags: Vec::new(),
        chunks: vec![chunk],
        diagnostics: Vec::new(),
    }
}

pub(super) fn snapshot_with_commit(
    repository_id: &str,
    source_scope: &str,
    commit: &str,
    content: &str,
) -> CodeIndexSnapshot {
    let mut snapshot = snapshot(repository_id, source_scope, content);
    snapshot.resolved_commit_sha = commit.to_owned();
    snapshot.tree_hash = format!("{commit}-tree");
    snapshot
}

pub(super) fn incremental_snapshot(
    repository_id: &str,
    source_scope: &str,
    base_commit: &str,
    content: &str,
) -> CodeIndexSnapshot {
    let mut snapshot = snapshot(repository_id, source_scope, content);
    snapshot.base_resolved_commit_sha = Some(base_commit.to_owned());
    snapshot.resolved_commit_sha = format!("{repository_id}-next-commit");
    snapshot.tree_hash = format!("{repository_id}-next-tree");
    snapshot.full_replace = false;
    snapshot
}

pub(super) fn session_for_snapshot(snapshot: &CodeIndexSnapshot) -> CodeIndexSession {
    CodeIndexSession {
        repository_id: snapshot.repository_id.clone(),
        source_scope: snapshot.source_scope.clone(),
        base_resolved_commit_sha: snapshot.base_resolved_commit_sha.clone(),
        resolved_commit_sha: snapshot.resolved_commit_sha.clone(),
        tree_hash: snapshot.tree_hash.clone(),
        path_filters: snapshot.path_filters.clone(),
        language_filters: snapshot.language_filters.clone(),
        full_replace: snapshot.full_replace,
        total_path_count: snapshot.files.len(),
        changed_path_count: snapshot.changed_path_count,
        skipped_unchanged_count: snapshot.skipped_unchanged_count,
        deleted_paths: snapshot.deleted_paths.clone(),
        tombstones: snapshot.tombstones.clone(),
        resource_budget: CodeIndexResourceBudget::default(),
    }
}

pub(super) fn batch_from_snapshot(snapshot: CodeIndexSnapshot) -> CodeIndexBatch {
    CodeIndexBatch {
        repository_id: snapshot.repository_id,
        source_scope: snapshot.source_scope,
        batch_index: 0,
        parsed_byte_count: snapshot.files.iter().map(|file| file.byte_len).sum(),
        files: snapshot.files,
        symbols: snapshot.symbols,
        references: snapshot.references,
        imports: snapshot.imports,
        dependencies: snapshot.dependencies,
        feature_flags: snapshot.feature_flags,
        chunks: snapshot.chunks,
        diagnostics: snapshot.diagnostics,
    }
}

pub(super) fn code_index_task_seed(
    repository_id: &str,
    alias: &str,
    fingerprint: &str,
    source_scope: &str,
    now_ms: u64,
) -> CodeIndexTaskSeed {
    CodeIndexTaskSeed {
        repository_id: repository_id.to_owned(),
        alias: alias.to_owned(),
        ref_selector: "HEAD".to_owned(),
        resolved_commit_sha: format!("{repository_id}-{source_scope}-commit"),
        tree_hash: format!("{repository_id}-{source_scope}-tree"),
        source_scope: source_scope.to_owned(),
        path_filters: Vec::new(),
        language_filters: Vec::new(),
        mode: CodeIndexMode::Full,
        input_fingerprint: fingerprint.to_owned(),
        resource_budget: CodeIndexResourceBudget::default(),
        payload_json: "{}".to_owned(),
        now_ms,
    }
}

pub(super) fn retrieval_request(repository: &str, query: &str) -> CodeRetrievalRequest {
    retrieval_request_for_ref(repository, "HEAD", query)
}

pub(super) fn retrieval_request_for_ref(
    repository: &str,
    ref_selector: &str,
    query: &str,
) -> CodeRetrievalRequest {
    CodeRetrievalRequest::new(
        query,
        CodeRepositorySelector::new(repository, ref_selector, Vec::new(), Vec::new())
            .expect("selector validates"),
        CodeQueryKind::Hybrid,
        10,
        FreshnessPolicy::AllowStale,
    )
    .expect("request validates")
}

pub(super) fn software_request(repository: &str, ref_selector: &str) -> SoftwareGlobalRequest {
    SoftwareGlobalRequest::new(
        CodeRepositorySelector::new(repository, ref_selector, Vec::new(), Vec::new())
            .expect("selector validates"),
        SoftwareGlobalKind::Files,
        FreshnessPolicy::AllowStale,
        10,
    )
    .expect("request validates")
}

fn range(start: usize, end: usize) -> RepositoryCodeRange {
    RepositoryCodeRange::new("range", start, end).expect("range validates")
}

pub(super) fn control_code_file_count(path: &Path) -> usize {
    let connection = Connection::open(path).expect("control db opens");
    connection
        .query_row("SELECT COUNT(*) FROM code_repository_files", [], |row| {
            row.get(0)
        })
        .expect("count succeeds")
}

pub(super) fn catalog_shard_locator(path: &Path, repository_id: &str) -> String {
    let connection = Connection::open(path).expect("control db opens");
    connection
        .query_row(
            "SELECT db_path FROM storage_repository_shards WHERE repository_id = ?1",
            [repository_id],
            |row| row.get(0),
        )
        .expect("catalog row exists")
}