v0.5.0: aggregates, BEAM callbacks, magic sets, query planner, runtim…#161
Merged
thanos merged 1 commit intoJun 22, 2026
Merged
Conversation
…e facts
M0.5 — Feasibility Spikes
- Spike A: callback as {:callback, %IR.Callback{}} IR literal round-trips
through compiler/evaluator (chest/spikes/README.md)
- Spike B: materialize(goal:) drives magic sets transform; results ≡ semi-naive
M1 — Query Planner Foundation - closed #127
- Add ExDatalog.Planner with plan/2, explain_plan/1,2 - closed #128
- Add planner structs: Plan, Stratum, Join, Predicate (lib/ex_datalog/planner/) - closed #129
- Engine strategy dispatch: evaluate/2 routes :semi_naive / :magic_sets - closed #130
- Telemetry [:ex_datalog, :planner, :start|:stop|:exception] - closed #131
- Tests: planner_test.exs, planner_explain_test.exs - closed #132
M2 — Aggregates (count/sum/min/max) - closed #133
- Add @aggregate_ops [:count, :sum, :min, :max] to Constraint;
from_tuple/1, valid_right?/2, valid_result?/2 extended - closed #134
- Add ExDatalog.Constraints.Aggregate (group_and_reduce/5; evaluate/3 raises) - closed #135
- Add Rule.has_aggregates?/1, aggregate_constraints/1, non_aggregate_constraints/1 - closed #136
- Safety: aggregate input var must be bound, result var in head, ≤1 agg/rule,
no aggregate in recursive rule - closed #137
- Stratification: post-pass in assign_strata/1 forces aggregate head above
all positive body relations; engine validate_stratification/1 extended - closed #138
- Evaluator: eval_aggregate_rule/3 (join → filter → callbacks → negation →
group_and_reduce → project); apply_constraints/3 partitions out aggregate ops - closed #139
- DSL: count/sum/min/max(X, Result) parsed before generic constraint-ops loop;
head-position aggregate raises DSL.CompileError - closed #140
- Tests: aggregate_test.exs + DSL tests in schema_test.exs - closed #141
M3 — BEAM Callback Predicates - closed #142
- Add ExDatalog.Callback struct (AST) + IR.Callback struct + {:callback, _} IR literal - closed #143
- Add ExDatalog.Constraints.BeamCallback with apply_callback/3;
spawn_monitor-based isolation (not Task.async) - closed #144
- Add Constraint.Context opts: [] field; threaded from Engine.Naive.do_evaluate_inner - closed #145
- Add Capabilities aggregate_constraints: boolean, beam_callbacks: boolean - closed #146
- Add Schema.PredicateMeta struct; predicate/5 macro; __register_predicate__/6 - closed #147
- Add resolve_positive_or_callback/2 in __build_program__;
converts matching body atoms to callbacks - closed #148
- Add Validator.check_callback/2 (module/function/arity),
Safety.check_callback_inputs/2 (args must be bound) - closed #149
- Evaluator: apply_callbacks/3 in normal and aggregate paths;
apply_callback_chain/2 + step_callback/1 - closed #150
- Program.validate_body/1 accepts {:callback, %Callback{}};
body_relations/1 ignores callbacks - closed #151
- Tests: beam_callback_test.exs - closed #152
M4 — Magic Sets (Experimental) - closed #153
- Add ExDatalog.MagicSets: transform/2 → {:ok, ir} | {:fallback, reason} - closed #154
- Scope: positive recursive programs, single goal, ground bound positions;
negation/aggregates → fallback - closed #155
- Transform: adornment → magic relation + seed fact → rewrite goal-relation
rules (prepend magic atom for bound head positions) - closed #156
- bound_positions/1 maps goal bound positions to head term positions - closed #157
- Verified: magic restricts derivation and equals semi-naive subset - closed #158
- Tests: magic_sets_test.exs + magic_sets_property_test.exs - closed #159
M5 — Docs, Benchmarks, CHANGELOG, Version Bump - closed #160
- Version bumped 0.4.1 → 0.5.0 in mix.exs
- Added {:benchee, "~> 1.3", only: :dev} dependency
- Added planner/magic-sets/callback module groups to mix.exs docs
- Added articles 06–09 and migration_v0.5.md as extras
- CHANGELOG.md: full v0.5.0 entry (Added/Changed/Notes)
- README.md: aggregate/callback/magic-sets sections, updated feature list,
architecture diagram, constraints table, docs links, roadmap
- Articles: 06_query_planning_in_datalog.md, 07_aggregates_in_datalog.md,
08_extending_datalog_with_beam_callbacks.md,
09_magic_sets_and_demand_driven_evaluation.md
- Migration guide: docs/migration_v0.5.md
- Livebook: livebooks/ex_datalog_v050.livemd (DSL edition)
- Benchmarks: bench/aggregate_bench.exs, bench/magic_sets_bench.exs
- Report: chest/benchmarks/v0.5.0-report.md
Runtime Facts API (pipe-friendly Schema → Program flow)
- Schema relation constructors: each relation generates a public function
(e.g., DeptCount.emp(:alice, :eng) → {"emp", [:alice, :eng]})
- Schema.new/0: returns blank program with relations + rules but no facts
- Program.add_fact/2 (tuple form): Program.add_fact(prog, {"emp", [:alice, :eng]})
- Program.add_facts/2: bulk addition from list of {relation, values} tuples
- Program.materialize/1,2: pipe-friendly ExDatalog.materialize/2 wrapper
- Schema.program/0 and materialize/1 unchanged for backward compatibility
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…e facts
M0.5 — Feasibility Spikes
M1 — Query Planner Foundation - closed #127
M2 — Aggregates (count/sum/min/max) - closed #133
from_tuple/1, valid_right?/2, valid_result?/2 extended - closed Add @aggregate_ops [:count, :sum, :min, :max] to Constraint; from_tuple/1, valid_right?/2, valid_result?/2 extended #134
no aggregate in recursive rule - closed Safety: aggregate input var must be bound, result var in head, ≤1 agg/rule, no aggregate in recursive rule #137
all positive body relations; engine validate_stratification/1 extended - closed Stratification: post-pass in assign_strata/1 forces aggregate head above all positive body relations; engine validate_stratification/1 extended #138
group_and_reduce → project); apply_constraints/3 partitions out aggregate ops - closed Evaluator: eval_aggregate_rule/3 (join → filter → callbacks → negation →group_and_reduce → project); apply_constraints/3 partitions out aggregate ops #139
head-position aggregate raises DSL.CompileError - closed DSL: count/sum/min/max(X, Result) parsed before generic constraint-ops loop;head-position aggregate raises DSL.CompileError #140
M3 — BEAM Callback Predicates - closed #142
M4 — Magic Sets (Experimental) - closed #153
M5 — Docs, Benchmarks, CHANGELOG, Version Bump - closed #160
Runtime Facts API (pipe-friendly Schema → Program flow)