haematite-cli 0.21.9

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use std::num::NonZeroU64;

use serde_json::{Value, json};

use super::support::{Fixture, TestResult, request, values};

#[test]
fn percentile_service_nearest_rank_returns_95_with_zero_skipped() -> TestResult {
    let documents: Vec<_> = (1..=100)
        .map(|reading| json!({"reading":reading}))
        .collect();
    let fixture = Fixture::new(None, &documents)?;
    let answer = fixture.run(
        &request("patients | percentile(.reading; 95)", NonZeroU64::MIN),
        &[],
    )?;
    assert_eq!(values(&answer)?, vec![json!(95)]);
    assert_eq!(answer.get("skipped").ok_or("missing skipped")?, 0);
    assert_eq!(
        answer.get("records_read").ok_or("missing records_read")?,
        100
    );
    assert_eq!(
        answer.get("stages").ok_or("missing stages")?,
        &json!(["percentile"])
    );
    assert!(answer.get("next").ok_or("missing next")?.is_null());
    let rows = answer
        .get("rows")
        .and_then(Value::as_array)
        .ok_or("missing rows")?;
    let origin = rows
        .first()
        .and_then(|row| row.get("origin"))
        .ok_or("missing origin")?;
    assert_eq!(origin.get("id").ok_or("missing id")?, "");
    assert_eq!(
        origin.get("collection").ok_or("missing collection")?,
        "patients"
    );
    assert_eq!(
        origin.get("version").ok_or("missing version")?,
        answer
            .get("selection")
            .and_then(|selection| selection.get("version"))
            .ok_or("missing selection.version")?
    );
    Ok(())
}

#[test]
fn percentile_service_counts_skips_and_excludes_denied_records() -> TestResult {
    let fixture = Fixture::new(
        None,
        &[
            json!({"reading":1}),
            json!({"reading":999}),
            json!({"reading":"3"}),
            json!({}),
            json!({"reading":null}),
            json!({"reading":2}),
        ],
    )?;
    let answer = fixture.run(
        &request("patients | percentile(.reading; 100)", NonZeroU64::MIN),
        &[("patients", "p1")],
    )?;
    assert_eq!(values(&answer)?, vec![json!(2)]);
    assert_eq!(answer.get("skipped").ok_or("missing skipped")?, 3);
    assert!(answer.get("next").ok_or("missing next")?.is_null());
    Ok(())
}

#[test]
fn percentile_service_empty_input_is_null_with_zero_skipped() -> TestResult {
    let fixture = Fixture::new(None, &[])?;
    let answer = fixture.run(
        &request("patients | percentile(.reading; 95)", NonZeroU64::MIN),
        &[],
    )?;
    assert_eq!(values(&answer)?, vec![Value::Null]);
    assert_eq!(answer.get("skipped").ok_or("missing skipped")?, 0);
    assert_eq!(answer.get("records_read").ok_or("missing scan count")?, 0);
    Ok(())
}

#[test]
fn percentile_service_101_is_named_before_worker_admission() -> TestResult {
    let mut fixture = Fixture::new(None, &[])?;
    fixture.no_worker();
    let error = fixture
        .run(
            &request("patients | percentile(.reading; 101)", NonZeroU64::MIN),
            &[],
        )
        .err()
        .ok_or("101 accepted")?;
    assert_eq!(error.code, "query_percentile_range");
    assert!(error.message.contains("percentile"));
    assert!(error.message.contains("0 to 100"));
    Ok(())
}

#[test]
fn percentile_service_scan_limit_refuses_without_a_partial_value() -> TestResult {
    let mut fixture = Fixture::new(None, &[json!({"reading":1}), json!({"reading":2})])?;
    fixture.scan(NonZeroU64::MIN);
    let error = fixture
        .run(
            &request("patients | percentile(.reading; 95)", NonZeroU64::MIN),
            &[],
        )
        .err()
        .ok_or("partial percentile accepted")?;
    assert_eq!(error.code, "query_scan_limit");
    assert_eq!(error.message, "records read exceed scan limit 1");
    Ok(())
}