feat: add where filter operator for arrays - #9
Conversation
Add proprietary 'where' operator that filters arrays by a predicate before applying .length or a quantifier (any/all/none). Examples: selections where (odd ge 1.4).length ge 4 selections where (odd ge 1.4) any (provider eq "X") selections where (odd ge 1.4) all (is_live eq true) selections where (odd ge 1.4) none (is_fraud eq true) The operator is implemented without materializing a filtered array: - 'where (P).length' uses a dedicated NodeWhereCount that counts elements matching the predicate, no allocation. - 'where (P) any/all/none (S)' is rewritten at parse time as a quantifier over the source with a composed predicate, reusing the existing zero-allocation quantifier evaluator. Performance is on par with native quantifiers (1 alloc from Go runtime []any boxing, ~110-135ns). Limitations: - No chained where (where (...) where (...)). - Only .length, any, all, none may follow where. - 'where' is a reserved keyword; contexts using a field named 'where' will conflict. - Not part of nikunjy/rules; rules using where won't run on that library.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughThis PR introduces a proprietary ChangesWhere Filter Operator
Sequence DiagramsequenceDiagram
participant Lexer
participant Parser
participant Validator
participant Evaluator
Lexer->>Parser: WHERE token + identifier + parens
Parser->>Parser: parseWhereExpression validates syntax
Parser->>Parser: rewrite quantifiers to boolean AST
Parser->>Validator: NodeWhereCount AST
Validator->>Validator: validateWhereCountOperation checks structure
Validator->>Evaluator: validated AST node
Evaluator->>Evaluator: evaluateWhereCount iterates & counts
Evaluator->>Evaluator: return integer result
🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
parser_test.go (1)
371-415: ⚡ Quick winAdd a dedicated
where + nonerewrite test.
parseWhereWithQuantifierhas a distinctNONErewrite branch, but this unit set only pinsANYandALL. Add one focusedNONEcase to prevent regressions in rewrite semantics.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@parser_test.go` around lines 371 - 415, Add a new unit test mirroring TestParserWhereWithAny/TestParserWhereWithAll to cover the NONE rewrite branch: call ParseRule with a "selections where (...) none (...)" input and assert the AST top node is NodeBinaryOp with Operator NONE (or that ParseRule triggers the rewrite implemented in parseWhereWithQuantifier for NONE); then verify the Right side is the expected composed expression for the NONE rewrite (e.g., an OR where the first part is NOT predicate, or whatever parseWhereWithQuantifier defines for NONE). Use the same assertion style as TestParserWhereWithAny/TestParserWhereWithAll and name the test TestParserWhereWithNone to prevent regressions in parseWhereWithQuantifier's NONE handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CLAUDE.md`:
- Line 131: The sentence "Encadeamento de `where` não é suportado. Acesso
pós-`where` é restrito a `.length`." is in Portuguese; replace it with an
English equivalent so the doc is consistent—e.g., "Chaining of `where` is not
supported. Post-`where` access is restricted to `.length`." Ensure you update
the line that mentions `where` and `.length` accordingly.
In `@validator.go`:
- Around line 39-40: The NodeWhereCount branch returns after basic checks and
does not recurse into the WHERE subtree, so predicate/source expressions escape
semantic validation; update the NodeWhereCount handling in
validateWhereCountOperation (and the similar block around lines 150-167) to
recursively validate the where subtree by invoking the existing recursive
validator(s) (e.g., call validateNode or reuse
validateWhereOperation/validateWherePredicate on the node's Source and Predicate
children) so ParseRule checks run on the predicate/source expressions and any
errors are reported.
---
Nitpick comments:
In `@parser_test.go`:
- Around line 371-415: Add a new unit test mirroring
TestParserWhereWithAny/TestParserWhereWithAll to cover the NONE rewrite branch:
call ParseRule with a "selections where (...) none (...)" input and assert the
AST top node is NodeBinaryOp with Operator NONE (or that ParseRule triggers the
rewrite implemented in parseWhereWithQuantifier for NONE); then verify the Right
side is the expected composed expression for the NONE rewrite (e.g., an OR where
the first part is NOT predicate, or whatever parseWhereWithQuantifier defines
for NONE). Use the same assertion style as
TestParserWhereWithAny/TestParserWhereWithAll and name the test
TestParserWhereWithNone to prevent regressions in parseWhereWithQuantifier's
NONE handling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cebff0fb-48a6-4b31-a0f5-b835f18e08ff
📒 Files selected for processing (15)
CLAUDE.mdREADME.mdast.gobenchmark_optimized_test.goconcept.mderrors.goevaluator.goexample_test.golexer_test.goparser.goparser_test.gotest/list_fixtures.gotest/rule_engine_test.gotoken.govalidator.go
- Translate Portuguese text in CLAUDE.md to English (where chaining/access notes) - Recursively validate NodeWhereCount source and predicate subtrees so semantic errors inside the where predicate are caught at parse time. Extracted into validateWhereCountNode to keep ValidateAST cognitive complexity in check. - Add TestParserWhereWithNone covering the NONE rewrite branch in parseWhereWithQuantifier (where (P) none (S) -> source none (P and S))
Add proprietary 'where' operator that filters arrays by a predicate before applying .length or a quantifier (any/all/none).
Examples:
selections where (odd ge 1.4).length ge 4
selections where (odd ge 1.4) any (provider eq "X")
selections where (odd ge 1.4) all (is_live eq true)
selections where (odd ge 1.4) none (is_fraud eq true)
The operator is implemented without materializing a filtered array:
Limitations:
📝 Summary
⚡ Performance Impact
✅ Checklist
Summary by CodeRabbit
New Features
Documentation
Tests & Examples