Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **A pseudo-attribute pattern never gives a variable its value** (#606). A variable bound by several patterns returns the value of the first real pattern in the `:where` text that binds it (#545); a `:db/valid-at` pattern that the planner ran first used to bind its entity variable itself, as a ref, so `[:find ?b ?t :where [?b :db/valid-at ?t] [?a :friend ?b] [?b :name "Bob"]]` returned the ref of `:bob` with source order and the keyword `:bob` stored by `:friend` natively. It returns the keyword now, whatever runs first. Only the keyword-or-ref kind changes; rows and counts are the same.
- **Every build reorders query clauses; the `wasm` feature does nothing** (#594, #596). The `wasm` Cargo feature kept patterns, `not` clauses and `or` branches in source order and turned off the `or` short-circuits (#250), for small browser datasets and a predictable order. With every answer independent of the plan (#594, #596, #606) it only made queries slower, and no first-party build enabled it (the browser package uses `browser`). The feature is kept, so builds that name it still resolve, but is deprecated and has no effect.
- **Aggregate and window answers no longer depend on the order of their input** (#547). Before, aggregates and window functions read their rows in the order the plan produced them, and several answers followed that order. Six cases changed. (1) `sum` over floats is exact: the values are added without rounding and the total is rounded once, so `1e16 + 1.0 + -1e16 + 1.0 + 0.5` gives `2.5` in every order (before, `1.5` or `2.5`). Window `sum` and `avg` likewise. (2) `sum` over integers saturates once, at the end: `i64::MAX + 1 + -1` gives `i64::MAX` (before, `i64::MAX - 1` or `i64::MAX` by order). (3) Window `sum` over integers adds them exactly; before they were added as floats, so a running total above 2^53 lost its low digits. (4) `min` / `max` of floats follow one order: `-0.0` before `0.0`, NaN after every other number (before, the first of two such values seen won). Window `min` / `max` use the same order over any values, so the minimum of keywords is the first in text order. (5) Window functions sort each partition by `:order-by` under one total order of values (numbers by numeric value, an integer before an equal float, then strings, booleans, refs, keywords, `nil`), so keywords, refs and booleans now sort (before, any two of them compared equal and kept their input order). Rows with equal `:order-by` values are peers: `rank` gives them the same rank, and `sum`, `count`, `min`, `max`, `avg` and registered window functions give every peer the value at the last peer, as SQL does; `row-number` numbers peers in the order of the other variables `:find` names. For example, with `?s` of 1.5, 5, 10, 10, `(sum ?s :over (:order-by ?s))` gave 1.5, 6.5, 16.5, 26.5, the 16.5 going to either tied row, and now gives 1.5, 6.5, 26.5, 26.5; ranking `:x :x :y :y` by `:order-by` gave ranks depending on the order the scan met them (1 2 3 4 when interleaved) and now gives 1 1 3 3. (6) In a query with aggregates, a window's argument, `:partition-by` and `:order-by` must be plain `:find` variables, or the query fails at parse time with the new `PRS-082`; before, any other variable read `nil` on every group row. The error a failing aggregate query reports is the first error, in `:find` order, of the first failing group in output order. A registered aggregate still receives its values in input order, which can depend on the plan; one whose result depends on that order may answer equivalent queries differently. (7) A group whose grouping variable holds floats that are equal as groups compare them (`-0.0` and `0.0`, or NaNs) returns the least of them in that order, so `-0.0` when the group holds it; before, it returned the first one the plan met.
- **Parse errors that were `INT-019` now carry their own `PRS` codes** (#643). The parser's long-tail syntax and structure errors (a bind slot with no name, a window without `:order-by`, a non-vector query, malformed `:with`, `:find`, valid-time map, retract fact, `not`/`not-join`/`or` body, pattern and rule) used one internal code, `INT-019`, with a `datalog parser: ` prefix. Each now has its own Parser-category code, `PRS-083` to `PRS-107`, documented in `docs/ERROR_REFERENCE.md`; the message is the old text without the prefix. A retract fact without exactly three elements was `INT-000` and is now `PRS-090`. Code that matches on `INT-019` (or `INT-000` for retract arity), or on the `Internal` category, for these errors must match the new codes. `INT-019` stays registered for parser invariants no input is known to reach.

### Added

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ Auto-migrates v7 → v8 on open (spec §9, with a backup meta page). v1–v6 are

## Test Coverage

**1620 tests** (1610 passing, 10 ignored; unit + integration + doc).
**1646 tests** (1636 passing, 10 ignored; unit + integration + doc).
See `docs/TEST_COVERAGE.md` for the full per-file breakdown.

**Testing conventions** — see the Testing Conventions section below before writing any tests.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ let r2 = pq.execute(&[("tx", BindValue::TxCount(2)), ("entity", BindValue::Entit

```bash
cargo run # interactive Datalog REPL
cargo test # run 1620 tests
cargo test # run 1646 tests
cargo run < demos/demo_recursive.txt # recursive rules demo
```

Expand Down
Loading
Loading