From c8922c94086d7395d0cb3457da76a5f9e3287a0d Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sun, 12 Apr 2026 03:15:02 -0400 Subject: [PATCH] parser: add negated key glob filter (!key:pattern) Fixes split agent query: all | type:semantic | !key:_* | sort:content-len | limit:1 Also adds glob_pattern rule that allows * and ? wildcards in key filters. Co-Authored-By: Proof of Concept --- src/hippocampus/query/parser.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/hippocampus/query/parser.rs b/src/hippocampus/query/parser.rs index ccc3ae5..6c2e826 100644 --- a/src/hippocampus/query/parser.rs +++ b/src/hippocampus/query/parser.rs @@ -97,7 +97,8 @@ peg::parser! { / "select:" f:field_list_colon() { Stage::Transform(Transform::Select(f)) } / "type:" t:ident() { make_type_filter(&t) } / "age:" c:cmp_duration() { Stage::Filter(Filter::Age(c)) } - / "key:" g:ident() { Stage::Filter(Filter::KeyGlob(g)) } + / "key:" g:glob_pattern() { Stage::Filter(Filter::KeyGlob(g)) } + / "!key:" g:glob_pattern() { Stage::Filter(Filter::Negated(Box::new(Filter::KeyGlob(g)))) } / "provenance:" p:ident() { Stage::Filter(Filter::Provenance(p)) } / "not-visited:" a:ident() "," d:integer() { Stage::Filter(Filter::NotVisited { agent: a, duration: d as i64 }) } / "visited:" a:ident() { Stage::Filter(Filter::Visited { agent: a }) } @@ -220,6 +221,12 @@ peg::parser! { = s:$(['a'..='z' | 'A'..='Z' | '_']['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '.']*) { s.to_string() } + + // Glob pattern for key matching (allows * and ?) + rule glob_pattern() -> String + = s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '.' | '*' | '?']+) { + s.to_string() + } } }