gobby-code 1.3.2

Fast Rust CLI for Gobby's code index — AST-aware search, symbol navigation, and dependency graph
Documentation
use std::collections::HashSet;

use crate::graph::typed_query;
use crate::models::{GraphResult, ProjectionProvenance};
use gobby_core::falkor::Row;

use super::super::payload::{row_string_owned, row_to_projection_metadata, row_usize};

pub(super) const CALL_TARGET_PREDICATE: &str =
    "target:CodeSymbol OR target:UnresolvedCallee OR target:ExternalSymbol";
pub(super) const NEIGHBOR_PREDICATE: &str =
    "neighbor:CodeSymbol OR neighbor:UnresolvedCallee OR neighbor:ExternalSymbol";
pub(super) const TARGET_TYPE_CASE: &str = "CASE \
     WHEN target:CodeSymbol THEN coalesce(target.kind, 'function') \
     WHEN target:ExternalSymbol THEN 'external' \
     ELSE 'unresolved' \
     END";
pub(super) const NEIGHBOR_TYPE_CASE: &str = "CASE \
     WHEN neighbor:CodeSymbol THEN coalesce(neighbor.kind, 'function') \
     WHEN neighbor:ExternalSymbol THEN 'external' \
     ELSE 'unresolved' \
     END";
pub(super) const CONFIDENCE_LABEL_CASE: &str = "CASE \
     WHEN 'AMBIGUOUS' IN provenances THEN 'AMBIGUOUS' \
     WHEN 'INFERRED' IN provenances THEN 'INFERRED' \
     ELSE 'EXTRACTED' \
     END";
pub(super) const NODE_TYPE_CASE: &str = "CASE \
     WHEN n:CodeFile THEN 'file' \
     WHEN n:CodeModule THEN 'module' \
     WHEN n:CodeSymbol THEN coalesce(n.kind, 'function') \
     WHEN n:ExternalSymbol THEN 'external' \
     ELSE 'unresolved' \
     END";
pub(super) const LINK_METADATA_RETURN: &str = "r.provenance AS provenance, \
     r.confidence AS confidence, \
     r.source_system AS source_system, \
     r.source_file_path AS metadata_source_file_path, \
     r.source_line AS source_line, \
     r.source_symbol_id AS source_symbol_id, \
     r.matching_method AS matching_method";
pub(super) const MAX_GRAPH_LIMIT: usize = 100;
pub(crate) fn row_to_graph_result(row: &Row) -> GraphResult {
    GraphResult {
        id: row
            .get("caller_id")
            .or_else(|| row.get("callee_id"))
            .or_else(|| row.get("source_id"))
            .or_else(|| row.get("node_id"))
            .or_else(|| row.get("symbol_id"))
            .or_else(|| row.get("id"))
            .and_then(|v| v.as_str())
            .unwrap_or("")
            .to_string(),
        name: row
            .get("caller_name")
            .or_else(|| row.get("callee_name"))
            .or_else(|| row.get("source_name"))
            .or_else(|| row.get("node_name"))
            .or_else(|| row.get("symbol_name"))
            .or_else(|| row.get("name"))
            .or_else(|| row.get("module_name"))
            .and_then(|v| v.as_str())
            .unwrap_or("")
            .to_string(),
        file_path: row
            .get("file")
            .or_else(|| row.get("file_path"))
            .and_then(|v| v.as_str())
            .unwrap_or("")
            .to_string(),
        line: row
            .get("line")
            .and_then(|v| v.as_u64())
            .and_then(|value| usize::try_from(value).ok())
            .unwrap_or(0),
        confidence: row
            .get("confidence_label")
            .or_else(|| row.get("provenance"))
            .and_then(|v| v.as_str())
            .and_then(ProjectionProvenance::from_wire_value)
            .unwrap_or_default(),
        relation: row
            .get("relation")
            .or_else(|| row.get("rel_type"))
            .and_then(|v| v.as_str())
            .map(String::from),
        distance: row
            .get("distance")
            .and_then(|v| v.as_u64())
            .and_then(|d| usize::try_from(d).ok()),
        metadata: row_to_projection_metadata(row),
    }
}
pub(super) fn clamp_limit(limit: usize) -> usize {
    typed_query::clamp_limit(limit, MAX_GRAPH_LIMIT)
}

pub(super) fn clamp_offset(offset: usize) -> usize {
    typed_query::clamp_offset(offset, MAX_GRAPH_LIMIT)
}
pub(in crate::graph::code_graph) fn dedupe_limited_blast_rows(
    mut rows: Vec<Row>,
    limit: usize,
) -> Vec<Row> {
    rows.sort_by(|left, right| {
        row_usize(left, &["distance"])
            .unwrap_or(usize::MAX)
            .cmp(&row_usize(right, &["distance"]).unwrap_or(usize::MAX))
            .then_with(|| {
                row_string_owned(left, &["node_name"])
                    .unwrap_or_default()
                    .cmp(&row_string_owned(right, &["node_name"]).unwrap_or_default())
            })
            .then_with(|| {
                row_string_owned(left, &["node_id"])
                    .unwrap_or_default()
                    .cmp(&row_string_owned(right, &["node_id"]).unwrap_or_default())
            })
    });

    let mut seen = HashSet::new();
    rows.retain(|row| {
        let Some(node_id) = row_string_owned(row, &["node_id"]) else {
            return false;
        };
        seen.insert(node_id)
    });
    rows.truncate(clamp_limit(limit));
    rows
}

pub(super) fn count_from_rows(rows: &[Row]) -> usize {
    rows.first()
        .and_then(|r| r.get("cnt"))
        .and_then(|v| {
            v.as_u64()
                .or_else(|| v.as_i64().and_then(|value| value.try_into().ok()))
        })
        .and_then(|value| usize::try_from(value).ok())
        .unwrap_or(0)
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;

    #[test]
    fn graph_result_confidence_defaults_to_extracted_without_metadata() {
        let row = Row::from([
            ("caller_id".to_string(), json!("caller-1")),
            ("caller_name".to_string(), json!("run")),
            ("file".to_string(), json!("src/lib.rs")),
            ("line".to_string(), json!(12)),
        ]);

        let result = row_to_graph_result(&row);

        assert_eq!(result.confidence, ProjectionProvenance::Extracted);
        assert!(result.metadata.is_none());
    }

    #[test]
    fn graph_result_confidence_uses_provenance_label_with_metadata_score() {
        let row = Row::from([
            ("source_id".to_string(), json!("caller-1")),
            ("source_name".to_string(), json!("run")),
            ("file".to_string(), json!("src/lib.rs")),
            ("line".to_string(), json!(12)),
            ("rel_type".to_string(), json!("CALLS")),
            ("provenance".to_string(), json!("INFERRED")),
            ("confidence".to_string(), json!(0.72)),
            ("source_system".to_string(), json!("semantic")),
        ]);

        let result = row_to_graph_result(&row);

        assert_eq!(result.confidence, ProjectionProvenance::Inferred);
        assert_eq!(
            result
                .metadata
                .as_ref()
                .and_then(|metadata| metadata.confidence),
            Some(0.72)
        );
    }
}