talon-core 0.4.2

Core retrieval engine for Talon: hybrid search (BM25 + semantic + reranker), indexing, and graph-aware ranking over markdown corpora.
Documentation
use rusqlite::{Connection, params};

use super::*;
use crate::config::{Scope, ScopeGlob, ScopePriority, ScopesConfig, TalonConfig, test_literals};
use crate::indexing::migrations::run_migrations;
use crate::query::MetaInput;
use crate::search::{WhereClause, WhereOperator};
use std::path::PathBuf;

fn test_config_with_scopes(scopes: Vec<(&str, &str)>) -> TalonConfig {
    let mut map = ScopesConfig::new();
    for (name, glob) in scopes {
        map.insert(
            name.to_string(),
            Scope {
                glob: ScopeGlob::Single(glob.to_string()),
                priority: ScopePriority::Normal,
                default: true,
                inspect: true,
            },
        );
    }
    test_literals::minimal_for_paths(
        PathBuf::from("/vault"),
        PathBuf::from("/vault/.talon/index.db"),
        "http://localhost:8080",
        map,
    )
}

fn fresh_db() -> Connection {
    let mut conn = Connection::open_in_memory().unwrap();
    run_migrations(&mut conn).unwrap();
    conn
}

fn insert_note_with_fm(
    conn: &Connection,
    vault_path: &str,
    frontmatter_json: &str,
    mtime_ms: i64,
) -> i64 {
    conn.execute(
        "INSERT INTO notes \
             (vault_path, title, tags, aliases, content, frontmatter, \
              mtime_ms, size_bytes, hash, docid, active) \
             VALUES (?, '', '[]', '[]', '', ?, ?, 0, 'h', 'd', 1)",
        params![vault_path, frontmatter_json, mtime_ms],
    )
    .unwrap();
    conn.last_insert_rowid()
}

fn insert_fm_field(conn: &Connection, note_id: i64, field: &str, value: &str) {
    conn.execute(
        "INSERT INTO note_frontmatter_fields \
             (note_id, field, value, value_norm) VALUES (?, ?, ?, ?)",
        params![note_id, field, value, value.to_lowercase()],
    )
    .unwrap();
}

fn insert_typed_fm_field(
    conn: &Connection,
    note_id: i64,
    field: &str,
    value: &str,
    value_type: &str,
) {
    conn.execute(
        "INSERT INTO note_frontmatter_fields \
             (note_id, field, value, value_type, value_norm) VALUES (?, ?, ?, ?, ?)",
        params![note_id, field, value, value_type, value.to_lowercase()],
    )
    .unwrap();
}

fn insert_tag(conn: &Connection, note_id: i64, tag: &str) {
    conn.execute(
        "INSERT INTO note_tags (note_id, tag, tag_norm) VALUES (?, ?, ?)",
        params![note_id, tag, tag.to_lowercase()],
    )
    .unwrap();
}
#[test]
fn tag_counts_aggregates_by_tag() {
    let conn = fresh_db();
    let n1 = insert_note_with_fm(&conn, "a.md", "{}", 0);
    let n2 = insert_note_with_fm(&conn, "b.md", "{}", 0);
    insert_tag(&conn, n1, "rust");
    insert_tag(&conn, n1, "programming");
    insert_tag(&conn, n2, "rust");
    insert_tag(&conn, n2, "algorithms");

    let resp = query_meta(
        &conn,
        &MetaInput {
            tag_counts: true,
            ..MetaInput::default()
        },
        None,
    );

    let tc = resp
        .tag_counts
        .expect("tag_counts must be Some when requested");
    assert_eq!(tc.get("rust"), Some(&2));
    assert_eq!(tc.get("programming"), Some(&1));
    assert_eq!(tc.get("algorithms"), Some(&1));
}
#[test]
fn where_equals_filters_notes() {
    let conn = fresh_db();
    let n1 = insert_note_with_fm(&conn, "project.md", "{}", 0);
    let n2 = insert_note_with_fm(&conn, "note.md", "{}", 0);
    insert_fm_field(&conn, n1, "type", "project");
    insert_fm_field(&conn, n2, "type", "note");

    let resp = query_meta(
        &conn,
        &MetaInput {
            where_: vec![WhereClause {
                key: "type".into(),
                op: WhereOperator::Equals,
                value: Some("project".into()),
            }],
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "project.md");
}
#[test]
fn where_exists_returns_notes_with_field() {
    let conn = fresh_db();
    let n1 = insert_note_with_fm(&conn, "done.md", "{}", 0);
    insert_note_with_fm(&conn, "empty.md", "{}", 0);
    insert_fm_field(&conn, n1, "status", "done");

    let resp = query_meta(
        &conn,
        &MetaInput {
            where_: vec![WhereClause {
                key: "status".into(),
                op: WhereOperator::Exists,
                value: None,
            }],
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "done.md");
}
#[test]
fn where_contains_matches_substring() {
    let conn = fresh_db();
    let n1 = insert_note_with_fm(&conn, "rust-notes.md", "{}", 0);
    let n2 = insert_note_with_fm(&conn, "python-notes.md", "{}", 0);
    insert_fm_field(&conn, n1, "description", "rust programming language");
    insert_fm_field(&conn, n2, "description", "python scripting");

    let resp = query_meta(
        &conn,
        &MetaInput {
            where_: vec![WhereClause {
                key: "description".into(),
                op: WhereOperator::Contains,
                value: Some("rust".into()),
            }],
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "rust-notes.md");
}
#[test]
fn where_numeric_comparison_uses_value_type() {
    let conn = fresh_db();
    let n1 = insert_note_with_fm(&conn, "high.md", "{}", 0);
    let n2 = insert_note_with_fm(&conn, "low.md", "{}", 0);
    insert_typed_fm_field(&conn, n1, "priority", "10", "number");
    insert_typed_fm_field(&conn, n2, "priority", "2", "number");

    let resp = query_meta(
        &conn,
        &MetaInput {
            where_: vec![WhereClause {
                key: "priority".into(),
                op: WhereOperator::GreaterThan,
                value: Some("3".into()),
            }],
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "high.md");
}
#[test]
fn where_date_comparison_uses_value_type() {
    let conn = fresh_db();
    let n1 = insert_note_with_fm(&conn, "new.md", "{}", 0);
    let n2 = insert_note_with_fm(&conn, "old.md", "{}", 0);
    insert_typed_fm_field(&conn, n1, "due", "2026-04-29", "date");
    insert_typed_fm_field(&conn, n2, "due", "2026-04-01", "date");

    let resp = query_meta(
        &conn,
        &MetaInput {
            where_: vec![WhereClause {
                key: "due".into(),
                op: WhereOperator::GreaterThan,
                value: Some("2026-04-15".into()),
            }],
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "new.md");
}
#[test]
fn sources_returns_notes_referencing_target() {
    let conn = fresh_db();
    let n1 = insert_note_with_fm(&conn, "referencing.md", "{}", 0);
    let n2 = insert_note_with_fm(&conn, "unrelated.md", "{}", 0);
    insert_fm_field(&conn, n1, "sources", "target.md");
    insert_fm_field(&conn, n2, "sources", "other.md");

    let resp = query_meta(
        &conn,
        &MetaInput {
            sources: Some("target.md".into()),
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "referencing.md");
}
#[test]
fn since_filter_excludes_old_notes() {
    let conn = fresh_db();
    insert_note_with_fm(&conn, "old.md", "{}", 1000);
    insert_note_with_fm(&conn, "new.md", "{}", 3000);

    let resp = query_meta(
        &conn,
        &MetaInput {
            since: Some("2000".into()),
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "new.md");
}
#[test]
fn scope_only_filters_by_configured_scope() {
    let conn = fresh_db();
    insert_note_with_fm(&conn, "Atlas/note.md", "{}", 0);
    insert_note_with_fm(&conn, "Search/note.md", "{}", 0);

    let config = test_config_with_scopes(vec![("atlas", "Atlas/**"), ("search", "Search/**")]);
    let resp = query_meta(
        &conn,
        &MetaInput {
            scope_only: vec!["atlas".into()],
            ..MetaInput::default()
        },
        Some(&config),
    );

    assert_eq!(resp.entries.len(), 1);
    assert_eq!(resp.entries[0].path.as_str(), "Atlas/note.md");
}
#[test]
fn select_projects_only_requested_fields() {
    let conn = fresh_db();
    let fm =
        r#"{"type":{"String":"project"},"status":{"String":"active"},"priority":{"Number":1.0}}"#;
    insert_note_with_fm(&conn, "proj.md", fm, 0);

    let resp = query_meta(
        &conn,
        &MetaInput {
            select: vec!["type".into()],
            ..MetaInput::default()
        },
        None,
    );

    assert_eq!(resp.entries.len(), 1);
    let fm = &resp.entries[0].frontmatter;
    assert!(fm.contains_key("type"), "selected field must be present");
    assert!(
        !fm.contains_key("status"),
        "non-selected field must be absent"
    );
    assert!(
        !fm.contains_key("priority"),
        "non-selected field must be absent"
    );
}