@omgbase/core 0.27.1 → 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
|
@@ -38,40 +38,47 @@ function tagAll(rows, t) {
|
|
|
38
38
|
r[TARGET] = t;
|
|
39
39
|
return rows;
|
|
40
40
|
}
|
|
41
|
-
// THE NAME RULE (spec/surface §1.2,
|
|
41
|
+
// THE NAME RULE (spec/surface §1.2, 5.0: "underscore = engine"). On every
|
|
42
|
+
// record kind a BARE name is a user-authored entry and an UNDERSCORE-prefixed
|
|
43
|
+
// name is engine-provided, however derived — the prefix declares an engine
|
|
44
|
+
// field on a record, and the bare namespace is the user's on every kind (any
|
|
45
|
+
// record may carry user data later, so docs, blocks, nodes, links, revisions
|
|
46
|
+
// and the root row all follow it now). `$` belongs to OQX: `$it`, `$key`,
|
|
42
47
|
// `$depth`, `$stop`, `$leaf`, `$frontier`, `$ordinal` are values the LANGUAGE
|
|
43
|
-
// injects into a scope; omgbase adds no `$` names.
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
// `
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
// `
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
48
|
+
// injects into a scope; omgbase adds no `$` names. The engine names: every
|
|
49
|
+
// row's `_id`/`_path`; docs' and blocks' `_raw`/`_hash`/`_updated_at`/
|
|
50
|
+
// `_created_at` (4.10: the commit `ts` of the thing's first revision / earliest
|
|
51
|
+
// `block_changes` row — "first observed by omgbase", not a filesystem time);
|
|
52
|
+
// docs' `_title` (the computed title) and `_tags` (authored tags ∪ body
|
|
53
|
+
// hashtags) and `_format`; a foreign key named for what it is (`_doc_id`,
|
|
54
|
+
// `_block_id`, `_via_id`, `_dst_id`, `_dst_path`, `_uri`), a column its column
|
|
55
|
+
// (`_type`, `_text`, `_depth`, `_ordinal`, `_kind`, `_predicate`, `_field`); the
|
|
56
|
+
// handles `_data`/`_frontmatter`/`_inline`, the reach-throughs `_doc`/`_block`/
|
|
57
|
+
// `_dst` and the relations (`_blocks`, `_children`, `_out_links`, …). A bare
|
|
58
|
+
// name is ALWAYS the author's: on a document a property (frontmatter + inline
|
|
59
|
+
// by the property rule — `title`, `tags`, `id`, `path`, `doc` included; nothing
|
|
60
|
+
// is reserved), on a block or node an `attrs` key (`checked`). `_data.<k>` is
|
|
61
|
+
// the same merged read as the bare `<k>` (kept as the handle for
|
|
62
|
+
// `entries(_data)`), `_frontmatter.<k>` / `_inline.<k>` one source each — and
|
|
63
|
+
// the only way to reach an authored key that itself begins with `_`. The self
|
|
64
|
+
// aliases (`doc` on a document, `block` on a block, `section` on a node) are
|
|
65
|
+
// gone: `$it` is the self. Collections stay bare (`from docs`, `^docs`) — a
|
|
66
|
+
// root name names a collection, not a row property — and so do the row
|
|
67
|
+
// functions in call position (`text("x")`, `under(…)`): a call is never an
|
|
68
|
+
// entry read. A bare target name — `docs`, `links`, … — inside a block is a
|
|
69
|
+
// loud error of its own (root-row.ts). `_revisions` on a document is a
|
|
70
|
+
// RELATION (its revision list, §1.2, 4.7) in `rel.docs` below, and names.ts's
|
|
71
|
+
// `RELATIONS.docs` knows it as one.
|
|
72
|
+
const DOC_ATTRIBUTES = new Set(["_id", "_path", "_raw", "_hash", "_updated_at", "_created_at", "_title", "_tags", "_format"]);
|
|
73
|
+
const BLOCK_ATTRIBUTES = new Set(["_id", "_path", "_raw", "_hash", "_updated_at", "_created_at", "_doc_id", "_type", "_text", "_attrs", "_depth", "_ordinal"]);
|
|
74
|
+
const NODE_ATTRIBUTES = new Set(["_id", "_path", "_doc_id", "_block_id", "_kind", "_name", "_value", "_attrs"]);
|
|
75
|
+
const EDGE_ATTRIBUTES = new Set(["_id", "_path", "_doc_id", "_block_id", "_via_id", "_dst_id", "_dst_path", "_uri", "_field", "_dst_kind", "_predicate", "_provenance", "_anchor"]);
|
|
69
76
|
// The history target (spec/surface §1.2, 4.7): a revision row's own columns
|
|
70
|
-
// under the names `docs_history`
|
|
71
|
-
// `
|
|
72
|
-
// `
|
|
77
|
+
// under the names `docs_history` uses (`_rev`, `_seq`, `_commit`, `_origin`,
|
|
78
|
+
// `_actor`, `_hash`), the commit's `_ts` and `_reason`, `_is_current`, and (4.9)
|
|
79
|
+
// `_archived` — the revision's bodies live in an archive segment (spec/store §7
|
|
73
80
|
// "Retention"; `docs_read { at }` reads through it when attached).
|
|
74
|
-
const REVISION_ATTRIBUTES = new Set(["
|
|
81
|
+
const REVISION_ATTRIBUTES = new Set(["_id", "_path", "_rev", "_seq", "_doc_id", "_commit", "_ts", "_origin", "_actor", "_reason", "_hash", "_is_current", "_archived"]);
|
|
75
82
|
/** The engine attributes per kind (spec/surface §1.2 table). Exported so the
|
|
76
83
|
* translator's tests pin the two against each other. */
|
|
77
84
|
export const ATTRIBUTES = {
|
|
@@ -85,9 +92,21 @@ export const ATTRIBUTES = {
|
|
|
85
92
|
// `current_rev`.
|
|
86
93
|
const REVISION_COLS = "r.rev_id, r.doc_id, r.seq, r.rendered_hash, r.path, r.commit_id, c.ts, c.origin, c.actor, c.reason, (d.current_rev = r.rev_id) AS is_current, (r.archive IS NOT NULL) AS archived";
|
|
87
94
|
const REVISION_FROM = "revisions r JOIN docs d ON d.doc_id = r.doc_id JOIN commits c ON c.commit_id = r.commit_id";
|
|
88
|
-
/** The source handles of a document (§1.2): `
|
|
95
|
+
/** The source handles of a document (§1.2): `_data` is the merged authored view
|
|
89
96
|
* (frontmatter + inline), the other two one source each. */
|
|
90
|
-
export const SOURCE_HANDLES = new Set(["
|
|
97
|
+
export const SOURCE_HANDLES = new Set(["_data", "_frontmatter", "_inline"]);
|
|
98
|
+
/** The `properties.source` a handle narrows a read to: `_data` → both authored sources (null). */
|
|
99
|
+
export function handleSource(handle) {
|
|
100
|
+
return handle === "_data" ? null : handle.slice(1);
|
|
101
|
+
}
|
|
102
|
+
/** The reach-through handles per kind (§1.2) — each a statically single row of another kind. */
|
|
103
|
+
export const REACH_THROUGHS = {
|
|
104
|
+
docs: new Set(),
|
|
105
|
+
blocks: new Set(["_doc"]),
|
|
106
|
+
nodes: new Set(["_doc", "_block"]),
|
|
107
|
+
links: new Set(["_doc", "_dst", "_block"]),
|
|
108
|
+
revisions: new Set(["_doc"]),
|
|
109
|
+
};
|
|
91
110
|
/** The value of a statically SINGLE relation that has no row — `dst` on an
|
|
92
111
|
* external or dangling link, `block` on a node without one (oqx 0.20, SEMANTICS
|
|
93
112
|
* §3): an object the engine treats as one row with no rows, so `dst { title }`
|
|
@@ -314,23 +333,23 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
314
333
|
// ---- relations (return row arrays) ----------------------------------------
|
|
315
334
|
const rel = {
|
|
316
335
|
docs: {
|
|
317
|
-
|
|
318
|
-
|
|
336
|
+
_nodes: (r) => docNodesInOrder(r.doc_id, r.path),
|
|
337
|
+
_blocks: (r) => tagAll(docBlocksPreorder(r.doc_id, r.path).map((x) => x.row), "blocks"),
|
|
319
338
|
// A document's revision list (spec/surface §1.2, 4.7), oldest first.
|
|
320
|
-
|
|
339
|
+
_revisions: (r) => docRevisions(r.doc_id),
|
|
321
340
|
// The linked / linking DOCUMENTS are reached through the link rows (3.0
|
|
322
|
-
// follow-up, §9: the `out` / `in` relations are gone): `
|
|
323
|
-
// distinct { from
|
|
324
|
-
|
|
325
|
-
|
|
341
|
+
// follow-up, §9: the `out` / `in` relations are gone): `_out_links collect
|
|
342
|
+
// distinct { from _dst }` and `_in_links collect distinct { from _doc }`.
|
|
343
|
+
_out_links: (r) => tagAll(all(`SELECT e.*, ? AS __path FROM edges e WHERE e.src_doc = ? AND e.to_commit IS NULL ORDER BY e.predicate, e.edge_id`, r.path, r.doc_id), "links"),
|
|
344
|
+
_in_links: (r) => tagAll(all(`SELECT e.*, d.path AS __path FROM edges e JOIN docs d ON d.doc_id = e.src_doc
|
|
326
345
|
WHERE e.dst_node = ? AND e.to_commit IS NULL AND d.deleted_commit IS NULL ORDER BY e.predicate, e.edge_id`, r.doc_id), "links"),
|
|
327
346
|
},
|
|
328
347
|
blocks: {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
348
|
+
_children: (r) => tagAll(all(`SELECT b.*, ? AS __path FROM blocks b WHERE b.parent_block = ? AND b.deleted_commit IS NULL ORDER BY b.ordinal, b.block_id`, r.__path, r.block_id), "blocks"),
|
|
349
|
+
_nodes: (r) => tagAll(all(`SELECT n.*, ? AS __path FROM nodes n WHERE n.block_id = ? ORDER BY n.span_start, n.node_id`, r.__path, r.block_id), "nodes"),
|
|
350
|
+
_out_links: (r) => tagAll(all(`SELECT e.*, ? AS __path FROM edges e WHERE e.src_block = ? AND e.to_commit IS NULL ORDER BY e.predicate, e.edge_id`, r.__path, r.block_id), "links"),
|
|
332
351
|
// enclosing section node(s): md:section whose range contains this block's top ordinal.
|
|
333
|
-
|
|
352
|
+
_section: (r) => {
|
|
334
353
|
const top = topOrdinal(r);
|
|
335
354
|
return tagAll(all(`SELECT n.*, ? AS __path FROM nodes n WHERE n.doc_id = ? AND n.kind = 'md:section'
|
|
336
355
|
AND json_extract(n.attrs,'$.first_ordinal') <= ? AND json_extract(n.attrs,'$.last_ordinal') >= ?
|
|
@@ -338,8 +357,8 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
338
357
|
},
|
|
339
358
|
},
|
|
340
359
|
nodes: {
|
|
341
|
-
//
|
|
342
|
-
|
|
360
|
+
// the node interpreted as a section (range attrs).
|
|
361
|
+
_blocks: (r) => {
|
|
343
362
|
const f = jattr(r, "first_ordinal"), l = jattr(r, "last_ordinal");
|
|
344
363
|
if (f == null || l == null)
|
|
345
364
|
return [];
|
|
@@ -347,7 +366,7 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
347
366
|
const kept = docBlocksPreorder(r.doc_id, r.__path).filter((x) => x.top >= f && x.top <= l).map((x) => x.row);
|
|
348
367
|
return tagAll(kept, "blocks");
|
|
349
368
|
},
|
|
350
|
-
|
|
369
|
+
_subsections: (r) => {
|
|
351
370
|
const f = jattr(r, "first_ordinal"), l = jattr(r, "last_ordinal"), lvl = jattr(r, "level");
|
|
352
371
|
if (f == null)
|
|
353
372
|
return [];
|
|
@@ -355,7 +374,7 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
355
374
|
AND json_extract(n.attrs,'$.first_ordinal') >= ? AND json_extract(n.attrs,'$.last_ordinal') <= ?
|
|
356
375
|
AND json_extract(n.attrs,'$.level') > ? ORDER BY json_extract(n.attrs,'$.first_ordinal'), n.node_id`, r.__path, r.doc_id, f, l, lvl), "nodes");
|
|
357
376
|
},
|
|
358
|
-
|
|
377
|
+
_children: (r) => {
|
|
359
378
|
const f = jattr(r, "first_ordinal"), l = jattr(r, "last_ordinal"), lvl = jattr(r, "level");
|
|
360
379
|
if (f == null)
|
|
361
380
|
return [];
|
|
@@ -382,12 +401,12 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
382
401
|
// (spec/surface §1, 3.0): the owner is handed out as a LAZY row whose identity
|
|
383
402
|
// columns are already known from the child — a block's/node's `doc_id` and
|
|
384
403
|
// `__path` name its document, an edge's `src_doc` and `__path` its source doc,
|
|
385
|
-
// a node's `block_id` (+ `doc_id`, `__path`) its block — so `
|
|
386
|
-
// `
|
|
387
|
-
// those columns and run NO statement, exactly like the bare `
|
|
388
|
-
// owner row is loaded on the first read of anything else
|
|
389
|
-
// `
|
|
390
|
-
// column). A Proxy over the backing object so the engine sees a plain tagged
|
|
404
|
+
// a node's `block_id` (+ `doc_id`, `__path`) its block — so `_doc._id` and
|
|
405
|
+
// `_doc._path` (and `_block._id`/`_block._path`/`_block._doc_id` on a node)
|
|
406
|
+
// read those columns and run NO statement, exactly like the bare `_doc_id`;
|
|
407
|
+
// the full owner row is loaded on the first read of anything else
|
|
408
|
+
// (`_doc.layer`, `_block._text`). The translator mirrors this in SQL
|
|
409
|
+
// (`_doc._id` → the FK column). A Proxy over the backing object so the engine sees a plain tagged
|
|
391
410
|
// row either way (indexing, rendering, `rowRef`).
|
|
392
411
|
const lazyOwner = (known, t, load) => {
|
|
393
412
|
const backing = tag({ ...known }, t);
|
|
@@ -428,20 +447,20 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
428
447
|
return tag(one(`SELECT * FROM docs WHERE doc_id = ?`, id), "docs");
|
|
429
448
|
return lazyOwner({ doc_id: id, path }, "docs", () => one(`SELECT * FROM docs WHERE doc_id = ?`, id));
|
|
430
449
|
};
|
|
431
|
-
// `
|
|
432
|
-
// DOCUMENT row when the link points at one (`
|
|
450
|
+
// `_dst` on a link row (spec/surface §1.2, 3.0 follow-up): the destination
|
|
451
|
+
// DOCUMENT row when the link points at one (`_dst_kind == "document"` and the
|
|
433
452
|
// document exists — a phantom target has the kind and no row), read by
|
|
434
|
-
// `
|
|
435
|
-
// destination (never reached into). `
|
|
453
|
+
// `_dst_id` exactly as `_dst_path` is; absent for a `block` or `external`
|
|
454
|
+
// destination (never reached into). `_doc` stays the source document.
|
|
436
455
|
const destinationDoc = (row) => {
|
|
437
456
|
if (row.dst_kind !== "document")
|
|
438
457
|
return undefined;
|
|
439
458
|
return tag(one(`SELECT * FROM docs WHERE doc_id = ?`, row.dst_node), "docs");
|
|
440
459
|
};
|
|
441
|
-
// `
|
|
442
|
-
// live row — the revision's `
|
|
443
|
-
// single-with-no-row marker, as `
|
|
444
|
-
// document: its revisions are rows, `
|
|
460
|
+
// `_doc` on a revision row (spec/surface §1.2, 4.7): the document's CURRENT
|
|
461
|
+
// live row — the revision's `_path` may be an earlier one — and absent (the
|
|
462
|
+
// single-with-no-row marker, as `_dst` on a dangling link) for a tombstoned
|
|
463
|
+
// document: its revisions are rows, `_doc == null` tells them apart.
|
|
445
464
|
const revisionDoc = (row) => tag(one(`SELECT * FROM docs WHERE doc_id = ? AND deleted_commit IS NULL`, row.doc_id), "docs");
|
|
446
465
|
const owningBlock = (row) => {
|
|
447
466
|
if (!row.block_id)
|
|
@@ -451,10 +470,10 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
451
470
|
return tag(load(), "blocks");
|
|
452
471
|
return lazyOwner({ block_id: row.block_id, doc_id: row.doc_id, __path: row.__path }, "blocks", load);
|
|
453
472
|
};
|
|
454
|
-
// `
|
|
455
|
-
// was written in — the blocks row `
|
|
473
|
+
// `_block` on a link row (spec/surface §1.2, 4.11): the SOURCE block the link
|
|
474
|
+
// was written in — the blocks row `_block_id` (the edge's `src_block`) names,
|
|
456
475
|
// in the source document (`__path` is already the block's document path) —
|
|
457
|
-
// mirroring `
|
|
476
|
+
// mirroring `_doc`; absent when the link has none (a frontmatter link).
|
|
458
477
|
const linkBlock = (row) => {
|
|
459
478
|
if (!row.src_block)
|
|
460
479
|
return undefined;
|
|
@@ -464,114 +483,114 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
464
483
|
return lazyOwner({ block_id: row.src_block, doc_id: row.src_doc, __path: row.__path }, "blocks", load);
|
|
465
484
|
};
|
|
466
485
|
// ---- engine attributes -----------------------------------------------------
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
//
|
|
473
|
-
//
|
|
486
|
+
// `_`-prefixed, snake_case (see the name rule above; spec/surface §1.2, 5.0).
|
|
487
|
+
// `_path` (and the edge field `_dst_path`) is the REFERENCE form (`/a/b.md`,
|
|
488
|
+
// §1 "Paths", 2.0): the rows carry the storage form (`path`, the `__path` join
|
|
489
|
+
// column) and the read roots it, so nothing below the binding changes. run.ts
|
|
490
|
+
// roots the string literals a query compares them with. `undefined` means
|
|
491
|
+
// "not an attribute" — the caller falls through to the handles, relations and
|
|
492
|
+
// the author's data.
|
|
474
493
|
const attribute = (row, t, name) => {
|
|
475
494
|
if (t === "docs")
|
|
476
495
|
switch (name) {
|
|
477
|
-
case "
|
|
478
|
-
case "
|
|
479
|
-
case "
|
|
480
|
-
case "
|
|
481
|
-
// `
|
|
482
|
-
// (`seq = 1`, the row `
|
|
496
|
+
case "_id": return row.doc_id;
|
|
497
|
+
case "_path": return referencePath(String(row.path));
|
|
498
|
+
case "_hash": return row.file_hash == null ? null : hex(row.file_hash);
|
|
499
|
+
case "_updated_at": return scalar(`SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.rev_id = ?`, row.current_rev) ?? null;
|
|
500
|
+
// `_created_at` (4.10): the commit `ts` of the document's first revision
|
|
501
|
+
// (`seq = 1`, the row `_revisions first { _ts values }` reads) — when
|
|
483
502
|
// omgbase first observed the document, not a filesystem time. The
|
|
484
503
|
// retention squash (spec/store §7.1, 15.0) keeps every revision and
|
|
485
504
|
// commit row, so the value survives archiving.
|
|
486
|
-
case "
|
|
487
|
-
// `
|
|
488
|
-
case "
|
|
489
|
-
// `
|
|
490
|
-
// title, else the first H1, else absent → null). `
|
|
491
|
-
// authored
|
|
492
|
-
case "
|
|
493
|
-
// `
|
|
505
|
+
case "_created_at": return scalar(`SELECT c.ts FROM revisions r JOIN commits c ON c.commit_id = r.commit_id WHERE r.doc_id = ? AND r.seq = 1`, row.doc_id) ?? null;
|
|
506
|
+
// `_raw`: the exact file bytes (spec/store §6.1, frontmatter included).
|
|
507
|
+
case "_raw": return docsRead(store, String(row.doc_id))?._raw ?? null;
|
|
508
|
+
// `_title`: the computed title (spec/properties §3.3 — the authored
|
|
509
|
+
// title, else the first H1, else absent → null). The bare `title` is the
|
|
510
|
+
// authored key alone.
|
|
511
|
+
case "_title": return docProp(String(row.doc_id), "$title", "computed") ?? null;
|
|
512
|
+
// `_tags`: the union of the authored tags (frontmatter + inline, by the
|
|
494
513
|
// property rule) and the body `#hashtags` (the computed `$tags` row,
|
|
495
514
|
// spec/properties §3.3), deduped, authored first in authored order, then
|
|
496
|
-
// the hashtags in document order; null when both are absent.
|
|
497
|
-
// `
|
|
498
|
-
case "
|
|
499
|
-
case "
|
|
515
|
+
// the hashtags in document order; null when both are absent. The bare
|
|
516
|
+
// `tags` is the authored list alone.
|
|
517
|
+
case "_tags": return docTags(String(row.doc_id));
|
|
518
|
+
case "_format": return row.format;
|
|
500
519
|
}
|
|
501
520
|
if (t === "blocks")
|
|
502
521
|
switch (name) {
|
|
503
|
-
case "
|
|
504
|
-
case "
|
|
505
|
-
// `
|
|
506
|
-
// container's raw holds its children verbatim); `
|
|
507
|
-
case "
|
|
508
|
-
case "
|
|
509
|
-
case "
|
|
510
|
-
// `
|
|
511
|
-
// `block_changes` — the same join as `
|
|
522
|
+
case "_id": return row.block_id;
|
|
523
|
+
case "_path": return referencePath(String(row.__path));
|
|
524
|
+
// `_raw`: the block's raw source bytes — the blob its `raw_hash` names (a
|
|
525
|
+
// container's raw holds its children verbatim); `_text` is the normalized text.
|
|
526
|
+
case "_raw": return row.raw_hash == null ? null : scalar(`SELECT bytes FROM blobs WHERE hash = ?`, row.raw_hash)?.toString("utf8") ?? null;
|
|
527
|
+
case "_hash": return row.raw_hash == null ? null : hex(row.raw_hash);
|
|
528
|
+
case "_updated_at": return scalar(`SELECT MAX(c.ts) FROM block_changes bc JOIN commits c ON c.commit_id = bc.commit_id WHERE bc.block_id = ?`, row.block_id) ?? null;
|
|
529
|
+
// `_created_at` (4.10): the EARLIEST commit `ts` among the block's
|
|
530
|
+
// `block_changes` — the same join as `_updated_at` under MIN: the commit
|
|
512
531
|
// that first wrote the id (`inserted`, or the split/merge lineage row
|
|
513
532
|
// that minted it). Store 14.2 keeps that row and the 15.0 squash keeps
|
|
514
533
|
// each block's earliest row (spec/store §7.1), so it survives archiving;
|
|
515
534
|
// a resurrected block keeps its original creation.
|
|
516
|
-
case "
|
|
517
|
-
case "
|
|
518
|
-
case "
|
|
519
|
-
case "
|
|
520
|
-
case "
|
|
521
|
-
case "
|
|
522
|
-
case "
|
|
535
|
+
case "_created_at": return scalar(`SELECT MIN(c.ts) FROM block_changes bc JOIN commits c ON c.commit_id = bc.commit_id WHERE bc.block_id = ?`, row.block_id) ?? null;
|
|
536
|
+
case "_doc_id": return row.doc_id;
|
|
537
|
+
case "_type": return row.type;
|
|
538
|
+
case "_text": return row.text;
|
|
539
|
+
case "_attrs": return parseJson(row.attrs);
|
|
540
|
+
case "_ordinal": return row.ordinal;
|
|
541
|
+
case "_depth": return row.depth;
|
|
523
542
|
}
|
|
524
543
|
if (t === "nodes")
|
|
525
544
|
switch (name) {
|
|
526
|
-
case "
|
|
527
|
-
case "
|
|
528
|
-
case "
|
|
529
|
-
case "
|
|
530
|
-
case "
|
|
531
|
-
case "
|
|
532
|
-
case "
|
|
533
|
-
case "
|
|
545
|
+
case "_id": return row.node_id;
|
|
546
|
+
case "_path": return referencePath(String(row.__path));
|
|
547
|
+
case "_doc_id": return row.doc_id;
|
|
548
|
+
case "_block_id": return row.block_id ?? null;
|
|
549
|
+
case "_kind": return row.kind;
|
|
550
|
+
case "_name": return row.name;
|
|
551
|
+
case "_value": return row.value;
|
|
552
|
+
case "_attrs": return parseJson(row.attrs);
|
|
534
553
|
}
|
|
535
554
|
if (t === "links")
|
|
536
555
|
switch (name) {
|
|
537
556
|
// the store's columns under the surface's names (spec/surface §1.2).
|
|
538
|
-
case "
|
|
539
|
-
case "
|
|
540
|
-
case "
|
|
541
|
-
case "
|
|
542
|
-
case "
|
|
543
|
-
case "
|
|
544
|
-
case "
|
|
557
|
+
case "_id": return row.edge_id;
|
|
558
|
+
case "_path": return referencePath(String(row.__path));
|
|
559
|
+
case "_doc_id": return row.src_doc;
|
|
560
|
+
case "_block_id": return row.src_block ?? null;
|
|
561
|
+
case "_via_id": return row.via_node ?? null;
|
|
562
|
+
case "_dst_id": return row.dst_node;
|
|
563
|
+
case "_dst_path": {
|
|
545
564
|
const p = scalar(`SELECT path FROM docs WHERE doc_id = ?`, row.dst_node);
|
|
546
565
|
return p == null ? null : referencePath(String(p));
|
|
547
566
|
}
|
|
548
|
-
case "
|
|
549
|
-
case "
|
|
550
|
-
case "
|
|
551
|
-
case "
|
|
552
|
-
case "
|
|
553
|
-
case "
|
|
567
|
+
case "_uri": return scalar(`SELECT uri FROM external_nodes WHERE node_id = ?`, row.dst_node) ?? null;
|
|
568
|
+
case "_field": return row.src_field ?? null;
|
|
569
|
+
case "_predicate":
|
|
570
|
+
case "_provenance":
|
|
571
|
+
case "_dst_kind":
|
|
572
|
+
case "_anchor": return row[name.slice(1)];
|
|
554
573
|
}
|
|
555
574
|
if (t === "revisions")
|
|
556
575
|
switch (name) {
|
|
557
|
-
// the `revisions` × `commits` columns under docs_history's names (spec/surface §1.2, 4.7).
|
|
558
|
-
case "
|
|
559
|
-
case "
|
|
560
|
-
case "
|
|
561
|
-
case "
|
|
562
|
-
case "
|
|
563
|
-
case "
|
|
564
|
-
case "
|
|
565
|
-
case "
|
|
566
|
-
case "
|
|
567
|
-
case "
|
|
568
|
-
case "
|
|
569
|
-
case "
|
|
570
|
-
case "
|
|
576
|
+
// the `revisions` × `commits` columns under docs_history's names, `_`-prefixed (spec/surface §1.2, 4.7).
|
|
577
|
+
case "_id":
|
|
578
|
+
case "_rev": return row.rev_id;
|
|
579
|
+
case "_path": return referencePath(String(row.path));
|
|
580
|
+
case "_seq": return row.seq;
|
|
581
|
+
case "_doc_id": return row.doc_id;
|
|
582
|
+
case "_commit": return row.commit_id;
|
|
583
|
+
case "_ts": return row.ts;
|
|
584
|
+
case "_origin": return row.origin;
|
|
585
|
+
case "_actor": return row.actor ?? null;
|
|
586
|
+
case "_reason": return row.reason ?? null;
|
|
587
|
+
case "_hash": return hex(row.rendered_hash);
|
|
588
|
+
case "_is_current": return row.is_current === 1 || row.is_current === true;
|
|
589
|
+
case "_archived": return row.archived === 1 || row.archived === true;
|
|
571
590
|
}
|
|
572
591
|
return undefined;
|
|
573
592
|
};
|
|
574
|
-
// `
|
|
593
|
+
// `_tags` on a document: authored ∪ hashtags, each list as the property rule
|
|
575
594
|
// reads it (a scalar-authored `tags: x` is one element), deduped by value
|
|
576
595
|
// (canonical JSON, so both engines agree on non-string elements).
|
|
577
596
|
const docTags = (docId) => {
|
|
@@ -595,10 +614,10 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
595
614
|
const getFrom = (row, key) => {
|
|
596
615
|
if (row == null)
|
|
597
616
|
return undefined;
|
|
598
|
-
// The root row: `^$it.
|
|
617
|
+
// The root row: `^$it._id` is the repository id, `^$it.<target>` the lazy
|
|
599
618
|
// root scan (the same handle `^<target>` / `root(name)` hands out).
|
|
600
619
|
if (row[ROOT_ROW]) {
|
|
601
|
-
if (key === "
|
|
620
|
+
if (key === "_id")
|
|
602
621
|
return repoId;
|
|
603
622
|
return rootFns[key] ? rootFns[key]() : undefined;
|
|
604
623
|
}
|
|
@@ -616,33 +635,38 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
616
635
|
// the row) or unknown — never an omgbase attribute. Row-scoped domain
|
|
617
636
|
// functions (text/semantic/under_*/…) never arrive here: run.ts rewrites
|
|
618
637
|
// them to `$it.fn(…)`, so they reach callMethod with the row as receiver.
|
|
619
|
-
//
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
638
|
+
// An underscore-prefixed name is the engine's (the name rule above): an
|
|
639
|
+
// attribute, a reach-through, a relation or a source handle — never the
|
|
640
|
+
// author's.
|
|
641
|
+
if (key.startsWith("_")) {
|
|
642
|
+
if (ATTRIBUTES[t].has(key))
|
|
643
|
+
return attribute(r, t, key);
|
|
644
|
+
// reach-through to owning entities, from a link row to its destination and
|
|
645
|
+
// from a revision to its document's current row — statically single
|
|
646
|
+
// relations: absent is the single-with-no-row marker.
|
|
647
|
+
if (t === "revisions" && key === "_doc")
|
|
648
|
+
return revisionDoc(r) ?? ABSENT_SINGLE;
|
|
649
|
+
if (t !== "docs" && key === "_doc")
|
|
650
|
+
return owningDoc(r) ?? ABSENT_SINGLE;
|
|
651
|
+
if (t === "nodes" && key === "_block")
|
|
652
|
+
return owningBlock(r) ?? ABSENT_SINGLE;
|
|
653
|
+
if (t === "links" && key === "_dst")
|
|
654
|
+
return destinationDoc(r) ?? ABSENT_SINGLE;
|
|
655
|
+
if (t === "links" && key === "_block")
|
|
656
|
+
return linkBlock(r) ?? ABSENT_SINGLE;
|
|
657
|
+
// relations.
|
|
658
|
+
const rels = rel[t];
|
|
659
|
+
if (rels[key])
|
|
660
|
+
return rels[key](r);
|
|
661
|
+
// The source handles of a document: `_data` is the merged authored view
|
|
662
|
+
// (frontmatter + inline), the other two one source each; `_data.<k>` is
|
|
663
|
+
// the bare `<k>`, and the one way to an authored key spelled `_x`.
|
|
664
|
+
if (t === "docs" && SOURCE_HANDLES.has(key))
|
|
665
|
+
return { [PROP_SOURCE]: true, docId: String(r.doc_id), source: handleSource(key) };
|
|
666
|
+
// Any other `_name` is no engine name of this kind (names.ts refuses it
|
|
667
|
+
// statically, before any row is read): absent.
|
|
668
|
+
return undefined;
|
|
669
|
+
}
|
|
646
670
|
// A bare target name that is not one of this row's relations reads a
|
|
647
671
|
// property the row has none of (spec/surface §1.1, 2.0): loud, naming the
|
|
648
672
|
// root-row spelling. `docs`/`links` never get here (run.ts refuses them
|
|
@@ -650,19 +674,12 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
650
674
|
// row and `revisions` on anything but a document do.
|
|
651
675
|
if (ROOTS.has(key))
|
|
652
676
|
throw new FilterInvalid(bareTargetMessage(key, null), "OQX");
|
|
653
|
-
// the author's data.
|
|
654
|
-
if (t === "docs")
|
|
655
|
-
// The source handles: `data` is the merged authored view (frontmatter +
|
|
656
|
-
// inline), the other two one source each; `data.<k>` reaches an authored
|
|
657
|
-
// key whose bare name is an engine attribute (`data.path`, `data.tags`).
|
|
658
|
-
if (SOURCE_HANDLES.has(key))
|
|
659
|
-
return { [PROP_SOURCE]: true, docId: String(r.doc_id), source: key === "data" ? null : key };
|
|
677
|
+
// the author's data — every bare name.
|
|
678
|
+
if (t === "docs")
|
|
660
679
|
return docProp(String(r.doc_id), key);
|
|
661
|
-
|
|
662
|
-
//
|
|
663
|
-
//
|
|
664
|
-
// absent key is undefined (silently false in a predicate), matching a doc's
|
|
665
|
-
// missing frontmatter key. The `attrs.<k>` form still works unchanged.
|
|
680
|
+
// blocks / nodes: a bare identifier flattens into attrs: `checked` reads
|
|
681
|
+
// `_attrs.checked`. An absent key is undefined (silently false in a
|
|
682
|
+
// predicate), matching a doc's missing frontmatter key.
|
|
666
683
|
if (t === "blocks" || t === "nodes")
|
|
667
684
|
return jattr(r, key);
|
|
668
685
|
return undefined;
|
|
@@ -847,12 +864,12 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
847
864
|
};
|
|
848
865
|
return {
|
|
849
866
|
// The root scope's names (spec/oqx §2 step 5 at the root): the five lazy
|
|
850
|
-
// scans and `
|
|
851
|
-
// the scan and `^
|
|
867
|
+
// scans and `_id`, the repository id — so `^docs` / `0^docs` from any row is
|
|
868
|
+
// the scan and `^_id` / `0^_id` the id.
|
|
852
869
|
root(name) {
|
|
853
870
|
if (opts.rowsRoot && name === opts.rowsRoot.name)
|
|
854
871
|
return opts.rowsRoot.rows;
|
|
855
|
-
if (name === "
|
|
872
|
+
if (name === "_id")
|
|
856
873
|
return repoId;
|
|
857
874
|
return rootFns[name] ? rootFns[name]() : undefined;
|
|
858
875
|
},
|
|
@@ -908,7 +925,7 @@ export function makeStoreContext(store, repoId, opts = {}) {
|
|
|
908
925
|
// pushdown can serve the property's autopromoted/cached bounds — see
|
|
909
926
|
// detectRange + val_json in store/properties.ts.
|
|
910
927
|
callFunction(name, args) {
|
|
911
|
-
// `entries(
|
|
928
|
+
// `entries(_data)` / `entries(_frontmatter)` / `entries(_inline)`: the source
|
|
912
929
|
// handle is lazy (a PropSourceRef, not a plain object), so materialize its
|
|
913
930
|
// property bag as entries here; any other argument falls through to the
|
|
914
931
|
// oqx builtin.
|
|
@@ -965,7 +982,7 @@ export function tagRows(rows, target) {
|
|
|
965
982
|
}
|
|
966
983
|
/**
|
|
967
984
|
* A store row surfacing as a VALUE in a result (spec/surface §1.4, rows as
|
|
968
|
-
* values, 1.2) is rendered as `{
|
|
985
|
+
* values, 1.2) is rendered as `{ _id, _path }` (5.0) — its id column and its
|
|
969
986
|
* document's path in the reference form (`/a.md`, §1 "Paths"), the same two keys
|
|
970
987
|
* every hit carries, spelled as the attributes that read them — never the store
|
|
971
988
|
* row itself.
|
|
@@ -981,7 +998,7 @@ export function rowRef(value) {
|
|
|
981
998
|
// a revision's path is `revisions.path` — the path it was committed under
|
|
982
999
|
// (a move re-paths the current revision; §1.2, 4.7).
|
|
983
1000
|
const path = t === "docs" || t === "revisions" ? r.path : r.__path;
|
|
984
|
-
return {
|
|
1001
|
+
return { _id: String(id), _path: path == null ? "" : referencePath(String(path)) };
|
|
985
1002
|
}
|
|
986
1003
|
export { TARGET };
|
|
987
1004
|
//# sourceMappingURL=context.js.map
|