@cavelang/query 0.27.3 → 0.29.0

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/Authors.md ADDED
@@ -0,0 +1,5 @@
1
+ # Authors
2
+
3
+ By adding their name to this file, all listed authors confirm they have copyright over their contributions to this project and are waiving these rights, placing their work in the public domain in accordance with the CC0 1.0 Universal Public Domain Dedication.
4
+
5
+ - Mirek Rusin (Switzerland)
package/License.md ADDED
@@ -0,0 +1,6 @@
1
+ # CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
2
+
3
+ To the extent possible under law, the authors listed in [Authors.md](./Authors.md) have waived all copyright and related or neighboring rights to this software and associated documentation files (the "Software").
4
+
5
+ For more information, please see:
6
+ https://creativecommons.org/publicdomain/zero/1.0/
package/README.md CHANGED
@@ -3,9 +3,28 @@
3
3
  CAVE-Q — the graph-pattern query layer (spec §12), compiled to SQL over an
4
4
  open `@cavelang/store`.
5
5
 
6
+ Current-belief selection, transaction boundaries, and alias closure come from
7
+ the store's public `QuerySql` primitives; CAVE-Q adds pattern joins, filters,
8
+ resolution, transitive traversal, and result binding without redefining those
9
+ shared semantics.
10
+
11
+ `query()`/`match()` expose storage rows for in-process reasoning engines. For
12
+ public JSON and durable integrations, use `queryRecords()`: every result is a
13
+ `cave.query-match/v1` carrying bindings plus optional `cave.claim/v1` claim or
14
+ transitive support records. `Record.decode` verifies the version and all
15
+ nested claim records.
16
+
17
+ For interactive or remote reads, `page()` returns a bounded
18
+ `cave.query-page/v1` envelope. The first request freezes the maximum visible
19
+ transaction; pass its opaque `next` cursor back with the same pattern,
20
+ options, and limit to continue. Appends made between pages are therefore
21
+ excluded, while a new first page sees them. The default page size is 100 and
22
+ the maximum is 1,000. `query()` and `queryRecords()` remain unbounded for
23
+ in-process callers that explicitly want the complete result.
24
+
6
25
  ```ts
7
26
  import { open } from '@cavelang/store'
8
- import { query } from '@cavelang/query'
27
+ import { page, query } from '@cavelang/query'
9
28
 
10
29
  const store = open('knowledge.db')
11
30
  query(store, '?x USES jwt')
@@ -19,7 +38,12 @@ query(store, 'terrier EXTENDS+ animal') // transitive
19
38
 
20
39
  query(store, '?x USES postgres', { aliases: true }) // + rows about aliased names (§13.6)
21
40
  query(store, 'server IS compromised', { asOf: '2026-01-15' }) // belief state at a past moment (§12.3)
41
+ query(store, 'mill/wage IS', { at: '1962' }) // valid-time filtering + trajectory interpolation (§32.4)
22
42
  query(store, 'service HAS owner: ?who', { resolve: true }) // §26 winners only — one row per contested fact
43
+
44
+ const first = page(store, '?x USES jwt', { limit: 50 })
45
+ const second = first.next === undefined ? undefined :
46
+ page(store, '?x USES jwt', { limit: 50, cursor: first.next })
23
47
  ```
24
48
 
25
49
  ## Pattern language (§12.1)
@@ -35,8 +59,18 @@ query(store, 'service HAS owner: ?who', { resolve: true }) // §26 winners only
35
59
  - **Inverse verbs** are valid: `?x PART-OF monorepo` compiles to
36
60
  `verb = 'CONTAINS' AND subject = 'monorepo'` with `?x` binding on the
37
61
  object side — the same physical query as the forward pattern.
62
+ - **Lifecycle spellings** are interchangeable after their declaration:
63
+ with `WORKS-AT RENAMED-TO EMPLOYED-BY`, patterns using either name compile
64
+ to the stable `WORKS-AT` storage verb. `asOf` reconstructs the registry at
65
+ the same boundary, so the replacement is unknown before its declaration.
38
66
  - `VERB+` is transitive (one or more hops), compiled to a recursive CTE
39
- over current, positive, non-retracted edges, depth-capped at 32.
67
+ over current, positive, non-retracted edges. Reachable endpoint pairs are
68
+ deduplicated as the recursion runs, so cycles terminate at a finite fixed
69
+ point and paths are not silently truncated at a hop limit.
70
+ A concrete subject seeds forward recursion; when only the object is
71
+ concrete, recursion runs backwards from it. Fully unbound patterns retain
72
+ the complete all-pairs closure. Supporting edge ids propagate through the
73
+ same seeded direction when `{ support: true }` is requested.
40
74
  Transitive works through inverses too (`packages/api PART-OF+ ?c` walks
41
75
  `CONTAINS` upward from the object side).
42
76
 
@@ -47,13 +81,15 @@ WHERE conf >= 0.8 (also accepts 80%)
47
81
  WHERE tag = security (bare key matches any value; topic:auth is exact)
48
82
  WHERE context = production
49
83
  WHERE value > 1000 req/s (numeric column; unit equality when given)
50
- WHERE tx > 2026-01-01 (dates are whole-day UTC intervals)
84
+ WHERE tx > 2026-01-01 (date-like values are whole UTC periods)
85
+ WHERE tx <= 2026-01-01T12:00:00 (offset-less timestamps mean UTC)
51
86
  ```
52
87
 
53
- `tx` filters compile a date to the interval `[day-start, next-day-start)`
54
- in UUIDv7 space: `=` means "recorded that day", `<=` includes the boundary
55
- day that `<` excludes, and `>` starts the day after. A timestamp value
56
- covers one second.
88
+ `tx` filters compile a date-like value to its UTC period in UUIDv7 space:
89
+ `=` means "recorded in that period", `<=` includes the boundary period that
90
+ `<` excludes, and `>` starts after it. A timestamp value covers one second.
91
+ An explicit `Z` or numeric offset is honored; a timestamp without either is
92
+ UTC, so `2026-01-01T12:00:00` equals `2026-01-01T12:00:00Z` on every host.
57
93
 
58
94
  ## Semantics
59
95
 
@@ -67,6 +103,11 @@ covers one second.
67
103
  (`latency IS 30ms` the pattern finds `latency IS 30ms` the claim).
68
104
  - A repeated variable forces equality in transitive patterns too:
69
105
  `?x EXTENDS+ ?x` finds nodes on cycles, not every reachable pair.
106
+ - Transitive recursion has no CAVE hop limit and never returns a silently
107
+ partial closure. It reaches a fixed point after at most the finite set of
108
+ endpoint pairs (quadratic in the number of participating entities); if the
109
+ SQLite runtime cannot complete that work, the query fails instead of
110
+ presenting a truncated result as complete.
70
111
  - Transitive patterns support endpoint slots only; tag/context/WHERE
71
112
  filters on them are rejected rather than silently ignored.
72
113
  - **`{ support: true }` attaches supporting edge rows to transitive
@@ -82,15 +123,21 @@ covers one second.
82
123
  alias-equal, transitive hops cross alias links — while bindings and rows
83
124
  keep stored names untouched (union-of-rows, never silent merging). The
84
125
  closure always reads current beliefs, even under `{ all: true }`.
85
- Values, attribute names and verbs are not entities and never resolve.
126
+ Values, attribute names and verbs are not entities. Verbs resolve through
127
+ their separate `RENAMED-TO` lifecycle registry (§5.8).
86
128
  - **`{ asOf }` resolves beliefs as of a past moment** (§12.3): only rows
87
129
  recorded up to the boundary participate, then resolution proceeds as
88
130
  usual — so a claim retracted later is still believed at the boundary,
89
- and one first recorded later is unknown. The boundary is a date (whole
90
- UTC day included), a timestamp (whole second included), or a
131
+ and one first recorded later is unknown. The boundary is a date-like value
132
+ (whole UTC period included), a timestamp (whole second included), or a
91
133
  transaction id (that append included). The alias closure and transitive
92
134
  hops reconstruct at the same instant; `{ all: true }` composes as
93
135
  full-history-up-to-the-boundary.
136
+ - **`{ at }` anchors valid time** (§32.4): timeless claims always remain
137
+ visible; date-like contexts and ranges must cover the selected instant; and
138
+ a trajectory value such as `200 -> 900 PLN/mo @1950..1974` is returned with
139
+ its exact interpolated value. It composes with `asOf`: transaction time
140
+ selects what was believed, while valid time selects when that belief applies.
94
141
  - **`{ resolve: true }` matches resolved winners only** (§26): coexisting
95
142
  series about one fact — §9.5 actor stamps, content sources, opposite
96
143
  polarity — collapse to the row the resolution policy picks (precedence
@@ -100,19 +147,37 @@ covers one second.
100
147
  through the closure) and `asOf` (candidates and the in-band policy
101
148
  declarations reconstruct at the boundary); incompatible with
102
149
  `{ all: true }`, which asks for the unresolved history.
150
+ - **Pagination is deterministic and transaction-snapshot stable.** SQL applies
151
+ `LIMIT`/`OFFSET` after the query's stable transaction or endpoint ordering,
152
+ and every continuation pins `asOf` to the first page's maximum transaction.
153
+ Cursors are scoped to the exact pattern, options, and page size. Valid-time
154
+ coverage and exact numeric approximation checks run after row selection, so
155
+ those pages consume bounded one-row SQL windows to advance past rejected
156
+ rows without skipping the next match. A heavily filtered page can therefore
157
+ contain fewer than its requested limit (including zero) while still carrying
158
+ `next`; following it continues from the bounded scan frontier.
103
159
 
104
160
  ## Tests
105
161
 
106
162
  ```
107
163
  pnpm --filter @cavelang/query test
164
+ pnpm --filter @cavelang/query bench:transitive
108
165
  ```
109
166
 
110
167
  Every §12.1 example pattern and every §12.2 filter runs against a live
111
168
  in-memory store, including inverse and transitive-inverse cases,
112
- current-vs-history semantics, negated patterns, the §13.6 alias
169
+ current-vs-history semantics, negated patterns, long paths across the former
170
+ 32-hop boundary, cycle-safe closure, the §13.6 alias
113
171
  closure (term widening, transitive hops across aliases, unmerge by
114
172
  retraction, value/attribute exemption), §12.3 as-of resolution
115
173
  (tx/date/timestamp boundaries, later retraction, as-of alias closure
116
174
  and transitive edges) and §26 winners-only matching (ingest re-runs vs
117
175
  human corrections, polarity suppression, reliability steering,
118
176
  resolved transitive paths, composition with aliases and as-of).
177
+ Valid-time coverage, bitemporal composition, and trajectory interpolation are
178
+ covered by the temporal query tests.
179
+
180
+ The deterministic transitive benchmark emits NDJSON timings and result counts
181
+ for a chain, a branching tree, and a cycle, comparing a source-seeded query
182
+ with the corresponding unbound all-pairs workload. Plan tests additionally
183
+ assert forward/reverse seed shape and SQLite object-index use.
@@ -0,0 +1,42 @@
1
+ /** Deterministic chain/branch/cycle benchmark for seeded transitive plans. */
2
+
3
+ import { performance } from 'node:perf_hooks'
4
+ import { open } from '@cavelang/store'
5
+ import { query } from '../src/compile.ts'
6
+
7
+ type Case = { readonly name: string, readonly edges: readonly string[], readonly seed: string }
8
+
9
+ const cases: readonly Case[] = [
10
+ {
11
+ name: 'chain',
12
+ edges: Array.from({ length: 120 }, (_, index) => `n/${index} REACHES n/${index + 1}`),
13
+ seed: 'n/0'
14
+ },
15
+ {
16
+ name: 'branches',
17
+ edges: Array.from({ length: 127 }, (_, index) => [
18
+ `tree/${index} REACHES tree/${index * 2 + 1}`,
19
+ `tree/${index} REACHES tree/${index * 2 + 2}`
20
+ ]).flat(),
21
+ seed: 'tree/0'
22
+ },
23
+ {
24
+ name: 'cycle',
25
+ edges: Array.from({ length: 120 }, (_, index) => `ring/${index} REACHES ring/${(index + 1) % 120}`),
26
+ seed: 'ring/0'
27
+ }
28
+ ]
29
+
30
+ for (const entry of cases) {
31
+ const store = open()
32
+ store.ingest(entry.edges.join('\n'))
33
+ const run = (input: string): { readonly ms: number, readonly matches: number } => {
34
+ const start = performance.now()
35
+ const matches = query(store, input).length
36
+ return { ms: Number((performance.now() - start).toFixed(3)), matches }
37
+ }
38
+ const bound = run(`${entry.seed} REACHES+ ?destination`)
39
+ const unbound = run('?source REACHES+ ?destination')
40
+ process.stdout.write(`${JSON.stringify({ scenario: entry.name, edges: entry.edges.length, bound, unbound })}\n`)
41
+ store.close()
42
+ }
@@ -0,0 +1,3 @@
1
+ /** Deterministic chain/branch/cycle benchmark for seeded transitive plans. */
2
+ export {};
3
+ //# sourceMappingURL=transitive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transitive.d.ts","sourceRoot":"","sources":["../../bench/transitive.ts"],"names":[],"mappings":"AAAA,8EAA8E"}
@@ -0,0 +1,38 @@
1
+ /** Deterministic chain/branch/cycle benchmark for seeded transitive plans. */
2
+ import { performance } from 'node:perf_hooks';
3
+ import { open } from '@cavelang/store';
4
+ import { query } from "../src/compile.js";
5
+ const cases = [
6
+ {
7
+ name: 'chain',
8
+ edges: Array.from({ length: 120 }, (_, index) => `n/${index} REACHES n/${index + 1}`),
9
+ seed: 'n/0'
10
+ },
11
+ {
12
+ name: 'branches',
13
+ edges: Array.from({ length: 127 }, (_, index) => [
14
+ `tree/${index} REACHES tree/${index * 2 + 1}`,
15
+ `tree/${index} REACHES tree/${index * 2 + 2}`
16
+ ]).flat(),
17
+ seed: 'tree/0'
18
+ },
19
+ {
20
+ name: 'cycle',
21
+ edges: Array.from({ length: 120 }, (_, index) => `ring/${index} REACHES ring/${(index + 1) % 120}`),
22
+ seed: 'ring/0'
23
+ }
24
+ ];
25
+ for (const entry of cases) {
26
+ const store = open();
27
+ store.ingest(entry.edges.join('\n'));
28
+ const run = (input) => {
29
+ const start = performance.now();
30
+ const matches = query(store, input).length;
31
+ return { ms: Number((performance.now() - start).toFixed(3)), matches };
32
+ };
33
+ const bound = run(`${entry.seed} REACHES+ ?destination`);
34
+ const unbound = run('?source REACHES+ ?destination');
35
+ process.stdout.write(`${JSON.stringify({ scenario: entry.name, edges: entry.edges.length, bound, unbound })}\n`);
36
+ store.close();
37
+ }
38
+ //# sourceMappingURL=transitive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transitive.js","sourceRoot":"","sources":["../../bench/transitive.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAIzC,MAAM,KAAK,GAAoB;IAC7B;QACE,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,cAAc,KAAK,GAAG,CAAC,EAAE,CAAC;QACrF,IAAI,EAAE,KAAK;KACZ;IACD;QACE,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/C,QAAQ,KAAK,iBAAiB,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE;YAC7C,QAAQ,KAAK,iBAAiB,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE;SAC9C,CAAC,CAAC,IAAI,EAAE;QACT,IAAI,EAAE,QAAQ;KACf;IACD;QACE,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,QAAQ,KAAK,iBAAiB,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC;QACnG,IAAI,EAAE,QAAQ;KACf;CACF,CAAA;AAED,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,EAAE,CAAA;IACpB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACpC,MAAM,GAAG,GAAG,CAAC,KAAa,EAAqD,EAAE;QAC/E,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,CAAA;QAC1C,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAA;IACxE,CAAC,CAAA;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,wBAAwB,CAAC,CAAA;IACxD,MAAM,OAAO,GAAG,GAAG,CAAC,+BAA+B,CAAC,CAAA;IACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,CAAA;IAChH,KAAK,CAAC,KAAK,EAAE,CAAA;AACf,CAAC"}
@@ -1,14 +1,9 @@
1
- import type { Store } from '@cavelang/store';
1
+ import type { Store } from '@cavelang/store/adapter';
2
2
  import * as Compile from './compile.ts';
3
3
  import * as Pattern from './pattern.ts';
4
4
  export type { Match, Options } from './compile.ts';
5
- /**
6
- * Exact numeric attribute values are matched through normalized storage
7
- * columns, not their as-written spelling: `0.9B users/wk` and
8
- * `900M users/wk` denote the same number/unit pair. The compiler's existing
9
- * value filter pushes the normalized comparison into SQL; the final check
10
- * preserves exact unit and approximation semantics.
11
- */
5
+ export type { Window } from './compile.ts';
6
+ export declare const window: (store: Store, pattern: Pattern.t, options?: Compile.Options) => Compile.Window;
12
7
  export declare const match: (store: Store, pattern: Pattern.t, options?: Compile.Options) => Compile.Match[];
13
8
  export declare const query: (store: Store, input: string, options?: Compile.Options) => Compile.Match[];
14
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,iBAAiB,CAAA;AAC5C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAEvC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAelD;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,GAChB,OAAO,KAAK,EACZ,SAAS,OAAO,CAAC,CAAC,EAClB,UAAS,OAAO,CAAC,OAAY,KAC5B,OAAO,CAAC,KAAK,EAgCf,CAAA;AAED,eAAO,MAAM,KAAK,GAChB,OAAO,KAAK,EACZ,OAAO,MAAM,EACb,UAAS,OAAO,CAAC,OAAY,KAC5B,OAAO,CAAC,KAAK,EAC6B,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;AAEvC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAClD,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AA4D1C,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,CAAC,CAAC,EAClB,UAAS,OAAO,CAAC,OAAY,KAC5B,OAAO,CAAC,MAA0C,CAAA;AAErD,eAAO,MAAM,KAAK,GAChB,OAAO,KAAK,EACZ,SAAS,OAAO,CAAC,CAAC,EAClB,UAAS,OAAO,CAAC,OAAY,KAC5B,OAAO,CAAC,KAAK,EAA8C,CAAA;AAE9D,eAAO,MAAM,KAAK,GAChB,OAAO,KAAK,EACZ,OAAO,MAAM,EACb,UAAS,OAAO,CAAC,OAAY,KAC5B,OAAO,CAAC,KAAK,EAC6B,CAAA"}
@@ -20,13 +20,13 @@ const storeAtBoundary = (store, options) => {
20
20
  * value filter pushes the normalized comparison into SQL; the final check
21
21
  * preserves exact unit and approximation semantics.
22
22
  */
23
- export const match = (store, pattern, options = {}) => {
23
+ const execute = (store, pattern, options = {}) => {
24
24
  if (pattern.payload.kind !== 'attribute' || pattern.payload.value.kind !== 'term') {
25
- return Compile.match(storeAtBoundary(store, options), pattern, options);
25
+ return Compile.window(storeAtBoundary(store, options), pattern, options);
26
26
  }
27
27
  const value = Value.parse(pattern.payload.value.text);
28
28
  if (value.kind !== 'number' || value.num === undefined) {
29
- return Compile.match(storeAtBoundary(store, options), pattern, options);
29
+ return Compile.window(storeAtBoundary(store, options), pattern, options);
30
30
  }
31
31
  const expectedNum = value.num;
32
32
  const filter = {
@@ -44,14 +44,16 @@ export const match = (store, pattern, options = {}) => {
44
44
  };
45
45
  const expectedUnit = value.unit ?? null;
46
46
  const expectedApprox = value.approx ? 1 : 0;
47
- return Compile.match(storeAtBoundary(store, options), normalized, options)
48
- .filter(result => {
49
- const row = result.row;
50
- return row !== undefined &&
51
- row.value_num === expectedNum &&
52
- row.value_unit === expectedUnit &&
53
- row.value_approx === expectedApprox;
54
- });
47
+ const result = Compile.window(storeAtBoundary(store, options), normalized, options);
48
+ return { ...result, matches: result.matches.filter(match => {
49
+ const row = match.row;
50
+ return row !== undefined &&
51
+ row.value_num === expectedNum &&
52
+ row.value_unit === expectedUnit &&
53
+ row.value_approx === expectedApprox;
54
+ }) };
55
55
  };
56
+ export const window = (store, pattern, options = {}) => execute(store, pattern, options);
57
+ export const match = (store, pattern, options = {}) => execute(store, pattern, options).matches;
56
58
  export const query = (store, input, options = {}) => match(store, Pattern.parse(input), options);
57
59
  //# sourceMappingURL=bounded.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bounded.js","sourceRoot":"","sources":["../../src/bounded.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bounded.js","sourceRoot":"","sources":["../../src/bounded.ts"],"names":[],"mappings":"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"}
@@ -14,12 +14,19 @@
14
14
  * on the object side.
15
15
  *
16
16
  * Transitive patterns (`terrier EXTENDS+ animal`) compile to a recursive
17
- * CTE over current, positive, non-retracted edges (depth-capped at 32).
17
+ * CTE over current, positive, non-retracted edges. Recursive state is the
18
+ * reachable endpoint pair itself, so SQL `UNION` deduplication terminates
19
+ * cycles without an arbitrary semantic depth cap.
18
20
  */
19
- import { Row } from '@cavelang/store';
20
- import type { Store } from '@cavelang/store';
21
+ import { Registry } from '@cavelang/canonical';
22
+ import { Resolve, Row } from '@cavelang/store/adapter';
23
+ import type { Store } from '@cavelang/store/adapter';
21
24
  import * as Pattern from './pattern.ts';
22
- /** One query solution: variable bindings plus the matched row (absent for transitive hops). */
25
+ /**
26
+ * One storage-oriented query solution. `row`/`rows` expose SQLite-shaped
27
+ * data for in-process reasoning engines; use `queryRecords()` for versioned
28
+ * public JSON and cross-process integrations.
29
+ */
23
30
  export type Match = {
24
31
  readonly bindings: Readonly<Record<string, string>>;
25
32
  readonly row?: Row.t;
@@ -42,6 +49,10 @@ export type Match = {
42
49
  };
43
50
  };
44
51
  export type Options = {
52
+ /** Maximum rows SQLite may return. Prefer the snapshot-aware page API for continuations. */
53
+ readonly limit?: number;
54
+ /** Internal SQL offset used by the snapshot-aware page API. */
55
+ readonly offset?: number;
45
56
  /** Match all appended rows, not only current beliefs. */
46
57
  readonly all?: boolean;
47
58
  /**
@@ -97,6 +108,15 @@ export type Options = {
97
108
  */
98
109
  readonly support?: boolean;
99
110
  };
111
+ type Compiled = {
112
+ readonly sql: string;
113
+ readonly params: (string | number)[];
114
+ readonly bind: (row: Record<string, unknown>) => Record<string, string>;
115
+ readonly transitive: boolean;
116
+ /** Variables bound to the value slot — interpolation substitutes these (spec §32.4). */
117
+ readonly valueVars: readonly string[];
118
+ };
119
+ export declare const compile: (pattern: Pattern.t, registry: Registry.t, options: Options, policy?: readonly Resolve.Entry[]) => Compiled;
100
120
  /**
101
121
  * Runs a CAVE-Q query against a store.
102
122
  *
@@ -114,5 +134,14 @@ export declare const query: (store: Store, input: string, options?: Options) =>
114
134
  * (the §24 rules engine substitutes bindings into premise patterns
115
135
  * between joins) rather than as text.
116
136
  */
137
+ export type Window = {
138
+ /** Matches remaining after any valid-time evaluation. */
139
+ readonly matches: Match[];
140
+ /** Rows returned by SQLite before valid-time evaluation. */
141
+ readonly scanned: number;
142
+ };
143
+ /** Execute one SQL window and report how many pre-filter rows it consumed. */
144
+ export declare const window: (store: Store, pattern: Pattern.t, options?: Options) => Window;
117
145
  export declare const match: (store: Store, pattern: Pattern.t, options?: Options) => Match[];
146
+ export {};
118
147
  //# sourceMappingURL=compile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAW,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAEvC,+FAA+F;AAC/F,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IACpB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,EAAE,CAAA;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACtF,CAAA;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,yDAAyD;IACzD,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AA6XD;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,EAAE,UAAS,OAAY,KAAG,KAAK,EACnC,CAAA;AAiC7C;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,EAAE,SAAS,OAAO,CAAC,CAAC,EAAE,UAAS,OAAY,KAAG,KAAK,EA+EpF,CAAA"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.ts"],"names":[],"mappings":"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"}