Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
25 lines
1 KiB
Rust
25 lines
1 KiB
Rust
//! `search` — FTS5 match over `slug` + `description`.
|
|
//!
|
|
//! Thin wrapper around `kei_entity_store::verbs::search` that decodes
|
|
//! the JSON `results` array into typed `Entry` values. An empty query
|
|
//! is rejected with `InvalidInput` before dispatch (the engine enforces
|
|
//! the same rule but we surface the typed variant eagerly).
|
|
|
|
use crate::entry::Entry;
|
|
use crate::error::DiscoverError;
|
|
use crate::schema::DISCOVER_SCHEMA;
|
|
use kei_entity_store::verbs::search as v_search;
|
|
use rusqlite::Connection;
|
|
use serde_json::json;
|
|
|
|
pub fn search(conn: &Connection, query: &str) -> Result<Vec<Entry>, DiscoverError> {
|
|
if query.trim().is_empty() {
|
|
return Err(DiscoverError::InvalidInput("search: query must be non-empty".into()));
|
|
}
|
|
let v = v_search::run(conn, &DISCOVER_SCHEMA, json!({ "query": query }))?;
|
|
let rows = v
|
|
.get("results")
|
|
.and_then(|x| x.as_array())
|
|
.ok_or_else(|| DiscoverError::Storage("search: missing results array".into()))?;
|
|
Ok(rows.iter().map(Entry::from_json).collect())
|
|
}
|