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 super::*;
use crate::search::SearchMode;
use crate::search::types::RawSearchResult;
use crate::search::types::SearchScores;
use crate::store::open_database;
use rusqlite::{Connection, params};
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};

fn unique_path() -> PathBuf {
    static C: AtomicU64 = AtomicU64::new(0);
    let n = C.fetch_add(1, Ordering::Relaxed);
    std::env::temp_dir().join(format!(
        "talon-search-affordance-test-{}-{n}.sqlite",
        std::process::id()
    ))
}

fn cleanup(path: &std::path::Path) {
    let _ = fs_err::remove_file(path);
    let _ = fs_err::remove_file(path.with_extension("sqlite-wal"));
    let _ = fs_err::remove_file(path.with_extension("sqlite-shm"));
}

fn insert_note_with_content(conn: &Connection, vault_path: &str, content: &str) -> i64 {
    assert!(
        conn.execute(
            "INSERT INTO notes
         (vault_path, title, tags, aliases, content, mtime_ms, size_bytes, hash, docid, active)
         VALUES (?, 'Title', '[]', '[]', ?, 0, 0, 'h', 'd', 1)",
            params![vault_path, content],
        )
        .is_ok(),
        "failed to insert test note"
    );
    conn.last_insert_rowid()
}

fn insert_fm_field(conn: &Connection, note_id: i64, field: &str, value: &str) {
    assert!(
        conn.execute(
            "INSERT INTO note_frontmatter_fields
         (note_id, field, value, value_norm) VALUES (?, ?, ?, ?)",
            params![note_id, field, value, value.to_lowercase()],
        )
        .is_ok(),
        "failed to insert test frontmatter field"
    );
}

fn raw(path: &str) -> RawSearchResult {
    RawSearchResult {
        path: path.into(),
        title: "Title".into(),
        tags: vec!["wiki".to_string(), "index".to_string()],
        aliases: vec!["Home".to_string()],
        snippet: "index".into(),
        score: 0.9,
        scores: SearchScores::default(),
        semantic_heading: None,
        semantic_char_start: None,
        semantic_char_end: None,
    }
}

#[test]
fn raw_to_search_result_exposes_wiki_navigation_metadata() {
    let path = unique_path();
    let conn = match open_database(&path) {
        Ok(conn) => conn,
        Err(err) => panic!("failed to open temp db: {err}"),
    };
    let note_id = insert_note_with_content(&conn, "wiki/index.md", "Index body");
    insert_note_with_content(&conn, "raw/source.md", "Source body");
    insert_fm_field(&conn, note_id, "sources", "[[Source|source note]]");
    insert_fm_field(&conn, note_id, "sources", "https://example.com/source");
    assert!(
        conn.execute(
            "INSERT INTO links (from_path, to_path, raw_target, alias) VALUES (?, ?, ?, ?)",
            params!["wiki/index.md", "raw/source.md", "Source", "source note"],
        )
        .is_ok(),
        "failed to insert source link"
    );
    assert!(
        conn.execute(
            "INSERT INTO links (from_path, to_path, raw_target) VALUES (?, ?, ?)",
            params!["wiki/topic.md", "wiki/index.md", "wiki/index.md"],
        )
        .is_ok(),
        "failed to insert test link"
    );
    assert!(
        conn.execute(
            "INSERT INTO links (from_path, to_path, raw_target) VALUES (?, ?, ?)",
            params!["wiki/index.md", "wiki/child.md", "child"],
        )
        .is_ok(),
        "failed to insert outgoing test link"
    );

    let raw = raw("wiki/index.md");
    let result = raw_to_search_result(
        &raw,
        SearchMode::Semantic,
        &conn,
        false,
        "index",
        raw.score,
        None,
    )
    .unwrap_or_else(|| panic!("raw result should convert"));

    assert!(result.is_index);
    assert_eq!(
        result.citations,
        vec!["raw/source.md", "https://example.com/source"]
    );
    assert_eq!(result.links, vec!["raw/source.md", "wiki/child.md"]);
    assert_eq!(result.backlinks, vec!["wiki/topic.md"]);
    assert_eq!(result.tags, vec!["wiki", "index"]);
    assert_eq!(result.aliases, vec!["Home"]);
    drop(conn);
    cleanup(&path);
}