@cavelang/query 0.35.0 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +498 -9
- package/dist/src/bounded.d.ts +1 -1
- package/dist/src/bounded.d.ts.map +1 -1
- package/dist/src/bounded.js +14 -7
- package/dist/src/bounded.js.map +1 -1
- package/dist/src/capture.d.ts +7 -0
- package/dist/src/capture.d.ts.map +1 -0
- package/dist/src/capture.js +52 -0
- package/dist/src/capture.js.map +1 -0
- package/dist/src/compile.d.ts +3 -3
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +107 -54
- package/dist/src/compile.js.map +1 -1
- package/dist/src/page.d.ts.map +1 -1
- package/dist/src/page.js +103 -45
- package/dist/src/page.js.map +1 -1
- package/dist/src/pattern.d.ts.map +1 -1
- package/dist/src/pattern.js +20 -10
- package/dist/src/pattern.js.map +1 -1
- package/dist/src/read-snapshot.d.ts +4 -0
- package/dist/src/read-snapshot.d.ts.map +1 -0
- package/dist/src/read-snapshot.js +29 -0
- package/dist/src/read-snapshot.js.map +1 -0
- package/dist/src/record.d.ts.map +1 -1
- package/dist/src/record.js +51 -16
- package/dist/src/record.js.map +1 -1
- package/dist/src/unicode.d.ts +3 -0
- package/dist/src/unicode.d.ts.map +1 -0
- package/dist/src/unicode.js +7 -0
- package/dist/src/unicode.js.map +1 -0
- package/package.json +6 -6
- package/src/bounded.ts +23 -8
- package/src/capture.ts +59 -0
- package/src/compile.ts +102 -56
- package/src/page.ts +102 -44
- package/src/pattern.ts +20 -10
- package/src/read-snapshot.ts +23 -0
- package/src/record.ts +52 -16
- package/src/unicode.ts +6 -0
package/README.md
CHANGED
|
@@ -8,19 +8,114 @@ the store's public `QuerySql` primitives; CAVE-Q adds pattern joins, filters,
|
|
|
8
8
|
resolution, transitive traversal, and result binding without redefining those
|
|
9
9
|
shared semantics.
|
|
10
10
|
|
|
11
|
+
Structured `match()` calls capture the declared slot, payload, context, tag and
|
|
12
|
+
filter fields before numeric detection or compilation. Fields at each pattern
|
|
13
|
+
position are read once into ordinary data, including inherited or non-enumerable properties, so
|
|
14
|
+
changing getters cannot select a different term at a later stage. Text queries
|
|
15
|
+
use their freshly parsed pattern directly.
|
|
16
|
+
Query and match options are captured once before historical vocabulary lookup,
|
|
17
|
+
SQL compilation and post-filtering. The same `asOf` boundary and row limit apply
|
|
18
|
+
throughout the operation even when supplied through changing getters.
|
|
19
|
+
Each query or structured match reads vocabulary and candidate claims within one
|
|
20
|
+
deferred SQLite snapshot, including source priorities with `resolve: true`.
|
|
21
|
+
A peer commit cannot combine old vocabulary or priorities with new claims in one result;
|
|
22
|
+
the next query sees the committed state. The snapshot nests inside caller-owned
|
|
23
|
+
transactions and sees their staged claims without committing them. Read and
|
|
24
|
+
snapshot-release failures preserve both errors and the original read cause.
|
|
25
|
+
`queryRecords()` captures its options before opening the read savepoint, so
|
|
26
|
+
adapter callbacks cannot replace its limit or historical boundary. It extends
|
|
27
|
+
the snapshot through claim/provenance record projection,
|
|
28
|
+
including transitive support rows. Concurrent appends or direct metadata changes
|
|
29
|
+
cannot mix selected rows with newer tags or provenance; the next call sees the
|
|
30
|
+
committed changes. A projection failure releases the read savepoint and retains
|
|
31
|
+
the thrown value without committing a caller-owned transaction. If releasing
|
|
32
|
+
that snapshot also throws, an `AggregateError` retains the projection failure
|
|
33
|
+
first in `errors` and as `cause`, followed by the release failure. Diagnostic
|
|
34
|
+
formatting tolerates thrown values that cannot be converted to text. After a
|
|
35
|
+
successful release, correcting the projection failure allows the same query to
|
|
36
|
+
retry inside the caller transaction; the caller still controls commit or rollback.
|
|
37
|
+
Lineage edges
|
|
38
|
+
are not embedded in these records. Calling `Record.of()` separately on previously
|
|
39
|
+
selected matches does not extend the original query snapshot; separate page
|
|
40
|
+
windows retain their pagination revision checks. Supported legacy provenance
|
|
41
|
+
backfill occurs during schema migration before the store is returned; read-only
|
|
42
|
+
opens reject an unmigrated schema. Reopening a current-schema database preserves
|
|
43
|
+
explicit empty provenance, and sync treats a present provenance table as
|
|
44
|
+
authoritative rather than filling its empty sets from claim contexts.
|
|
45
|
+
Empty provenance arrays are valid; empty-string entries are malformed.
|
|
46
|
+
If record projection encounters a malformed entry, correcting the stored evidence
|
|
47
|
+
allows a retry within the same caller transaction. Both the failed and successful
|
|
48
|
+
read leave the caller in control of committing or rolling back its staged claims.
|
|
49
|
+
|
|
50
|
+
Text queries reject unpaired UTF-16 surrogates with their one-based source line
|
|
51
|
+
before parsing. Structured patterns passed to `match` are checked before SQL
|
|
52
|
+
compilation as well, including slots, contexts, tags and filters. This prevents
|
|
53
|
+
SQLite's UTF-8 conversion from turning malformed input into a match for `�`.
|
|
54
|
+
Valid Unicode (including emoji), embedded NUL, and an explicitly authored `�`
|
|
55
|
+
remain queryable; failed reads leave stored history unchanged.
|
|
56
|
+
|
|
11
57
|
`query()`/`match()` expose storage rows for in-process reasoning engines. For
|
|
12
58
|
public JSON and durable integrations, use `queryRecords()`: every result is a
|
|
13
59
|
`cave.query-match/v1` carrying bindings plus optional `cave.claim/v1` claim or
|
|
14
|
-
transitive support records. `Record.
|
|
15
|
-
|
|
60
|
+
transitive support records. `Record.of` captures the match's bindings, evidence
|
|
61
|
+
rows and interpolation fields once before projecting evidence. Later caller
|
|
62
|
+
mutation, including during evidence projection, cannot substitute those captured
|
|
63
|
+
values. These fields must contain structured-cloneable data.
|
|
64
|
+
Construction and decoding share the binding-map and interpolation checks below;
|
|
65
|
+
construction rejects malformed metadata or holes/non-object entries in supporting
|
|
66
|
+
rows before projecting any evidence.
|
|
67
|
+
Object inputs to `Record.decode` are captured before
|
|
68
|
+
metadata validation and their nested data is owned by the decoded result;
|
|
69
|
+
changing getters or later caller mutation cannot replace validated bindings or
|
|
70
|
+
interpolation values. Binding maps must still have a plain or null prototype.
|
|
71
|
+
Like claim-record decoding, object input must contain structured-cloneable data.
|
|
72
|
+
`Record.decode` verifies the version and all
|
|
73
|
+
nested claim records, including consistency of their scalar, trajectory and
|
|
74
|
+
uncertainty projections with raw value text. The same checks apply to direct
|
|
75
|
+
claim evidence and each supporting record. Optional interpolation metadata must contain a finite
|
|
76
|
+
numeric `num`, string `text`, and a string `unit` when supplied; malformed
|
|
77
|
+
metadata is rejected for both object and JSON input.
|
|
78
|
+
Bindings must be a plain object of string values (a null-prototype map is also
|
|
79
|
+
accepted). Boxed strings, dates, maps, sets, and class instances are rejected
|
|
80
|
+
rather than accepted with a different or lossy JSON representation.
|
|
81
|
+
Interpolation `num` retains the computed numeric precision, while `text` and
|
|
82
|
+
value-slot bindings use the trajectory formatter's four significant digits.
|
|
83
|
+
For example, a computed `549.995 req/s` is displayed and bound as `550 req/s`;
|
|
84
|
+
the record preserves `at.num: 549.995`. If display rounding would overflow,
|
|
85
|
+
the formatter keeps the finite unrounded value instead. Decoding preserves
|
|
86
|
+
the intentional rounding difference instead of requiring exact numeric equality
|
|
87
|
+
with `text`.
|
|
88
|
+
Supporting evidence must be a dense array of valid claim records. Array holes,
|
|
89
|
+
`undefined` and `null` entries are rejected; an empty support array is valid.
|
|
90
|
+
Object input is read by array index, matching JSON array contents; a custom
|
|
91
|
+
iterator cannot hide invalid entries or discard supporting evidence.
|
|
16
92
|
|
|
17
93
|
For interactive or remote reads, `page()` returns a bounded
|
|
18
94
|
`cave.query-page/v1` envelope. The first request freezes the maximum visible
|
|
19
95
|
transaction; pass its opaque `next` cursor back with the same pattern,
|
|
20
|
-
options, and limit to continue.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
96
|
+
options, and limit to continue. Later local appends are excluded, while a new
|
|
97
|
+
first page sees them. Alias resolution uses that same frozen boundary: a later
|
|
98
|
+
alias retraction from another connection does not change direct or transitive
|
|
99
|
+
continuation results. A fresh first page sees the retraction and new claims.
|
|
100
|
+
Later value revisions and retractions also leave an existing continuation's
|
|
101
|
+
claims unchanged, including exact-number filtered pages. Reusing the same cursor
|
|
102
|
+
with the same options returns the same page while that historical snapshot stays
|
|
103
|
+
valid; reading a cursor does not consume it.
|
|
104
|
+
If sync adds older rows or lineage touching the cutoff,
|
|
105
|
+
continuation fails with a restart instruction instead of repeating or skipping
|
|
106
|
+
results. The default page size is 100 and
|
|
107
|
+
the maximum is 1,000. Defaults apply only when the limit is omitted or
|
|
108
|
+
undefined; explicit null is invalid on both first and continuation requests.
|
|
109
|
+
Correcting an invalid limit allows reuse of the original cursor. `query()` and `queryRecords()` remain unbounded for
|
|
110
|
+
in-process callers that explicitly want the complete result. When supplying a
|
|
111
|
+
SQL `limit`, use a positive safe integer; its `offset` must be a non-negative
|
|
112
|
+
safe integer. An omitted or undefined offset defaults to zero; explicit null
|
|
113
|
+
is invalid when a limit is supplied. Values beyond `Number.MAX_SAFE_INTEGER` are rejected before SQL
|
|
114
|
+
binding, avoiding rounded bounds and adapter-dependent errors.
|
|
115
|
+
|
|
116
|
+
Result bindings are ordinary objects with an own property for each bound
|
|
117
|
+
variable. Names such as `__proto__`, `constructor` and `toString` retain their
|
|
118
|
+
values, including in transitive results and JSON serialization.
|
|
24
119
|
|
|
25
120
|
```ts
|
|
26
121
|
import { open } from '@cavelang/store'
|
|
@@ -50,10 +145,20 @@ const second = first.next === undefined ? undefined :
|
|
|
50
145
|
|
|
51
146
|
- `?name` variables bind subject, verb, object or attribute value;
|
|
52
147
|
a variable repeated in two positions forces equality (`?x NEEDS ?x`).
|
|
148
|
+
A bare `?` is invalid: supply a name, or use `_` for a wildcard.
|
|
149
|
+
Programmatic `match` patterns also require a non-empty variable `name`.
|
|
53
150
|
- `_` is a wildcard.
|
|
54
151
|
- `attr: ?v` matches attribute claims.
|
|
55
152
|
- `@ctx` and `#tag[:value]` on the pattern line filter contexts/tags
|
|
56
153
|
(flat `#tag` matches flat tags only, mirroring `store.byTag`).
|
|
154
|
+
Every requested context and tag must be present. Lists of up to 16 items use
|
|
155
|
+
direct indexed predicates; larger lists use one bound JSON array each. This
|
|
156
|
+
bounds SQL expression depth and parameter count from metadata lists while
|
|
157
|
+
retaining the direct lookup path for ordinary queries. Native SQLite and the
|
|
158
|
+
playground's SQLite WASM have regressions
|
|
159
|
+
with 1,500 contexts and 1,500 tags, including missing-item rejection; Unicode
|
|
160
|
+
and embedded NUL suffixes retain exact matching. This does not impose a general
|
|
161
|
+
query-size budget.
|
|
57
162
|
- `VERB NOT` matches negated claims; patterns without `NOT` match
|
|
58
163
|
positive ones — direction is always explicit.
|
|
59
164
|
- **Inverse verbs** are valid: `?x PART-OF monorepo` compiles to
|
|
@@ -76,6 +181,22 @@ const second = first.next === undefined ? undefined :
|
|
|
76
181
|
|
|
77
182
|
## Filters (§12.2)
|
|
78
183
|
|
|
184
|
+
Filter diagnostics use one-based line numbers from the original query text.
|
|
185
|
+
Blank and full-line comment lines count toward the location even though they
|
|
186
|
+
are ignored when parsing; LF and CRLF inputs use the same numbering.
|
|
187
|
+
Numeric confidence thresholds must be finite; `NaN`, infinities, and exponent
|
|
188
|
+
overflow are parse errors. Finite thresholds outside the stored confidence range
|
|
189
|
+
remain valid comparisons, such as `WHERE conf > 1` matching no claims.
|
|
190
|
+
|
|
191
|
+
Up to 16 `WHERE` filters compile to direct predicates. Longer lists group
|
|
192
|
+
operands by predicate shape into bound JSON arrays, keeping SQL expression
|
|
193
|
+
depth and parameter count bounded by the supported filter forms. Every filter
|
|
194
|
+
must still hold, including comparisons against missing numeric values or units,
|
|
195
|
+
which reject the row. Native SQLite and SQLite WASM regressions exercise 33,000
|
|
196
|
+
filters, mixed requirements, metadata and numeric/transaction comparisons.
|
|
197
|
+
The full query and operand arrays remain in memory; this is not a general
|
|
198
|
+
query-size or execution-time budget.
|
|
199
|
+
|
|
79
200
|
```
|
|
80
201
|
WHERE conf >= 0.8 (also accepts 80%)
|
|
81
202
|
WHERE tag = security (bare key matches any value; topic:auth is exact)
|
|
@@ -90,6 +211,10 @@ WHERE tx <= 2026-01-01T12:00:00 (offset-less timestamps mean UTC)
|
|
|
90
211
|
`<` excludes, and `>` starts after it. A timestamp value covers one second.
|
|
91
212
|
An explicit `Z` or numeric offset is honored; a timestamp without either is
|
|
92
213
|
UTC, so `2026-01-01T12:00:00` equals `2026-01-01T12:00:00Z` on every host.
|
|
214
|
+
Transaction periods before the UUID epoch (1970-01-01T00:00:00Z) are empty;
|
|
215
|
+
`asOf` and `tx` comparisons accept those dates without attempting a negative
|
|
216
|
+
UUID timestamp. Periods crossing the epoch retain their nonnegative portion.
|
|
217
|
+
Valid-time `at` remains independent and can select claims about earlier dates.
|
|
93
218
|
|
|
94
219
|
## Semantics
|
|
95
220
|
|
|
@@ -133,11 +258,18 @@ UTC, so `2026-01-01T12:00:00` equals `2026-01-01T12:00:00Z` on every host.
|
|
|
133
258
|
transaction id (that append included). The alias closure and transitive
|
|
134
259
|
hops reconstruct at the same instant; `{ all: true }` composes as
|
|
135
260
|
full-history-up-to-the-boundary.
|
|
261
|
+
Qualifier parents obey the same boundary as declarations: later `WHEN`,
|
|
262
|
+
`VIA`, or `BECAUSE` parents cannot remove vocabulary from an earlier query.
|
|
136
263
|
- **`{ at }` anchors valid time** (§32.4): timeless claims always remain
|
|
137
264
|
visible; date-like contexts and ranges must cover the selected instant; and
|
|
138
265
|
a trajectory value such as `200 -> 900 PLN/mo @1950..1974` is returned with
|
|
139
266
|
its exact interpolated value. It composes with `asOf`: transaction time
|
|
140
267
|
selects what was believed, while valid time selects when that belief applies.
|
|
268
|
+
Finite trajectory endpoints remain finite during interpolation even when
|
|
269
|
+
their difference would overflow, and endpoint instants retain endpoint values.
|
|
270
|
+
Multiple range contexts, including a closed range combined with an open
|
|
271
|
+
range, leave the trajectory textual. Valid-time coverage still uses the
|
|
272
|
+
normal union of time contexts.
|
|
141
273
|
- **`{ resolve: true }` matches resolved winners only** (§26): coexisting
|
|
142
274
|
series about one fact — §9.5 actor stamps, content sources, opposite
|
|
143
275
|
polarity — collapse to the row the resolution policy picks (precedence
|
|
@@ -150,12 +282,44 @@ UTC, so `2026-01-01T12:00:00` equals `2026-01-01T12:00:00Z` on every host.
|
|
|
150
282
|
- **Pagination is deterministic and transaction-snapshot stable.** SQL applies
|
|
151
283
|
`LIMIT`/`OFFSET` after the query's stable transaction or endpoint ordering,
|
|
152
284
|
and every continuation pins `asOf` to the first page's maximum transaction.
|
|
153
|
-
Cursors are scoped to the exact pattern, options, and page size.
|
|
285
|
+
Cursors are scoped to the exact pattern, options, and page size. Each page
|
|
286
|
+
reads the declared option fields once, including inherited or non-enumerable
|
|
287
|
+
values, so snapshot selection, execution and cursor identity use the same
|
|
288
|
+
values even when supplied through getters. Query syntax
|
|
289
|
+
and option compatibility are validated even when the store or requested
|
|
290
|
+
historical snapshot is empty. Valid-time
|
|
154
291
|
coverage and exact numeric approximation checks run after row selection, so
|
|
155
|
-
those pages
|
|
156
|
-
|
|
292
|
+
those pages read candidate batches capped at the scan budget. An internal
|
|
293
|
+
row-position index preserves each match's original offset through both
|
|
294
|
+
post-filters. A full page resumes immediately after its last returned match,
|
|
295
|
+
leaving later fetched candidates for the next call. A heavily filtered page can therefore
|
|
157
296
|
contain fewer than its requested limit (including zero) while still carrying
|
|
158
297
|
`next`; following it continues from the bounded scan frontier.
|
|
298
|
+
Each page materializes its selected records within a read snapshot, including
|
|
299
|
+
all numeric/valid-time candidate batches and their tag/provenance projection.
|
|
300
|
+
Metadata changed by a peer during projection appears on the next call.
|
|
301
|
+
Projection failure releases the page snapshot without committing a caller
|
|
302
|
+
transaction; if release also throws, the aggregate retains the projection
|
|
303
|
+
failure first and as its cause.
|
|
304
|
+
Each page checks an append-only revision before and after its reads: row count
|
|
305
|
+
and local rowid tail below the cutoff, plus edge count and tail for lineage
|
|
306
|
+
touching either side of that historical row set. Changes reject the page
|
|
307
|
+
with `pagination snapshot changed; restart from the first page`. Wholly
|
|
308
|
+
future rows and edges remain compatible. Revision tokens do not detect direct
|
|
309
|
+
metadata edits between separate page calls. The cursor is database-local;
|
|
310
|
+
its internal encoding is version 2 (the public page envelope remains v1).
|
|
311
|
+
Older or malformed tokens also require a restart. Rejecting a malformed token
|
|
312
|
+
does not mutate the store or invalidate an otherwise valid continuation.
|
|
313
|
+
This contract relies on
|
|
314
|
+
immutable stored claims and side metadata; arbitrary raw SQL rewrites are
|
|
315
|
+
outside the append-only pagination contract.
|
|
316
|
+
|
|
317
|
+
Live connections refresh vocabulary after another SQLite connection commits.
|
|
318
|
+
`store.registry()`, query compilation, and inverse reads therefore see new
|
|
319
|
+
verb and lifecycle declarations without reopening or writing. The read path
|
|
320
|
+
works on read-only connections and reuses its registry cache while SQLite's
|
|
321
|
+
data-version counter is unchanged. Raw SQL writes on the same connection still
|
|
322
|
+
require `reloadRegistry`; precompiled SQL retains their supplied vocabulary.
|
|
159
323
|
|
|
160
324
|
## Tests
|
|
161
325
|
|
|
@@ -181,3 +345,328 @@ The deterministic transitive benchmark emits NDJSON timings and result counts
|
|
|
181
345
|
for a chain, a branching tree, and a cycle, comparing a source-seeded query
|
|
182
346
|
with the corresponding unbound all-pairs workload. Plan tests additionally
|
|
183
347
|
assert forward/reverse seed shape and SQLite object-index use.
|
|
348
|
+
|
|
349
|
+
## Pagination benchmark
|
|
350
|
+
|
|
351
|
+
`pnpm bench:pagination` measures first-page valid-time and exact-number queries
|
|
352
|
+
against 1,000 and 10,000 claims, with a page limit of 100 and all candidates
|
|
353
|
+
passing the post-filter. A selective valid-time fixture uses a one-result page
|
|
354
|
+
with 99 expired candidates before each matching claim. First-page measurements
|
|
355
|
+
report five samples and their median. Each fixture also follows every cursor
|
|
356
|
+
in three full traversals, reporting page and match counts plus the median.
|
|
357
|
+
Node, SQLite and platform versions accompany the output. Completeness, ordering,
|
|
358
|
+
constant snapshot and termination checks run outside the timing interval.
|
|
359
|
+
The store is populated before timing, so these are repeated in-process reads,
|
|
360
|
+
not CLI startup measurements or fixed CI latency gates.
|
|
361
|
+
|
|
362
|
+
On macOS arm64 with Node 26.5.0 and SQLite 3.53.3, batching changed the median
|
|
363
|
+
first-page times as follows:
|
|
364
|
+
|
|
365
|
+
| Rows | Valid-time before / after | Exact-number before / after |
|
|
366
|
+
|---|---|---|
|
|
367
|
+
| 1,000 | 116.54 / 4.71 ms | 116.49 / 4.20 ms |
|
|
368
|
+
| 10,000 | 1,079.97 / 24.39 ms | 1,093.66 / 25.06 ms |
|
|
369
|
+
|
|
370
|
+
The scan budget and continuation semantics stay unchanged. The selective
|
|
371
|
+
one-result fixture initially measured 113.75 ms at 1,000 rows and 1,068.77 ms at
|
|
372
|
+
10,000 rows. Tracking original row positions now permits larger candidate reads
|
|
373
|
+
even for that small match limit; medians fell to 2.87 ms and 22.95 ms respectively.
|
|
374
|
+
The internal position index is allocated only for filtered page reads and never
|
|
375
|
+
appears in query records or continuation tokens.
|
|
376
|
+
|
|
377
|
+
A historical-vocabulary cache was trialled and removed before this change
|
|
378
|
+
because its 10,000-row selective median remained about 1.07 seconds. Reducing
|
|
379
|
+
repeated SQL reads provided the measurable improvement. Results are not fixed
|
|
380
|
+
latency guarantees.
|
|
381
|
+
|
|
382
|
+
With the row-position implementation, three-sample full-traversal medians on the
|
|
383
|
+
same runtime were:
|
|
384
|
+
|
|
385
|
+
| Claims | Pages | Valid-time (all matches) | Exact-number (all matches) | Selective valid-time |
|
|
386
|
+
|---|---|---|---|---|
|
|
387
|
+
| 1,000 | 10 | 47.53 ms / 1,000 matches | 44.75 ms / 1,000 matches | 30.75 ms / 10 matches |
|
|
388
|
+
| 10,000 | 100 | 2,887.18 ms / 10,000 matches | 2,889.77 ms / 10,000 matches | 2,739.98 ms / 100 matches |
|
|
389
|
+
|
|
390
|
+
Traversal timing includes following cursors and retaining page results; assertions
|
|
391
|
+
run afterward. The fixture uses immutable in-memory data and does not model
|
|
392
|
+
concurrent ingestion, HTTP transport or a streaming consumer's memory use.
|
|
393
|
+
Increasing the fixture tenfold increased total traversal time much more than
|
|
394
|
+
tenfold. First-page latency therefore does not establish full-scan scalability;
|
|
395
|
+
repeated snapshot checks and offset-based SQL remain costs to assess for larger
|
|
396
|
+
workloads.
|
|
397
|
+
|
|
398
|
+
### Current-runtime pagination baseline
|
|
399
|
+
|
|
400
|
+
Sequential reruns of the unchanged fixtures on macOS arm64 with SQLite 3.53.4
|
|
401
|
+
retain first-page and full-traversal samples in
|
|
402
|
+
[`benchmarks/pagination-current-review.json`](../../benchmarks/pagination-current-review.json).
|
|
403
|
+
At 10,000 claims, the medians were:
|
|
404
|
+
|
|
405
|
+
| Query | Node 24.21.0 first page / traversal | Node 26.8.1 first page / traversal |
|
|
406
|
+
|---|---|---|
|
|
407
|
+
| Valid-time | 25.33 ms / 3.146 s | 25.50 ms / 3.109 s |
|
|
408
|
+
| Exact-number | 25.25 ms / 3.210 s | 25.09 ms / 3.114 s |
|
|
409
|
+
| Selective valid-time | 22.18 ms / 2.772 s | 22.13 ms / 2.746 s |
|
|
410
|
+
|
|
411
|
+
These are current baselines, not before/after optimization measurements. Each
|
|
412
|
+
first-page median uses five samples and each traversal median uses three; the
|
|
413
|
+
benchmark has no separate untimed warmup. All ordering, completeness, snapshot
|
|
414
|
+
and termination assertions passed. Full traversal still costs substantially more
|
|
415
|
+
than a first page. Before changing cursor semantics or introducing caches,
|
|
416
|
+
measure time spent in SQL windows, snapshot revision checks and record projection
|
|
417
|
+
separately. Any optimization must retain rejection of historical arrivals and
|
|
418
|
+
new lineage touching the snapshot, while accepting wholly future appends.
|
|
419
|
+
|
|
420
|
+
### Pagination cost attribution
|
|
421
|
+
|
|
422
|
+
Run `node --disable-warning=ExperimentalWarning scripts/pagination-profile.mjs`
|
|
423
|
+
alone for diagnostic attribution. Each 1,000/10,000-row fixture traverses once
|
|
424
|
+
without instrumentation, then once with synchronous method timers. It compares
|
|
425
|
+
complete results and checks order, termination, the fixed snapshot and unchanged
|
|
426
|
+
history outside timing. These are single diagnostic runs in a fixed order, not
|
|
427
|
+
latency medians or an estimate of instrumentation overhead. Original store methods
|
|
428
|
+
retain their own database, so their internal SQL is charged to vocabulary or
|
|
429
|
+
projection rather than counted again in the SQL categories. Unassigned time
|
|
430
|
+
includes other JavaScript work and instrumentation overhead.
|
|
431
|
+
|
|
432
|
+
[Raw profiles](../../benchmarks/pagination-profile-review.json) include runtime
|
|
433
|
+
versions, source hashes, method counts, category times and the plain traversals.
|
|
434
|
+
At 10,000 claims on macOS arm64 / SQLite 3.53.4:
|
|
435
|
+
|
|
436
|
+
| Query | Node 24.21.0 SQL windows / total | Node 26.8.1 SQL windows / total |
|
|
437
|
+
|---|---|---|
|
|
438
|
+
| Valid-time | 2.698 / 3.128 s | 2.663 / 3.085 s |
|
|
439
|
+
| Exact-number | 2.794 / 3.209 s | 2.700 / 3.093 s |
|
|
440
|
+
| Selective valid-time | 2.675 / 2.783 s | 2.664 / 2.779 s |
|
|
441
|
+
|
|
442
|
+
SQL windows dominated these pre-optimization profiles. Snapshot revision checks take under 43 ms
|
|
443
|
+
per traversal and historical vocabulary under 9 ms; caching either is therefore
|
|
444
|
+
unlikely to remove most of this fixture's cost. This motivated the bounded tuple-membership optimization below, retaining the
|
|
445
|
+
existing snapshot checks. Compare any
|
|
446
|
+
candidate on revised claim histories as well as one-row-per-key fixtures: a
|
|
447
|
+
faster query must not revive a superseded or retracted belief. The profile does
|
|
448
|
+
not identify which part of SQLite execution dominates or establish a general
|
|
449
|
+
query-performance guarantee.
|
|
450
|
+
|
|
451
|
+
### Current-belief SQL comparison
|
|
452
|
+
|
|
453
|
+
`node scripts/current-query-bench.mjs` compares the production grouped latest-row
|
|
454
|
+
join with a read-only experimental correlated `MAX(tx)` lookup. Both use 10,000
|
|
455
|
+
historical rows and issue 100 SQL requests of 100 rows. With 10,000 current keys,
|
|
456
|
+
the requests traverse 100 pages; with 100 current keys, they repeat the single
|
|
457
|
+
current page. Three samples, execution plans and runtime versions are reported.
|
|
458
|
+
Row identities must agree across both alternatives; assertions run after timing.
|
|
459
|
+
This isolates SQL selection and does not include semantic record construction,
|
|
460
|
+
valid-time filtering or pagination revision checks.
|
|
461
|
+
|
|
462
|
+
On the runtime above, medians were:
|
|
463
|
+
|
|
464
|
+
| Current keys | Grouped production SQL | Correlated alternative |
|
|
465
|
+
|---|---|---|
|
|
466
|
+
| 10,000 | 844.81 ms | 517.86 ms |
|
|
467
|
+
| 100 | 381.47 ms | 518.86 ms |
|
|
468
|
+
|
|
469
|
+
The alternative improves the all-distinct fixture but regresses the fixture with
|
|
470
|
+
many revisions per key, so it is not used as a blanket replacement. Both plans
|
|
471
|
+
still sort results for transaction ordering. Future query-plan changes should
|
|
472
|
+
cover both history distributions and preserve historical boundaries and latest
|
|
473
|
+
row semantics before replacing the shared store fragment.
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
### Late full-row fetch trial
|
|
477
|
+
|
|
478
|
+
`node --disable-warning=ExperimentalWarning scripts/pagination-row-width-bench.mjs`
|
|
479
|
+
compares full-row sorting with selecting ordered page IDs first and fetching
|
|
480
|
+
complete rows afterward. Both keep the same grouped latest-belief selection and
|
|
481
|
+
historical boundary. Each fixture has 10,000 historical rows and issues 100
|
|
482
|
+
requests of 100 rows, traversing distinct keys or repeatedly reading one page
|
|
483
|
+
of heavily revised keys. Three timed samples alternate variant order, with full
|
|
484
|
+
row equality and page-size assertions outside timing; there is no separate
|
|
485
|
+
warmup. [Raw results and plans](../../benchmarks/pagination-row-width-review.json)
|
|
486
|
+
retain SQL and runtime metadata.
|
|
487
|
+
|
|
488
|
+
On macOS arm64 with SQLite 3.53.4, medians were:
|
|
489
|
+
|
|
490
|
+
| Current keys | Node 24.21.0 full / late fetch | Node 26.8.1 full / late fetch |
|
|
491
|
+
|---|---|---|
|
|
492
|
+
| 10,000 | 1078.14 / 945.02 ms | 1056.83 / 880.51 ms |
|
|
493
|
+
| 100 | 405.61 / 421.93 ms | 404.55 / 403.53 ms |
|
|
494
|
+
|
|
495
|
+
The distinct-key fixture improves by about 12–17%, but the revised-key fixture
|
|
496
|
+
is about 4% slower on Node 24 and nearly unchanged on Node 26. This is not enough
|
|
497
|
+
evidence for a blanket production replacement. The trial remains read-only
|
|
498
|
+
experimental SQL; it does not change query execution or cursor formats. It also
|
|
499
|
+
omits record projection, valid-time post-filtering and snapshot revision checks,
|
|
500
|
+
so its timings are not end-to-end page latencies. Further trials should target
|
|
501
|
+
repeated selection work without sacrificing revised-history behavior.
|
|
502
|
+
|
|
503
|
+
### Current-row join plan trial
|
|
504
|
+
|
|
505
|
+
`node --disable-warning=ExperimentalWarning scripts/current-join-bench.mjs`
|
|
506
|
+
retains both transaction and claim-key equality checks, but adds unary plus to
|
|
507
|
+
the outer claim-key expression. The experiment uses the same two history
|
|
508
|
+
fixtures and three alternating-order samples as the row-width trial above.
|
|
509
|
+
Complete returned rows must agree. On Node 24.21.0 and 26.8.1 with SQLite 3.53.4,
|
|
510
|
+
the query plan remained unchanged: SQLite still looked up grouped latest rows
|
|
511
|
+
through an automatic claim-key index. This did not establish a speedup.
|
|
512
|
+
|
|
513
|
+
`--plans-only` inspects a second variant with unary plus on both claim-key
|
|
514
|
+
expressions without timing or executing it. It loses the automatic lookup and
|
|
515
|
+
scans the grouped rows repeatedly. A Node 24 timing attempt was interrupted
|
|
516
|
+
with SIGINT after becoming substantially slower; no completed timing is claimed
|
|
517
|
+
for that attempt. [Raw completed samples and plans](../../benchmarks/current-join-review.json)
|
|
518
|
+
retain the evidence from both runtimes. Neither experiment changes production
|
|
519
|
+
SQL. Do not simply drop the claim-key check: the SQL schema indexes transaction
|
|
520
|
+
IDs but does not declare them unique, and structural schema validation does not
|
|
521
|
+
validate every stored row's identity. A read-plan optimization must preserve the
|
|
522
|
+
existing join semantics instead of assuming stronger physical constraints.
|
|
523
|
+
|
|
524
|
+
### Bounded tuple-membership selection
|
|
525
|
+
|
|
526
|
+
Bounded, unresolved direct queries now select current rows using membership in
|
|
527
|
+
`(claim_key, MAX(tx))` pairs. Both identity columns and the complete historical
|
|
528
|
+
source remain part of selection, so filtering a page cannot revive an older or
|
|
529
|
+
retracted belief. Unbounded, resolved and transitive plans retain their existing
|
|
530
|
+
selection strategy. Snapshot revision checks, ordering, scan budgets and cursor
|
|
531
|
+
formats are unchanged.
|
|
532
|
+
|
|
533
|
+
`node --disable-warning=ExperimentalWarning scripts/current-membership-bench.mjs`
|
|
534
|
+
compares the former join and tuple membership on the same distinct/revised-key
|
|
535
|
+
SQL fixtures used above, with three alternating-order samples and full-row
|
|
536
|
+
comparison outside timing. Membership improves both distributions on Node 24.21.0
|
|
537
|
+
and 26.8.1. Sequential end-to-end reruns of `scripts/pagination-bench.mjs` also
|
|
538
|
+
pass every traversal assertion. At 10,000 claims on macOS arm64 / SQLite 3.53.4:
|
|
539
|
+
|
|
540
|
+
| Traversal | Node 24.21.0 before → after | Node 26.8.1 before → after |
|
|
541
|
+
|---|---|---|
|
|
542
|
+
| Valid-time | 3.146 → 2.561 s | 3.109 → 2.587 s |
|
|
543
|
+
| Exact-number | 3.210 → 2.541 s | 3.114 → 2.611 s |
|
|
544
|
+
| Selective valid-time | 2.772 → 2.239 s | 2.746 → 2.239 s |
|
|
545
|
+
|
|
546
|
+
[Raw controls and before/after samples](../../benchmarks/pagination-membership-review.json)
|
|
547
|
+
retain the three-sample traversal and five-sample first-page measurements.
|
|
548
|
+
These gains apply to the recorded in-memory workloads, not every query or
|
|
549
|
+
adapter. Regression tests compare bounded and unbounded results across historical
|
|
550
|
+
boundaries, numeric filters, retractions and reactivation; existing tests retain
|
|
551
|
+
alias, pagination revision, resolved and transitive coverage. Full traversal
|
|
552
|
+
still repeats selection and offset work, so this is not a general scan-cost bound.
|
|
553
|
+
|
|
554
|
+
## Query read-snapshot trial
|
|
555
|
+
|
|
556
|
+
Run `node --disable-warning=ExperimentalWarning scripts/query-snapshot-bench.mjs`
|
|
557
|
+
alone. It queries `?item IS service` with `limit: 1` over 100 and 1,000 current
|
|
558
|
+
claims, in memory and through a read-only WAL connection, both outside and inside
|
|
559
|
+
a caller read transaction. Each result is a median of five batches of 20 calls,
|
|
560
|
+
after one warm-up call. Setup, transaction entry/exit and result assertions are
|
|
561
|
+
outside the timing. Resolved queries are included as a control: they already
|
|
562
|
+
used snapshots before ordinary matching gained the same consistency guarantee.
|
|
563
|
+
|
|
564
|
+
On macOS arm64, the following ordinary-query medians compare the preceding
|
|
565
|
+
resolved-only snapshot path with snapshots around all matching. The baseline was
|
|
566
|
+
measured by temporarily restoring the previous conditional path; the script
|
|
567
|
+
itself always measures the checked-out implementation and has no unsafe mode.
|
|
568
|
+
|
|
569
|
+
| Claims | Database | Caller transaction | Node 24 before → after | Node 26 before → after |
|
|
570
|
+
|---|---|---|---|---|
|
|
571
|
+
| 100 | memory | no | 0.172 → 0.174 ms | 0.173 → 0.180 ms |
|
|
572
|
+
| 100 | memory | yes | 0.167 → 0.167 ms | 0.172 → 0.165 ms |
|
|
573
|
+
| 100 | wal-read-only | no | 0.168 → 0.167 ms | 0.173 → 0.167 ms |
|
|
574
|
+
| 100 | wal-read-only | yes | 0.167 → 0.169 ms | 0.160 → 0.161 ms |
|
|
575
|
+
| 1,000 | memory | no | 1.058 → 1.043 ms | 1.045 → 1.042 ms |
|
|
576
|
+
| 1,000 | memory | yes | 1.061 → 1.042 ms | 1.062 → 1.048 ms |
|
|
577
|
+
| 1,000 | wal-read-only | no | 1.041 → 1.061 ms | 1.080 → 1.063 ms |
|
|
578
|
+
| 1,000 | wal-read-only | yes | 1.051 → 1.062 ms | 1.090 → 1.042 ms |
|
|
579
|
+
|
|
580
|
+
Runtime versions were Node 24.16.0 and 26.5.0. Resolved control medians ranged
|
|
581
|
+
from 1.080–1.139 ms at 100 claims and 5.758–6.410 ms at 1,000 claims across both
|
|
582
|
+
runs. The small before/after differences do not isolate a reliable savepoint
|
|
583
|
+
cost or establish a speedup. Baseline runs preceded final runs, so cache and
|
|
584
|
+
execution-order effects remain possible. These fixtures do not bound large-graph
|
|
585
|
+
costs, contention, transitive queries, or WASM performance. Snapshot correctness
|
|
586
|
+
is established by the separate concurrent-writer regressions, not these timings.
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
## Structured-record projection trial
|
|
590
|
+
|
|
591
|
+
Run `node --disable-warning=ExperimentalWarning scripts/query-record-bench.mjs`
|
|
592
|
+
alone. It returns 100 or 1,000 records for `?item IS service`, with either no
|
|
593
|
+
metadata or three contexts, three tags and source provenance. Memory and read-only
|
|
594
|
+
WAL stores are exercised outside and inside a caller read transaction. Each
|
|
595
|
+
median uses five batches of three calls after one warm-up. Setup, transaction
|
|
596
|
+
entry/exit, full record decoding and result equality checks are untimed.
|
|
597
|
+
Raw reports include Node launch arguments and selected source-file SHA-256 hashes
|
|
598
|
+
captured before the workloads. Launch arguments identify an enabled `--import`
|
|
599
|
+
baseline loader. Hashes describe the on-disk inputs, including the loader files;
|
|
600
|
+
the guarded loaders describe their in-memory transformations. This is selected
|
|
601
|
+
source provenance, not a complete dependency or machine-environment fingerprint.
|
|
602
|
+
|
|
603
|
+
The [paired measurements](../../benchmarks/query-record-validation-review.json)
|
|
604
|
+
compare the earlier reviewed implementation with a
|
|
605
|
+
[benchmark-only loader](../../benchmarks/query-record-baseline.mjs) that omits
|
|
606
|
+
record-construction identity/key guards and the outer projection snapshot. The
|
|
607
|
+
loader checks its source replacements and does not edit runtime files. The
|
|
608
|
+
historical loader is tied to the source hashes in that artifact and now rejects
|
|
609
|
+
the changed constructor. Use the capture comparison below for the current source.
|
|
610
|
+
|
|
611
|
+
For 1,000 returned records on macOS arm64, medians were:
|
|
612
|
+
|
|
613
|
+
| Metadata | Database | Caller transaction | Node 24.21.0 before → reviewed | Node 26.8.1 before → reviewed |
|
|
614
|
+
|---|---|---|---|---|
|
|
615
|
+
| none | memory | no | 14.77 → 16.60 ms | 15.02 → 16.67 ms |
|
|
616
|
+
| none | memory | yes | 13.37 → 15.24 ms | 14.95 → 15.79 ms |
|
|
617
|
+
| none | read-only WAL | no | 17.59 → 15.74 ms | 17.71 → 15.95 ms |
|
|
618
|
+
| none | read-only WAL | yes | 13.11 → 15.21 ms | 14.92 → 15.18 ms |
|
|
619
|
+
| populated | memory | no | 32.73 → 33.67 ms | 31.17 → 32.26 ms |
|
|
620
|
+
| populated | memory | yes | 32.49 → 33.19 ms | 30.95 → 32.21 ms |
|
|
621
|
+
| populated | read-only WAL | no | 38.69 → 33.12 ms | 36.41 → 37.28 ms |
|
|
622
|
+
| populated | read-only WAL | yes | 32.22 → 33.32 ms | 32.31 → 36.28 ms |
|
|
623
|
+
|
|
624
|
+
This combined comparison does not isolate the cost of a particular guard or
|
|
625
|
+
savepoint. Baselines preceded current runs, so cache and run-order effects can
|
|
626
|
+
explain some differences; faster cases do not establish a speedup. These results
|
|
627
|
+
do not justify weakening consistency checks. They do not bound large graphs,
|
|
628
|
+
transitive support, malformed-data handling, HTTP or browser performance. The
|
|
629
|
+
artifact retains all 100-record cases, raw samples and source hashes.
|
|
630
|
+
|
|
631
|
+
A [later capture trial](../../benchmarks/query-record-capture-review.json) measures
|
|
632
|
+
claim and provenance capture plus provenance validation with identity guards and
|
|
633
|
+
query snapshots retained on both paths. Its guarded
|
|
634
|
+
[baseline loader](../../benchmarks/query-record-capture-baseline.mjs) is enabled
|
|
635
|
+
with `--import ./benchmarks/query-record-capture-baseline.mjs`. The same 16 cases
|
|
636
|
+
and untimed correctness checks apply. Baseline and current runs were sequential
|
|
637
|
+
on Node 24, then Node 26, without concurrent builds or tests.
|
|
638
|
+
|
|
639
|
+
For 1,000 returned records, current median ranges across memory/WAL and caller
|
|
640
|
+
transaction settings were:
|
|
641
|
+
|
|
642
|
+
| Metadata | Node 24.21.0 | Node 26.8.1 |
|
|
643
|
+
|---|---|---|
|
|
644
|
+
| none | 21.07–23.27 ms | 20.98–21.35 ms |
|
|
645
|
+
| populated | 40.23–41.42 ms | 40.33–41.50 ms |
|
|
646
|
+
|
|
647
|
+
On Node 24, the capture boundary added roughly 6–9 ms in most 1,000-record cases.
|
|
648
|
+
One Node 26 baseline case was anomalously slow; its apparent improvement is not
|
|
649
|
+
interpreted as a speedup. An additional trial combining both captures into one
|
|
650
|
+
`structuredClone` call showed no consistent benefit and was not retained. All
|
|
651
|
+
samples and the trial's source hash are preserved in the artifact. These local
|
|
652
|
+
measurements support keeping the ownership guarantees, not a general latency
|
|
653
|
+
bound or an independently measured cost for each validation step.
|
|
654
|
+
|
|
655
|
+
The [query-match capture trial](../../benchmarks/query-match-capture-review.json)
|
|
656
|
+
isolates the later `Query.Record.of` capture and metadata validation boundary
|
|
657
|
+
while retaining nested claim/provenance capture and query snapshots. Its guarded
|
|
658
|
+
[baseline loader](../../benchmarks/query-match-baseline.mjs) uses
|
|
659
|
+
`--import ./benchmarks/query-match-baseline.mjs` with the same benchmark command.
|
|
660
|
+
Sequential before/current runs on Node 24 and then Node 26 passed all equality
|
|
661
|
+
and decode assertions. For 1,000 direct records, current median ranges were:
|
|
662
|
+
|
|
663
|
+
| Metadata | Node 24.21.0 | Node 26.8.1 |
|
|
664
|
+
|---|---|---|
|
|
665
|
+
| none | 22.15–24.38 ms | 22.81–24.29 ms |
|
|
666
|
+
| populated | 43.39–43.89 ms | 42.15–43.02 ms |
|
|
667
|
+
|
|
668
|
+
The observed increment was 0.3–3.4 ms per 1,000 records across these cases.
|
|
669
|
+
The artifact retains raw samples, commands and source hashes. These are direct,
|
|
670
|
+
non-interpolated matches; dense transitive support and interpolation need separate
|
|
671
|
+
measurements. One local paired trial does not establish a latency guarantee or
|
|
672
|
+
separate the cost of capture from metadata validation.
|
package/dist/src/bounded.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as Compile from './compile.ts';
|
|
|
3
3
|
import * as Pattern from './pattern.ts';
|
|
4
4
|
export type { Match, Options } from './compile.ts';
|
|
5
5
|
export type { Window } from './compile.ts';
|
|
6
|
-
export declare const window: (store: Store, pattern: Pattern.t, options?: Compile.Options) => Compile.Window;
|
|
6
|
+
export declare const window: (store: Store, pattern: Pattern.t, options?: Compile.Options, positions?: WeakMap<object, number>) => Compile.Window;
|
|
7
7
|
export declare const match: (store: Store, pattern: Pattern.t, options?: Compile.Options) => Compile.Match[];
|
|
8
8
|
export declare const query: (store: Store, input: string, options?: Compile.Options) => Compile.Match[];
|
|
9
9
|
//# sourceMappingURL=bounded.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bounded.d.ts","sourceRoot":"","sources":["../../src/bounded.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"bounded.d.ts","sourceRoot":"","sources":["../../src/bounded.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAIvC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAClD,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAwE1C,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,CAAC,CAAC,EAClB,UAAS,OAAO,CAAC,OAAY,EAC7B,YAAY,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,KAClC,OAAO,CAAC,MAAqD,CAAA;AAEhE,eAAO,MAAM,KAAK,GAChB,OAAO,KAAK,EACZ,SAAS,OAAO,CAAC,CAAC,EAClB,UAAS,OAAO,CAAC,OAAY,KAC5B,OAAO,CAAC,KAAK,EAA8D,CAAA;AAE9E,eAAO,MAAM,KAAK,GAChB,OAAO,KAAK,EACZ,OAAO,MAAM,EACb,UAAS,OAAO,CAAC,OAAY,KAC5B,OAAO,CAAC,KAAK,EACuC,CAAA"}
|
package/dist/src/bounded.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Value } from '@cavelang/core';
|
|
2
2
|
import * as Compile from "./compile.js";
|
|
3
3
|
import * as Pattern from "./pattern.js";
|
|
4
|
+
import { captureOptions, capturePattern } from "./capture.js";
|
|
5
|
+
import { readSnapshot } from "./read-snapshot.js";
|
|
4
6
|
/**
|
|
5
7
|
* Compile historical queries against vocabulary reconstructed at the same
|
|
6
8
|
* transaction-time boundary as the rows. The store remains otherwise
|
|
@@ -20,13 +22,18 @@ const storeAtBoundary = (store, options) => {
|
|
|
20
22
|
* value filter pushes the normalized comparison into SQL; the final check
|
|
21
23
|
* preserves exact unit and approximation semantics.
|
|
22
24
|
*/
|
|
23
|
-
const execute = (store, pattern, options = {}) => {
|
|
25
|
+
const execute = (store, pattern, options = {}, positions) => {
|
|
26
|
+
// Use the same caller values for historical vocabulary, SQL and post-filters.
|
|
27
|
+
options = captureOptions(options);
|
|
28
|
+
return readSnapshot(store, () => executeCaptured(store, pattern, options, positions));
|
|
29
|
+
};
|
|
30
|
+
const executeCaptured = (store, pattern, options, positions) => {
|
|
24
31
|
if (pattern.payload.kind !== 'attribute' || pattern.payload.value.kind !== 'term') {
|
|
25
|
-
return Compile.window(storeAtBoundary(store, options), pattern, options);
|
|
32
|
+
return Compile.window(storeAtBoundary(store, options), pattern, options, positions);
|
|
26
33
|
}
|
|
27
34
|
const value = Value.parse(pattern.payload.value.text);
|
|
28
35
|
if (value.kind !== 'number' || value.num === undefined) {
|
|
29
|
-
return Compile.window(storeAtBoundary(store, options), pattern, options);
|
|
36
|
+
return Compile.window(storeAtBoundary(store, options), pattern, options, positions);
|
|
30
37
|
}
|
|
31
38
|
const expectedNum = value.num;
|
|
32
39
|
const filter = {
|
|
@@ -44,7 +51,7 @@ const execute = (store, pattern, options = {}) => {
|
|
|
44
51
|
};
|
|
45
52
|
const expectedUnit = value.unit ?? null;
|
|
46
53
|
const expectedApprox = value.approx ? 1 : 0;
|
|
47
|
-
const result = Compile.window(storeAtBoundary(store, options), normalized, options);
|
|
54
|
+
const result = Compile.window(storeAtBoundary(store, options), normalized, options, positions);
|
|
48
55
|
return { ...result, matches: result.matches.filter(match => {
|
|
49
56
|
const row = match.row;
|
|
50
57
|
return row !== undefined &&
|
|
@@ -53,7 +60,7 @@ const execute = (store, pattern, options = {}) => {
|
|
|
53
60
|
row.value_approx === expectedApprox;
|
|
54
61
|
}) };
|
|
55
62
|
};
|
|
56
|
-
export const window = (store, pattern, options = {}) => execute(store, pattern, options);
|
|
57
|
-
export const match = (store, pattern, options = {}) => execute(store, pattern, options).matches;
|
|
58
|
-
export const query = (store, input, options = {}) =>
|
|
63
|
+
export const window = (store, pattern, options = {}, positions) => execute(store, pattern, options, positions);
|
|
64
|
+
export const match = (store, pattern, options = {}) => execute(store, capturePattern(pattern), options).matches;
|
|
65
|
+
export const query = (store, input, options = {}) => execute(store, Pattern.parse(input), options).matches;
|
|
59
66
|
//# sourceMappingURL=bounded.js.map
|
package/dist/src/bounded.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bounded.js","sourceRoot":"","sources":["../../src/bounded.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAEtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"bounded.js","sourceRoot":"","sources":["../../src/bounded.ts"],"names":[],"mappings":"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"}
|