@omgbase/core 0.28.0 → 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/dist/src/core/read/document.d.ts +11 -10
- package/dist/src/core/read/document.js +12 -11
- package/dist/src/core/read/nodes.d.ts +10 -10
- package/dist/src/core/read/nodes.js +11 -11
- package/dist/src/core/read/reader.d.ts +37 -24
- package/dist/src/core/read/reader.js +44 -31
- package/dist/src/graph/history.d.ts +25 -22
- package/dist/src/graph/history.js +17 -17
- package/dist/src/graph/inbound-links.d.ts +7 -7
- package/dist/src/graph/inbound-links.js +7 -7
- package/dist/src/graph/link-health.d.ts +9 -9
- package/dist/src/graph/link-health.js +9 -9
- package/dist/src/graph/links.d.ts +3 -3
- package/dist/src/graph/links.js +4 -4
- package/dist/src/mcp/arguments.d.ts +10 -3
- package/dist/src/mcp/arguments.js +32 -9
- package/dist/src/mcp/errors.d.ts +1 -1
- package/dist/src/mcp/graph.d.ts +22 -22
- package/dist/src/mcp/graph.js +53 -46
- package/dist/src/mcp/reference.d.ts +29 -1
- package/dist/src/mcp/reference.js +350 -222
- package/dist/src/mcp/server.d.ts +9 -0
- package/dist/src/mcp/server.js +169 -107
- package/dist/src/mutate/apply.d.ts +6 -6
- package/dist/src/mutate/apply.js +1 -1
- package/dist/src/mutate/canonical.d.ts +1 -1
- package/dist/src/mutate/canonical.js +2 -2
- package/dist/src/mutate/commit.d.ts +3 -3
- package/dist/src/mutate/commit.js +4 -4
- package/dist/src/mutate/docs.d.ts +1 -1
- package/dist/src/mutate/docs.js +8 -8
- package/dist/src/mutate/effects.d.ts +17 -17
- package/dist/src/mutate/effects.js +113 -113
- package/dist/src/mutate/macros.d.ts +5 -5
- package/dist/src/mutate/macros.js +1 -1
- package/dist/src/mutate/materialize.js +2 -2
- package/dist/src/mutate/ops.js +2 -2
- package/dist/src/mutate/opset.d.ts +7 -7
- package/dist/src/mutate/plan-update.js +2 -2
- package/dist/src/mutate/plan.d.ts +8 -8
- package/dist/src/mutate/plan.js +25 -25
- package/dist/src/mutate/select.d.ts +4 -4
- package/dist/src/mutate/select.js +52 -52
- package/dist/src/mutate/sugar.d.ts +10 -10
- package/dist/src/mutate/sugar.js +21 -21
- package/dist/src/oqx-js/context.d.ts +8 -4
- package/dist/src/oqx-js/context.js +206 -189
- package/dist/src/oqx-js/names.d.ts +28 -17
- package/dist/src/oqx-js/names.js +115 -78
- package/dist/src/oqx-js/planner.d.ts +4 -8
- package/dist/src/oqx-js/planner.js +6 -10
- package/dist/src/oqx-js/root-row.d.ts +6 -5
- package/dist/src/oqx-js/root-row.js +15 -16
- package/dist/src/oqx-js/run.d.ts +18 -17
- package/dist/src/oqx-js/run.js +57 -54
- package/dist/src/oqx-js/sql/translate.d.ts +5 -5
- package/dist/src/oqx-js/sql/translate.js +162 -161
- package/dist/src/oqx-js/store-index.d.ts +1 -1
- package/dist/src/oqx-js/store-index.js +28 -30
- package/dist/src/search/resolve.d.ts +2 -2
- package/dist/src/search/resolve.js +1 -1
- package/dist/src/search/rrf.js +2 -2
- package/dist/src/search/text.d.ts +5 -5
- package/dist/src/search/text.js +2 -2
- package/dist/src/spec-versions.d.ts +6 -6
- package/dist/src/spec-versions.js +6 -6
- package/dist/src/surface-paths.d.ts +18 -17
- package/dist/src/surface-paths.js +23 -21
- package/dist/src/sync/admin.d.ts +2 -2
- package/dist/src/sync/admin.js +1 -1
- package/package.json +1 -1
package/dist/src/oqx-js/run.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// omgbase's OQX entry point, served by `@omgbase/oqx`: parse the source, run it
|
|
2
2
|
// through the in-memory engine over a store-backed DataContext (context.ts), and
|
|
3
|
-
// shape the engine's result into omgbase's OqxResult (lean {
|
|
4
|
-
// — the envelope keys ARE the attributes, spec/surface §1.4
|
|
3
|
+
// shape the engine's result into omgbase's OqxResult (lean {_id, _path, …}
|
|
4
|
+
// hits — the envelope keys ARE the attributes, spec/surface §1.4 (5.0) — keyset
|
|
5
5
|
// pagination, count/exists scalars). Same signature + shape as the former
|
|
6
6
|
// in-tree compiler, so every caller and the corpus are unchanged.
|
|
7
7
|
import { parse, PlannedEngine, InMemoryEngine, OqxError, resolveAliases, transform, visit, build, semantics } from "@omgbase/oqx";
|
|
@@ -29,18 +29,18 @@ const ROW_FNS = new Set([
|
|
|
29
29
|
"yaml_path", "json_pointer", "has_edge", "has_anchor", "child_count", "parent_type",
|
|
30
30
|
]);
|
|
31
31
|
// Paths on the surface are the reference form (spec/surface §1 "Paths", 2.0):
|
|
32
|
-
// `
|
|
33
|
-
// compares with one of them — `
|
|
34
|
-
// `
|
|
32
|
+
// `_path` and the edge field `_dst_path` read `/a/b.md`. A string literal a
|
|
33
|
+
// query compares with one of them — `_path == "a.md"`, `"a.md" != _dst_path`,
|
|
34
|
+
// `_path.startsWith("lab/")`, `_doc._path == "a.md"` — is rooted first, so both
|
|
35
35
|
// spellings match; a property or binding compared with a path is never touched
|
|
36
|
-
// (it is the author's value)
|
|
37
|
-
//
|
|
38
|
-
// member read is a path read only through a ROW handle (`
|
|
39
|
-
// `$it`).
|
|
36
|
+
// (it is the author's value) — so an authored `path:` key, bare or through a
|
|
37
|
+
// source handle (`path`, `_data.path`, `_frontmatter.path`), is compared as
|
|
38
|
+
// written: a member read is a path read only through a ROW handle (`_doc`,
|
|
39
|
+
// `_block`, `_dst`, `$it`).
|
|
40
40
|
// The planner sees the rewritten tree too, so the pushed SQL and the in-memory
|
|
41
41
|
// engine agree by construction.
|
|
42
|
-
const PATH_ATTRIBUTES = new Set(["
|
|
43
|
-
const ROW_HANDLES = new Set(["
|
|
42
|
+
const PATH_ATTRIBUTES = new Set(["_path", "_dst_path"]);
|
|
43
|
+
const ROW_HANDLES = new Set(["_doc", "_block", "_dst", "$it"]);
|
|
44
44
|
function isPathRead(e) {
|
|
45
45
|
if (e.kind === "ident" || e.kind === "outer")
|
|
46
46
|
return PATH_ATTRIBUTES.has(e.name);
|
|
@@ -65,11 +65,11 @@ export function rootPathLiterals(e) {
|
|
|
65
65
|
return e;
|
|
66
66
|
}
|
|
67
67
|
// The root row (root-row.ts, spec/surface §1.1, 2.0): `$repo` anywhere, and a
|
|
68
|
-
// bare
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
68
|
+
// bare root name at scope depth ≥ 1 (a property read of a row that has none —
|
|
69
|
+
// since 5.0 every relation is `_`-prefixed, so a bare `blocks`/`nodes`/
|
|
70
|
+
// `revisions` is never one either), are refused before evaluation — one `visit`
|
|
71
|
+
// over the parsed tree, so the error does not depend on which rows the data
|
|
72
|
+
// happens to hold and the planned and in-memory paths agree trivially. A
|
|
73
73
|
// `^<target>` with more carets than enclosing scopes (`^docs count { }` at the
|
|
74
74
|
// top level) would read absent and count 0: refused too, naming the bare
|
|
75
75
|
// spelling.
|
|
@@ -85,7 +85,7 @@ export function checkRootSpellings(q) {
|
|
|
85
85
|
return;
|
|
86
86
|
if (node.name === "$repo")
|
|
87
87
|
throw new FilterInvalid(REPO_REMOVED_MESSAGE, "OQX");
|
|
88
|
-
if (node.kind === "ident" && ctx.depth >= 1 && (node.name
|
|
88
|
+
if (node.kind === "ident" && ctx.depth >= 1 && ROOTS.has(node.name)) {
|
|
89
89
|
throw new FilterInvalid(bareTargetMessage(node.name, ctx.depth), "OQX");
|
|
90
90
|
}
|
|
91
91
|
if (node.kind === "outer" && ROOTS.has(node.name) && node.levels > ctx.depth) {
|
|
@@ -154,14 +154,15 @@ export function collectSemanticPhrases(source) {
|
|
|
154
154
|
});
|
|
155
155
|
return [...phrases];
|
|
156
156
|
}
|
|
157
|
-
const ID_ITEM = build.field("__oqx_id", build.ident("
|
|
158
|
-
const PATH_ITEM = build.field("__oqx_path", build.ident("
|
|
157
|
+
const ID_ITEM = build.field("__oqx_id", build.ident("_id"));
|
|
158
|
+
const PATH_ITEM = build.field("__oqx_path", build.ident("_path"));
|
|
159
159
|
// The runner's own projection names (`__oqx_id`, `__oqx_path`, `__oqx_self`,
|
|
160
160
|
// `__oqx_value`) and the selector compiler's slots (`__omg_sel_<t>_<slot>`,
|
|
161
161
|
// mutate/select.ts) share two reserved prefixes. A user alias under either would
|
|
162
162
|
// shadow an injected item (`select __oqx_id: 1` overwrote the hit's `id` through
|
|
163
163
|
// 4.0) or collide with a slot, so it is refused before anything runs — over the
|
|
164
|
-
// query's own top-level items, the only ones the runner injects beside.
|
|
164
|
+
// query's own top-level items, the only ones the runner injects beside. (The
|
|
165
|
+
// engine prefix of 5.0 is a single `_`; two underscores stay the runner's.)
|
|
165
166
|
const RESERVED_ALIAS_PREFIXES = ["__oqx_", "__omg_"];
|
|
166
167
|
export function reservedAlias(items) {
|
|
167
168
|
for (const item of items) {
|
|
@@ -172,23 +173,25 @@ export function reservedAlias(items) {
|
|
|
172
173
|
return null;
|
|
173
174
|
}
|
|
174
175
|
// Result projections may not overwrite the envelope (spec/surface §1.4, 3.0):
|
|
175
|
-
// a projection whose output key is `
|
|
176
|
-
// the envelope's own selection — the
|
|
177
|
-
// collapses onto the envelope key (`select
|
|
178
|
-
// and is otherwise a loud error asking for an alias: `select
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
// the
|
|
183
|
-
|
|
176
|
+
// a projection whose output key is `_id` or `_path` is allowed only when it IS
|
|
177
|
+
// the envelope's own selection — the attribute of the same name, which
|
|
178
|
+
// collapses onto the envelope key (`select _id, _path` is simply the envelope)
|
|
179
|
+
// — and is otherwise a loud error asking for an alias: `select _path: layer`
|
|
180
|
+
// must pick another name. (Since 5.0 the author's `path:`/`id:` keys are the
|
|
181
|
+
// bare `path`/`id`, their own columns — nothing collides by accident; only an
|
|
182
|
+
// alias spelled `_id:`/`_path:` can.) Checked over the resolved items (an alias
|
|
183
|
+
// is just a name here), before the engine runs, so the error never depends on
|
|
184
|
+
// the rows. A `values` projection returns no hits, so the envelope — and the
|
|
185
|
+
// rule — do not apply.
|
|
186
|
+
const ENVELOPE_KEYS = new Set(["_id", "_path"]);
|
|
184
187
|
function envelopeCollision(items) {
|
|
185
188
|
for (const item of items) {
|
|
186
189
|
if (!ENVELOPE_KEYS.has(item.name))
|
|
187
190
|
continue;
|
|
188
191
|
if (item.kind === "field" && item.expr.kind === "ident" && item.expr.name === item.name)
|
|
189
192
|
continue;
|
|
190
|
-
const hint = item.name === "
|
|
191
|
-
return new FilterInvalid(`projection \`${item.name}\` collides with the hit envelope — alias it (\`${hint}
|
|
193
|
+
const hint = item.name === "_path" ? "p" : "i";
|
|
194
|
+
return new FilterInvalid(`projection \`${item.name}\` collides with the hit envelope — alias it (\`${hint}: …\`)`, "OQX");
|
|
192
195
|
}
|
|
193
196
|
return null;
|
|
194
197
|
}
|
|
@@ -197,8 +200,8 @@ function envelopeCollision(items) {
|
|
|
197
200
|
// the five collections, `revisions` included — the planner's `rootTarget` is
|
|
198
201
|
// narrower: the four it can plan) and nothing re-projects them; a `follow` destination (`follow before` over a
|
|
199
202
|
// frontmatter list of paths), a `from E` re-projection or any other source can
|
|
200
|
-
// reach a scalar, which the injected `
|
|
201
|
-
// junk hit `{
|
|
203
|
+
// reach a scalar, which the injected `_id`/`_path` reads would render as the
|
|
204
|
+
// junk hit `{ _id: "undefined", _path: "" }`. For those queries the row itself is
|
|
202
205
|
// projected too (`$it`), and `toHit` fails the query when it is not a row. Only
|
|
203
206
|
// then: a row clone per hit is free here but not in the Rust port, and a root
|
|
204
207
|
// scan cannot need it. A `values` projection returns no hits, so it is exempt
|
|
@@ -236,8 +239,8 @@ const VALUE_KEY = "__oqx_value";
|
|
|
236
239
|
// spec/oqx §12), a `values` projection of `$it`, a field bound to a
|
|
237
240
|
// row — and a store row is not a wire shape (column names, `attrs` as a JSON
|
|
238
241
|
// string, the `__path` join column, Buffers). Walk the projected value and
|
|
239
|
-
// render every tagged row as `{
|
|
240
|
-
// (
|
|
242
|
+
// render every tagged row as `{ _id, _path }` — the hit envelope's own keys
|
|
243
|
+
// (5.0), one notation for "a document reference" everywhere a row shape
|
|
241
244
|
// appears in a result; everything else passes through untouched (plain records
|
|
242
245
|
// and arrays are descended, scalars kept). Hits are records the engine built
|
|
243
246
|
// from the injected id/path items, never rows.
|
|
@@ -264,22 +267,22 @@ function shapeRow(row) {
|
|
|
264
267
|
throw notAStoreRow(__oqx_self);
|
|
265
268
|
return { id: String(__oqx_id), path: String(__oqx_path ?? ""), proj: renderValue(rest) };
|
|
266
269
|
}
|
|
267
|
-
// The envelope keys lead; a user projection of `
|
|
270
|
+
// The envelope keys lead; a user projection of `_id`/`_path` collapses onto
|
|
268
271
|
// them in place (the same value, read by the same attribute).
|
|
269
272
|
function toHit(s) {
|
|
270
|
-
return {
|
|
273
|
+
return { _id: s.id, _path: s.path, ...s.proj };
|
|
271
274
|
}
|
|
272
|
-
// `bare` (4.2): the projection alone. A projected `
|
|
273
|
-
// column here — the
|
|
274
|
-
//
|
|
275
|
+
// `bare` (4.2): the projection alone. A projected `_id`/`_path` is an ordinary
|
|
276
|
+
// column here — the attribute's value, under the key the query gave it — and
|
|
277
|
+
// nothing is injected beside it.
|
|
275
278
|
function toBareHit(s) {
|
|
276
279
|
return s.proj;
|
|
277
280
|
}
|
|
278
281
|
// Top-level `select distinct`: dedup hits by their USER projection — every
|
|
279
|
-
// field except the envelope's `
|
|
280
|
-
// collapses onto (so `select distinct
|
|
282
|
+
// field except the envelope's `_id`/`_path`, which a projection of the attribute
|
|
283
|
+
// collapses onto (so `select distinct _id` dedups on nothing but the empty
|
|
281
284
|
// projection, as it always has); under `bare` there is no envelope, so a
|
|
282
|
-
// projected `
|
|
285
|
+
// projected `_id`/`_path` IS part of the projection and counts. Keeps the first
|
|
283
286
|
// (so the retained hit carries a real identity). Order-preserving.
|
|
284
287
|
function dedupByProjection(rows, bare) {
|
|
285
288
|
const seen = new Set();
|
|
@@ -460,11 +463,11 @@ function runResolved(store, repoId, raw, opts) {
|
|
|
460
463
|
return { hits: [], truncated: false, cursor: null, consumer: "none", none: res.consumer === "none" ? res.none : true };
|
|
461
464
|
}
|
|
462
465
|
// A grouped query (oqx 0.24, SEMANTICS §24) yields GROUPS, not store rows:
|
|
463
|
-
// the envelope does not apply — there is no `
|
|
466
|
+
// the envelope does not apply — there is no `_id`/`_path` to inject and no
|
|
464
467
|
// keyset to page by — so a hit is the group's projection as the query wrote
|
|
465
468
|
// it (`{ layer, n }`), exactly what `bare` yields for a row query; `bare` is
|
|
466
469
|
// accepted and changes nothing. Rows that surface as values (`rows collect {
|
|
467
|
-
// }` with an empty projection, `collect(
|
|
470
|
+
// }` with an empty projection, `collect($it)`) render as `{ _id, _path }` refs
|
|
468
471
|
// like every row-as-value. Paging is by position: the query's own
|
|
469
472
|
// `limit`/`offset` define the set, the tool's `limit` takes the first page,
|
|
470
473
|
// `truncated` says whether more groups follow, the cursor is always null (as
|
|
@@ -478,7 +481,7 @@ function runResolved(store, repoId, raw, opts) {
|
|
|
478
481
|
// cannot land inside a document's elements: a flattened query pages
|
|
479
482
|
// positionally with a null cursor, as a grouped query and a custom `order by`
|
|
480
483
|
// do (a keyset extended with the flatten ordinal is a later round). A bound
|
|
481
|
-
// name of `
|
|
484
|
+
// name of `_id` or `_path` would shadow the envelope's own reads (the name
|
|
482
485
|
// shadows a same-named row property on the flattened row): refused, like a
|
|
483
486
|
// projection that collides with the envelope.
|
|
484
487
|
const flattened = parsed.flatten.length > 0;
|
|
@@ -486,11 +489,11 @@ function runResolved(store, repoId, raw, opts) {
|
|
|
486
489
|
if (ENVELOPE_KEYS.has(f.name))
|
|
487
490
|
throw new FilterInvalid(`flatten \`as ${f.name}\` collides with the hit envelope — a flattened row is still the row, whose \`${f.name}\` the envelope reads; bind another name`, "OQX");
|
|
488
491
|
}
|
|
489
|
-
// collect / first / single: inject
|
|
492
|
+
// collect / first / single: inject _id + _path so every hit carries them. A
|
|
490
493
|
// top-level `select distinct` is applied HERE, not in the engine: the injected
|
|
491
|
-
//
|
|
492
|
-
// we run without engine-distinct and dedup hits by their USER projection
|
|
493
|
-
// keeping the first row's
|
|
494
|
+
// _id/_path are unique per row and would defeat the engine's projection dedup,
|
|
495
|
+
// so we run without engine-distinct and dedup hits by their USER projection
|
|
496
|
+
// below, keeping the first row's _id/_path.
|
|
494
497
|
const topDistinct = parsed.distinct;
|
|
495
498
|
// A top-level `values` projection runs as a RECORD projection whose single
|
|
496
499
|
// item is renamed to VALUE_KEY (the engine's own values mode is switched off),
|
|
@@ -500,7 +503,7 @@ function runResolved(store, repoId, raw, opts) {
|
|
|
500
503
|
const userSelect = topValues ? [{ ...parsed.select[0], name: VALUE_KEY }] : parsed.select;
|
|
501
504
|
// `bare` (4.2): the hits are the projection alone — refused without one and
|
|
502
505
|
// with `values`; with no envelope there is no collision to refuse either, a
|
|
503
|
-
// projected `
|
|
506
|
+
// projected `_id`/`_path` is simply a column.
|
|
504
507
|
const bare = opts.bare === true;
|
|
505
508
|
if (bare) {
|
|
506
509
|
const misuse = bareMisuse(parsed);
|
|
@@ -597,10 +600,10 @@ export async function oqxRunAsync(store, repoId, source, opts = {}, embedQuery)
|
|
|
597
600
|
}
|
|
598
601
|
return oqxRun(store, repoId, source, { ...opts, semanticVectors });
|
|
599
602
|
}
|
|
600
|
-
// The collect page's keyset is (path, id) — the hit's `
|
|
601
|
-
// form (`/a.md`), and its `
|
|
603
|
+
// The collect page's keyset is (path, id) — the hit's `_path`, so the reference
|
|
604
|
+
// form (`/a.md`), and its `_id`: the kernel's shared cursor encoding
|
|
602
605
|
// (core/cursor.ts) with a two-part tuple of VALUES (no key names ride in it, so
|
|
603
|
-
// a 2.x cursor stays valid on
|
|
606
|
+
// a 2.x cursor stays valid on 5.0). A malformed cursor is CursorInvalid, which the MCP layer maps
|
|
604
607
|
// to filter_invalid; so is a cursor whose path is not rooted — one issued by a
|
|
605
608
|
// 1.x surface, whose keyset would otherwise sort before every rooted hit and
|
|
606
609
|
// silently replay the first page (spec/surface §1.4, 2.0).
|
|
@@ -59,12 +59,12 @@ export interface Operand extends Frag {
|
|
|
59
59
|
pathCol?: string;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* Per target, the
|
|
62
|
+
* Per target, the engine names (and `_doc.<k>` keys, via the docs set) that
|
|
63
63
|
* `context.ts` resolves to something other than a scalar field or property: the
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* reach-through handles, the relations, the property source handles and
|
|
65
|
+
* (blocks/nodes) the whole `_attrs` object. A comparison naming one of these is
|
|
66
|
+
* declined (spec/surface §1 decline (b)) — read as a property it would be
|
|
67
|
+
* `NULL`, where in memory the value is a row, an array or an object.
|
|
68
68
|
* `translate.test.ts` asserts this set against the store context.
|
|
69
69
|
*/
|
|
70
70
|
export declare const NON_PROPERTY_NAMES: Readonly<Record<Target, ReadonlySet<string>>>;
|