8000 feat: Phase 7.7b — User-Defined Functions (v0.17.0) by adityamukho · Pull Request #70 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

feat: Phase 7.7b — User-Defined Functions (v0.17.0) - #70

Merged
adityamukho merged 15 commits into
mainfrom
phase/7-7b-udfs
Apr 3, 2026
Merged

adityamukho merged 15 commits into
mainfrom
phase/7-7b-udfs

Conversation

@adityamukho
Copy link
Copy Markdown
Collaborator

Summary

  • Add Minigraf::register_aggregate(name, init, step, finalise) — custom aggregate functions usable in both :find grouping and :over (window) clauses
  • Add Minigraf::register_predicate(name, f) — custom single-argument filter predicates usable in [(name? ?var)] :where clauses
  • Parser now defers unknown aggregate/window/predicate names to runtime (no parse error); AggImpl enum discriminates built-in vs UDF paths

Test Plan

  • 9 new integration tests in tests/udf_test.rs — custom aggregate, empty result, predicate filter, window UDF, name collision guards, runtime error paths, thread safety
  • 727 tests passing total
  • cargo clippy -- -D warnings clean

🤖 Generated with Claude Code

adityamukho and others added 15 commits April 3, 2026 01:13
- Add UnaryOp::Udf variant to test_unary_op_variants_exist
- Add WindowFunc::Udf test case to test_window_spec_func_name
- Update UnaryOp::Udf doc-comment to align with WindowFunc::Udf wording
- Update executor.rs comment to clarify that UDF aggregates route through the
  accumulator-based handler and will be dispatched via FunctionRegistry in Task 4

All 707 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…egistry for 7.7b

- Replace AggregateDesc.{window_compatible,window_ops,is_builtin} fields with AggImpl enum (Builtin(WindowOps) | Udf(UdfOps))
- Add UdfOps: type-erased Arc<dyn Fn> closures for init/step/finalise
- Add PredicateDesc: Arc<dyn Fn(&Value) -> bool> with is_builtin sentinel
- Add predicates: HashMap to FunctionRegistry; populate built-in name sentinels
- Add register_aggregate_desc / register_predicate_desc (Err on duplicate)
- Add get_predicate (filters out built-in sentinels)
- Update is_window_compatible to use name-based logic instead of field
- Update executor.rs: match on AggImpl instead of old field access; UDF window stub returns Err for Task 4
- 6 new unit tests; all 713 tests pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…g predicates

- Modify parse_window_expr to emit WindowFunc::Udf for unknown window function names
- Modify parse_expr to emit UnaryOp::Udf for unknown 1-arg predicates
- Unknown 2-arg forms still rejected with error
- lag/lead still explicitly rejected (deferred post-1.0)
- Add 5 new tests: parse_udf_window_function, parse_udf_predicate_clause,
  parse_unknown_two_arg_predicate_rejected, parse_lag_still_rejected,
  parse_lead_still_rejected
- Update parse_unknown_window_func_rejected to parse_unknown_window_func_as_udf
  (reflects new behavior)
- All 718 tests passing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…and predicate clauses

- eval_expr: add registry: Option<&FunctionRegistry> parameter; handle
  UnaryOp::Udf by dispatching to registered predicate fn
- apply_expr_clauses: add registry: &FunctionRegistry parameter, return
  anyhow::Result<Vec<Binding>>, pre-validate unknown UDF predicate names
- compute_aggregation: replace AggImpl::Udf stub with real step/finalise loop
- apply_window_functions: replace AggImpl::Builtin-only path with a match
  on AggImpl::Builtin vs AggImpl::Udf, each using their respective ops
- Thread FunctionRegistry through not_body_matches, evaluate_branch, and
  apply_or_clauses so UDF predicates work inside not/or bodies
- Update evaluator.rs apply_expr_clauses_in_evaluator and apply_or_clauses
  call sites to match new signatures
- Update all test call sites (eval_expr +None, evaluate_branch
  +FunctionRegistry::with_builtins(), apply_expr_clauses +registry +unwrap)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also fix parse_aggregate_expr to allow unknown aggregate names through as
UDF candidates (resolved at runtime) instead of rejecting at parse time.
Update parser.rs and aggregation_test.rs tests accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mplete)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…_COVERAGE

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also fixes BTreeSet deduplication key ordering bug in apply_or_clauses
(HashMap::iter() order is non-deterministic; sort key entries before
inserting into BTreeSet to ensure identical bindings deduplicate correctly).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@adityamukho
adityamukho merged commit 2188e34 into main Apr 3, 2026
10 checks passed
@adityamukho
adityamukho deleted the phase/7-7b-udfs branch April 3, 2026 03:42
@codecov
codecov Bot commented Apr 3, 2026
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.96104% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.70%. Comparing base (1cf0eff) to head (4c8270d).
⚠️ Report is 21 commits behind head on main.

Files with missing lines Patch % Lines
src/query/datalog/functions.rs 81.81% 6 Missing ⚠️
src/db.rs 79.16% 5 Missing ⚠️
src/query/datalog/executor.rs 94.59% 4 Missing ⚠️
src/query/datalog/evaluator.rs 60.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #70      +/-   ##
==========================================
+ Coverage   84.50%   84.70%   +0.19%     
==========================================
  Files          25       25              
  Lines        4402     4484      +82     
==========================================
+ Hits         3720     3798      +78     
- Misses        682      686       +4     
Files with missing lines Coverage Δ
src/query/datalog/parser.rs 86.05% <100.00%> (+0.07%) ⬆️
src/query/datalog/types.rs 87.58% <100.00%> (+0.08%) ⬆️
src/query/datalog/evaluator.rs 90.73% <60.00%> (+0.05%) ⬆️
src/query/datalog/executor.rs 94.49% <94.59%> (+1.19%) ⬆️
src/db.rs 91.13% <79.16%> (-1.12%) ⬇️
src/query/datalog/functions.rs 84.01% <81.81%> (-1.11%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@adityamukho adityamukho mentioned this pull request Oct 25, 2026
10 tasks done
Sign up for free 61F4 to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0