nils-memo-cli 0.3.3

CLI crate for nils-memo-cli in the nils-cli workspace.
Documentation
use serde_json::json;

use crate::cli::OutputMode;
use crate::errors::AppError;
use crate::output::{emit_json_results_with_meta, format_item_id, text};
use crate::storage::Storage;
use crate::storage::repository::QueryState;
use crate::storage::search;

pub fn run(
    storage: &Storage,
    output_mode: OutputMode,
    state: QueryState,
    query: &str,
    limit: usize,
) -> Result<(), AppError> {
    let query = query.trim();
    if query.is_empty() {
        return Err(AppError::usage("search requires a non-empty query"));
    }

    let rows = storage.with_connection(|conn| search::search_items(conn, query, state, limit))?;

    if output_mode.is_json() {
        let results = rows
            .iter()
            .map(|row| {
                json!({
                    "item_id": format_item_id(row.item_id),
                    "created_at": row.created_at,
                    "score": row.score,
                    "matched_fields": row.matched_fields,
                    "preview": row.preview,
                    "content_type": row.content_type,
                    "validation_status": row.validation_status,
                })
            })
            .collect::<Vec<_>>();
        return emit_json_results_with_meta(
            "memo-cli.search.v1",
            "memo-cli search",
            results,
            None,
            Some(json!({
                "query": query,
                "limit": limit,
                "state": query_state_label(state),
            })),
        );
    }

    text::print_search(&rows);

    Ok(())
}

fn query_state_label(state: QueryState) -> &'static str {
    match state {
        QueryState::All => "all",
        QueryState::Pending => "pending",
        QueryState::Enriched => "enriched",
    }
}