haematite-cli 0.21.3

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use super::{Question, Stage, pipeline};
use crate::serve::protocol::Metric;

type TestResult = Result<(), Box<dyn std::error::Error>>;

#[test]
fn rerank_parses_words_and_keeps_the_stage_byte_span() -> TestResult {
    let text = "patients | rerank(.body_vec; \"chest pain\"; cosine) | '$score'";
    let plan = pipeline(text).map_err(|error| error.to_string())?;
    let stage = plan.stages.first().ok_or("missing rerank stage")?;
    assert_eq!(
        stage.value,
        Stage::Rerank {
            field: "body_vec".to_owned(),
            question: Question::Text("chest pain".to_owned()),
            measure: Metric::Cosine,
        }
    );
    assert_eq!(
        text.get(stage.span.start..stage.span.end),
        Some("rerank(.body_vec; \"chest pain\"; cosine)")
    );
    Ok(())
}

#[test]
fn rerank_parses_a_record_question_after_an_upstream_limit() -> TestResult {
    let plan = pipeline(concat!(
        "patients | similar(.a; record(\"p0\"); dot) | limit(20)",
        " | rerank(.b; record(\"p1\"); l2)",
    ))
    .map_err(|error| error.to_string())?;
    let stage = plan.stages.last().ok_or("missing rerank stage")?;
    assert_eq!(
        stage.value,
        Stage::Rerank {
            field: "b".to_owned(),
            question: Question::Record("p1".to_owned()),
            measure: Metric::L2,
        }
    );
    Ok(())
}

#[test]
fn rerank_refuses_missing_or_unknown_measures_and_empty_record_ids() -> TestResult {
    for text in [
        "patients | rerank(.b; \"words\")",
        "patients | rerank(.b; \"words\"; pearson)",
        "patients | rerank(.b; record(\"\"); dot)",
        "patients | rerank(.b, .c; \"words\"; dot)",
    ] {
        let error = pipeline(text).err().ok_or("invalid rerank was accepted")?;
        assert!(error.to_string().contains("rerank") || error.to_string().contains("record"));
    }
    Ok(())
}

#[test]
fn rerank_after_jq_is_refused_at_its_word() -> TestResult {
    let text = "patients | '.name' | rerank(.b; record(\"p0\"); dot)";
    let error = pipeline(text).err().ok_or("rerank after jq was accepted")?;
    assert_eq!(error.code(), "query_parse");
    assert_eq!(
        text.get(error.span().start..error.span().end),
        Some("rerank")
    );
    Ok(())
}