relay-knowledge 1.1.10

Graph-database-based knowledge graph project.
Documentation
use rusqlite::types::Value;

use super::code_query_support::{
    candidate_patterns, push_language_filter_values, push_path_filter_values,
    push_query_path_substring_filter_values,
};
use crate::domain::{CodeQueryKind, CodeRepositoryStatus, CodeRetrievalRequest};

pub(super) fn fts_values_for_limited_with_language_and_call_direction(
    source_scope: &str,
    status: &CodeRepositoryStatus,
    request: &CodeRetrievalRequest,
    fts_query: &str,
    fts_limit: usize,
    limit: usize,
) -> Vec<Value> {
    let mut values = vec![
        Value::Text(source_scope.to_owned()),
        Value::Text(fts_query.to_owned()),
        Value::Text(source_scope.to_owned()),
    ];
    push_path_filter_values(&mut values, &status.path_filters);
    push_path_filter_values(&mut values, &request.repository.path_filters);
    push_query_path_substring_filter_values(&mut values, &request.query_path_substrings);
    push_language_filter_values(&mut values, &status.language_filters);
    push_language_filter_values(&mut values, &request.repository.language_filters);
    push_language_filter_values(&mut values, &request.query_language_filters);
    push_call_direction_filter_values(&mut values, request);
    values.push(Value::Integer(fts_limit as i64));
    values.push(Value::Integer(limit as i64));

    values
}

pub(super) fn call_direction_fts_filter_sql(request: &CodeRetrievalRequest) -> String {
    let Some(surface) = call_direction_filter_surface(request.code_query_kind) else {
        return String::new();
    };
    let patterns = candidate_patterns(&request.query, 8);
    if patterns.is_empty() {
        return String::new();
    }
    let clauses = patterns
        .iter()
        .map(|_| format!("{surface} LIKE ? ESCAPE '\\'"))
        .collect::<Vec<_>>()
        .join(" OR ");

    format!(
        "AND EXISTS (
            SELECT 1
            FROM code_repository_calls call_filter
            LEFT JOIN code_repository_symbols caller_filter
              ON caller_filter.source_scope = call_filter.source_scope
             AND caller_filter.symbol_snapshot_id = call_filter.caller_symbol_snapshot_id
            LEFT JOIN code_repository_symbols callee_filter
              ON callee_filter.source_scope = call_filter.source_scope
             AND callee_filter.symbol_snapshot_id = call_filter.callee_symbol_snapshot_id
            WHERE call_filter.source_scope = code_repository_search.source_scope
              AND call_filter.call_id = code_repository_search.record_id
              AND ({clauses})
        )"
    )
}

fn push_call_direction_filter_values(values: &mut Vec<Value>, request: &CodeRetrievalRequest) {
    if call_direction_filter_surface(request.code_query_kind).is_none() {
        return;
    }
    values.extend(
        candidate_patterns(&request.query, 8)
            .into_iter()
            .map(Value::Text),
    );
}

fn call_direction_filter_surface(kind: CodeQueryKind) -> Option<&'static str> {
    match kind {
        CodeQueryKind::Callers => {
            Some("lower(call_filter.callee_name || ' ' || coalesce(callee_filter.signature, ''))")
        }
        CodeQueryKind::Callees => Some(
            "lower(coalesce(call_filter.caller_name, '') || ' ' || coalesce(caller_filter.signature, ''))",
        ),
        _ => None,
    }
}