@_linked/core 2.34.0 → 2.35.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/CHANGELOG.md +10 -0
- package/README.md +24 -0
- package/lib/esm/index.d.ts +2 -1
- package/lib/esm/index.js +2 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/live/LiveQueryStore.d.ts +22 -0
- package/lib/esm/live/LiveQueryStore.js +86 -19
- package/lib/esm/live/LiveQueryStore.js.map +1 -1
- package/lib/esm/live/changes.d.ts +9 -1
- package/lib/esm/live/changes.js +7 -2
- package/lib/esm/live/changes.js.map +1 -1
- package/lib/esm/live/keys.d.ts +6 -0
- package/lib/esm/live/keys.js +10 -1
- package/lib/esm/live/keys.js.map +1 -1
- package/lib/esm/live/matcher.d.ts +4 -1
- package/lib/esm/live/matcher.js +10 -5
- package/lib/esm/live/matcher.js.map +1 -1
- package/lib/esm/queries/AskBuilder.d.ts +6 -0
- package/lib/esm/queries/AskBuilder.js +14 -0
- package/lib/esm/queries/AskBuilder.js.map +1 -1
- package/lib/esm/queries/CountBuilder.d.ts +6 -0
- package/lib/esm/queries/CountBuilder.js +14 -0
- package/lib/esm/queries/CountBuilder.js.map +1 -1
- package/lib/esm/queries/CreateBuilder.d.ts +4 -0
- package/lib/esm/queries/CreateBuilder.js +15 -1
- package/lib/esm/queries/CreateBuilder.js.map +1 -1
- package/lib/esm/queries/DeleteBuilder.d.ts +4 -0
- package/lib/esm/queries/DeleteBuilder.js +15 -1
- package/lib/esm/queries/DeleteBuilder.js.map +1 -1
- package/lib/esm/queries/FieldSet.d.ts +10 -0
- package/lib/esm/queries/FieldSet.js +85 -18
- package/lib/esm/queries/FieldSet.js.map +1 -1
- package/lib/esm/queries/IRLower.js +3 -2
- package/lib/esm/queries/IRLower.js.map +1 -1
- package/lib/esm/queries/IRMutation.js +15 -14
- package/lib/esm/queries/IRMutation.js.map +1 -1
- package/lib/esm/queries/MutationSerialization.js +2 -2
- package/lib/esm/queries/MutationSerialization.js.map +1 -1
- package/lib/esm/queries/PropertyPath.js +2 -2
- package/lib/esm/queries/PropertyPath.js.map +1 -1
- package/lib/esm/queries/QueryBuilder.d.ts +7 -0
- package/lib/esm/queries/QueryBuilder.js +40 -3
- package/lib/esm/queries/QueryBuilder.js.map +1 -1
- package/lib/esm/queries/SelectQuery.js +2 -2
- package/lib/esm/queries/SelectQuery.js.map +1 -1
- package/lib/esm/queries/UpdateBuilder.d.ts +4 -0
- package/lib/esm/queries/UpdateBuilder.js +15 -1
- package/lib/esm/queries/UpdateBuilder.js.map +1 -1
- package/lib/esm/queries/fromJSON.d.ts +12 -1
- package/lib/esm/queries/fromJSON.js +5 -1
- package/lib/esm/queries/fromJSON.js.map +1 -1
- package/lib/esm/queries/lower.js +12 -5
- package/lib/esm/queries/lower.js.map +1 -1
- package/lib/esm/queries/queryDependencies.js +14 -10
- package/lib/esm/queries/queryDependencies.js.map +1 -1
- package/lib/esm/queries/resolveShape.js +14 -2
- package/lib/esm/queries/resolveShape.js.map +1 -1
- package/lib/esm/shapes/Shape.js +2 -1
- package/lib/esm/shapes/Shape.js.map +1 -1
- package/lib/esm/shapes/nodeShapeData.js +7 -10
- package/lib/esm/shapes/nodeShapeData.js.map +1 -1
- package/lib/esm/shapes/registerRuntimeShape.js +3 -1
- package/lib/esm/shapes/registerRuntimeShape.js.map +1 -1
- package/lib/esm/shapes/syncShapes.d.ts +6 -2
- package/lib/esm/shapes/syncShapes.js +16 -9
- package/lib/esm/shapes/syncShapes.js.map +1 -1
- package/lib/esm/shapes/validation.js +2 -2
- package/lib/esm/shapes/validation.js.map +1 -1
- package/lib/esm/sparql/irToAlgebra.js +117 -52
- package/lib/esm/sparql/irToAlgebra.js.map +1 -1
- package/lib/esm/sparql/ownedLinkCheck.js +6 -1
- package/lib/esm/sparql/ownedLinkCheck.js.map +1 -1
- package/lib/esm/utils/LinkedStorage.d.ts +7 -0
- package/lib/esm/utils/LinkedStorage.js +39 -12
- package/lib/esm/utils/LinkedStorage.js.map +1 -1
- package/lib/esm/utils/ShapeCatalog.d.ts +57 -0
- package/lib/esm/utils/ShapeCatalog.js +86 -0
- package/lib/esm/utils/ShapeCatalog.js.map +1 -0
- package/lib/esm/utils/ShapeClass.d.ts +73 -8
- package/lib/esm/utils/ShapeClass.js +245 -66
- package/lib/esm/utils/ShapeClass.js.map +1 -1
- package/lib/esm/utils/registryCache.d.ts +15 -0
- package/lib/esm/utils/registryCache.js +50 -0
- package/lib/esm/utils/registryCache.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.35.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#343](https://github.com/linked-fw/core/pull/343) [`84ddff8`](https://github.com/linked-fw/core/commit/84ddff8fc91a773296461da6983237ba1a1f8c31) Thanks [@flyon](https://github.com/flyon)! - ShapeCatalog and withShapeCatalog: build and run queries against a catalog without registering it.
|
|
8
|
+
|
|
9
|
+
`ShapeCatalog.from(shapes, {name})` builds an immutable set of shapes (core's six built-ins always included from core's code); `withShapeCatalog(catalog, fn)` makes it the shapes every registry accessor reads while `fn` runs. Builders, field sets and IRs capture the catalog and re-enter it when they are lowered, compiled or live-tracked later, so one shape IRI can mean different shapes in different catalogs at once. `fromJSON(json, {catalog})` decodes against a catalog; the wire format is unchanged. Registry caches are kept per catalog, and an app that never uses a catalog runs as before.
|
|
10
|
+
|
|
11
|
+
`syncShapes` now also writes core's six built-in shapes (`Shape`, `NodeShape`, `PropertyShape`, `List`, `PathNode`, `PathList`) into the dataset, with the same hash skip as every other shape. The first sync after upgrading writes them once; after that a sync rewrites one only when its hash changes, which happens when processes on different core versions sync the same dataset (each rewrites the built-ins its version describes differently). Under `orphanScope: 'ownedNamespaces'` core's namespace is never pruned. A `ShapeCatalog` ignores built-in rows in its data and resolves the six from code.
|
|
12
|
+
|
|
3
13
|
## 2.34.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1246,6 +1246,30 @@ import {lower} from '@_linked/core';
|
|
|
1246
1246
|
const ir = lower(CreateBuilder.from(Person).set({name: 'Alice'}));
|
|
1247
1247
|
```
|
|
1248
1248
|
|
|
1249
|
+
### Shape catalogs — queries against shapes you do not register
|
|
1250
|
+
|
|
1251
|
+
The shape registry holds one definition per IRI. A host serving several projects (or branches)
|
|
1252
|
+
that share shape IRIs with different properties resolves each query against a `ShapeCatalog`
|
|
1253
|
+
instead:
|
|
1254
|
+
|
|
1255
|
+
```typescript
|
|
1256
|
+
import {ShapeCatalog, withShapeCatalog, fromJSON} from '@_linked/core';
|
|
1257
|
+
|
|
1258
|
+
const branch = ShapeCatalog.from(nodeShapeWires, {name: 'project-1#main'}); // immutable
|
|
1259
|
+
const query = withShapeCatalog(branch, () =>
|
|
1260
|
+
SelectBuilder.from('https://example.org/shape/Person').select(['name']),
|
|
1261
|
+
);
|
|
1262
|
+
await query; // lowers and compiles against `branch`, though the scope has closed
|
|
1263
|
+
|
|
1264
|
+
const received = fromJSON(json, {catalog: branch}); // the wire never carries a catalog
|
|
1265
|
+
```
|
|
1266
|
+
|
|
1267
|
+
A builder keeps the catalog it was made in (`catalogOf(query)`), through clones, `exists()`,
|
|
1268
|
+
`count()`, lowering, compile and live queries. Inside a scope every registry read sees the
|
|
1269
|
+
catalog's shapes plus core's six built-ins (always from code, though `syncShapes` writes them
|
|
1270
|
+
into every dataset); a class the catalog does not hold keeps resolving
|
|
1271
|
+
globally. See [runtime instances](./docs/architecture/runtime-instances.md#shape-catalogs).
|
|
1272
|
+
|
|
1249
1273
|
### DSL-JSON — the standard query format
|
|
1250
1274
|
|
|
1251
1275
|
Every Linked query — select **and** every mutation — has one canonical, language-neutral form:
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -13,7 +13,8 @@ export { SelectBuilder, QueryBuilder } from './queries/QueryBuilder.js';
|
|
|
13
13
|
export { lower } from './queries/lower.js';
|
|
14
14
|
export type { LowerableQuery } from './queries/lower.js';
|
|
15
15
|
export { fromJSON } from './queries/fromJSON.js';
|
|
16
|
-
export type { QueryJSON } from './queries/fromJSON.js';
|
|
16
|
+
export type { QueryJSON, FromJSONOptions } from './queries/fromJSON.js';
|
|
17
|
+
export { ShapeCatalog, withShapeCatalog, getActiveShapeCatalog, catalogOf, shapeCatalogKey, } from './utils/ShapeCatalog.js';
|
|
17
18
|
export { getQueryContext, setQueryContext, subscribeQueryContext, PendingQueryContext, UnresolvedContextError, } from './queries/QueryContext.js';
|
|
18
19
|
export { subscribeQueryDispatch } from './queries/queryDispatch.js';
|
|
19
20
|
export type { QueryDispatchEvent, QueryDispatchListener } from './queries/queryDispatch.js';
|
package/lib/esm/index.js
CHANGED
|
@@ -20,6 +20,8 @@ export { LinkedStorage } from './utils/LinkedStorage.js';
|
|
|
20
20
|
export { SelectBuilder, QueryBuilder } from './queries/QueryBuilder.js';
|
|
21
21
|
export { lower } from './queries/lower.js';
|
|
22
22
|
export { fromJSON } from './queries/fromJSON.js';
|
|
23
|
+
// Shape catalogs: resolve queries against a set of shapes without registering them.
|
|
24
|
+
export { ShapeCatalog, withShapeCatalog, getActiveShapeCatalog, catalogOf, shapeCatalogKey, } from './utils/ShapeCatalog.js';
|
|
23
25
|
export { getQueryContext, setQueryContext, subscribeQueryContext, PendingQueryContext, UnresolvedContextError, } from './queries/QueryContext.js';
|
|
24
26
|
export { subscribeQueryDispatch } from './queries/queryDispatch.js';
|
|
25
27
|
export { CONTEXT_REF_KEY, encodeContextRef, isContextRefJSON, resolveContextId, } from './queries/ContextRef.js';
|
package/lib/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,0DAA0D;AAC1D,OAAO,mBAAmB,CAAC;AAC3B,8EAA8E;AAC9E,OAAO,WAAW,CAAC;AACnB,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,uBAAuB,EAAC,MAAM,qCAAqC,CAAC;AAC5E,sEAAsE;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACxC,kEAAkE;AAClE,OAAO,EAAC,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAQnF,OAAO,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAC;AACvD,2CAA2C;AAC3C,OAAO,EAAC,aAAa,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAEzC,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAE/C,OAAO,EACL,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAC,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AAElE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAEzE,sBAAsB;AACtB,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAM/C,+BAA+B;AAC/B,OAAO,EAAC,UAAU,EAAE,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAC,YAAY,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAGrE,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAGzD,8CAA8C;AAC9C,OAAO,EAAC,cAAc,EAAC,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAC,IAAI,EAAC,MAAM,uBAAuB,CAAC;AAe3C,sEAAsE;AACtE,OAAO,EACL,cAAc,EACd,WAAW,GACZ,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;AAWxC,0FAA0F;AAC1F,OAAO,EAAC,iBAAiB,EAAE,eAAe,EAAC,MAAM,gCAAgC,CAAC;AAElF,OAAO,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AAEhE,mDAAmD;AACnD,OAAO,EAAC,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAC","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n// Registers every shape core defines (side effects only).\nimport './shapes/index.js';\n// Registers the live-query store so `query.live()` works (side effects only).\nimport './live.js';\nexport {syncShapes, syncShape} from './shapes/syncShapes.js';\nexport type {SyncShapesOptions, SyncShapeOptions} from './shapes/syncShapes.js';\nexport {\n singleOwnerShapeIri,\n singleOwnerProperties,\n buildSingleOwnerConstraints,\n} from './shapes/singleOwnerConstraint.js';\nexport {rdfList} from './shapes/List.js';\nexport {serializePathToNodeData} from './shapes/serializePathToNodeData.js';\n// Core public API surface (documented as root imports in the README).\nexport {Shape} from './shapes/Shape.js';\n// SHACL-aligned validation of plain data objects against a shape.\nexport {validate, assertValid, ShapeValidationError} from './shapes/validation.js';\nexport type {\n ValidationReport,\n ValidationResult,\n ValidationMode,\n ValidateOptions,\n ValidatableShape,\n} from './shapes/validation.js';\nexport {LinkedStorage} from './utils/LinkedStorage.js';\n// New dynamic query building API (Phase 2)\nexport {SelectBuilder, QueryBuilder} from './queries/QueryBuilder.js';\nexport {lower} from './queries/lower.js';\nexport type {LowerableQuery} from './queries/lower.js';\nexport {fromJSON} from './queries/fromJSON.js';\nexport type {QueryJSON} from './queries/fromJSON.js';\nexport {\n getQueryContext,\n setQueryContext,\n subscribeQueryContext,\n PendingQueryContext,\n UnresolvedContextError,\n} from './queries/QueryContext.js';\nexport {subscribeQueryDispatch} from './queries/queryDispatch.js';\nexport type {QueryDispatchEvent, QueryDispatchListener} from './queries/queryDispatch.js';\nexport {\n CONTEXT_REF_KEY,\n encodeContextRef,\n isContextRefJSON,\n resolveContextId,\n} from './queries/ContextRef.js';\nexport type {ContextRefJSON} from './queries/ContextRef.js';\nexport {PropertyPath, walkPropertyPath} from './queries/PropertyPath.js';\n\n// Phase 3a — FieldSet\nexport {FieldSet} from './queries/FieldSet.js';\nexport type {FieldSetEntry, FieldSetInput, FieldSetJSON, FieldSetFieldJSON} from './queries/FieldSet.js';\n\n// Phase 4 — Serialization types\nexport type {QueryBuilderJSON} from './queries/QueryBuilder.js';\n\n// Phase 3b — Mutation builders\nexport {AskBuilder, isAskQuery} from './queries/AskBuilder.js';\nexport type {AskSpec} from './queries/AskBuilder.js';\nexport type {AskQuery, AskQueryJSON, RawAskInput} from './queries/AskQuery.js';\nexport {CountBuilder, isCountQuery} from './queries/CountBuilder.js';\nexport type {CountSpec} from './queries/CountBuilder.js';\nexport type {CountQuery, CountQueryJSON, RawCountInput} from './queries/CountQuery.js';\nexport {CreateBuilder} from './queries/CreateBuilder.js';\nexport {UpdateBuilder} from './queries/UpdateBuilder.js';\nexport {DeleteBuilder} from './queries/DeleteBuilder.js';\nexport type {DeleteId} from './queries/DeleteBuilder.js';\n\n// Expressions — computed fields and functions\nexport {ExpressionNode} from './expressions/ExpressionNode.js';\nexport type {ExpressionInput, PropertyRefMap} from './expressions/ExpressionNode.js';\nexport {Expr} from './expressions/Expr.js';\nexport type {\n ExpressionUpdateProxy,\n ExpressionUpdateResult,\n BaseExpressionMethods,\n NumericExpressionMethods,\n StringExpressionMethods,\n DateExpressionMethods,\n BooleanExpressionMethods,\n} from './expressions/ExpressionMethods.js';\n\n// Phase 5 — Component query integration\nexport type {LinkedComponentInterface, QueryComponentLike} from './queries/SelectQuery.js';\n\n\n// Mutation DSL-JSON serialization (create/update/delete to/from JSON)\nexport {\n encodeNodeData,\n encodeValue,\n} from './queries/MutationSerialization.js';\nexport {\n decodeNodeData,\n lowerMutationJSON,\n} from './queries/lowerMutationJSON.js';\nexport type {\n MutationJSON,\n CreateMutationJSON,\n UpdateMutationJSON,\n DeleteMutationJSON,\n MutationValueJSON,\n MutationNodeDataJSON,\n} from './queries/MutationSerialization.js';\n\n\n// Live-query dependency helpers — what a query reads and a mutation writes, as predicates\nexport {queryDependencies, mutationEffects} from './queries/queryDependencies.js';\nexport type {QueryDependencies, MutationEffects} from './queries/queryDependencies.js';\nexport {findPropertyShapeById} from './shapes/nodeShapeData.js';\n\n// Live queries — see documentation/live-queries.md\nexport {LiveQueryStore, getLiveQueryStore, resetLiveQueryStore, publishChange, invalidate} from './live/LiveQueryStore.js';\nexport type {ChangeEvent} from './live/changes.js';\nexport type {\n LiveQuery,\n LiveState,\n LiveStatus,\n LiveListener,\n LiveQueryOptions,\n LiveQueryStoreOptions,\n} from './live/LiveQueryStore.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,0DAA0D;AAC1D,OAAO,mBAAmB,CAAC;AAC3B,8EAA8E;AAC9E,OAAO,WAAW,CAAC;AACnB,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,uBAAuB,EAAC,MAAM,qCAAqC,CAAC;AAC5E,sEAAsE;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACxC,kEAAkE;AAClE,OAAO,EAAC,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAQnF,OAAO,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAC;AACvD,2CAA2C;AAC3C,OAAO,EAAC,aAAa,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAEzC,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAE/C,oFAAoF;AACpF,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,SAAS,EACT,eAAe,GAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAC,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AAElE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAEzE,sBAAsB;AACtB,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAM/C,+BAA+B;AAC/B,OAAO,EAAC,UAAU,EAAE,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAC,YAAY,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAGrE,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAGzD,8CAA8C;AAC9C,OAAO,EAAC,cAAc,EAAC,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAC,IAAI,EAAC,MAAM,uBAAuB,CAAC;AAe3C,sEAAsE;AACtE,OAAO,EACL,cAAc,EACd,WAAW,GACZ,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;AAWxC,0FAA0F;AAC1F,OAAO,EAAC,iBAAiB,EAAE,eAAe,EAAC,MAAM,gCAAgC,CAAC;AAElF,OAAO,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AAEhE,mDAAmD;AACnD,OAAO,EAAC,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAC","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n// Registers every shape core defines (side effects only).\nimport './shapes/index.js';\n// Registers the live-query store so `query.live()` works (side effects only).\nimport './live.js';\nexport {syncShapes, syncShape} from './shapes/syncShapes.js';\nexport type {SyncShapesOptions, SyncShapeOptions} from './shapes/syncShapes.js';\nexport {\n singleOwnerShapeIri,\n singleOwnerProperties,\n buildSingleOwnerConstraints,\n} from './shapes/singleOwnerConstraint.js';\nexport {rdfList} from './shapes/List.js';\nexport {serializePathToNodeData} from './shapes/serializePathToNodeData.js';\n// Core public API surface (documented as root imports in the README).\nexport {Shape} from './shapes/Shape.js';\n// SHACL-aligned validation of plain data objects against a shape.\nexport {validate, assertValid, ShapeValidationError} from './shapes/validation.js';\nexport type {\n ValidationReport,\n ValidationResult,\n ValidationMode,\n ValidateOptions,\n ValidatableShape,\n} from './shapes/validation.js';\nexport {LinkedStorage} from './utils/LinkedStorage.js';\n// New dynamic query building API (Phase 2)\nexport {SelectBuilder, QueryBuilder} from './queries/QueryBuilder.js';\nexport {lower} from './queries/lower.js';\nexport type {LowerableQuery} from './queries/lower.js';\nexport {fromJSON} from './queries/fromJSON.js';\nexport type {QueryJSON, FromJSONOptions} from './queries/fromJSON.js';\n// Shape catalogs: resolve queries against a set of shapes without registering them.\nexport {\n ShapeCatalog,\n withShapeCatalog,\n getActiveShapeCatalog,\n catalogOf,\n shapeCatalogKey,\n} from './utils/ShapeCatalog.js';\nexport {\n getQueryContext,\n setQueryContext,\n subscribeQueryContext,\n PendingQueryContext,\n UnresolvedContextError,\n} from './queries/QueryContext.js';\nexport {subscribeQueryDispatch} from './queries/queryDispatch.js';\nexport type {QueryDispatchEvent, QueryDispatchListener} from './queries/queryDispatch.js';\nexport {\n CONTEXT_REF_KEY,\n encodeContextRef,\n isContextRefJSON,\n resolveContextId,\n} from './queries/ContextRef.js';\nexport type {ContextRefJSON} from './queries/ContextRef.js';\nexport {PropertyPath, walkPropertyPath} from './queries/PropertyPath.js';\n\n// Phase 3a — FieldSet\nexport {FieldSet} from './queries/FieldSet.js';\nexport type {FieldSetEntry, FieldSetInput, FieldSetJSON, FieldSetFieldJSON} from './queries/FieldSet.js';\n\n// Phase 4 — Serialization types\nexport type {QueryBuilderJSON} from './queries/QueryBuilder.js';\n\n// Phase 3b — Mutation builders\nexport {AskBuilder, isAskQuery} from './queries/AskBuilder.js';\nexport type {AskSpec} from './queries/AskBuilder.js';\nexport type {AskQuery, AskQueryJSON, RawAskInput} from './queries/AskQuery.js';\nexport {CountBuilder, isCountQuery} from './queries/CountBuilder.js';\nexport type {CountSpec} from './queries/CountBuilder.js';\nexport type {CountQuery, CountQueryJSON, RawCountInput} from './queries/CountQuery.js';\nexport {CreateBuilder} from './queries/CreateBuilder.js';\nexport {UpdateBuilder} from './queries/UpdateBuilder.js';\nexport {DeleteBuilder} from './queries/DeleteBuilder.js';\nexport type {DeleteId} from './queries/DeleteBuilder.js';\n\n// Expressions — computed fields and functions\nexport {ExpressionNode} from './expressions/ExpressionNode.js';\nexport type {ExpressionInput, PropertyRefMap} from './expressions/ExpressionNode.js';\nexport {Expr} from './expressions/Expr.js';\nexport type {\n ExpressionUpdateProxy,\n ExpressionUpdateResult,\n BaseExpressionMethods,\n NumericExpressionMethods,\n StringExpressionMethods,\n DateExpressionMethods,\n BooleanExpressionMethods,\n} from './expressions/ExpressionMethods.js';\n\n// Phase 5 — Component query integration\nexport type {LinkedComponentInterface, QueryComponentLike} from './queries/SelectQuery.js';\n\n\n// Mutation DSL-JSON serialization (create/update/delete to/from JSON)\nexport {\n encodeNodeData,\n encodeValue,\n} from './queries/MutationSerialization.js';\nexport {\n decodeNodeData,\n lowerMutationJSON,\n} from './queries/lowerMutationJSON.js';\nexport type {\n MutationJSON,\n CreateMutationJSON,\n UpdateMutationJSON,\n DeleteMutationJSON,\n MutationValueJSON,\n MutationNodeDataJSON,\n} from './queries/MutationSerialization.js';\n\n\n// Live-query dependency helpers — what a query reads and a mutation writes, as predicates\nexport {queryDependencies, mutationEffects} from './queries/queryDependencies.js';\nexport type {QueryDependencies, MutationEffects} from './queries/queryDependencies.js';\nexport {findPropertyShapeById} from './shapes/nodeShapeData.js';\n\n// Live queries — see documentation/live-queries.md\nexport {LiveQueryStore, getLiveQueryStore, resetLiveQueryStore, publishChange, invalidate} from './live/LiveQueryStore.js';\nexport type {ChangeEvent} from './live/changes.js';\nexport type {\n LiveQuery,\n LiveState,\n LiveStatus,\n LiveListener,\n LiveQueryOptions,\n LiveQueryStoreOptions,\n} from './live/LiveQueryStore.js';\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type MutationEffects, type QueryDependencies } from '../queries/queryDependencies.js';
|
|
2
|
+
import type { ShapeCatalog } from '../utils/ShapeCatalog.js';
|
|
2
3
|
import type { ShapeConstructor } from '../shapes/Shape.js';
|
|
3
4
|
import { type ChangeEvent, type ChangeOrigin } from './changes.js';
|
|
4
5
|
import { type InstanceParams, type LiveBuilder, type LiveQueryKind } from './keys.js';
|
|
@@ -64,6 +65,11 @@ export interface LiveQuery<R = unknown> extends PromiseLike<R> {
|
|
|
64
65
|
export type Template = {
|
|
65
66
|
key: string;
|
|
66
67
|
kind: LiveQueryKind;
|
|
68
|
+
/**
|
|
69
|
+
* The catalog the template's queries resolve in (undefined = the global registry). Part
|
|
70
|
+
* of its identity: the same JSON in two catalogs is two templates.
|
|
71
|
+
*/
|
|
72
|
+
catalog?: ShapeCatalog;
|
|
67
73
|
name?: string;
|
|
68
74
|
json: Record<string, unknown>;
|
|
69
75
|
/** Subject-stripped builder, used for dependency analysis only. */
|
|
@@ -124,6 +130,8 @@ export declare class LiveQueryStore {
|
|
|
124
130
|
private readonly _recentChanges;
|
|
125
131
|
private _pendingRefetch;
|
|
126
132
|
private _flushScheduled;
|
|
133
|
+
/** How many templates each catalog has; a change is decoded once per catalog listed here. */
|
|
134
|
+
private readonly _catalogTemplates;
|
|
127
135
|
constructor();
|
|
128
136
|
/** Register (or find) the template of `query`. Options merge into an existing template. */
|
|
129
137
|
template(query: LiveBuilder, opts?: LiveQueryOptions): Template;
|
|
@@ -190,6 +198,19 @@ export declare class LiveQueryStore {
|
|
|
190
198
|
* in quick succession are two changes — and manual invalidations never are.
|
|
191
199
|
*/
|
|
192
200
|
publish(event: ChangeEvent, origin?: ChangeOrigin): void;
|
|
201
|
+
/**
|
|
202
|
+
* `within` limits the change to one catalog's templates (undefined = the global registry's):
|
|
203
|
+
* a local mutation changes the data of the catalog it was made in, and only that one.
|
|
204
|
+
*/
|
|
205
|
+
private _publish;
|
|
206
|
+
/**
|
|
207
|
+
* The effects of a change in the global registry and in each catalog that has
|
|
208
|
+
* templates. A mutation is decoded once per catalog; one that does not resolve in a
|
|
209
|
+
* catalog (its shape is not there) leaves that catalog's templates alone, and effects
|
|
210
|
+
* given as data apply to a catalog only when it holds their shape. Throws only when
|
|
211
|
+
* the change resolves nowhere, as a change that cannot be decoded did before catalogs.
|
|
212
|
+
*/
|
|
213
|
+
private _decodePerCatalog;
|
|
193
214
|
private _scheduleFlush;
|
|
194
215
|
/**
|
|
195
216
|
* Local mutations. Select and ask events are ignored: the store's own fetches
|
|
@@ -220,6 +241,7 @@ export declare class LiveQueryStore {
|
|
|
220
241
|
private _onContextChange;
|
|
221
242
|
/** Remove an instance from its template (and the template when it is empty and not pinned). */
|
|
222
243
|
private _dropInstance;
|
|
244
|
+
private _forgetCatalogTemplate;
|
|
223
245
|
private _scheduleGc;
|
|
224
246
|
private _cancelGc;
|
|
225
247
|
}
|
|
@@ -17,10 +17,10 @@ import { subscribeQueryContext, UnresolvedContextError } from '../queries/QueryC
|
|
|
17
17
|
import { resolveContextId } from '../queries/ContextRef.js';
|
|
18
18
|
import { subscribeQueryDispatch } from '../queries/queryDispatch.js';
|
|
19
19
|
import { mutationEffects, queryDependencies, } from '../queries/queryDependencies.js';
|
|
20
|
-
import { getShapeClass } from '../utils/ShapeClass.js';
|
|
20
|
+
import { catalogOf, getActiveShapeCatalog, getShapeClass, withShapeCatalog, } from '../utils/ShapeClass.js';
|
|
21
21
|
import { effectsHash, normalizeChange } from './changes.js';
|
|
22
22
|
import { selectInstances } from './matcher.js';
|
|
23
|
-
import { kindOf, paramsKey, splitQuery,
|
|
23
|
+
import { kindOf, paramsKey, splitQuery, stripSubjects, templateKeyFor, } from './keys.js';
|
|
24
24
|
import { setLiveQueryStore, peekLiveQueryStore } from './registry.js';
|
|
25
25
|
const IDLE = Object.freeze({ status: 'pending', notFound: false, refreshing: false });
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
@@ -48,6 +48,8 @@ export class LiveQueryStore {
|
|
|
48
48
|
this._recentChanges = new Map();
|
|
49
49
|
this._pendingRefetch = new Set();
|
|
50
50
|
this._flushScheduled = false;
|
|
51
|
+
/** How many templates each catalog has; a change is decoded once per catalog listed here. */
|
|
52
|
+
this._catalogTemplates = new Map();
|
|
51
53
|
this._disposers.push(subscribeQueryContext((name) => this._onContextChange(name)));
|
|
52
54
|
this._disposers.push(subscribeQueryDispatch((e) => this._onDispatch(e)));
|
|
53
55
|
this._disposers.push(LinkedStorage.onRoutingChanged(() => this._onRoutingChanged()));
|
|
@@ -61,20 +63,16 @@ export class LiveQueryStore {
|
|
|
61
63
|
return this._template(splitQuery(query).templateJson, query, opts);
|
|
62
64
|
}
|
|
63
65
|
_template(templateJson, query, opts) {
|
|
64
|
-
|
|
66
|
+
var _a;
|
|
67
|
+
const catalog = catalogOf(query);
|
|
68
|
+
const key = templateKeyFor(templateJson, catalog);
|
|
65
69
|
let t = this._templates.get(key);
|
|
66
70
|
if (!t) {
|
|
67
|
-
t = {
|
|
68
|
-
key,
|
|
69
|
-
kind: kindOf(query),
|
|
70
|
-
json: templateJson,
|
|
71
|
-
builder: stripSubjects(query),
|
|
72
|
-
shapeIri: typeof templateJson.shape === 'string' ? templateJson.shape : undefined,
|
|
73
|
-
reactive: true,
|
|
74
|
-
pinned: false,
|
|
75
|
-
instances: new Map(),
|
|
76
|
-
};
|
|
71
|
+
t = Object.assign(Object.assign({ key, kind: kindOf(query) }, (catalog !== undefined ? { catalog } : {})), { json: templateJson, builder: stripSubjects(query), shapeIri: typeof templateJson.shape === 'string' ? templateJson.shape : undefined, reactive: true, pinned: false, instances: new Map() });
|
|
77
72
|
this._templates.set(key, t);
|
|
73
|
+
if (catalog !== undefined) {
|
|
74
|
+
this._catalogTemplates.set(catalog, ((_a = this._catalogTemplates.get(catalog)) !== null && _a !== void 0 ? _a : 0) + 1);
|
|
75
|
+
}
|
|
78
76
|
}
|
|
79
77
|
if (opts.name !== undefined)
|
|
80
78
|
t.name = opts.name;
|
|
@@ -245,7 +243,7 @@ export class LiveQueryStore {
|
|
|
245
243
|
instances.add(i);
|
|
246
244
|
}
|
|
247
245
|
else if (typeof target.__queryKind === 'string') {
|
|
248
|
-
const t = this._templates.get(
|
|
246
|
+
const t = this._templates.get(templateKeyFor(splitQuery(target).templateJson, catalogOf(target)));
|
|
249
247
|
if (t)
|
|
250
248
|
for (const i of t.instances.values())
|
|
251
249
|
instances.add(i);
|
|
@@ -281,7 +279,17 @@ export class LiveQueryStore {
|
|
|
281
279
|
* in quick succession are two changes — and manual invalidations never are.
|
|
282
280
|
*/
|
|
283
281
|
publish(event, origin = 'app') {
|
|
284
|
-
|
|
282
|
+
this._publish(event, origin);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* `within` limits the change to one catalog's templates (undefined = the global registry's):
|
|
286
|
+
* a local mutation changes the data of the catalog it was made in, and only that one.
|
|
287
|
+
*/
|
|
288
|
+
_publish(event, origin, within) {
|
|
289
|
+
const decoded = within
|
|
290
|
+
? [[within.catalog, normalizeChange(event, { catalog: within.catalog })]]
|
|
291
|
+
: this._decodePerCatalog(event);
|
|
292
|
+
const effects = decoded[0][1];
|
|
285
293
|
if (origin !== 'manual') {
|
|
286
294
|
const hash = effectsHash(effects);
|
|
287
295
|
const now = Date.now();
|
|
@@ -297,10 +305,52 @@ export class LiveQueryStore {
|
|
|
297
305
|
this._recentChanges.delete(h);
|
|
298
306
|
}
|
|
299
307
|
}
|
|
300
|
-
|
|
301
|
-
|
|
308
|
+
if (decoded.length === 1 && decoded[0][0] === undefined && this._catalogTemplates.size === 0) {
|
|
309
|
+
for (const inst of selectInstances(this, effects))
|
|
310
|
+
this._pendingRefetch.add(inst);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
for (const [catalog, e] of decoded) {
|
|
314
|
+
for (const inst of selectInstances(this, e, { catalog }))
|
|
315
|
+
this._pendingRefetch.add(inst);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
302
318
|
this._scheduleFlush();
|
|
303
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* The effects of a change in the global registry and in each catalog that has
|
|
322
|
+
* templates. A mutation is decoded once per catalog; one that does not resolve in a
|
|
323
|
+
* catalog (its shape is not there) leaves that catalog's templates alone, and effects
|
|
324
|
+
* given as data apply to a catalog only when it holds their shape. Throws only when
|
|
325
|
+
* the change resolves nowhere, as a change that cannot be decoded did before catalogs.
|
|
326
|
+
*/
|
|
327
|
+
_decodePerCatalog(event) {
|
|
328
|
+
if (this._catalogTemplates.size === 0) {
|
|
329
|
+
return [[undefined, normalizeChange(event, { catalog: undefined })]];
|
|
330
|
+
}
|
|
331
|
+
const out = [];
|
|
332
|
+
let globalError;
|
|
333
|
+
try {
|
|
334
|
+
out.push([undefined, normalizeChange(event, { catalog: undefined })]);
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
globalError = err;
|
|
338
|
+
}
|
|
339
|
+
for (const catalog of this._catalogTemplates.keys()) {
|
|
340
|
+
try {
|
|
341
|
+
const effects = normalizeChange(event, { catalog });
|
|
342
|
+
if ('effects' in event && !catalog.has(effects.shape))
|
|
343
|
+
continue;
|
|
344
|
+
out.push([catalog, effects]);
|
|
345
|
+
}
|
|
346
|
+
catch (_a) {
|
|
347
|
+
// Not a change to this catalog's shapes.
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (out.length === 0)
|
|
351
|
+
throw globalError;
|
|
352
|
+
return out;
|
|
353
|
+
}
|
|
304
354
|
_scheduleFlush() {
|
|
305
355
|
if (this._flushScheduled)
|
|
306
356
|
return;
|
|
@@ -321,7 +371,12 @@ export class LiveQueryStore {
|
|
|
321
371
|
if (e.kind !== 'create' && e.kind !== 'update' && e.kind !== 'delete')
|
|
322
372
|
return;
|
|
323
373
|
const query = e.query;
|
|
324
|
-
|
|
374
|
+
// The routing lookup reads the registry, so it runs in the mutation's catalog.
|
|
375
|
+
const catalog = catalogOf(query);
|
|
376
|
+
const shapeClassOf = (id) => catalog === getActiveShapeCatalog()
|
|
377
|
+
? getShapeClass(id)
|
|
378
|
+
: withShapeCatalog(catalog, () => getShapeClass(id));
|
|
379
|
+
const dataset = (_a = e.target) !== null && _a !== void 0 ? _a : LinkedStorage.getDatasetForShapeClass((((_b = query.shape) === null || _b === void 0 ? void 0 : _b.id) ? shapeClassOf(query.shape.id) : undefined));
|
|
325
380
|
if (dataset === null || dataset === void 0 ? void 0 : dataset.authoritativeChanges)
|
|
326
381
|
return; // the dataset's own feed will report it
|
|
327
382
|
e.result.then((result) => {
|
|
@@ -333,7 +388,7 @@ export class LiveQueryStore {
|
|
|
333
388
|
console.error('[linked] could not derive the effects of a mutation; live queries were not refetched', err);
|
|
334
389
|
return;
|
|
335
390
|
}
|
|
336
|
-
this.
|
|
391
|
+
this._publish({ effects }, 'local', { catalog });
|
|
337
392
|
}, () => { });
|
|
338
393
|
}
|
|
339
394
|
/** Subscribe to the change feeds of the datasets currently routed; drop feeds of datasets that left. */
|
|
@@ -383,6 +438,7 @@ export class LiveQueryStore {
|
|
|
383
438
|
this._dropInstance(i, true);
|
|
384
439
|
}
|
|
385
440
|
this._templates.clear();
|
|
441
|
+
this._catalogTemplates.clear();
|
|
386
442
|
this.templatesByProp.clear();
|
|
387
443
|
this.templatesByShape.clear();
|
|
388
444
|
this.instancesById.clear();
|
|
@@ -548,8 +604,19 @@ export class LiveQueryStore {
|
|
|
548
604
|
if (!keepTemplate && t.instances.size === 0 && !t.pinned) {
|
|
549
605
|
this._templates.delete(t.key);
|
|
550
606
|
this._unindexTemplate(t);
|
|
607
|
+
this._forgetCatalogTemplate(t);
|
|
551
608
|
}
|
|
552
609
|
}
|
|
610
|
+
_forgetCatalogTemplate(t) {
|
|
611
|
+
var _a;
|
|
612
|
+
if (t.catalog === undefined)
|
|
613
|
+
return;
|
|
614
|
+
const left = ((_a = this._catalogTemplates.get(t.catalog)) !== null && _a !== void 0 ? _a : 1) - 1;
|
|
615
|
+
if (left > 0)
|
|
616
|
+
this._catalogTemplates.set(t.catalog, left);
|
|
617
|
+
else
|
|
618
|
+
this._catalogTemplates.delete(t.catalog);
|
|
619
|
+
}
|
|
553
620
|
_scheduleGc(inst) {
|
|
554
621
|
var _a, _b;
|
|
555
622
|
this._cancelGc(inst);
|