haematite-cli 0.21.10

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
#![forbid(unsafe_code)]

use std::error::Error;

use haematite::db::{DatabaseConfig, DatabaseError};
use haematite::store::NodeCacheBudget;
use haematite_cli::serve::protocol::Selection;
use haematite_cli::serve::storage::{Failure, Storage};

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

#[test]
fn fresh_served_store_reopens_with_the_path_writer() -> TestResult {
    let directory = tempfile::tempdir()?;
    let path = directory.path().join("database");
    let storage = Storage::create(
        DatabaseConfig {
            data_dir: path.clone(),
            shard_count: 1,
            distributed: None,
            executor_threads: Some(1),
            node_cache_budget: Some(NodeCacheBudget::Unlimited),
            retention: haematite::Retention::KeepAll,
        },
        NodeCacheBudget::Unlimited,
        long_wait_interval(),
    )?;
    let selection = Selection {
        branch: "main".to_owned(),
        version: None,
    };
    let before = storage.capture(&selection)?;
    drop(storage);
    let storage = Storage::open(&path, NodeCacheBudget::Unlimited, long_wait_interval())?;
    let after = storage.capture(&selection)?;
    assert_eq!(after.version, before.version);
    assert_eq!(after.shards, before.shards);
    storage.reader()?;
    Ok(())
}

#[test]
fn path_writer_error_maps_to_the_named_serve_refusal() {
    let failure = Failure::from(DatabaseError::PathWriterRequired { found: 1 });
    assert_eq!(failure.code, "store_writer_unsupported");
    assert_eq!(
        failure.message,
        "store format stamp 1; serve writes only bytes-v2 stores"
    );
    assert_eq!(failure.path, None);
}

#[test]
fn other_database_errors_keep_the_storage_failure_mapping() {
    let failure = Failure::from(DatabaseError::InvalidShardCount);
    assert_eq!(failure.code, "storage_unavailable");
    assert_eq!(failure.message, "database shard_count must be at least 1");
}

const fn long_wait_interval() -> std::time::Duration {
    const LONG_WAIT_INTERVAL: std::time::Duration = std::time::Duration::from_secs(1);
    LONG_WAIT_INTERVAL
}