talon-core 0.4.2

Core retrieval engine for Talon: hybrid search (BM25 + semantic + reranker), indexing, and graph-aware ranking over markdown corpora.
Documentation
#![allow(clippy::unwrap_used)]

use std::path::PathBuf;

use rusqlite::Connection;
use rusqlite::params;

use super::*;
use crate::contracts::PositiveCount;
use crate::indexing::migrations::run_migrations;
use crate::query::ReadInput;

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

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

fn vault_root() -> PathBuf {
    PathBuf::from("/vault")
}

fn read_input(path: &str) -> ReadInput {
    ReadInput {
        path: Some(path.to_string()),
        raw: false,
        from_line: None,
        max_lines: None,
    }
}

#[test]
fn strips_frontmatter_by_default() {
    let conn = fresh_db();
    insert_note(
        &conn,
        "notes/example.md",
        "Example",
        "---\ntitle: Example\ntags: [rust]\n---\n\nHello world\n",
    );

    let resp = run_read(&conn, &vault_root(), &read_input("notes/example.md"));
    let result = &resp.results[0];

    assert!(result.found);
    let content = result.content.as_deref().unwrap();
    assert!(
        !content.contains("---"),
        "frontmatter delimiters must be stripped"
    );
    assert!(
        !content.contains("title:"),
        "frontmatter fields must be stripped"
    );
    assert!(content.contains("Hello world"));
}

#[test]
fn raw_mode_preserves_frontmatter() {
    let conn = fresh_db();
    insert_note(
        &conn,
        "notes/raw.md",
        "Raw",
        "---\ntitle: Raw\n---\n\nBody here\n",
    );

    let resp = run_read(
        &conn,
        &vault_root(),
        &ReadInput {
            path: Some("notes/raw.md".to_string()),
            raw: true,
            from_line: None,
            max_lines: None,
        },
    );
    let result = &resp.results[0];
    assert!(result.found);
    let content = result.content.as_deref().unwrap();
    assert!(
        content.contains("---"),
        "raw mode must preserve frontmatter delimiters"
    );
    assert!(content.contains("title: Raw"));
}

#[test]
fn line_range_clips_body() {
    let conn = fresh_db();
    let body = "line1\nline2\nline3\nline4\nline5\n";
    insert_note(&conn, "notes/lines.md", "Lines", body);

    let resp = run_read(
        &conn,
        &vault_root(),
        &ReadInput {
            path: Some("notes/lines.md".to_string()),
            raw: true,
            from_line: Some(PositiveCount::new(2, "from_line").unwrap()),
            max_lines: Some(PositiveCount::new(2, "max_lines").unwrap()),
        },
    );
    let result = &resp.results[0];
    assert!(result.found);
    let content = result.content.as_deref().unwrap();
    assert_eq!(content, "line2\nline3");
}

#[test]
fn missing_note_returns_not_found() {
    let conn = fresh_db();

    let resp = run_read(&conn, &vault_root(), &read_input("does/not/exist.md"));
    assert_eq!(resp.results.len(), 1);
    let result = &resp.results[0];
    assert!(!result.found);
    assert!(result.content.is_none());
}

#[test]
fn extension_less_path_resolves_md_note() {
    let conn = fresh_db();
    insert_note(&conn, "notes/example.md", "Example", "Hello");

    let resp = run_read(&conn, &vault_root(), &read_input("notes/example"));
    let result = &resp.results[0];
    assert!(result.found, "should resolve without .md extension");
    assert_eq!(result.vault_path.as_str(), "notes/example.md");
}

#[test]
fn links_and_backlinks_hydrated() {
    let conn = fresh_db();
    insert_note(&conn, "a.md", "A", "content");
    insert_note(&conn, "b.md", "B", "content");
    conn.execute(
        "INSERT INTO links (from_path, to_path, raw_target) VALUES (?, ?, ?)",
        params!["a.md", "b.md", "[[b]]"],
    )
    .unwrap();

    let resp = run_read(&conn, &vault_root(), &read_input("a.md"));
    let result = &resp.results[0];
    assert!(result.found);
    assert!(
        result.links.contains(&"b.md".to_string()),
        "outgoing link must be present"
    );

    let resp_b = run_read(&conn, &vault_root(), &read_input("b.md"));
    let result_b = &resp_b.results[0];
    assert!(
        result_b.backlinks.contains(&"a.md".to_string()),
        "backlink must be present"
    );
}

#[test]
fn obsidian_reference_reads_resolved_heading_section() {
    let conn = fresh_db();
    insert_note(
        &conn,
        "wiki/Hot Sauce Formulation.md",
        "Hot Sauce Formulation",
        "# Hot Sauce Formulation\n\nIntro\n\n## Targets\nBottle-ready sauce\n## Other\nNot included\n",
    );

    let resp = run_read(
        &conn,
        &vault_root(),
        &read_input("[[Hot Sauce Formulation#Targets|targets]]"),
    );
    let result = &resp.results[0];

    assert!(result.found);
    assert_eq!(result.vault_path.as_str(), "wiki/Hot Sauce Formulation.md");
    assert_eq!(
        result.content.as_deref(),
        Some("## Targets\nBottle-ready sauce")
    );
    let section = result
        .section
        .as_ref()
        .unwrap_or_else(|| panic!("section metadata"));
    assert_eq!(section.heading, "Targets");
    assert_eq!(section.from_line, 5);
    assert_eq!(section.to_line, 6);
    assert_eq!(
        section.obsidian_ref,
        "[[wiki/Hot Sauce Formulation.md#Targets]]"
    );
}

#[test]
fn obsidian_reference_missing_heading_does_not_dump_whole_note() {
    let conn = fresh_db();
    insert_note(
        &conn,
        "wiki/Hot Sauce Formulation.md",
        "Hot Sauce Formulation",
        "# Hot Sauce Formulation\n\nBody\n",
    );

    let resp = run_read(
        &conn,
        &vault_root(),
        &read_input("[[Hot Sauce Formulation#Missing]]"),
    );
    let result = &resp.results[0];

    assert!(!result.found);
    assert_eq!(result.vault_path.as_str(), "wiki/Hot Sauce Formulation.md");
    assert!(result.content.is_none());
}