@cavelang/query 0.27.14 → 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 +5 -0
- package/License.md +6 -0
- package/README.md +76 -11
- package/bench/transitive.ts +42 -0
- package/dist/bench/transitive.d.ts +3 -0
- package/dist/bench/transitive.d.ts.map +1 -0
- package/dist/bench/transitive.js +38 -0
- package/dist/bench/transitive.js.map +1 -0
- package/dist/src/bounded.d.ts +3 -8
- package/dist/src/bounded.d.ts.map +1 -1
- package/dist/src/bounded.js +13 -11
- package/dist/src/bounded.js.map +1 -1
- package/dist/src/compile.d.ts +33 -4
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +153 -103
- package/dist/src/compile.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/page.d.ts +23 -0
- package/dist/src/page.d.ts.map +1 -0
- package/dist/src/page.js +131 -0
- package/dist/src/page.js.map +1 -0
- package/dist/src/record.d.ts +21 -0
- package/dist/src/record.d.ts.map +1 -0
- package/dist/src/record.js +41 -0
- package/dist/src/record.js.map +1 -0
- package/package.json +21 -8
- package/src/bounded.ts +26 -13
- package/src/compile.ts +151 -78
- package/src/index.ts +4 -0
- package/src/page.ts +149 -0
- package/src/record.ts +64 -0
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
|
|
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 (
|
|
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
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
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
|
|
90
|
-
UTC
|
|
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
|
|
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 @@
|
|
|
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"}
|
package/dist/src/bounded.d.ts
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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"}
|
package/dist/src/bounded.js
CHANGED
|
@@ -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
|
-
|
|
23
|
+
const execute = (store, pattern, options = {}) => {
|
|
24
24
|
if (pattern.payload.kind !== 'attribute' || pattern.payload.value.kind !== 'term') {
|
|
25
|
-
return Compile.
|
|
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.
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
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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"}
|
package/dist/src/compile.d.ts
CHANGED
|
@@ -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
|
|
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 {
|
|
20
|
-
import
|
|
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
|
-
/**
|
|
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
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.ts"],"names":[],"mappings":"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"}
|