query: unify PEG and engine parsers

PEG parser now handles both expression syntax (degree > 5 | sort degree)
and pipeline syntax (all | type:episodic | sort:timestamp). Deleted
Stage::parse() and helpers from engine.rs — it's now pure execution.

All callers use parse_stages() from parser.rs as the single entry point.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
ProofOfConcept 2026-04-11 20:42:58 -04:00
parent bc991c3521
commit aad227e487
8 changed files with 562 additions and 253 deletions

View file

@ -3,25 +3,26 @@
pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full: bool, debug: bool, fuzzy: bool, content: bool) -> Result<(), String> {
use std::collections::BTreeMap;
use crate::search::{Stage, Algorithm, AlgoStage};
// When running inside an agent session, exclude already-surfaced nodes
let seen = crate::session::HookSession::from_env()
.map(|s| s.seen())
.unwrap_or_default();
// Parse pipeline stages (unified: algorithms, filters, transforms, generators)
let stages: Vec<crate::search::Stage> = if pipeline_args.is_empty() {
vec![crate::search::Stage::Algorithm(crate::search::AlgoStage::parse("spread").unwrap())]
// Build pipeline: if args provided, parse them; otherwise default to spread
let stages: Vec<Stage> = if pipeline_args.is_empty() {
vec![Stage::Algorithm(AlgoStage { algo: Algorithm::Spread, params: std::collections::HashMap::new() })]
} else {
pipeline_args.iter()
.map(|a| crate::search::Stage::parse(a))
.collect::<Result<Vec<_>, _>>()?
// Join args with | and parse as unified query
let pipeline_str = format!("all | {}", pipeline_args.join(" | "));
crate::query_parser::parse_stages(&pipeline_str)?
};
// Check if pipeline needs full Store (has filters/transforms/generators)
let needs_store = stages.iter().any(|s| !matches!(s, crate::search::Stage::Algorithm(_)));
let needs_store = stages.iter().any(|s| !matches!(s, Stage::Algorithm(_)));
// Check if pipeline starts with a generator (doesn't need seed terms)
let has_generator = stages.first().map(|s| matches!(s, crate::search::Stage::Generator(_))).unwrap_or(false);
let has_generator = stages.first().map(|s| matches!(s, Stage::Generator(_))).unwrap_or(false);
if terms.is_empty() && !has_generator {
return Err("search requires terms or a generator stage (e.g. 'all')".into());