@_linked/core 2.30.1 → 2.32.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 +67 -0
- package/README.md +107 -60
- package/lib/esm/ontologies/linked-core.js +3 -2
- package/lib/esm/ontologies/linked-core.js.map +1 -1
- package/lib/esm/ontologies/shacl.d.ts +3 -0
- package/lib/esm/ontologies/shacl.js +6 -0
- package/lib/esm/ontologies/shacl.js.map +1 -1
- package/lib/esm/queries/IRMutation.js +1 -1
- package/lib/esm/queries/IRMutation.js.map +1 -1
- package/lib/esm/queries/IntermediateRepresentation.d.ts +0 -5
- package/lib/esm/queries/IntermediateRepresentation.js.map +1 -1
- package/lib/esm/queries/MutationQuery.js +0 -15
- package/lib/esm/queries/MutationQuery.js.map +1 -1
- package/lib/esm/queries/MutationSerialization.d.ts +6 -5
- package/lib/esm/queries/MutationSerialization.js +1 -9
- package/lib/esm/queries/MutationSerialization.js.map +1 -1
- package/lib/esm/queries/QueryFactory.d.ts +0 -6
- package/lib/esm/queries/QueryFactory.js.map +1 -1
- package/lib/esm/queries/lowerMutationJSON.js +1 -6
- package/lib/esm/queries/lowerMutationJSON.js.map +1 -1
- package/lib/esm/shapes/List.class.d.ts +3 -3
- package/lib/esm/shapes/List.class.js +3 -3
- package/lib/esm/shapes/List.class.js.map +1 -1
- package/lib/esm/shapes/List.d.ts +0 -1
- package/lib/esm/shapes/List.js.map +1 -1
- package/lib/esm/shapes/PathList.d.ts +24 -0
- package/lib/esm/shapes/PathList.js +60 -0
- package/lib/esm/shapes/PathList.js.map +1 -0
- package/lib/esm/shapes/PathNode.d.ts +8 -9
- package/lib/esm/shapes/PathNode.js +20 -14
- package/lib/esm/shapes/PathNode.js.map +1 -1
- package/lib/esm/shapes/SHACL.d.ts +15 -13
- package/lib/esm/shapes/SHACL.js +8 -0
- package/lib/esm/shapes/SHACL.js.map +1 -1
- package/lib/esm/shapes/index.d.ts +1 -0
- package/lib/esm/shapes/index.js +1 -0
- package/lib/esm/shapes/index.js.map +1 -1
- package/lib/esm/shapes/nodeShapeData.d.ts +4 -1
- package/lib/esm/shapes/nodeShapeData.js.map +1 -1
- package/lib/esm/shapes/serializePathToNodeData.d.ts +12 -11
- package/lib/esm/shapes/serializePathToNodeData.js +12 -11
- package/lib/esm/shapes/serializePathToNodeData.js.map +1 -1
- package/lib/esm/shapes/singleOwnerConstraint.d.ts +5 -7
- package/lib/esm/shapes/singleOwnerConstraint.js +65 -21
- package/lib/esm/shapes/singleOwnerConstraint.js.map +1 -1
- package/lib/esm/shapes/syncShapes.js +2 -2
- 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.d.ts +15 -33
- package/lib/esm/sparql/irToAlgebra.js +680 -431
- package/lib/esm/sparql/irToAlgebra.js.map +1 -1
- package/lib/esm/sparql/ownedLinkCheck.d.ts +6 -10
- package/lib/esm/sparql/ownedLinkCheck.js +10 -11
- package/lib/esm/sparql/ownedLinkCheck.js.map +1 -1
- package/lib/esm/utils/Package.d.ts +3 -2
- package/lib/esm/utils/Package.js +21 -8
- package/lib/esm/utils/Package.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IntermediateRepresentation.js","sourceRoot":"","sources":["../../../src/queries/IntermediateRepresentation.ts"],"names":[],"mappings":"","sourcesContent":["import {NodeReferenceValue} from './QueryFactory.js';\nimport type {PathExpr} from '../paths/PropertyPathExpr.js';\n\nexport type IRDirection = 'ASC' | 'DESC';\nexport type IRAlias = string;\n\nexport type IRValue = string | number | boolean | null;\n\nexport type IRQuery =\n | IRSelectQuery\n | IRAskQuery\n | IRCountQuery\n | IRCreateMutation\n | IRUpdateMutation\n | IRUpsertMutation\n | IRDeleteMutation\n | IRDeleteAllMutation\n | IRDeleteWhereMutation\n | IRUpdateWhereMutation;\n\nexport type IRSelectQuery = {\n kind: 'select';\n root: IRShapeScanPattern;\n patterns: IRGraphPattern[];\n projection: IRProjectionItem[];\n where?: IRExpression;\n orderBy?: IROrderByItem[];\n limit?: number;\n offset?: number;\n subjectId?: string;\n subjectIds?: string[];\n singleResult?: boolean;\n resultMap?: IRResultMapEntry[];\n};\n\n/**\n * A query whose answer is a boolean.\n *\n * Carries a pattern and nothing else. There is no `projection`, `orderBy`,\n * `limit` or `offset`: each of those shapes or windows a *solution sequence*, and\n * an ask has none — so rather than being ignored during conversion, or guarded\n * against, they are unrepresentable.\n *\n * `root` is **optional**. Absent means no `rdf:type` constraint at all — \"does a\n * node with this IRI exist\", under any shape or none — which lowers to\n * `ASK { <iri> ?p ?o }`. A rootless ask carries no `patterns` or `where`, since\n * both reference properties and a property is only resolvable through a shape.\n */\nexport type IRAskQuery = {\n kind: 'ask';\n root?: IRShapeScanPattern;\n patterns: IRGraphPattern[];\n where?: IRExpression;\n subjectId?: string;\n subjectIds?: string[];\n};\n\n/**\n * A query whose answer is a single number: how many instances of a shape match.\n *\n * Like {@link IRAskQuery}, it carries a **pattern and nothing else**. There is no\n * `projection`, `orderBy`, `limit` or `offset`: each of those shapes or windows a\n * *solution sequence*, and a count has none — the number it answers is a property\n * of the whole match set. So rather than being ignored during conversion, or\n * guarded against, they are unrepresentable.\n *\n * That is the entire reason this is a distinct IR kind and not a flag on\n * {@link IRSelectQuery}: a count of a windowed query is meaningless, and a type\n * that cannot hold the window cannot half-drop it.\n *\n * `root` is **required**, unlike an ask's. A shapeless count would count every\n * node in the store, which is never what a caller means.\n */\nexport type IRCountQuery = {\n kind: 'count';\n root: IRShapeScanPattern;\n patterns: IRGraphPattern[];\n where?: IRExpression;\n subjectId?: string;\n subjectIds?: string[];\n /**\n * The variable the `COUNT` is bound to (`(COUNT(DISTINCT ?a0) AS ?count)`).\n * Carried in the IR rather than hardcoded in two places so lowering and result\n * mapping cannot disagree about it.\n */\n alias: IRAlias;\n};\n\nexport type IRProjectionItem = {\n alias: IRAlias;\n expression: IRExpression;\n};\n\nexport type IROrderByItem = {\n expression: IRExpression;\n direction: IRDirection;\n};\n\nexport type IRResultMapEntry = {\n key: string;\n alias: IRAlias;\n};\n\nexport type IRGraphPattern =\n | IRShapeScanPattern\n | IRTraversePattern\n | IRJoinPattern\n | IROptionalPattern\n | IRUnionPattern\n | IRExistsPattern\n | IRMinusPattern;\n\nexport type IRShapeScanPattern = {\n kind: 'shape_scan';\n shape: string;\n alias: IRAlias;\n};\n\nexport type IRTraversePattern = {\n kind: 'traverse';\n from: IRAlias;\n to: IRAlias;\n property: string;\n pathExpr?: PathExpr;\n filter?: IRExpression;\n maxCount?: number;\n /**\n * Inner LIMIT/OFFSET/ORDER BY for a nested select on this traversal's\n * related collection. When set, the root→child traverse is wrapped in a\n * SPARQL sub-SELECT to bound the collection per parent. Only valid when the\n * outer query targets a single root subject (enforced in irToAlgebra).\n */\n innerLimit?: number;\n innerOffset?: number;\n innerOrderBy?: IRInnerOrderBy[];\n};\n\nexport type IRInnerOrderBy = {\n property: string;\n direction: IRDirection;\n};\n\nexport type IRJoinPattern = {\n kind: 'join';\n patterns: IRGraphPattern[];\n};\n\nexport type IROptionalPattern = {\n kind: 'optional';\n pattern: IRGraphPattern;\n};\n\nexport type IRUnionPattern = {\n kind: 'union';\n branches: IRGraphPattern[];\n};\n\nexport type IRExistsPattern = {\n kind: 'exists';\n pattern: IRGraphPattern;\n};\n\nexport type IRMinusPattern = {\n kind: 'minus';\n pattern: IRGraphPattern;\n filter?: IRExpression;\n};\n\nexport type IRExpression =\n | IRLiteralExpression\n | IRReferenceExpression\n | IRAliasExpression\n | IRPropertyExpression\n | IRContextPropertyExpression\n | IRBinaryExpression\n | IRLogicalExpression\n | IRNotExpression\n | IRFunctionExpression\n | IRAggregateExpression\n | IRExistsExpression\n | IRInExpression;\n\n/**\n * Membership test — `value IN (…)` / `NOT IN (…)`.\n * `source` is forward-shaped: today only the explicit-`list` arm exists (Rung 1);\n * a `{query}` arm (Rung 2 — membership against a subquery, lowering to EXISTS)\n * can be added without changing the node's identity or the `oneOf`/`notOneOf` DSL.\n */\nexport type IRInExpression = {\n kind: 'in_expr';\n negated: boolean;\n value: IRExpression;\n source: {list: IRExpression[]};\n};\n\nexport type IRLiteralExpression = {\n kind: 'literal_expr';\n /**\n * `Date` is admitted alongside `IRValue`: a temporal comparison has to reach the\n * SPARQL layer still knowing it is temporal, or the literal is emitted untyped\n * and never equals the `^^xsd:dateTime` term the mutation side writes.\n */\n value: IRValue | Date;\n};\n\nexport type IRReferenceExpression = {\n kind: 'reference_expr';\n /** The referenced node IRI. Optional only while a `contextName` is unresolved. */\n value?: string;\n /**\n * A query-context reference (`{@ctx}` on the wire). When set, `value` is filled\n * by `lower()` from the live context map — resolved or thrown there, never baked\n * at build time. Absent for a plain node reference.\n */\n contextName?: string;\n};\n\nexport type IRAliasExpression = {\n kind: 'alias_expr';\n alias: IRAlias;\n};\n\nexport type IRPropertyExpression = {\n kind: 'property_expr';\n sourceAlias: IRAlias;\n property: string;\n pathExpr?: import('../paths/PropertyPathExpr.js').PathExpr;\n maxCount?: number;\n};\n\nexport type IRContextPropertyExpression = {\n kind: 'context_property_expr';\n /** The context entity IRI. Optional only while a `contextName` is unresolved. */\n contextIri?: string;\n /** A query-context reference resolved into `contextIri` by `lower()`. */\n contextName?: string;\n property: string;\n};\n\nexport type IRBinaryOperator =\n | '='\n | '!='\n | '>'\n | '>='\n | '<'\n | '<='\n | '+'\n | '-'\n | '*'\n | '/';\n\nexport type IRBinaryExpression = {\n kind: 'binary_expr';\n operator: IRBinaryOperator;\n left: IRExpression;\n right: IRExpression;\n};\n\nexport type IRLogicalOperator = 'and' | 'or';\n\nexport type IRLogicalExpression = {\n kind: 'logical_expr';\n operator: IRLogicalOperator;\n expressions: IRExpression[];\n};\n\nexport type IRNotExpression = {\n kind: 'not_expr';\n expression: IRExpression;\n};\n\nexport type IRFunctionExpression = {\n kind: 'function_expr';\n name: string;\n args: IRExpression[];\n};\n\nexport type IRAggregateExpression = {\n kind: 'aggregate_expr';\n name: 'count' | 'sum' | 'avg' | 'min' | 'max';\n args: IRExpression[];\n};\n\nexport type IRExistsExpression = {\n kind: 'exists_expr';\n pattern: IRGraphPattern;\n filter?: IRExpression;\n};\n\nexport type IRCreateMutation = {\n kind: 'create';\n shape: string;\n data: IRNodeData;\n};\n\nexport type IRTraversalPattern = {\n from: string; // source alias\n property: string; // property IRI\n to: string; // target alias\n};\n\nexport type IRUpdateMutation = {\n kind: 'update';\n shape: string;\n id: string;\n data: IRNodeData;\n traversalPatterns?: IRTraversalPattern[];\n};\n\n/**\n * Create-or-replace against a known id, in one request.\n *\n * Structurally identical to {@link IRUpdateMutation} — it lowers through the same\n * DELETE/INSERT/WHERE body — and differs in exactly one emitted triple: upsert also\n * asserts `?id rdf:type <targetClass>`, which the update path never writes.\n *\n * That single triple is the whole difference between the two, because `update`'s WHERE\n * is a bare `OPTIONAL` and so already matches when the node is absent. It is a distinct\n * IR kind rather than a flag on the update mutation so that a consumer which does not\n * know about upsert fails loudly, instead of quietly writing an untyped node and\n * reporting success.\n */\nexport type IRUpsertMutation = {\n kind: 'upsert';\n shape: string;\n id: string;\n data: IRNodeData;\n traversalPatterns?: IRTraversalPattern[];\n};\n\nexport type IRDeleteMutation = {\n kind: 'delete';\n shape: string;\n ids: NodeReferenceValue[];\n};\n\nexport type IRDeleteAllMutation = {\n kind: 'delete_all';\n shape: string;\n};\n\nexport type IRDeleteWhereMutation = {\n kind: 'delete_where';\n shape: string;\n where: IRExpression;\n wherePatterns: IRGraphPattern[];\n};\n\nexport type IRUpdateWhereMutation = {\n kind: 'update_where';\n shape: string;\n data: IRNodeData;\n where?: IRExpression;\n wherePatterns?: IRGraphPattern[];\n traversalPatterns?: IRTraversalPattern[];\n};\n\nexport type IRNodeData = {\n shape: string;\n fields: IRFieldUpdate[];\n id?: string;\n /**\n * A nested node written as a fresh blank node with only its field triples: no IRI, no\n * `rdf:type` (see `NodeDescriptionValue.__blank`). Never set together with `id`.\n */\n blank?: true;\n};\n\nexport type IRFieldUpdate = {\n property: string;\n value: IRFieldValue;\n};\n\nexport type IRSetModificationValue = {\n add?: IRFieldValue[];\n remove?: NodeReferenceValue[];\n};\n\nexport type IRFieldValue =\n | IRValue\n | Date\n | NodeReferenceValue\n | IRNodeData\n | IRSetModificationValue\n | IRFieldValue[]\n | IRExpression\n | undefined;\n\n// ---------------------------------------------------------------------------\n// Store result types\n// ---------------------------------------------------------------------------\n// These types describe what an IDataset implementation should return.\n// The calling layer (LinkedStorage via queryDispatch) threads the precise\n// DSL-level TypeScript result type back to the caller, so the store\n// only needs to produce data that satisfies these structural contracts.\n// ---------------------------------------------------------------------------\n\n/**\n * A single result row — an object with a node id and dynamic fields.\n * Used in select and create results.\n */\nexport type ResultRow = {id: string; [key: string]: ResultFieldValue};\n\n/**\n * Possible field values in a select or create result row.\n */\nexport type ResultFieldValue =\n | string\n | number\n | boolean\n | Date\n | null\n | undefined\n | ResultRow\n | ResultRow[]\n | string[]\n | number[]\n | boolean[]\n | Date[];\n\n/**\n * What `selectQuery` should return.\n *\n * - Array of rows for multi-result queries (the default).\n * - A single row when `query.singleResult` is true (`.one()` or subject-targeted query).\n * - `null` when `singleResult` is true and the target node doesn't exist.\n */\nexport type SelectResult = ResultRow[] | ResultRow | null;\n\n/**\n * What `createQuery` should return.\n *\n * A single row with the generated `id` and the created field values.\n * Nested creates appear as nested `ResultRow` objects (with their own ids).\n * Array fields (e.g. friends) appear as `ResultRow[]`.\n */\nexport type CreateResult = ResultRow;\n\n/**\n * When a set property is fully overwritten, the result contains `updatedTo`\n * with the new complete set of values.\n */\nexport type SetOverwriteResult = {updatedTo: ResultRow[]};\n\n/**\n * When a set property is incrementally modified with `{add, remove}`,\n * the result contains the added and removed entries.\n */\nexport type SetModificationResult = {added: ResultRow[]; removed: ResultRow[]};\n\n/**\n * Possible field values in an update result row.\n * Extends `ResultFieldValue` with set modification shapes.\n */\nexport type UpdateFieldValue =\n | ResultFieldValue\n | SetOverwriteResult\n | SetModificationResult;\n\n/**\n * What `updateQuery` should return.\n *\n * A single row with the target node's `id` and only the changed fields.\n * Fields not included in the update are omitted (not returned).\n *\n * Field value shapes depend on the type of update:\n * - Literal fields: the new value (string, number, boolean, Date).\n * - Single object fields: a `ResultRow` with the referenced/created node.\n * - Set overwrite (passing an array): `{updatedTo: ResultRow[]}`.\n * - Set add/remove (passing `{add, remove}`): `{added: ResultRow[], removed: ResultRow[]}`.\n * - Unset single field (passing `undefined` or `null`): field is `undefined`.\n * - Unset multi-value field (passing `undefined`): empty array `[]`.\n */\nexport type UpdateResult = {id: string; [key: string]: UpdateFieldValue};\n"]}
|
|
1
|
+
{"version":3,"file":"IntermediateRepresentation.js","sourceRoot":"","sources":["../../../src/queries/IntermediateRepresentation.ts"],"names":[],"mappings":"","sourcesContent":["import {NodeReferenceValue} from './QueryFactory.js';\nimport type {PathExpr} from '../paths/PropertyPathExpr.js';\n\nexport type IRDirection = 'ASC' | 'DESC';\nexport type IRAlias = string;\n\nexport type IRValue = string | number | boolean | null;\n\nexport type IRQuery =\n | IRSelectQuery\n | IRAskQuery\n | IRCountQuery\n | IRCreateMutation\n | IRUpdateMutation\n | IRUpsertMutation\n | IRDeleteMutation\n | IRDeleteAllMutation\n | IRDeleteWhereMutation\n | IRUpdateWhereMutation;\n\nexport type IRSelectQuery = {\n kind: 'select';\n root: IRShapeScanPattern;\n patterns: IRGraphPattern[];\n projection: IRProjectionItem[];\n where?: IRExpression;\n orderBy?: IROrderByItem[];\n limit?: number;\n offset?: number;\n subjectId?: string;\n subjectIds?: string[];\n singleResult?: boolean;\n resultMap?: IRResultMapEntry[];\n};\n\n/**\n * A query whose answer is a boolean.\n *\n * Carries a pattern and nothing else. There is no `projection`, `orderBy`,\n * `limit` or `offset`: each of those shapes or windows a *solution sequence*, and\n * an ask has none — so rather than being ignored during conversion, or guarded\n * against, they are unrepresentable.\n *\n * `root` is **optional**. Absent means no `rdf:type` constraint at all — \"does a\n * node with this IRI exist\", under any shape or none — which lowers to\n * `ASK { <iri> ?p ?o }`. A rootless ask carries no `patterns` or `where`, since\n * both reference properties and a property is only resolvable through a shape.\n */\nexport type IRAskQuery = {\n kind: 'ask';\n root?: IRShapeScanPattern;\n patterns: IRGraphPattern[];\n where?: IRExpression;\n subjectId?: string;\n subjectIds?: string[];\n};\n\n/**\n * A query whose answer is a single number: how many instances of a shape match.\n *\n * Like {@link IRAskQuery}, it carries a **pattern and nothing else**. There is no\n * `projection`, `orderBy`, `limit` or `offset`: each of those shapes or windows a\n * *solution sequence*, and a count has none — the number it answers is a property\n * of the whole match set. So rather than being ignored during conversion, or\n * guarded against, they are unrepresentable.\n *\n * That is the entire reason this is a distinct IR kind and not a flag on\n * {@link IRSelectQuery}: a count of a windowed query is meaningless, and a type\n * that cannot hold the window cannot half-drop it.\n *\n * `root` is **required**, unlike an ask's. A shapeless count would count every\n * node in the store, which is never what a caller means.\n */\nexport type IRCountQuery = {\n kind: 'count';\n root: IRShapeScanPattern;\n patterns: IRGraphPattern[];\n where?: IRExpression;\n subjectId?: string;\n subjectIds?: string[];\n /**\n * The variable the `COUNT` is bound to (`(COUNT(DISTINCT ?a0) AS ?count)`).\n * Carried in the IR rather than hardcoded in two places so lowering and result\n * mapping cannot disagree about it.\n */\n alias: IRAlias;\n};\n\nexport type IRProjectionItem = {\n alias: IRAlias;\n expression: IRExpression;\n};\n\nexport type IROrderByItem = {\n expression: IRExpression;\n direction: IRDirection;\n};\n\nexport type IRResultMapEntry = {\n key: string;\n alias: IRAlias;\n};\n\nexport type IRGraphPattern =\n | IRShapeScanPattern\n | IRTraversePattern\n | IRJoinPattern\n | IROptionalPattern\n | IRUnionPattern\n | IRExistsPattern\n | IRMinusPattern;\n\nexport type IRShapeScanPattern = {\n kind: 'shape_scan';\n shape: string;\n alias: IRAlias;\n};\n\nexport type IRTraversePattern = {\n kind: 'traverse';\n from: IRAlias;\n to: IRAlias;\n property: string;\n pathExpr?: PathExpr;\n filter?: IRExpression;\n maxCount?: number;\n /**\n * Inner LIMIT/OFFSET/ORDER BY for a nested select on this traversal's\n * related collection. When set, the root→child traverse is wrapped in a\n * SPARQL sub-SELECT to bound the collection per parent. Only valid when the\n * outer query targets a single root subject (enforced in irToAlgebra).\n */\n innerLimit?: number;\n innerOffset?: number;\n innerOrderBy?: IRInnerOrderBy[];\n};\n\nexport type IRInnerOrderBy = {\n property: string;\n direction: IRDirection;\n};\n\nexport type IRJoinPattern = {\n kind: 'join';\n patterns: IRGraphPattern[];\n};\n\nexport type IROptionalPattern = {\n kind: 'optional';\n pattern: IRGraphPattern;\n};\n\nexport type IRUnionPattern = {\n kind: 'union';\n branches: IRGraphPattern[];\n};\n\nexport type IRExistsPattern = {\n kind: 'exists';\n pattern: IRGraphPattern;\n};\n\nexport type IRMinusPattern = {\n kind: 'minus';\n pattern: IRGraphPattern;\n filter?: IRExpression;\n};\n\nexport type IRExpression =\n | IRLiteralExpression\n | IRReferenceExpression\n | IRAliasExpression\n | IRPropertyExpression\n | IRContextPropertyExpression\n | IRBinaryExpression\n | IRLogicalExpression\n | IRNotExpression\n | IRFunctionExpression\n | IRAggregateExpression\n | IRExistsExpression\n | IRInExpression;\n\n/**\n * Membership test — `value IN (…)` / `NOT IN (…)`.\n * `source` is forward-shaped: today only the explicit-`list` arm exists (Rung 1);\n * a `{query}` arm (Rung 2 — membership against a subquery, lowering to EXISTS)\n * can be added without changing the node's identity or the `oneOf`/`notOneOf` DSL.\n */\nexport type IRInExpression = {\n kind: 'in_expr';\n negated: boolean;\n value: IRExpression;\n source: {list: IRExpression[]};\n};\n\nexport type IRLiteralExpression = {\n kind: 'literal_expr';\n /**\n * `Date` is admitted alongside `IRValue`: a temporal comparison has to reach the\n * SPARQL layer still knowing it is temporal, or the literal is emitted untyped\n * and never equals the `^^xsd:dateTime` term the mutation side writes.\n */\n value: IRValue | Date;\n};\n\nexport type IRReferenceExpression = {\n kind: 'reference_expr';\n /** The referenced node IRI. Optional only while a `contextName` is unresolved. */\n value?: string;\n /**\n * A query-context reference (`{@ctx}` on the wire). When set, `value` is filled\n * by `lower()` from the live context map — resolved or thrown there, never baked\n * at build time. Absent for a plain node reference.\n */\n contextName?: string;\n};\n\nexport type IRAliasExpression = {\n kind: 'alias_expr';\n alias: IRAlias;\n};\n\nexport type IRPropertyExpression = {\n kind: 'property_expr';\n sourceAlias: IRAlias;\n property: string;\n pathExpr?: import('../paths/PropertyPathExpr.js').PathExpr;\n maxCount?: number;\n};\n\nexport type IRContextPropertyExpression = {\n kind: 'context_property_expr';\n /** The context entity IRI. Optional only while a `contextName` is unresolved. */\n contextIri?: string;\n /** A query-context reference resolved into `contextIri` by `lower()`. */\n contextName?: string;\n property: string;\n};\n\nexport type IRBinaryOperator =\n | '='\n | '!='\n | '>'\n | '>='\n | '<'\n | '<='\n | '+'\n | '-'\n | '*'\n | '/';\n\nexport type IRBinaryExpression = {\n kind: 'binary_expr';\n operator: IRBinaryOperator;\n left: IRExpression;\n right: IRExpression;\n};\n\nexport type IRLogicalOperator = 'and' | 'or';\n\nexport type IRLogicalExpression = {\n kind: 'logical_expr';\n operator: IRLogicalOperator;\n expressions: IRExpression[];\n};\n\nexport type IRNotExpression = {\n kind: 'not_expr';\n expression: IRExpression;\n};\n\nexport type IRFunctionExpression = {\n kind: 'function_expr';\n name: string;\n args: IRExpression[];\n};\n\nexport type IRAggregateExpression = {\n kind: 'aggregate_expr';\n name: 'count' | 'sum' | 'avg' | 'min' | 'max';\n args: IRExpression[];\n};\n\nexport type IRExistsExpression = {\n kind: 'exists_expr';\n pattern: IRGraphPattern;\n filter?: IRExpression;\n};\n\nexport type IRCreateMutation = {\n kind: 'create';\n shape: string;\n data: IRNodeData;\n};\n\nexport type IRTraversalPattern = {\n from: string; // source alias\n property: string; // property IRI\n to: string; // target alias\n};\n\nexport type IRUpdateMutation = {\n kind: 'update';\n shape: string;\n id: string;\n data: IRNodeData;\n traversalPatterns?: IRTraversalPattern[];\n};\n\n/**\n * Create-or-replace against a known id, in one request.\n *\n * Structurally identical to {@link IRUpdateMutation} — it lowers through the same\n * DELETE/INSERT/WHERE body — and differs in exactly one emitted triple: upsert also\n * asserts `?id rdf:type <targetClass>`, which the update path never writes.\n *\n * That single triple is the whole difference between the two, because `update`'s WHERE\n * is a bare `OPTIONAL` and so already matches when the node is absent. It is a distinct\n * IR kind rather than a flag on the update mutation so that a consumer which does not\n * know about upsert fails loudly, instead of quietly writing an untyped node and\n * reporting success.\n */\nexport type IRUpsertMutation = {\n kind: 'upsert';\n shape: string;\n id: string;\n data: IRNodeData;\n traversalPatterns?: IRTraversalPattern[];\n};\n\nexport type IRDeleteMutation = {\n kind: 'delete';\n shape: string;\n ids: NodeReferenceValue[];\n};\n\nexport type IRDeleteAllMutation = {\n kind: 'delete_all';\n shape: string;\n};\n\nexport type IRDeleteWhereMutation = {\n kind: 'delete_where';\n shape: string;\n where: IRExpression;\n wherePatterns: IRGraphPattern[];\n};\n\nexport type IRUpdateWhereMutation = {\n kind: 'update_where';\n shape: string;\n data: IRNodeData;\n where?: IRExpression;\n wherePatterns?: IRGraphPattern[];\n traversalPatterns?: IRTraversalPattern[];\n};\n\nexport type IRNodeData = {\n shape: string;\n fields: IRFieldUpdate[];\n id?: string;\n};\n\nexport type IRFieldUpdate = {\n property: string;\n value: IRFieldValue;\n};\n\nexport type IRSetModificationValue = {\n add?: IRFieldValue[];\n remove?: NodeReferenceValue[];\n};\n\nexport type IRFieldValue =\n | IRValue\n | Date\n | NodeReferenceValue\n | IRNodeData\n | IRSetModificationValue\n | IRFieldValue[]\n | IRExpression\n | undefined;\n\n// ---------------------------------------------------------------------------\n// Store result types\n// ---------------------------------------------------------------------------\n// These types describe what an IDataset implementation should return.\n// The calling layer (LinkedStorage via queryDispatch) threads the precise\n// DSL-level TypeScript result type back to the caller, so the store\n// only needs to produce data that satisfies these structural contracts.\n// ---------------------------------------------------------------------------\n\n/**\n * A single result row — an object with a node id and dynamic fields.\n * Used in select and create results.\n */\nexport type ResultRow = {id: string; [key: string]: ResultFieldValue};\n\n/**\n * Possible field values in a select or create result row.\n */\nexport type ResultFieldValue =\n | string\n | number\n | boolean\n | Date\n | null\n | undefined\n | ResultRow\n | ResultRow[]\n | string[]\n | number[]\n | boolean[]\n | Date[];\n\n/**\n * What `selectQuery` should return.\n *\n * - Array of rows for multi-result queries (the default).\n * - A single row when `query.singleResult` is true (`.one()` or subject-targeted query).\n * - `null` when `singleResult` is true and the target node doesn't exist.\n */\nexport type SelectResult = ResultRow[] | ResultRow | null;\n\n/**\n * What `createQuery` should return.\n *\n * A single row with the generated `id` and the created field values.\n * Nested creates appear as nested `ResultRow` objects (with their own ids).\n * Array fields (e.g. friends) appear as `ResultRow[]`.\n */\nexport type CreateResult = ResultRow;\n\n/**\n * When a set property is fully overwritten, the result contains `updatedTo`\n * with the new complete set of values.\n */\nexport type SetOverwriteResult = {updatedTo: ResultRow[]};\n\n/**\n * When a set property is incrementally modified with `{add, remove}`,\n * the result contains the added and removed entries.\n */\nexport type SetModificationResult = {added: ResultRow[]; removed: ResultRow[]};\n\n/**\n * Possible field values in an update result row.\n * Extends `ResultFieldValue` with set modification shapes.\n */\nexport type UpdateFieldValue =\n | ResultFieldValue\n | SetOverwriteResult\n | SetModificationResult;\n\n/**\n * What `updateQuery` should return.\n *\n * A single row with the target node's `id` and only the changed fields.\n * Fields not included in the update are omitted (not returned).\n *\n * Field value shapes depend on the type of update:\n * - Literal fields: the new value (string, number, boolean, Date).\n * - Single object fields: a `ResultRow` with the referenced/created node.\n * - Set overwrite (passing an array): `{updatedTo: ResultRow[]}`.\n * - Set add/remove (passing `{add, remove}`): `{added: ResultRow[], removed: ResultRow[]}`.\n * - Unset single field (passing `undefined` or `null`): field is `undefined`.\n * - Unset multi-value field (passing `undefined`): empty array `[]`.\n */\nexport type UpdateResult = {id: string; [key: string]: UpdateFieldValue};\n"]}
|
|
@@ -128,18 +128,6 @@ export class MutationQueryFactory extends QueryFactory {
|
|
|
128
128
|
const props = getPropertyShapes(shape, true);
|
|
129
129
|
const fields = [];
|
|
130
130
|
let id;
|
|
131
|
-
// `__blank` asks for an anonymous node (a blank node without a type). It has no id by
|
|
132
|
-
// definition, so it cannot be combined with one.
|
|
133
|
-
const blank = obj.__blank === true;
|
|
134
|
-
if ('__blank' in obj) {
|
|
135
|
-
if (obj.__blank !== true) {
|
|
136
|
-
throw new Error(`__blank must be true when given, got ${JSON.stringify(obj.__blank)}`);
|
|
137
|
-
}
|
|
138
|
-
delete obj.__blank;
|
|
139
|
-
if ('__id' in obj || 'id' in obj) {
|
|
140
|
-
throw new Error('A node cannot be both __blank and carry an id (__id or id).');
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
131
|
if ('__id' in obj) {
|
|
144
132
|
//if the object has a __id key, then we should use that in the result
|
|
145
133
|
id = obj.__id.toString();
|
|
@@ -171,9 +159,6 @@ export class MutationQueryFactory extends QueryFactory {
|
|
|
171
159
|
if (id) {
|
|
172
160
|
res.__id = id;
|
|
173
161
|
}
|
|
174
|
-
if (blank) {
|
|
175
|
-
res.__blank = true;
|
|
176
|
-
}
|
|
177
162
|
return res;
|
|
178
163
|
}
|
|
179
164
|
createNodePropertyValue(value, propShape) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MutationQuery.js","sourceRoot":"","sources":["../../../src/queries/MutationQuery.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,EAKL,YAAY,GAMb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAC,iBAAiB,EAAC,MAAM,4BAA4B,CAAC;AAG7D,OAAO,EAAC,YAAY,EAAE,uBAAuB,EAAC,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAC,gBAAgB,EAAiB,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAC,wBAAwB,EAAC,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EACL,WAAW,EACX,yBAAyB,GAE1B,MAAM,yBAAyB,CAAC;AAgBjC,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IACpD;;;;;;;;;OASG;IACH,QAAQ,CACN,KAAoB,EACpB,IAAa,EACb,UAA2B,EAAE;QAE7B,OAAO,IAAI,CAAC,mBAAmB,CAAC,IAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC;IAED,mFAAmF;IACnF,iBAAiB,CAAC,GAAsB;QACtC,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IAES,mBAAmB,CAC3B,GAAG,EACH,KAAoB,EACpB,EAAC,eAAe,GAAG,KAAK,EAAE,QAAQ,KAAqB,EAAE;QAEzD,IAAI,QAAQ,CAAC;QACb,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,YAAY,IAAI,CAAC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACtE,IAAI,CAAC,eAAe,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;gBACpC,MAAM,IAAI,KAAK,CACb,wDAAwD,CACzD,CAAC;YACJ,CAAC;YACD,QAAQ,GAAG,GAAG,CAAC;QACjB,CAAC;aAAM,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC;YACrC,+EAA+E;YAC/E,+EAA+E;YAC/E,kEAAkE;YAClE,uFAAuF;YACvF,0CAA0C;YAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5E,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,CAAC,EAAE,IAAI,SAAS,EAAE,CAAC,CAAC;YACxE,CAAC;YACD,MAAM,KAAK,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBAClD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC3D,CAAC;YACD,gEAAgE;YAChE,QAAQ,GAAG,MAAM,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,QAAQ,EAAE,CAAC;YACb,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,CAAC,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAES,iBAAiB,CAAC,GAAG,EAAE,KAAK;QACpC,IAAI,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC;QACrB,IAAI,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC;QAC3B,IAAI,eAAe,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,IAAI,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QACrD,0EAA0E;QAC1E,yEAAyE;QACzE,wEAAwE;QACxE,wDAAwD;QACxD,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC,IAAI,eAAe,KAAK,OAAO,CAAC;IAC9D,CAAC;IAES,sBAAsB,CAC9B,GAAyB,EACzB,KAAwB;QAExB,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,GAAG,GAAyB,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAES,qBAAqB,CAC7B,GAAoC,EACpC,KAAwB;QAExB,iFAAiF;QACjF,+DAA+D;QAC/D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACjE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAES,kBAAkB,CAC1B,GAAoC,EACpC,KAAwB;QAExB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,EAAE,KAAK,CAAkB,CAAC,CAAC;QAC5E,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAkB,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAES,wBAAwB,CAChC,KAAK,EACL,KAAwB;QAExB,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,GAAoC,CAAC;QAC9C,CAAC;QACD,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,qBAAqB,KAAK,CAAC,KAAK,6DAA6D,CAC9F,CAAC;QACJ,CAAC;IACH,CAAC;IAES,sBAAsB,CAC9B,QAAiC,EACjC,KAAoB;QAEpB,sDAAsD;QACtD,MAAM,GAAG,qBAAO,QAAQ,CAAC,CAAC;QAC1B,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,MAAM,GAA8B,EAAE,CAAC;QAC7C,IAAI,EAAE,CAAC;QACP,sFAAsF;QACtF,iDAAiD;QACjD,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;QACnC,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;YACrB,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACzF,CAAC;YACD,OAAO,GAAG,CAAC,OAAO,CAAC;YACnB,IAAI,MAAM,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;YACjF,CAAC;QACH,CAAC;QACD,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YAClB,qEAAqE;YACrE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACzB,4CAA4C;YAC5C,OAAO,GAAG,CAAC,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YACvB,8DAA8D;YAC9D,kDAAkD;YAClD,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,CAAC;QACD,KAAK,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;YACpB,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;YACnD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,wEAAwE;gBACxE,yEAAyE;gBACzE,sEAAsE;gBACtE,MAAM,KAAK,CAAC,yBAAyB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;QACD,MAAM,GAAG,GAAyB;YAChC,MAAM;YACN,KAAK;SACN,CAAC;QACF,IAAI,EAAE,EAAE,CAAC;YACP,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QAChB,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;QACrB,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAES,uBAAuB,CAC/B,KAAK,EACL,SAA4B;QAE5B,OAAO;YACL,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC;SACpB,CAAC;IAC/B,CAAC;IAES,kBAAkB,CAC1B,KAAK,EACL,SAA6B,EAC7B,cAAuB,IAAI;QAE3B,wFAAwF;QACxF,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,KAAmC,CAAC;QAC7C,CAAC;QAED,4EAA4E;QAC5E,4EAA4E;QAC5E,+EAA+E;QAC/E,yDAAyD;QACzD,CAAC;YACC,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,GAAG;gBAAE,OAAO,GAAiC,CAAC;QACpD,CAAC;QAED,yBAAyB;QACzB,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,KAAK,KAAK,SAAS;YAC1B,KAAK,YAAY,IAAI,EACrB,CAAC;YACD,OAAO,KAA2B,CAAC;QACrC,CAAC;QAED,mDAAmD;QACnD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;YACrE,CAAC;YACD,oEAAoE;YACpE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACrB,OAAO,IAAI,CAAC,kBAAkB,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YACtD,CAAC,CAAgC,CAAC;QACpC,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,WAAW,EAAE,CAAC;YACxC,OAAO,KAAK,CAAC;QACf,CAAC;aAAM,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1B,+FAA+F;YAC/F,OAAO,SAAS,CAAC;QACnB,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChC,OAAO,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,IAAI,UAAU,GAAkB,IAAI,CAAC;gBACrC,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;oBACzB,MAAM,UAAU,GAAG,uBAAuB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;oBACjE,UAAU,GAAG,CAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,KAAK,KAAI,IAAI,CAAC;oBACvC,IAAI,CAAC,UAAU,EAAE,CAAC;wBAChB,MAAM,IAAI,KAAK,CACb,6BAA6B,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,CACvD,CAAC;oBACJ,CAAC;gBACH,CAAC;gBACD,sEAAsE;gBACtE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;oBAC1B,uIAAuI;oBACvI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;wBAChB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;4BACvB,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAC;wBACJ,CAAC;wBACD,UAAU,GAAI,KAAK,CAAC,KAAsB,CAAC,KAAK,CAAC;oBACnD,CAAC;yBAAM,CAAC;wBACN,6GAA6G;wBAC7G,+GAA+G;wBAC/G,MAAM,IAAI,KAAK,CACb,0GAA0G,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,SAAS,CAAC,KAAK,4DAA4D,CACzN,CAAC;oBACJ,CAAC;gBACH,CAAC;gBACD,4CAA4C;gBAC5C,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAChB,0EAA0E;oBAC1E,8EAA8E;oBAC9E,MAAM,QAAQ,GAAI,KAAK,CAAC,KAAsB,CAAC,KAAK,CAAC;oBACrD,IAAI,QAAQ,IAAI,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;wBACnD,UAAU,GAAG,QAAQ,CAAC;oBACxB,CAAC;yBAAM,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,KAAK,UAAU,CAAC,EAAE,EAAE,CAAC;wBACtD,MAAM,IAAI,KAAK,CACb,iCAAiC,SAAS,CAAC,KAAK,+BAA+B,UAAU,CAAC,KAAK,IAAI,UAAU,CAAC,EAAE,6BAA6B,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,KAAK,MAAI,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,EAAE,CAAA,IAAI,kBAAkB,GAAG,CACtM,CAAC;oBACJ,CAAC;oBACD,qEAAqE;oBACrE,sEAAsE;oBACtE,qEAAqE;oBACrE,8BAA8B;oBAC9B,MAAM,EAAC,KAAK,EAAE,MAAM,KAAa,KAAK,EAAb,IAAI,UAAI,KAAK,EAAhC,SAAwB,CAAQ,CAAC;oBACvC,KAAK,GAAG,IAAI,CAAC;gBACf,CAAC;gBAED,IAAI,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;oBAC7C,OAAO,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;gBACvD,CAAC;qBAAM,CAAC;oBACN,OAAO,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,OAAO,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;IAES,eAAe,CAAC,GAAG;QAC3B,oDAAoD;QACpD,oFAAoF;QACpF,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;IACjG,CAAC;IAES,qBAAqB,CAC7B,KAAwB;QAExB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACrB,OAAO,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC;YAC9C,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAES,4BAA4B,CACpC,CAAwB;QAExB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,EAAC,EAAE,EAAE,CAAC,EAAC,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAES,oBAAoB,CAAC,GAAiB;QAC9C,OAAO,EAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAC,CAAC;IACtB,CAAC;CACF","sourcesContent":["import {\n type LiteralUpdateValue,\n type NodeDescriptionValue,\n NodeReferenceValue,\n type PropUpdateValue,\n QueryFactory,\n type SetModification,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n type UpdateNodePropertyValue,\n type UpdatePartial,\n} from './QueryFactory.js';\nimport {getPropertyShapes} from '../shapes/nodeShapeData.js';\nimport type {NodeShapeData, PropertyShapeData} from '../shapes/SHACL.js';\nimport {Shape, type ShapeConstructor} from '../shapes/Shape.js';\nimport {isSubShapeOf, resolveShapeConstructor} from '../utils/ShapeClass.js';\nimport {isExpressionNode, ExpressionNode} from '../expressions/ExpressionNode.js';\nimport {createProxiedPathBuilder} from './ProxiedPathBuilder.js';\nimport {asContextRef} from './QueryContext.js';\nimport {\n assertValid,\n undeclaredPropertyMessage,\n type ValidationMode,\n} from '../shapes/validation.js';\n\nexport type NodeId = {id: string} | string;\n\n/** Options for {@link MutationQueryFactory.describe}. */\nexport interface DescribeOptions {\n /** Create data may carry a top-level `id`; update data may not. */\n allowTopLevelId?: boolean;\n /**\n * Validate the data against the shape before normalizing, throwing a\n * `ShapeValidationError` with every violation. Omit to skip validation\n * (normalization-only, e.g. when the caller has already validated).\n */\n validate?: ValidationMode;\n}\n\nexport class MutationQueryFactory extends QueryFactory {\n /**\n * Normalize raw create/update data into a {@link NodeDescriptionValue} — the\n * IR-free step shared by `toJSON()` and `lower()`. Kept on this base (which\n * imports no IR) so the builders can normalize for serialization without\n * pulling the canonical-IR pipeline.\n *\n * This is also the single validation gate: pass `validate` and the resolved\n * data is checked against the shape first, so `toJSON()`, `lower()` and\n * `exec()` reject exactly the same input. See `shapes/validation`.\n */\n describe(\n shape: NodeShapeData,\n data: unknown,\n options: DescribeOptions = {},\n ): NodeDescriptionValue {\n return this.convertUpdateObject(data as any, shape, options);\n }\n\n /** Normalize delete ids (strings / `{id}`) to `NodeReferenceValue[]` (IR-free). */\n normalizeNodeRefs(ids: NodeId[] | NodeId): NodeReferenceValue[] {\n return this.convertNodeReferences(ids);\n }\n\n protected convertUpdateObject(\n obj,\n shape: NodeShapeData,\n {allowTopLevelId = false, validate}: DescribeOptions = {},\n ): NodeDescriptionValue {\n let resolved;\n if (typeof obj === 'object' && !(obj instanceof Date) && obj !== null) {\n if (!allowTopLevelId && 'id' in obj) {\n throw new Error(\n 'You cannot use id in the top level of an update object',\n );\n }\n resolved = obj;\n } else if (typeof obj === 'function') {\n // A shape authored in a project exists only as metadata, so it has no authored\n // class. `getOrCreateShapeAdapter` derives a constructor from that metadata --\n // which is the documented return leg of the shape round trip (see\n // registerRuntimeShape). Resolving with `getShapeClass` alone made every runtime shape\n // fail here with \"Shape class not found\".\n const shapeClass = shape.id ? resolveShapeConstructor(shape.id) : undefined;\n if (!shapeClass) {\n throw new Error(`Shape class not found for ${shape.id || 'unknown'}`);\n }\n const proxy = createProxiedPathBuilder(shapeClass);\n const result = obj(proxy);\n if (typeof result !== 'object' || result === null) {\n throw new Error('Update function must return an object');\n }\n // Validate what the callback produced, not the callback itself.\n resolved = result;\n } else {\n throw new Error('Invalid update object');\n }\n if (validate) {\n assertValid(shape, resolved, {mode: validate});\n }\n return this.convertNodeDescription(resolved, shape);\n }\n\n protected isSetModification(obj, shape) {\n let hasAdd = obj.add;\n let hasRemove = obj.remove;\n let numKeysExpected = (hasAdd ? 1 : 0) + (hasRemove ? 1 : 0);\n let numKeys = Object.getOwnPropertyNames(obj).length;\n // A set modification is ONLY add/remove keys. Mixing them with other keys\n // (e.g. {add:[…], name:'x'}) must NOT be silently treated as a set mod —\n // that dropped the sibling fields. Require an exact key-count match for\n // both add and remove (mirrors isSetModificationValue).\n return (hasAdd || hasRemove) && numKeysExpected === numKeys;\n }\n\n protected convertSetModification(\n obj: SetModification<any>,\n shape: PropertyShapeData,\n ): SetModificationValue {\n if (!obj.add && !obj.remove) {\n throw new Error('Set modification should have either add or remove key');\n }\n const res: SetModificationValue = {};\n if (obj.add) {\n res.$add = this.convertSetAddValue(obj.add, shape);\n }\n if (obj.remove) {\n res.$remove = this.convertSetRemoveValue(obj.remove, shape);\n }\n return res;\n }\n\n protected convertSetRemoveValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): NodeReferenceValue[] {\n //the user can either pass an array of node references or a single node reference\n //either way we should return an array of node reference values\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertSingleRemoveValue(o, shape));\n } else {\n return [this.convertSingleRemoveValue(obj, shape)];\n }\n }\n\n protected convertSetAddValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): UpdatePartial[] {\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertUpdateValue(o, shape) as UpdatePartial);\n } else {\n return [this.convertUpdateValue(obj, shape) as UpdatePartial];\n }\n }\n\n protected convertSingleRemoveValue(\n value,\n shape: PropertyShapeData,\n ): NodeReferenceValue {\n const ctx = asContextRef(value);\n if (ctx) {\n return ctx as unknown as NodeReferenceValue;\n }\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n throw new Error(\n `Invalid value for ${shape.label}.$remove. Expected an object with an id as key: {id:string}`,\n );\n }\n }\n\n protected convertNodeDescription(\n inputObj: Record<string, unknown>,\n shape: NodeShapeData,\n ): NodeDescriptionValue {\n // Shallow-copy so we never mutate the caller's object\n const obj = {...inputObj};\n const props = getPropertyShapes(shape, true);\n const fields: UpdateNodePropertyValue[] = [];\n let id;\n // `__blank` asks for an anonymous node (a blank node without a type). It has no id by\n // definition, so it cannot be combined with one.\n const blank = obj.__blank === true;\n if ('__blank' in obj) {\n if (obj.__blank !== true) {\n throw new Error(`__blank must be true when given, got ${JSON.stringify(obj.__blank)}`);\n }\n delete obj.__blank;\n if ('__id' in obj || 'id' in obj) {\n throw new Error('A node cannot be both __blank and carry an id (__id or id).');\n }\n }\n if ('__id' in obj) {\n //if the object has a __id key, then we should use that in the result\n id = obj.__id.toString();\n //but we should not include it in the fields\n delete obj.__id;\n } else if ('id' in obj) {\n //if the object has an id key alongside other data properties,\n //treat it as a nested create with a predefined ID\n id = String(obj.id);\n delete obj.id;\n }\n for (var key in obj) {\n let propShape = props.find((p) => p.label === key);\n if (!propShape) {\n // Also reported as an `sh:ClosedConstraintComponent` violation when the\n // caller validates; kept here because normalization cannot build a field\n // without a property shape (`describe()` may run without validation).\n throw Error(undeclaredPropertyMessage(key, shape));\n } else {\n fields.push(this.createNodePropertyValue(obj[key], propShape));\n }\n }\n const res: NodeDescriptionValue = {\n fields,\n shape,\n };\n if (id) {\n res.__id = id;\n }\n if (blank) {\n res.__blank = true;\n }\n\n return res;\n }\n\n protected createNodePropertyValue(\n value,\n propShape: PropertyShapeData,\n ): UpdateNodePropertyValue {\n return {\n prop: propShape,\n val: this.convertUpdateValue(value, propShape),\n } as UpdateNodePropertyValue;\n }\n\n protected convertUpdateValue(\n value,\n propShape?: PropertyShapeData,\n allowArrays: boolean = true,\n ): PropUpdateValue {\n // ExpressionNode → pass through as-is (will be converted to IRExpression by IRMutation)\n if (isExpressionNode(value)) {\n return value as unknown as PropUpdateValue;\n }\n\n // Query-context reference → preserve the live ref (do NOT collapse to {id},\n // which would read an unresolved `.id` as undefined). Handles both an unset\n // PendingQueryContext and a resolved context shape; both serialize as a {@ctx}\n // marker and are resolved — or throw — at lowering time.\n {\n const ctx = asContextRef(value);\n if (ctx) return ctx as unknown as PropUpdateValue;\n }\n\n //single value which will\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value instanceof Date\n ) {\n return value as LiteralUpdateValue;\n }\n\n //if multiple items are given as value of this prop\n if (Array.isArray(value)) {\n if (!allowArrays) {\n throw new Error('Nested arrays are not allowed as values of keys');\n }\n //then convert each value, but disallow nested arrays moving forward\n return value.map((o) => {\n return this.convertUpdateValue(o, propShape, false);\n }) as SinglePropertyUpdateValue[];\n } else if (typeof value === 'undefined') {\n return value;\n } else if (value === null) {\n //unsetting a value with null is also possible. But we pass it as undefined in the query object\n return undefined;\n } else if (typeof value === 'object') {\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n let valueShape: NodeShapeData = null;\n if (propShape.valueShape) {\n const shapeClass = resolveShapeConstructor(propShape.valueShape);\n valueShape = shapeClass?.shape || null;\n if (!valueShape) {\n throw new Error(\n `Shape class not found for ${propShape.valueShape.id}`,\n );\n }\n }\n //pass the value shape of the property as the node shape of this value\n if (!propShape.valueShape) {\n //It's possible to define the shape of the value in the value itself for properties who do not define the shape in their objectProperty\n if (value.shape) {\n if (!value.shape.shape) {\n throw new Error(\n `The value of property \"shape\" is invalid and should be a class that extends Shape.`,\n );\n }\n valueShape = (value.shape as typeof Shape).shape;\n } else {\n //TODO: not sure if this should be an error. Does every @linkedObject need to define the shape of the values?\n // If not, then how do we continue? because currently we use the value shape to look up further property shapes\n throw new Error(\n `Cannot update properties with plain objects if the shape of the values is not known. Make sure get/set ${propShape.parentNodeShape.label}.${propShape.label} defines the 'shape' key in its @objectProperty decorator.`,\n );\n }\n }\n //never keep a shape key in the value object\n if (value.shape) {\n // A value may name its own concrete shape when that is the declared value\n // shape or a subclass of it (a Company under an Organization-typed property).\n const ownShape = (value.shape as typeof Shape).shape;\n if (ownShape && isSubShapeOf(ownShape, valueShape)) {\n valueShape = ownShape;\n } else if (!ownShape || ownShape.id !== valueShape.id) {\n throw new Error(\n `The 'shape' key of a value of ${propShape.label} must be its declared shape ${valueShape.label || valueShape.id} or a subclass of it, got ${ownShape?.label || ownShape?.id || 'an invalid shape'}.`,\n );\n }\n // Drop it from a copy, never from the caller's object: the same data\n // is lowered again after the mutation ran (LiveQueryStore derives the\n // mutation's effects from it), and without its `shape` key the value\n // can no longer be validated.\n const {shape: _shape, ...rest} = value;\n value = rest;\n }\n\n if (this.isSetModification(value, propShape)) {\n return this.convertSetModification(value, propShape);\n } else {\n return this.convertNodeDescription(value, valueShape);\n }\n }\n }\n throw new Error(`Unsupported update value type: ${typeof value}`);\n }\n\n protected isNodeReference(obj): obj is NodeReferenceValue {\n //check if obj is an object with only an id property\n //if additional data properties are present, it's a nested create with predefined ID\n return typeof obj === 'object' && obj !== null && 'id' in obj && Object.keys(obj).length === 1;\n }\n\n protected convertNodeReferences(\n input: NodeId[] | NodeId,\n ): NodeReferenceValue[] {\n if (Array.isArray(input)) {\n return input.map((o) => {\n return this.convertNodeReferenceOrString(o);\n });\n } else {\n return [this.convertNodeReferenceOrString(input)];\n }\n }\n\n protected convertNodeReferenceOrString(\n o: {id: string} | string,\n ): NodeReferenceValue {\n if (typeof o === 'string') {\n return {id: o};\n } else if (this.isNodeReference(o)) {\n return this.convertNodeReference(o);\n } else {\n throw new Error(`Invalid node reference: ${JSON.stringify(o)}`);\n }\n }\n\n protected convertNodeReference(obj: {id: string}): NodeReferenceValue {\n return {id: obj.id};\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MutationQuery.js","sourceRoot":"","sources":["../../../src/queries/MutationQuery.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type LiteralUpdateValue,\n type NodeDescriptionValue,\n NodeReferenceValue,\n type PropUpdateValue,\n QueryFactory,\n type SetModification,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n type UpdateNodePropertyValue,\n type UpdatePartial,\n} from './QueryFactory.js';\nimport {getPropertyShapes} from '../shapes/nodeShapeData.js';\nimport type {NodeShapeData, PropertyShapeData} from '../shapes/SHACL.js';\nimport {Shape, type ShapeConstructor} from '../shapes/Shape.js';\nimport {isSubShapeOf, resolveShapeConstructor} from '../utils/ShapeClass.js';\nimport {isExpressionNode, ExpressionNode} from '../expressions/ExpressionNode.js';\nimport {createProxiedPathBuilder} from './ProxiedPathBuilder.js';\nimport {asContextRef} from './QueryContext.js';\nimport {\n assertValid,\n undeclaredPropertyMessage,\n type ValidationMode,\n} from '../shapes/validation.js';\n\nexport type NodeId = {id: string} | string;\n\n/** Options for {@link MutationQueryFactory.describe}. */\nexport interface DescribeOptions {\n /** Create data may carry a top-level `id`; update data may not. */\n allowTopLevelId?: boolean;\n /**\n * Validate the data against the shape before normalizing, throwing a\n * `ShapeValidationError` with every violation. Omit to skip validation\n * (normalization-only, e.g. when the caller has already validated).\n */\n validate?: ValidationMode;\n}\n\nexport class MutationQueryFactory extends QueryFactory {\n /**\n * Normalize raw create/update data into a {@link NodeDescriptionValue} — the\n * IR-free step shared by `toJSON()` and `lower()`. Kept on this base (which\n * imports no IR) so the builders can normalize for serialization without\n * pulling the canonical-IR pipeline.\n *\n * This is also the single validation gate: pass `validate` and the resolved\n * data is checked against the shape first, so `toJSON()`, `lower()` and\n * `exec()` reject exactly the same input. See `shapes/validation`.\n */\n describe(\n shape: NodeShapeData,\n data: unknown,\n options: DescribeOptions = {},\n ): NodeDescriptionValue {\n return this.convertUpdateObject(data as any, shape, options);\n }\n\n /** Normalize delete ids (strings / `{id}`) to `NodeReferenceValue[]` (IR-free). */\n normalizeNodeRefs(ids: NodeId[] | NodeId): NodeReferenceValue[] {\n return this.convertNodeReferences(ids);\n }\n\n protected convertUpdateObject(\n obj,\n shape: NodeShapeData,\n {allowTopLevelId = false, validate}: DescribeOptions = {},\n ): NodeDescriptionValue {\n let resolved;\n if (typeof obj === 'object' && !(obj instanceof Date) && obj !== null) {\n if (!allowTopLevelId && 'id' in obj) {\n throw new Error(\n 'You cannot use id in the top level of an update object',\n );\n }\n resolved = obj;\n } else if (typeof obj === 'function') {\n // A shape authored in a project exists only as metadata, so it has no authored\n // class. `getOrCreateShapeAdapter` derives a constructor from that metadata --\n // which is the documented return leg of the shape round trip (see\n // registerRuntimeShape). Resolving with `getShapeClass` alone made every runtime shape\n // fail here with \"Shape class not found\".\n const shapeClass = shape.id ? resolveShapeConstructor(shape.id) : undefined;\n if (!shapeClass) {\n throw new Error(`Shape class not found for ${shape.id || 'unknown'}`);\n }\n const proxy = createProxiedPathBuilder(shapeClass);\n const result = obj(proxy);\n if (typeof result !== 'object' || result === null) {\n throw new Error('Update function must return an object');\n }\n // Validate what the callback produced, not the callback itself.\n resolved = result;\n } else {\n throw new Error('Invalid update object');\n }\n if (validate) {\n assertValid(shape, resolved, {mode: validate});\n }\n return this.convertNodeDescription(resolved, shape);\n }\n\n protected isSetModification(obj, shape) {\n let hasAdd = obj.add;\n let hasRemove = obj.remove;\n let numKeysExpected = (hasAdd ? 1 : 0) + (hasRemove ? 1 : 0);\n let numKeys = Object.getOwnPropertyNames(obj).length;\n // A set modification is ONLY add/remove keys. Mixing them with other keys\n // (e.g. {add:[…], name:'x'}) must NOT be silently treated as a set mod —\n // that dropped the sibling fields. Require an exact key-count match for\n // both add and remove (mirrors isSetModificationValue).\n return (hasAdd || hasRemove) && numKeysExpected === numKeys;\n }\n\n protected convertSetModification(\n obj: SetModification<any>,\n shape: PropertyShapeData,\n ): SetModificationValue {\n if (!obj.add && !obj.remove) {\n throw new Error('Set modification should have either add or remove key');\n }\n const res: SetModificationValue = {};\n if (obj.add) {\n res.$add = this.convertSetAddValue(obj.add, shape);\n }\n if (obj.remove) {\n res.$remove = this.convertSetRemoveValue(obj.remove, shape);\n }\n return res;\n }\n\n protected convertSetRemoveValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): NodeReferenceValue[] {\n //the user can either pass an array of node references or a single node reference\n //either way we should return an array of node reference values\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertSingleRemoveValue(o, shape));\n } else {\n return [this.convertSingleRemoveValue(obj, shape)];\n }\n }\n\n protected convertSetAddValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): UpdatePartial[] {\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertUpdateValue(o, shape) as UpdatePartial);\n } else {\n return [this.convertUpdateValue(obj, shape) as UpdatePartial];\n }\n }\n\n protected convertSingleRemoveValue(\n value,\n shape: PropertyShapeData,\n ): NodeReferenceValue {\n const ctx = asContextRef(value);\n if (ctx) {\n return ctx as unknown as NodeReferenceValue;\n }\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n throw new Error(\n `Invalid value for ${shape.label}.$remove. Expected an object with an id as key: {id:string}`,\n );\n }\n }\n\n protected convertNodeDescription(\n inputObj: Record<string, unknown>,\n shape: NodeShapeData,\n ): NodeDescriptionValue {\n // Shallow-copy so we never mutate the caller's object\n const obj = {...inputObj};\n const props = getPropertyShapes(shape, true);\n const fields: UpdateNodePropertyValue[] = [];\n let id;\n if ('__id' in obj) {\n //if the object has a __id key, then we should use that in the result\n id = obj.__id.toString();\n //but we should not include it in the fields\n delete obj.__id;\n } else if ('id' in obj) {\n //if the object has an id key alongside other data properties,\n //treat it as a nested create with a predefined ID\n id = String(obj.id);\n delete obj.id;\n }\n for (var key in obj) {\n let propShape = props.find((p) => p.label === key);\n if (!propShape) {\n // Also reported as an `sh:ClosedConstraintComponent` violation when the\n // caller validates; kept here because normalization cannot build a field\n // without a property shape (`describe()` may run without validation).\n throw Error(undeclaredPropertyMessage(key, shape));\n } else {\n fields.push(this.createNodePropertyValue(obj[key], propShape));\n }\n }\n const res: NodeDescriptionValue = {\n fields,\n shape,\n };\n if (id) {\n res.__id = id;\n }\n\n return res;\n }\n\n protected createNodePropertyValue(\n value,\n propShape: PropertyShapeData,\n ): UpdateNodePropertyValue {\n return {\n prop: propShape,\n val: this.convertUpdateValue(value, propShape),\n } as UpdateNodePropertyValue;\n }\n\n protected convertUpdateValue(\n value,\n propShape?: PropertyShapeData,\n allowArrays: boolean = true,\n ): PropUpdateValue {\n // ExpressionNode → pass through as-is (will be converted to IRExpression by IRMutation)\n if (isExpressionNode(value)) {\n return value as unknown as PropUpdateValue;\n }\n\n // Query-context reference → preserve the live ref (do NOT collapse to {id},\n // which would read an unresolved `.id` as undefined). Handles both an unset\n // PendingQueryContext and a resolved context shape; both serialize as a {@ctx}\n // marker and are resolved — or throw — at lowering time.\n {\n const ctx = asContextRef(value);\n if (ctx) return ctx as unknown as PropUpdateValue;\n }\n\n //single value which will\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value instanceof Date\n ) {\n return value as LiteralUpdateValue;\n }\n\n //if multiple items are given as value of this prop\n if (Array.isArray(value)) {\n if (!allowArrays) {\n throw new Error('Nested arrays are not allowed as values of keys');\n }\n //then convert each value, but disallow nested arrays moving forward\n return value.map((o) => {\n return this.convertUpdateValue(o, propShape, false);\n }) as SinglePropertyUpdateValue[];\n } else if (typeof value === 'undefined') {\n return value;\n } else if (value === null) {\n //unsetting a value with null is also possible. But we pass it as undefined in the query object\n return undefined;\n } else if (typeof value === 'object') {\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n let valueShape: NodeShapeData = null;\n if (propShape.valueShape) {\n const shapeClass = resolveShapeConstructor(propShape.valueShape);\n valueShape = shapeClass?.shape || null;\n if (!valueShape) {\n throw new Error(\n `Shape class not found for ${propShape.valueShape.id}`,\n );\n }\n }\n //pass the value shape of the property as the node shape of this value\n if (!propShape.valueShape) {\n //It's possible to define the shape of the value in the value itself for properties who do not define the shape in their objectProperty\n if (value.shape) {\n if (!value.shape.shape) {\n throw new Error(\n `The value of property \"shape\" is invalid and should be a class that extends Shape.`,\n );\n }\n valueShape = (value.shape as typeof Shape).shape;\n } else {\n //TODO: not sure if this should be an error. Does every @linkedObject need to define the shape of the values?\n // If not, then how do we continue? because currently we use the value shape to look up further property shapes\n throw new Error(\n `Cannot update properties with plain objects if the shape of the values is not known. Make sure get/set ${propShape.parentNodeShape.label}.${propShape.label} defines the 'shape' key in its @objectProperty decorator.`,\n );\n }\n }\n //never keep a shape key in the value object\n if (value.shape) {\n // A value may name its own concrete shape when that is the declared value\n // shape or a subclass of it (a Company under an Organization-typed property).\n const ownShape = (value.shape as typeof Shape).shape;\n if (ownShape && isSubShapeOf(ownShape, valueShape)) {\n valueShape = ownShape;\n } else if (!ownShape || ownShape.id !== valueShape.id) {\n throw new Error(\n `The 'shape' key of a value of ${propShape.label} must be its declared shape ${valueShape.label || valueShape.id} or a subclass of it, got ${ownShape?.label || ownShape?.id || 'an invalid shape'}.`,\n );\n }\n // Drop it from a copy, never from the caller's object: the same data\n // is lowered again after the mutation ran (LiveQueryStore derives the\n // mutation's effects from it), and without its `shape` key the value\n // can no longer be validated.\n const {shape: _shape, ...rest} = value;\n value = rest;\n }\n\n if (this.isSetModification(value, propShape)) {\n return this.convertSetModification(value, propShape);\n } else {\n return this.convertNodeDescription(value, valueShape);\n }\n }\n }\n throw new Error(`Unsupported update value type: ${typeof value}`);\n }\n\n protected isNodeReference(obj): obj is NodeReferenceValue {\n //check if obj is an object with only an id property\n //if additional data properties are present, it's a nested create with predefined ID\n return typeof obj === 'object' && obj !== null && 'id' in obj && Object.keys(obj).length === 1;\n }\n\n protected convertNodeReferences(\n input: NodeId[] | NodeId,\n ): NodeReferenceValue[] {\n if (Array.isArray(input)) {\n return input.map((o) => {\n return this.convertNodeReferenceOrString(o);\n });\n } else {\n return [this.convertNodeReferenceOrString(input)];\n }\n }\n\n protected convertNodeReferenceOrString(\n o: {id: string} | string,\n ): NodeReferenceValue {\n if (typeof o === 'string') {\n return {id: o};\n } else if (this.isNodeReference(o)) {\n return this.convertNodeReference(o);\n } else {\n throw new Error(`Invalid node reference: ${JSON.stringify(o)}`);\n }\n }\n\n protected convertNodeReference(obj: {id: string}): NodeReferenceValue {\n return {id: obj.id};\n }\n}\n"]}
|
|
@@ -41,11 +41,12 @@ export type MutationValueJSON = string | number | boolean | null | {
|
|
|
41
41
|
'@unset': true;
|
|
42
42
|
} | MutationNodeDataJSON | DslJsonValue;
|
|
43
43
|
/**
|
|
44
|
-
* A node description in **path-keyed** form: `label → value`, plus
|
|
45
|
-
* keys — `__id` (a fixed/predefined id)
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
44
|
+
* A node description in **path-keyed** form: `label → value`, plus two reserved
|
|
45
|
+
* keys — `__id` (a fixed/predefined id) and `__shape` (the concrete shape IRI,
|
|
46
|
+
* emitted only when it differs from the shape inferred from context, e.g. a
|
|
47
|
+
* subclass instance under a superclass-typed relation). Whether a nested node is
|
|
48
|
+
* written as a blank node is not on the wire: the lowering decides it from the
|
|
49
|
+
* property's `sh:nodeKind`.
|
|
49
50
|
*/
|
|
50
51
|
export type MutationNodeDataJSON = {
|
|
51
52
|
[key: string]: MutationValueJSON | undefined;
|
|
@@ -29,8 +29,6 @@ import { encodeValueExpr, decodeValueExpr, } from './DslJsonExpression.js';
|
|
|
29
29
|
/** Reserved node-data keys (not property labels). */
|
|
30
30
|
const NODE_ID_KEY = '__id';
|
|
31
31
|
const NODE_SHAPE_KEY = '__shape';
|
|
32
|
-
/** Marks a nested node written as a blank node (`NodeDescriptionValue.__blank`). */
|
|
33
|
-
const NODE_BLANK_KEY = '__blank';
|
|
34
32
|
// =============================================================================
|
|
35
33
|
// Value codec
|
|
36
34
|
// =============================================================================
|
|
@@ -97,8 +95,6 @@ export function encodeNodeData(desc, expectedShape) {
|
|
|
97
95
|
const json = {};
|
|
98
96
|
if (desc.__id)
|
|
99
97
|
json[NODE_ID_KEY] = desc.__id;
|
|
100
|
-
if (desc.__blank)
|
|
101
|
-
json[NODE_BLANK_KEY] = true;
|
|
102
98
|
if (!expectedShape || desc.shape.id !== expectedShape.id) {
|
|
103
99
|
json[NODE_SHAPE_KEY] = desc.shape.id;
|
|
104
100
|
}
|
|
@@ -217,12 +213,8 @@ export function decodeNodeDataToRaw(json, shape) {
|
|
|
217
213
|
const obj = {};
|
|
218
214
|
if (typeof json[NODE_ID_KEY] === 'string')
|
|
219
215
|
obj.id = json[NODE_ID_KEY];
|
|
220
|
-
if (json[NODE_BLANK_KEY] === true)
|
|
221
|
-
obj.__blank = true;
|
|
222
216
|
for (const [key, val] of Object.entries(json)) {
|
|
223
|
-
if (key === NODE_ID_KEY || key === NODE_SHAPE_KEY ||
|
|
224
|
-
continue;
|
|
225
|
-
if (val === undefined)
|
|
217
|
+
if (key === NODE_ID_KEY || key === NODE_SHAPE_KEY || val === undefined)
|
|
226
218
|
continue;
|
|
227
219
|
// Skip prototype-polluting keys from untrusted DSL-JSON input.
|
|
228
220
|
if (key === '__proto__' || key === 'constructor' || key === 'prototype')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MutationSerialization.js","sourceRoot":"","sources":["../../../src/queries/MutationSerialization.ts"],"names":[],"mappings":"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","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\n/**\n * Lossless JSON (de)serialization for mutations (create / update / delete) — the\n * **IR-free wire codec**. The companion IR side (`decodeNodeData` / `lowerMutationJSON`)\n * lives in `lowerMutationJSON.ts` so this module never pulls the canonical-IR pipeline.\n *\n * The serialization unit is the normalized `NodeDescriptionValue` produced by the\n * IR-free factory base (`MutationQueryFactory.describe()`) — i.e. after `.set()` and\n * after any update-expression callback has been evaluated, but before canonical IR.\n * Property keys are serialized as **labels** (shape-relative, lightweight); decoding\n * resolves them back via the registered shape.\n *\n * Values use the DSL-JSON grammar (documentation/dsl-json.md): a bare scalar is a\n * literal; objects tag the kinds `JSON.stringify` can't represent natively\n * (`{@date}`, `{@id}`, `{@ctx}`, `{@list}`, `{@add,@remove}`, `{@unset}`); and a\n * computed value is an S-expr array via the shared `DslJsonExpression` codec —\n * so the wire carries no IR.\n */\nimport {\n type NodeDescriptionValue,\n type NodeReferenceValue,\n type PropUpdateValue,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n isSetModificationValue,\n} from './QueryFactory.js';\nimport {getPropertyShape} from '../shapes/nodeShapeData.js';\nimport {ExpressionNode, isExpressionNode} from '../expressions/ExpressionNode.js';\nimport type {WherePathJSON} from './QueryBuilderSerialization.js';\nimport type {ContextRefJSON} from './ContextRef.js';\nimport {PendingQueryContext} from './QueryContext.js';\nimport {getShapeClass, resolveShapeConstructor} from '../utils/ShapeClass.js';\nimport type {ShapeConstructor} from '../shapes/Shape.js';\nimport type {NodeShapeData, PropertyShapeData} from '../shapes/SHACL.js';\nimport {\n encodeValueExpr,\n decodeValueExpr,\n type DslJsonValue,\n} from './DslJsonExpression.js';\n\n// =============================================================================\n// JSON types\n// =============================================================================\n\n/**\n * A mutation field value in the DSL-JSON grammar. A bare scalar is a literal; objects\n * tag the non-JSON-native kinds (`@`-sigiled); a computed value is an S-expr array (no IR); a\n * nested-node create is a bare path-keyed object ({@link MutationNodeDataJSON}),\n * disambiguated from the tagged forms by having no reserved value-key.\n */\nexport type MutationValueJSON =\n | string\n | number\n | boolean\n | null\n | {'@date': string}\n | {'@id': string}\n | {'@ctx': string}\n | {'@list': MutationValueJSON[]}\n | {'@add'?: MutationValueJSON[]; '@remove'?: string[]}\n | {'@unset': true}\n | MutationNodeDataJSON // nested-node create (bare, path-keyed)\n | DslJsonValue; // computed expression (S-expr) / {@path}\n\n/**\n * A node description in **path-keyed** form: `label → value`, plus three reserved\n * keys — `__id` (a fixed/predefined id), `__blank` (`true`: a nested node written as\n * a blank node) and `__shape` (the concrete shape IRI, emitted only when it differs\n * from the shape inferred from context, e.g. a subclass instance under a\n * superclass-typed relation).\n */\nexport type MutationNodeDataJSON = {\n [key: string]: MutationValueJSON | undefined;\n};\n\n/** Reserved node-data keys (not property labels). */\nconst NODE_ID_KEY = '__id';\nconst NODE_SHAPE_KEY = '__shape';\n/** Marks a nested node written as a blank node (`NodeDescriptionValue.__blank`). */\nconst NODE_BLANK_KEY = '__blank';\n\nexport type CreateMutationJSON = {\n v?: string;\n op: 'create';\n shape: string;\n data: MutationNodeDataJSON;\n};\n\nexport type UpdateMutationJSON = {\n v?: string;\n op: 'update';\n shape: string;\n mode: 'for' | 'forAll' | 'where';\n /** A node id, or a `{@ctx: name}` context reference resolved at lowering. */\n targetId?: string | ContextRefJSON;\n where?: WherePathJSON;\n data: MutationNodeDataJSON;\n};\n\n/**\n * Create-or-replace against a known id.\n *\n * A distinct `op` rather than `op: 'update'` with a new `mode`. An unaware consumer that\n * received `{op: 'update', mode: 'upsert'}` would fall past its `mode === 'for'` and\n * `mode === 'where'` branches into the update-where path with no where clause — an update\n * applied to *every instance of the shape*. A distinct op instead hits `fromJSON`'s\n * existing `default:` and throws \"Unknown query op\": loud, and safe.\n */\nexport type UpsertMutationJSON = {\n v?: string;\n op: 'upsert';\n shape: string;\n /** Upsert targets one known id; there is no `forAll`/`where` form. */\n mode: 'for';\n /** A node id, or a `{@ctx: name}` context reference resolved at lowering. */\n targetId?: string | ContextRefJSON;\n data: MutationNodeDataJSON;\n};\n\nexport type DeleteMutationJSON =\n | {v?: string; op: 'delete'; shape: string; mode: 'ids'; ids: (string | ContextRefJSON)[]}\n | {v?: string; op: 'delete'; shape: string; mode: 'all'}\n | {v?: string; op: 'delete'; shape: string; mode: 'where'; where: WherePathJSON};\n\nexport type MutationJSON =\n | CreateMutationJSON\n | UpdateMutationJSON\n | UpsertMutationJSON\n | DeleteMutationJSON;\n\n// =============================================================================\n// Value codec\n// =============================================================================\n\n/** The shape a nested node is expected to have (a property's value shape), if resolvable. */\nexport function valueShapeOf(prop?: PropertyShapeData): NodeShapeData | undefined {\n const id = (prop as unknown as {valueShape?: {id: string}})?.valueShape?.id;\n return id ? getShapeClass(id)?.shape : undefined;\n}\n\n/** Encode a single (non-array, non-setMod) property value. `prop` gives the nested-node shape. */\nfunction encodeSingleValue(\n value: SinglePropertyUpdateValue,\n prop?: PropertyShapeData,\n): MutationValueJSON {\n if (value === undefined) return {'@unset': true};\n if (isExpressionNode(value)) {\n // A computed value is an S-expr (or {@path}) via the shared codec — no IR.\n return encodeValueExpr(value.ir, value._refs) as MutationValueJSON;\n }\n if (value instanceof Date) return {'@date': value.toISOString()};\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n if (value && typeof value === 'object') {\n // Query-context reference — carry the name, resolve at lowering (checked\n // before the generic `.id` branch since a PendingQueryContext has an `.id` getter).\n if (value instanceof PendingQueryContext) {\n return {'@ctx': value.contextName};\n }\n if ('fields' in value) {\n // Nested-node create — bare path-keyed; expected shape = the relation's value shape.\n return encodeNodeData(value as NodeDescriptionValue, valueShapeOf(prop));\n }\n if ('id' in value) return {'@id': (value as NodeReferenceValue).id};\n }\n throw new Error(`Cannot serialize mutation value: ${JSON.stringify(value)}`);\n}\n\n/** Encode any property value, including arrays and set modifications. */\nexport function encodeValue(\n value: PropUpdateValue,\n prop?: PropertyShapeData,\n): MutationValueJSON {\n if (value === undefined) return {'@unset': true};\n if (Array.isArray(value)) {\n return {'@list': value.map((v) => encodeSingleValue(v, prop))};\n }\n if (isSetModificationValue(value)) {\n const mod = value as SetModificationValue;\n const json: {'@add'?: MutationValueJSON[]; '@remove'?: string[]} = {};\n if (mod.$add) json['@add'] = mod.$add.map((v) => encodeValue(v as PropUpdateValue, prop));\n if (mod.$remove) json['@remove'] = mod.$remove.map((r) => r.id);\n return json;\n }\n return encodeSingleValue(value as SinglePropertyUpdateValue, prop);\n}\n\n/**\n * Encode a normalized node description to path-keyed form. `expectedShape` is the\n * shape inferable from context (the envelope, or the parent relation's value shape);\n * `__shape` is emitted only when the concrete shape differs (a subclass instance).\n */\nexport function encodeNodeData(\n desc: NodeDescriptionValue,\n expectedShape?: NodeShapeData,\n): MutationNodeDataJSON {\n const json: MutationNodeDataJSON = {};\n if (desc.__id) json[NODE_ID_KEY] = desc.__id;\n if (desc.__blank) json[NODE_BLANK_KEY] = true;\n if (!expectedShape || desc.shape.id !== expectedShape.id) {\n json[NODE_SHAPE_KEY] = desc.shape.id;\n }\n for (const f of desc.fields) {\n json[f.prop.label] = encodeValue(f.val, f.prop);\n }\n return json;\n}\n\n// =============================================================================\n// JSON → raw UpdatePartial (for builder rehydration / fromJSON)\n// =============================================================================\n\n// Bound the DSL-JSON decode recursion (rehydration path) against a deeply-nested\n// payload exhausting the stack. Mirrors the cap in lowerMutationJSON.\nconst MAX_DECODE_DEPTH = 128;\nlet _decodeDepth = 0;\n\n/**\n * Decode a DSL-JSON value back to a raw DSL value (the form `.set()` accepts).\n * `currentShape` resolves computed `{@path}`/S-expr; `prop` gives a nested node's shape.\n * Depth-guarded wrapper around {@link decodeValueToRawInner}.\n */\nfunction decodeValueToRaw(\n json: MutationValueJSON,\n currentShape: NodeShapeData | undefined,\n prop?: PropertyShapeData,\n): unknown {\n if (++_decodeDepth > MAX_DECODE_DEPTH) {\n _decodeDepth = 0;\n throw new Error('DSL-JSON value nested too deeply');\n }\n try {\n return decodeValueToRawInner(json, currentShape, prop);\n } finally {\n _decodeDepth--;\n }\n}\n\nfunction decodeValueToRawInner(\n json: MutationValueJSON,\n currentShape: NodeShapeData | undefined,\n prop?: PropertyShapeData,\n): unknown {\n // S-expr computed value\n if (Array.isArray(json)) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, requireShapeForExpr(currentShape));\n return new ExpressionNode(ir, refs);\n }\n if (json === null) return null;\n if (typeof json !== 'object') return json; // bare scalar literal\n const o = json as Record<string, unknown>;\n if ('@unset' in o) return undefined;\n if ('@date' in o) return new Date(o['@date'] as string);\n // Rehydration path: preserve the live reference so it re-serializes as a\n // `{@ctx}` marker and resolves at the rebuilt builder's own lowering.\n if ('@ctx' in o) return new PendingQueryContext(o['@ctx'] as string);\n if ('@id' in o) return {id: o['@id']};\n if ('@list' in o) {\n return (o['@list'] as MutationValueJSON[]).map((i) => decodeValueToRaw(i, currentShape, prop));\n }\n if ('@add' in o || '@remove' in o) {\n // Raw DSL set-modifications use `@add`/`@remove` on the wire.\n const mod: {add?: unknown[]; remove?: {id: string}[]} = {};\n if (o['@add']) mod.add = (o['@add'] as MutationValueJSON[]).map((i) => decodeValueToRaw(i, currentShape, prop));\n if (o['@remove']) mod.remove = (o['@remove'] as string[]).map((id) => ({id}));\n return mod;\n }\n // A computed-path value (`{@path}`) used as a value.\n if ('@path' in o) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, requireShapeForExpr(currentShape));\n return new ExpressionNode(ir, refs);\n }\n // Otherwise: a bare path-keyed nested-node create.\n return decodeNestedNodeDataToRaw(o as MutationNodeDataJSON, valueShapeOf(prop) ?? currentShape);\n}\n\n/**\n * Decode a nested node and, when it names its concrete shape (`__shape`), carry that\n * shape as the reserved `shape` key `.set()` accepts on a nested value. Without it the\n * builders validate and lower the value against the property's declared value shape —\n * or none, for a polymorphic slot like `PropertyShape.path` — and reject the fields\n * only the concrete shape has.\n */\n/**\n * The class for a node's `__shape`. Either registry — a project-authored shape exists only\n * as metadata. Throws like `lowerMutationJSON` does, so both decode paths reject an\n * unregistered shape instead of one of them silently validating against another.\n */\nfunction requireNodeShapeClass(shapeId: string): ShapeConstructor {\n const shapeClass = resolveShapeConstructor(shapeId);\n if (!shapeClass) {\n throw new Error(\n `Shape '${shapeId}' is not registered. The receiving side must have the shape registered to decode mutation DSL-JSON.`,\n );\n }\n return shapeClass;\n}\n\nfunction decodeNestedNodeDataToRaw(\n json: MutationNodeDataJSON,\n shape: NodeShapeData | undefined,\n): Record<string, unknown> {\n const obj = decodeNodeDataToRaw(json, shape);\n const shapeId = json[NODE_SHAPE_KEY];\n if (typeof shapeId === 'string') obj.shape = requireNodeShapeClass(shapeId);\n return obj;\n}\n\nfunction requireShapeForExpr(shape: NodeShapeData | undefined): NodeShapeData {\n if (!shape) {\n throw new Error('A shape is required to decode a computed mutation value');\n }\n return shape;\n}\n\n/**\n * Decode path-keyed node data into a raw object the mutation builders' `.set()` accepts.\n * `__id` becomes `id`; `__shape` (if present) overrides the inferred `shape`. Mirrors\n * {@link encodeNodeData}.\n */\nexport function decodeNodeDataToRaw(\n json: MutationNodeDataJSON,\n shape?: NodeShapeData,\n): Record<string, unknown> {\n const nodeShape =\n typeof json[NODE_SHAPE_KEY] === 'string'\n ? requireNodeShapeClass(json[NODE_SHAPE_KEY] as string).shape\n : shape;\n const obj: Record<string, unknown> = {};\n if (typeof json[NODE_ID_KEY] === 'string') obj.id = json[NODE_ID_KEY];\n if (json[NODE_BLANK_KEY] === true) obj.__blank = true;\n for (const [key, val] of Object.entries(json)) {\n if (key === NODE_ID_KEY || key === NODE_SHAPE_KEY || key === NODE_BLANK_KEY) continue;\n if (val === undefined) continue;\n // Skip prototype-polluting keys from untrusted DSL-JSON input.\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;\n const prop = nodeShape ? getPropertyShape(nodeShape, key) : undefined;\n obj[key] = decodeValueToRaw(val as MutationValueJSON, nodeShape, prop);\n }\n return obj;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MutationSerialization.js","sourceRoot":"","sources":["../../../src/queries/MutationSerialization.ts"],"names":[],"mappings":"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","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\n/**\n * Lossless JSON (de)serialization for mutations (create / update / delete) — the\n * **IR-free wire codec**. The companion IR side (`decodeNodeData` / `lowerMutationJSON`)\n * lives in `lowerMutationJSON.ts` so this module never pulls the canonical-IR pipeline.\n *\n * The serialization unit is the normalized `NodeDescriptionValue` produced by the\n * IR-free factory base (`MutationQueryFactory.describe()`) — i.e. after `.set()` and\n * after any update-expression callback has been evaluated, but before canonical IR.\n * Property keys are serialized as **labels** (shape-relative, lightweight); decoding\n * resolves them back via the registered shape.\n *\n * Values use the DSL-JSON grammar (documentation/dsl-json.md): a bare scalar is a\n * literal; objects tag the kinds `JSON.stringify` can't represent natively\n * (`{@date}`, `{@id}`, `{@ctx}`, `{@list}`, `{@add,@remove}`, `{@unset}`); and a\n * computed value is an S-expr array via the shared `DslJsonExpression` codec —\n * so the wire carries no IR.\n */\nimport {\n type NodeDescriptionValue,\n type NodeReferenceValue,\n type PropUpdateValue,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n isSetModificationValue,\n} from './QueryFactory.js';\nimport {getPropertyShape} from '../shapes/nodeShapeData.js';\nimport {ExpressionNode, isExpressionNode} from '../expressions/ExpressionNode.js';\nimport type {WherePathJSON} from './QueryBuilderSerialization.js';\nimport type {ContextRefJSON} from './ContextRef.js';\nimport {PendingQueryContext} from './QueryContext.js';\nimport {getShapeClass, resolveShapeConstructor} from '../utils/ShapeClass.js';\nimport type {ShapeConstructor} from '../shapes/Shape.js';\nimport type {NodeShapeData, PropertyShapeData} from '../shapes/SHACL.js';\nimport {\n encodeValueExpr,\n decodeValueExpr,\n type DslJsonValue,\n} from './DslJsonExpression.js';\n\n// =============================================================================\n// JSON types\n// =============================================================================\n\n/**\n * A mutation field value in the DSL-JSON grammar. A bare scalar is a literal; objects\n * tag the non-JSON-native kinds (`@`-sigiled); a computed value is an S-expr array (no IR); a\n * nested-node create is a bare path-keyed object ({@link MutationNodeDataJSON}),\n * disambiguated from the tagged forms by having no reserved value-key.\n */\nexport type MutationValueJSON =\n | string\n | number\n | boolean\n | null\n | {'@date': string}\n | {'@id': string}\n | {'@ctx': string}\n | {'@list': MutationValueJSON[]}\n | {'@add'?: MutationValueJSON[]; '@remove'?: string[]}\n | {'@unset': true}\n | MutationNodeDataJSON // nested-node create (bare, path-keyed)\n | DslJsonValue; // computed expression (S-expr) / {@path}\n\n/**\n * A node description in **path-keyed** form: `label → value`, plus two reserved\n * keys — `__id` (a fixed/predefined id) and `__shape` (the concrete shape IRI,\n * emitted only when it differs from the shape inferred from context, e.g. a\n * subclass instance under a superclass-typed relation). Whether a nested node is\n * written as a blank node is not on the wire: the lowering decides it from the\n * property's `sh:nodeKind`.\n */\nexport type MutationNodeDataJSON = {\n [key: string]: MutationValueJSON | undefined;\n};\n\n/** Reserved node-data keys (not property labels). */\nconst NODE_ID_KEY = '__id';\nconst NODE_SHAPE_KEY = '__shape';\n\nexport type CreateMutationJSON = {\n v?: string;\n op: 'create';\n shape: string;\n data: MutationNodeDataJSON;\n};\n\nexport type UpdateMutationJSON = {\n v?: string;\n op: 'update';\n shape: string;\n mode: 'for' | 'forAll' | 'where';\n /** A node id, or a `{@ctx: name}` context reference resolved at lowering. */\n targetId?: string | ContextRefJSON;\n where?: WherePathJSON;\n data: MutationNodeDataJSON;\n};\n\n/**\n * Create-or-replace against a known id.\n *\n * A distinct `op` rather than `op: 'update'` with a new `mode`. An unaware consumer that\n * received `{op: 'update', mode: 'upsert'}` would fall past its `mode === 'for'` and\n * `mode === 'where'` branches into the update-where path with no where clause — an update\n * applied to *every instance of the shape*. A distinct op instead hits `fromJSON`'s\n * existing `default:` and throws \"Unknown query op\": loud, and safe.\n */\nexport type UpsertMutationJSON = {\n v?: string;\n op: 'upsert';\n shape: string;\n /** Upsert targets one known id; there is no `forAll`/`where` form. */\n mode: 'for';\n /** A node id, or a `{@ctx: name}` context reference resolved at lowering. */\n targetId?: string | ContextRefJSON;\n data: MutationNodeDataJSON;\n};\n\nexport type DeleteMutationJSON =\n | {v?: string; op: 'delete'; shape: string; mode: 'ids'; ids: (string | ContextRefJSON)[]}\n | {v?: string; op: 'delete'; shape: string; mode: 'all'}\n | {v?: string; op: 'delete'; shape: string; mode: 'where'; where: WherePathJSON};\n\nexport type MutationJSON =\n | CreateMutationJSON\n | UpdateMutationJSON\n | UpsertMutationJSON\n | DeleteMutationJSON;\n\n// =============================================================================\n// Value codec\n// =============================================================================\n\n/** The shape a nested node is expected to have (a property's value shape), if resolvable. */\nexport function valueShapeOf(prop?: PropertyShapeData): NodeShapeData | undefined {\n const id = (prop as unknown as {valueShape?: {id: string}})?.valueShape?.id;\n return id ? getShapeClass(id)?.shape : undefined;\n}\n\n/** Encode a single (non-array, non-setMod) property value. `prop` gives the nested-node shape. */\nfunction encodeSingleValue(\n value: SinglePropertyUpdateValue,\n prop?: PropertyShapeData,\n): MutationValueJSON {\n if (value === undefined) return {'@unset': true};\n if (isExpressionNode(value)) {\n // A computed value is an S-expr (or {@path}) via the shared codec — no IR.\n return encodeValueExpr(value.ir, value._refs) as MutationValueJSON;\n }\n if (value instanceof Date) return {'@date': value.toISOString()};\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n if (value && typeof value === 'object') {\n // Query-context reference — carry the name, resolve at lowering (checked\n // before the generic `.id` branch since a PendingQueryContext has an `.id` getter).\n if (value instanceof PendingQueryContext) {\n return {'@ctx': value.contextName};\n }\n if ('fields' in value) {\n // Nested-node create — bare path-keyed; expected shape = the relation's value shape.\n return encodeNodeData(value as NodeDescriptionValue, valueShapeOf(prop));\n }\n if ('id' in value) return {'@id': (value as NodeReferenceValue).id};\n }\n throw new Error(`Cannot serialize mutation value: ${JSON.stringify(value)}`);\n}\n\n/** Encode any property value, including arrays and set modifications. */\nexport function encodeValue(\n value: PropUpdateValue,\n prop?: PropertyShapeData,\n): MutationValueJSON {\n if (value === undefined) return {'@unset': true};\n if (Array.isArray(value)) {\n return {'@list': value.map((v) => encodeSingleValue(v, prop))};\n }\n if (isSetModificationValue(value)) {\n const mod = value as SetModificationValue;\n const json: {'@add'?: MutationValueJSON[]; '@remove'?: string[]} = {};\n if (mod.$add) json['@add'] = mod.$add.map((v) => encodeValue(v as PropUpdateValue, prop));\n if (mod.$remove) json['@remove'] = mod.$remove.map((r) => r.id);\n return json;\n }\n return encodeSingleValue(value as SinglePropertyUpdateValue, prop);\n}\n\n/**\n * Encode a normalized node description to path-keyed form. `expectedShape` is the\n * shape inferable from context (the envelope, or the parent relation's value shape);\n * `__shape` is emitted only when the concrete shape differs (a subclass instance).\n */\nexport function encodeNodeData(\n desc: NodeDescriptionValue,\n expectedShape?: NodeShapeData,\n): MutationNodeDataJSON {\n const json: MutationNodeDataJSON = {};\n if (desc.__id) json[NODE_ID_KEY] = desc.__id;\n if (!expectedShape || desc.shape.id !== expectedShape.id) {\n json[NODE_SHAPE_KEY] = desc.shape.id;\n }\n for (const f of desc.fields) {\n json[f.prop.label] = encodeValue(f.val, f.prop);\n }\n return json;\n}\n\n// =============================================================================\n// JSON → raw UpdatePartial (for builder rehydration / fromJSON)\n// =============================================================================\n\n// Bound the DSL-JSON decode recursion (rehydration path) against a deeply-nested\n// payload exhausting the stack. Mirrors the cap in lowerMutationJSON.\nconst MAX_DECODE_DEPTH = 128;\nlet _decodeDepth = 0;\n\n/**\n * Decode a DSL-JSON value back to a raw DSL value (the form `.set()` accepts).\n * `currentShape` resolves computed `{@path}`/S-expr; `prop` gives a nested node's shape.\n * Depth-guarded wrapper around {@link decodeValueToRawInner}.\n */\nfunction decodeValueToRaw(\n json: MutationValueJSON,\n currentShape: NodeShapeData | undefined,\n prop?: PropertyShapeData,\n): unknown {\n if (++_decodeDepth > MAX_DECODE_DEPTH) {\n _decodeDepth = 0;\n throw new Error('DSL-JSON value nested too deeply');\n }\n try {\n return decodeValueToRawInner(json, currentShape, prop);\n } finally {\n _decodeDepth--;\n }\n}\n\nfunction decodeValueToRawInner(\n json: MutationValueJSON,\n currentShape: NodeShapeData | undefined,\n prop?: PropertyShapeData,\n): unknown {\n // S-expr computed value\n if (Array.isArray(json)) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, requireShapeForExpr(currentShape));\n return new ExpressionNode(ir, refs);\n }\n if (json === null) return null;\n if (typeof json !== 'object') return json; // bare scalar literal\n const o = json as Record<string, unknown>;\n if ('@unset' in o) return undefined;\n if ('@date' in o) return new Date(o['@date'] as string);\n // Rehydration path: preserve the live reference so it re-serializes as a\n // `{@ctx}` marker and resolves at the rebuilt builder's own lowering.\n if ('@ctx' in o) return new PendingQueryContext(o['@ctx'] as string);\n if ('@id' in o) return {id: o['@id']};\n if ('@list' in o) {\n return (o['@list'] as MutationValueJSON[]).map((i) => decodeValueToRaw(i, currentShape, prop));\n }\n if ('@add' in o || '@remove' in o) {\n // Raw DSL set-modifications use `@add`/`@remove` on the wire.\n const mod: {add?: unknown[]; remove?: {id: string}[]} = {};\n if (o['@add']) mod.add = (o['@add'] as MutationValueJSON[]).map((i) => decodeValueToRaw(i, currentShape, prop));\n if (o['@remove']) mod.remove = (o['@remove'] as string[]).map((id) => ({id}));\n return mod;\n }\n // A computed-path value (`{@path}`) used as a value.\n if ('@path' in o) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, requireShapeForExpr(currentShape));\n return new ExpressionNode(ir, refs);\n }\n // Otherwise: a bare path-keyed nested-node create.\n return decodeNestedNodeDataToRaw(o as MutationNodeDataJSON, valueShapeOf(prop) ?? currentShape);\n}\n\n/**\n * Decode a nested node and, when it names its concrete shape (`__shape`), carry that\n * shape as the reserved `shape` key `.set()` accepts on a nested value. Without it the\n * builders validate and lower the value against the property's declared value shape —\n * or none, for a polymorphic slot like `PropertyShape.path` — and reject the fields\n * only the concrete shape has.\n */\n/**\n * The class for a node's `__shape`. Either registry — a project-authored shape exists only\n * as metadata. Throws like `lowerMutationJSON` does, so both decode paths reject an\n * unregistered shape instead of one of them silently validating against another.\n */\nfunction requireNodeShapeClass(shapeId: string): ShapeConstructor {\n const shapeClass = resolveShapeConstructor(shapeId);\n if (!shapeClass) {\n throw new Error(\n `Shape '${shapeId}' is not registered. The receiving side must have the shape registered to decode mutation DSL-JSON.`,\n );\n }\n return shapeClass;\n}\n\nfunction decodeNestedNodeDataToRaw(\n json: MutationNodeDataJSON,\n shape: NodeShapeData | undefined,\n): Record<string, unknown> {\n const obj = decodeNodeDataToRaw(json, shape);\n const shapeId = json[NODE_SHAPE_KEY];\n if (typeof shapeId === 'string') obj.shape = requireNodeShapeClass(shapeId);\n return obj;\n}\n\nfunction requireShapeForExpr(shape: NodeShapeData | undefined): NodeShapeData {\n if (!shape) {\n throw new Error('A shape is required to decode a computed mutation value');\n }\n return shape;\n}\n\n/**\n * Decode path-keyed node data into a raw object the mutation builders' `.set()` accepts.\n * `__id` becomes `id`; `__shape` (if present) overrides the inferred `shape`. Mirrors\n * {@link encodeNodeData}.\n */\nexport function decodeNodeDataToRaw(\n json: MutationNodeDataJSON,\n shape?: NodeShapeData,\n): Record<string, unknown> {\n const nodeShape =\n typeof json[NODE_SHAPE_KEY] === 'string'\n ? requireNodeShapeClass(json[NODE_SHAPE_KEY] as string).shape\n : shape;\n const obj: Record<string, unknown> = {};\n if (typeof json[NODE_ID_KEY] === 'string') obj.id = json[NODE_ID_KEY];\n for (const [key, val] of Object.entries(json)) {\n if (key === NODE_ID_KEY || key === NODE_SHAPE_KEY || val === undefined) continue;\n // Skip prototype-polluting keys from untrusted DSL-JSON input.\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;\n const prop = nodeShape ? getPropertyShape(nodeShape, key) : undefined;\n obj[key] = decodeValueToRaw(val as MutationValueJSON, nodeShape, prop);\n }\n return obj;\n}\n"]}
|
|
@@ -64,12 +64,6 @@ export type NodeDescriptionValue = {
|
|
|
64
64
|
* Optional, if not provided a new id will be generated.
|
|
65
65
|
*/
|
|
66
66
|
__id?: string;
|
|
67
|
-
/**
|
|
68
|
-
* Write this nested node as a fresh blank node carrying only its field triples (no
|
|
69
|
-
* `rdf:type`). For RDF syntax structures whose meaning comes from the triple that
|
|
70
|
-
* references them, like a SHACL property path. Create-only and never with `__id`.
|
|
71
|
-
*/
|
|
72
|
-
__blank?: true;
|
|
73
67
|
};
|
|
74
68
|
export type UpdateNodePropertyValue = {
|
|
75
69
|
prop: PropertyShapeData;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryFactory.js","sourceRoot":"","sources":["../../../src/queries/QueryFactory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"QueryFactory.js","sourceRoot":"","sources":["../../../src/queries/QueryFactory.ts"],"names":[],"mappings":"AAmKA,OAAO,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAG1D,MAAM,OAAgB,YAAY;CAAG;AAErC,MAAM,UAAU,sBAAsB,CACpC,KAAU;IAEV,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE9D,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC;IAC3B,IAAI,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;IACjC,IAAI,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;IACxC,mBAAmB;IACnB,OAAO,CACL,CAAC,SAAS,IAAI,YAAY,IAAI,OAAO,KAAK,CAAC,CAAC;QAC5C,CAAC,SAAS,IAAI,OAAO,KAAK,CAAC,CAAC;QAC5B,CAAC,YAAY,IAAI,OAAO,KAAK,CAAC,CAAC,CAChC,CAAC;AACJ,CAAC","sourcesContent":["import type {NodeShapeData, PropertyShapeData} from '../shapes/SHACL.js';\nimport {Shape} from '../shapes/Shape.js';\nimport {ShapeSet} from '../collections/ShapeSet.js';\nimport type {NodeReferenceValue} from '../utils/NodeReference.js';\nimport {ExpressionNode} from '../expressions/ExpressionNode.js';\n\nexport type Prettify<T> = T extends infer R\n ? {\n [K in keyof R]: R[K];\n }\n : never;\n\n/**\n * Recursively adds an id property to all objects in the object.\n * Also makes all keys optional.\n */\ntype _AddId<U> = U extends string | number | boolean | Date | null | undefined\n ? U\n : U extends Array<infer T>\n ? Array<_AddId<T>>\n : WithId<U>;\n\ntype RemoveId<U> = Omit<U, 'id'>;\n\ntype WithId<U> = U & {id: string};\n\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\ntype CombineTypes<T> = {\n [K in keyof UnionToIntersection<T>]: T extends {[P in K]?: infer V}\n ? _AddId<V>\n : never;\n};\n\ntype IsPlainObject<T> = T extends object\n ? T extends any[]\n ? false\n : T extends Function\n ? false\n : T extends Date\n ? false\n : T extends RegExp\n ? false\n : T extends Error\n ? false\n : T extends null\n ? false\n : T extends undefined\n ? false\n : T extends object\n ? true\n : false\n : false;\n\ntype RecursiveTransform<T, IsCreate = false> = T extends\n | string\n | number\n | boolean\n | Date\n | null\n | undefined\n ? T\n : T extends Array<infer U>\n ? UpdatedSet<Prettify<RecursiveTransform<U>>, IsCreate>\n : IsSetModification<T> extends true\n ? ModifiedSet<T, IsCreate>\n : IsPlainObject<T> extends true\n ? // ? WithId<{ [K in keyof T]-?: Prettify<RecursiveTransform<T[K]>> }>\n WithId<{[K in keyof T]: Prettify<RecursiveTransform<T[K], IsCreate>>}>\n : T;\n\n//for update() we use {updatedTo} but for create() we actually just return the array of new values;\ntype UpdatedSet<U, IsCreate> = IsCreate extends true\n ? U[]\n : {\n updatedTo: U[];\n };\ntype IsSetModification<T> = T extends {add?: any; remove?: any} ? true : false;\ntype AddedType<T> = T extends {add: (infer U)[]}\n ? U\n : T extends {add: infer U}\n ? U\n : never;\n\ntype RemovedType<T> = T extends {remove: (infer U)[]}\n ? U\n : T extends {remove: infer U}\n ? U\n : never;\n\ntype ModifiedSet<T, IsCreate = false> = {\n added: AddId<AddedType<T>, IsCreate>[];\n removed: AddId<RemovedType<T>, IsCreate>[];\n};\n\nexport type AddId<T, IsCreate = false> = Prettify<\n RecursiveTransform<T, IsCreate>\n>;\n\nexport type UpdatePartial<S = Shape> =\n | UpdateNodeDescription<S>\n | NodeReferenceValue;\ntype UpdateNodeDescription<Shape> = Partial<\n Omit<\n {\n [P in KeysWithoutFunctions<Shape>]: ShapePropValueToUpdatePartial<\n Shape[P]\n >;\n },\n 'node' | 'nodeShape' | 'namedNode' | 'targetClass'\n >\n>;\ntype KeysWithoutFunctions<T> = {\n [K in keyof T]: T[K] extends Function ? never : K;\n}[keyof T];\n\ntype ShapePropValueToUpdatePartial<ShapeProperty> = ShapeProperty extends Shape\n ? UpdatePartial<ShapeProperty>\n : ShapeProperty extends ShapeSet<infer SSType>\n ? SetUpdateValue<SSType>\n : ShapeProperty | ExpressionNode;\n\ntype SetUpdateValue<SSType> = UpdatePartial<SSType>[] | SetModification<SSType>;\n\nexport type SetModification<SSType> = {\n add?: UpdatePartial<SSType>[] | UpdatePartial<SSType>;\n remove?: UpdatePartial<SSType>[] | UpdatePartial<SSType>;\n};\n\nexport type SetModificationValue = {\n $add?: UpdatePartial[];\n $remove?: NodeReferenceValue[];\n};\n\ntype UnsetValue = undefined;\nexport type LiteralUpdateValue = string | number | boolean | Date;\nexport type PropUpdateValue =\n | SinglePropertyUpdateValue\n | SinglePropertyUpdateValue[]\n | SetModificationValue;\nexport type SinglePropertyUpdateValue =\n | NodeDescriptionValue\n | NodeReferenceValue\n | LiteralUpdateValue\n | UnsetValue;\nexport type NodeDescriptionValue = {\n shape: NodeShapeData;\n fields: UpdateNodePropertyValue[];\n /**\n * The id of the node to be created.\n * Optional, if not provided a new id will be generated.\n */\n __id?: string;\n};\nexport type UpdateNodePropertyValue = {\n prop: PropertyShapeData;\n val: PropUpdateValue;\n};\nexport type ShapeReferenceValue = {id: string; shape: NodeReferenceValue};\nexport {toNodeReference} from '../utils/NodeReference.js';\nexport type {NodeReferenceValue};\n\nexport abstract class QueryFactory {}\n\nexport function isSetModificationValue(\n value: any,\n): value is SetModificationValue {\n if (value === null || typeof value !== 'object') return false;\n\n let hasAddKey = value.$add;\n let hasRemoveKey = value.$remove;\n let numKeys = Object.keys(value).length;\n //has no other keys\n return (\n (hasAddKey && hasRemoveKey && numKeys === 2) ||\n (hasAddKey && numKeys === 1) ||\n (hasRemoveKey && numKeys === 1)\n );\n}\n\n"]}
|
|
@@ -98,7 +98,7 @@ export function decodeNodeData(json, shape) {
|
|
|
98
98
|
const nodeShape = typeof json.__shape === 'string' ? requireShape(json.__shape) : shape;
|
|
99
99
|
const fields = [];
|
|
100
100
|
for (const [key, val] of Object.entries(json)) {
|
|
101
|
-
if (key === '__id' || key === '__shape' ||
|
|
101
|
+
if (key === '__id' || key === '__shape' || val === undefined)
|
|
102
102
|
continue;
|
|
103
103
|
const prop = getPropertyShape(nodeShape, key);
|
|
104
104
|
if (!prop) {
|
|
@@ -109,11 +109,6 @@ export function decodeNodeData(json, shape) {
|
|
|
109
109
|
const desc = { shape: nodeShape, fields };
|
|
110
110
|
if (typeof json.__id === 'string')
|
|
111
111
|
desc.__id = json.__id;
|
|
112
|
-
if (json.__blank !== undefined) {
|
|
113
|
-
if (json.__blank !== true)
|
|
114
|
-
throw new Error(`__blank must be true when given, got ${JSON.stringify(json.__blank)}`);
|
|
115
|
-
desc.__blank = true;
|
|
116
|
-
}
|
|
117
112
|
return desc;
|
|
118
113
|
}
|
|
119
114
|
function lowerWhere(shape, json) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lowerMutationJSON.js","sourceRoot":"","sources":["../../../src/queries/lowerMutationJSON.ts"],"names":[],"mappings":"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","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\n/**\n * Lower mutation DSL-JSON to canonical IR.\n *\n * This is the **IR side** of mutation (de)serialization, kept deliberately\n * separate from the IR-free wire codec in `MutationSerialization.ts`. The\n * canonical-IR builders (`IRMutation` / `IRLower` / …) are reachable only from\n * here and from `lower()`, so a client that serializes mutations to JSON and\n * forwards them (without ever lowering) tree-shakes the whole IR pipeline away.\n */\nimport type {NodeShapeData} from '../shapes/SHACL.js';\nimport {getPropertyShape} from '../shapes/nodeShapeData.js';\nimport {\n type NodeDescriptionValue,\n type PropUpdateValue,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n type UpdateNodePropertyValue,\n} from './QueryFactory.js';\nimport {ExpressionNode} from '../expressions/ExpressionNode.js';\nimport {getNodeShape, getShapeClass} from '../utils/ShapeClass.js';\nimport type {IRExpression, IRGraphPattern} from './IntermediateRepresentation.js';\nimport {\n deserializeWherePath,\n type WherePathJSON,\n} from './QueryBuilderSerialization.js';\nimport {toWhere} from './IRDesugar.js';\nimport {lowerWhereToIR} from './IRLower.js';\nimport {\n buildCanonicalCreateMutationIR,\n buildCanonicalUpdateMutationIR,\n buildCanonicalUpsertMutationIR,\n buildCanonicalUpdateWhereMutationIR,\n buildCanonicalDeleteMutationIR,\n buildCanonicalDeleteAllMutationIR,\n buildCanonicalDeleteWhereMutationIR,\n} from './IRMutation.js';\nimport type {IRCreateQuery} from './CreateQuery.js';\nimport type {IRUpdateQuery} from './UpdateQuery.js';\nimport type {IRDeleteQuery} from './DeleteQuery.js';\nimport {isContextRefJSON, resolveContextId} from './ContextRef.js';\nimport {assertWireVersion} from './wireVersion.js';\nimport {\n decodeNodeDataToRaw,\n valueShapeOf,\n type MutationJSON,\n type MutationNodeDataJSON,\n type MutationValueJSON,\n} from './MutationSerialization.js';\nimport {assertValid, type ValidationMode} from '../shapes/validation.js';\nimport {decodeValueExpr, type DslJsonValue} from './DslJsonExpression.js';\nimport type {PropertyShapeData} from '../shapes/SHACL.js';\n\nfunction requireShape(shapeId: string): NodeShapeData {\n // Either registry: a project-authored shape arrives as metadata with no class, and\n // requiring a class here made every mutation against one fail at the boundary.\n const shape = getShapeClass(shapeId)?.shape ?? getNodeShape(shapeId);\n if (!shape) {\n throw new Error(\n `Shape '${shapeId}' is not registered. The receiving side must have the shape registered to lower mutation DSL-JSON.`,\n );\n }\n return shape;\n}\n\n// Bound the DSL-JSON decode recursion so a deeply-nested payload from\n// `fromJSON()` cannot exhaust the stack (RangeError DoS). Normal mutation data\n// nests only a handful of levels; 128 is far above any real query.\nconst MAX_DECODE_DEPTH = 128;\nlet _decodeDepth = 0;\n\n/**\n * Decode a DSL-JSON value to the normalized form the canonical-IR builders consume.\n * `currentShape` resolves computed `{@path}`/S-expr; `prop` gives a nested node's shape.\n * Depth-guarded wrapper around {@link decodeValueInner}.\n */\nfunction decodeValue(\n json: MutationValueJSON,\n currentShape: NodeShapeData,\n prop?: PropertyShapeData,\n): PropUpdateValue {\n if (++_decodeDepth > MAX_DECODE_DEPTH) {\n _decodeDepth = 0;\n throw new Error('DSL-JSON value nested too deeply');\n }\n try {\n return decodeValueInner(json, currentShape, prop);\n } finally {\n _decodeDepth--;\n }\n}\n\nfunction decodeValueInner(\n json: MutationValueJSON,\n currentShape: NodeShapeData,\n prop?: PropertyShapeData,\n): PropUpdateValue {\n // S-expr computed value (no IR on the wire)\n if (Array.isArray(json)) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, currentShape);\n return new ExpressionNode(ir, refs) as unknown as PropUpdateValue;\n }\n if (json === null) return null as unknown as PropUpdateValue;\n if (typeof json !== 'object') return json as PropUpdateValue; // bare scalar literal\n const o = json as Record<string, unknown>;\n if ('@unset' in o) return undefined;\n if ('@date' in o) return new Date(o['@date'] as string) as unknown as PropUpdateValue;\n if ('@ctx' in o) {\n // Lowering path: a mutation must hit a concrete node, so resolve the\n // context now and throw if it isn't set.\n const id = resolveContextId(o['@ctx'] as string, true)!;\n return {id} as PropUpdateValue;\n }\n if ('@id' in o) return {id: o['@id']} as PropUpdateValue;\n if ('@list' in o) {\n return (o['@list'] as MutationValueJSON[]).map(\n (item) => decodeValue(item, currentShape, prop) as SinglePropertyUpdateValue,\n );\n }\n if ('@add' in o || '@remove' in o) {\n const mod: SetModificationValue = {};\n if (o['@add']) {\n mod.$add = (o['@add'] as MutationValueJSON[]).map((v) =>\n decodeValue(v, currentShape, prop),\n ) as SetModificationValue['$add'];\n }\n if (o['@remove']) mod.$remove = (o['@remove'] as string[]).map((id) => ({id}));\n return mod as PropUpdateValue;\n }\n if ('@path' in o) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, currentShape);\n return new ExpressionNode(ir, refs) as unknown as PropUpdateValue;\n }\n // Otherwise: a bare path-keyed nested-node create.\n return decodeNodeData(\n o as MutationNodeDataJSON,\n valueShapeOf(prop) ?? currentShape,\n ) as unknown as PropUpdateValue;\n}\n\n/**\n * Rebuild a normalized node description from path-keyed JSON, resolving labels via the\n * shape. `shape` is the shape inferred from context; `__shape` overrides it.\n */\nexport function decodeNodeData(\n json: MutationNodeDataJSON,\n shape?: NodeShapeData,\n): NodeDescriptionValue {\n const nodeShape =\n typeof json.__shape === 'string' ? requireShape(json.__shape) : shape!;\n const fields: UpdateNodePropertyValue[] = [];\n for (const [key, val] of Object.entries(json)) {\n if (key === '__id' || key === '__shape' || key === '__blank' || val === undefined) continue;\n const prop = getPropertyShape(nodeShape, key);\n if (!prop) {\n throw new Error(\n `Property '${key}' not found on shape '${nodeShape.label || nodeShape.id}'`,\n );\n }\n fields.push({prop, val: decodeValue(val as MutationValueJSON, nodeShape, prop)} as UpdateNodePropertyValue);\n }\n const desc: NodeDescriptionValue = {shape: nodeShape, fields};\n if (typeof json.__id === 'string') desc.__id = json.__id;\n if (json.__blank !== undefined) {\n if (json.__blank !== true) throw new Error(`__blank must be true when given, got ${JSON.stringify(json.__blank)}`);\n desc.__blank = true;\n }\n return desc;\n}\n\nfunction lowerWhere(\n shape: NodeShapeData,\n json: WherePathJSON,\n): {where: IRExpression; wherePatterns: IRGraphPattern[]} {\n const wherePath = deserializeWherePath(shape, json);\n return lowerWhereToIR(toWhere(wherePath));\n}\n\n/**\n * Lower a mutation DSL-JSON envelope to the canonical IR mutation the dataset\n * expects. Mirrors the IR that `lower()` produces from the live builder.\n */\n/**\n * Validate inbound node data against its shape before it becomes IR.\n *\n * The builders validate through `describe()`, which sees raw DSL data. This path\n * never touches a builder, so without this an inbound mutation would be held to\n * a weaker standard than a locally-built one — on the *less* trusted input, at\n * that. `decodeNodeDataToRaw` produces exactly the raw form `describe()` would\n * have validated (it is what `CreateBuilder.fromJSON` feeds through `.set()`),\n * so both paths run the same checks. The second decode is the cost of validating\n * at a boundary; it happens once per inbound mutation.\n */\nfunction assertInboundDataValid(\n json: MutationNodeDataJSON,\n shape: NodeShapeData,\n mode: ValidationMode,\n): void {\n assertValid(shape, decodeNodeDataToRaw(json, shape), {mode});\n}\n\nexport function lowerMutationJSON(\n json: MutationJSON,\n): IRCreateQuery | IRUpdateQuery | IRDeleteQuery {\n assertWireVersion(json.v);\n switch (json.op) {\n case 'create': {\n const shape = requireShape(json.shape);\n assertInboundDataValid(json.data, shape, 'complete');\n return buildCanonicalCreateMutationIR({\n shape,\n description: decodeNodeData(json.data, shape),\n });\n }\n case 'upsert': {\n const shape = requireShape(json.shape);\n assertInboundDataValid(json.data, shape, 'partial');\n const updates = decodeNodeData(json.data, shape);\n const id = isContextRefJSON(json.targetId)\n ? resolveContextId(json.targetId['@ctx'], true)\n : json.targetId;\n if (!id) {\n throw new Error('upsert requires a targetId');\n }\n return buildCanonicalUpsertMutationIR({id, shape, updates});\n }\n case 'update': {\n const shape = requireShape(json.shape);\n assertInboundDataValid(json.data, shape, 'partial');\n const updates = decodeNodeData(json.data, shape);\n if (json.mode === 'for') {\n // A `{@ctx}` target resolves against the current context map; a mutation\n // must hit a concrete subject, so an unresolved context throws.\n const id = isContextRefJSON(json.targetId)\n ? resolveContextId(json.targetId['@ctx'], true)\n : json.targetId;\n if (!id) {\n throw new Error('update mode \"for\" requires a targetId');\n }\n return buildCanonicalUpdateMutationIR({id, shape, updates});\n }\n let where: IRExpression | undefined;\n let wherePatterns: IRGraphPattern[] | undefined;\n if (json.mode === 'where') {\n if (!json.where) throw new Error('update mode \"where\" requires a where clause');\n ({where, wherePatterns} = lowerWhere(shape, json.where));\n }\n return buildCanonicalUpdateWhereMutationIR({shape, updates, where, wherePatterns});\n }\n case 'delete': {\n const shape = requireShape(json.shape);\n if (json.mode === 'ids') {\n return buildCanonicalDeleteMutationIR({\n shape,\n // A `{@ctx}` id resolves against the live map; a delete must hit a\n // concrete node, so an unresolved context throws.\n ids: json.ids.map((id) =>\n isContextRefJSON(id) ? {id: resolveContextId(id['@ctx'], true)!} : {id},\n ),\n });\n }\n if (json.mode === 'all') {\n return buildCanonicalDeleteAllMutationIR({shape});\n }\n const {where, wherePatterns} = lowerWhere(shape, json.where);\n return buildCanonicalDeleteWhereMutationIR({shape, where, wherePatterns});\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lowerMutationJSON.js","sourceRoot":"","sources":["../../../src/queries/lowerMutationJSON.ts"],"names":[],"mappings":"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","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\n/**\n * Lower mutation DSL-JSON to canonical IR.\n *\n * This is the **IR side** of mutation (de)serialization, kept deliberately\n * separate from the IR-free wire codec in `MutationSerialization.ts`. The\n * canonical-IR builders (`IRMutation` / `IRLower` / …) are reachable only from\n * here and from `lower()`, so a client that serializes mutations to JSON and\n * forwards them (without ever lowering) tree-shakes the whole IR pipeline away.\n */\nimport type {NodeShapeData} from '../shapes/SHACL.js';\nimport {getPropertyShape} from '../shapes/nodeShapeData.js';\nimport {\n type NodeDescriptionValue,\n type PropUpdateValue,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n type UpdateNodePropertyValue,\n} from './QueryFactory.js';\nimport {ExpressionNode} from '../expressions/ExpressionNode.js';\nimport {getNodeShape, getShapeClass} from '../utils/ShapeClass.js';\nimport type {IRExpression, IRGraphPattern} from './IntermediateRepresentation.js';\nimport {\n deserializeWherePath,\n type WherePathJSON,\n} from './QueryBuilderSerialization.js';\nimport {toWhere} from './IRDesugar.js';\nimport {lowerWhereToIR} from './IRLower.js';\nimport {\n buildCanonicalCreateMutationIR,\n buildCanonicalUpdateMutationIR,\n buildCanonicalUpsertMutationIR,\n buildCanonicalUpdateWhereMutationIR,\n buildCanonicalDeleteMutationIR,\n buildCanonicalDeleteAllMutationIR,\n buildCanonicalDeleteWhereMutationIR,\n} from './IRMutation.js';\nimport type {IRCreateQuery} from './CreateQuery.js';\nimport type {IRUpdateQuery} from './UpdateQuery.js';\nimport type {IRDeleteQuery} from './DeleteQuery.js';\nimport {isContextRefJSON, resolveContextId} from './ContextRef.js';\nimport {assertWireVersion} from './wireVersion.js';\nimport {\n decodeNodeDataToRaw,\n valueShapeOf,\n type MutationJSON,\n type MutationNodeDataJSON,\n type MutationValueJSON,\n} from './MutationSerialization.js';\nimport {assertValid, type ValidationMode} from '../shapes/validation.js';\nimport {decodeValueExpr, type DslJsonValue} from './DslJsonExpression.js';\nimport type {PropertyShapeData} from '../shapes/SHACL.js';\n\nfunction requireShape(shapeId: string): NodeShapeData {\n // Either registry: a project-authored shape arrives as metadata with no class, and\n // requiring a class here made every mutation against one fail at the boundary.\n const shape = getShapeClass(shapeId)?.shape ?? getNodeShape(shapeId);\n if (!shape) {\n throw new Error(\n `Shape '${shapeId}' is not registered. The receiving side must have the shape registered to lower mutation DSL-JSON.`,\n );\n }\n return shape;\n}\n\n// Bound the DSL-JSON decode recursion so a deeply-nested payload from\n// `fromJSON()` cannot exhaust the stack (RangeError DoS). Normal mutation data\n// nests only a handful of levels; 128 is far above any real query.\nconst MAX_DECODE_DEPTH = 128;\nlet _decodeDepth = 0;\n\n/**\n * Decode a DSL-JSON value to the normalized form the canonical-IR builders consume.\n * `currentShape` resolves computed `{@path}`/S-expr; `prop` gives a nested node's shape.\n * Depth-guarded wrapper around {@link decodeValueInner}.\n */\nfunction decodeValue(\n json: MutationValueJSON,\n currentShape: NodeShapeData,\n prop?: PropertyShapeData,\n): PropUpdateValue {\n if (++_decodeDepth > MAX_DECODE_DEPTH) {\n _decodeDepth = 0;\n throw new Error('DSL-JSON value nested too deeply');\n }\n try {\n return decodeValueInner(json, currentShape, prop);\n } finally {\n _decodeDepth--;\n }\n}\n\nfunction decodeValueInner(\n json: MutationValueJSON,\n currentShape: NodeShapeData,\n prop?: PropertyShapeData,\n): PropUpdateValue {\n // S-expr computed value (no IR on the wire)\n if (Array.isArray(json)) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, currentShape);\n return new ExpressionNode(ir, refs) as unknown as PropUpdateValue;\n }\n if (json === null) return null as unknown as PropUpdateValue;\n if (typeof json !== 'object') return json as PropUpdateValue; // bare scalar literal\n const o = json as Record<string, unknown>;\n if ('@unset' in o) return undefined;\n if ('@date' in o) return new Date(o['@date'] as string) as unknown as PropUpdateValue;\n if ('@ctx' in o) {\n // Lowering path: a mutation must hit a concrete node, so resolve the\n // context now and throw if it isn't set.\n const id = resolveContextId(o['@ctx'] as string, true)!;\n return {id} as PropUpdateValue;\n }\n if ('@id' in o) return {id: o['@id']} as PropUpdateValue;\n if ('@list' in o) {\n return (o['@list'] as MutationValueJSON[]).map(\n (item) => decodeValue(item, currentShape, prop) as SinglePropertyUpdateValue,\n );\n }\n if ('@add' in o || '@remove' in o) {\n const mod: SetModificationValue = {};\n if (o['@add']) {\n mod.$add = (o['@add'] as MutationValueJSON[]).map((v) =>\n decodeValue(v, currentShape, prop),\n ) as SetModificationValue['$add'];\n }\n if (o['@remove']) mod.$remove = (o['@remove'] as string[]).map((id) => ({id}));\n return mod as PropUpdateValue;\n }\n if ('@path' in o) {\n const {ir, refs} = decodeValueExpr(json as DslJsonValue, currentShape);\n return new ExpressionNode(ir, refs) as unknown as PropUpdateValue;\n }\n // Otherwise: a bare path-keyed nested-node create.\n return decodeNodeData(\n o as MutationNodeDataJSON,\n valueShapeOf(prop) ?? currentShape,\n ) as unknown as PropUpdateValue;\n}\n\n/**\n * Rebuild a normalized node description from path-keyed JSON, resolving labels via the\n * shape. `shape` is the shape inferred from context; `__shape` overrides it.\n */\nexport function decodeNodeData(\n json: MutationNodeDataJSON,\n shape?: NodeShapeData,\n): NodeDescriptionValue {\n const nodeShape =\n typeof json.__shape === 'string' ? requireShape(json.__shape) : shape!;\n const fields: UpdateNodePropertyValue[] = [];\n for (const [key, val] of Object.entries(json)) {\n if (key === '__id' || key === '__shape' || val === undefined) continue;\n const prop = getPropertyShape(nodeShape, key);\n if (!prop) {\n throw new Error(\n `Property '${key}' not found on shape '${nodeShape.label || nodeShape.id}'`,\n );\n }\n fields.push({prop, val: decodeValue(val as MutationValueJSON, nodeShape, prop)} as UpdateNodePropertyValue);\n }\n const desc: NodeDescriptionValue = {shape: nodeShape, fields};\n if (typeof json.__id === 'string') desc.__id = json.__id;\n return desc;\n}\n\nfunction lowerWhere(\n shape: NodeShapeData,\n json: WherePathJSON,\n): {where: IRExpression; wherePatterns: IRGraphPattern[]} {\n const wherePath = deserializeWherePath(shape, json);\n return lowerWhereToIR(toWhere(wherePath));\n}\n\n/**\n * Lower a mutation DSL-JSON envelope to the canonical IR mutation the dataset\n * expects. Mirrors the IR that `lower()` produces from the live builder.\n */\n/**\n * Validate inbound node data against its shape before it becomes IR.\n *\n * The builders validate through `describe()`, which sees raw DSL data. This path\n * never touches a builder, so without this an inbound mutation would be held to\n * a weaker standard than a locally-built one — on the *less* trusted input, at\n * that. `decodeNodeDataToRaw` produces exactly the raw form `describe()` would\n * have validated (it is what `CreateBuilder.fromJSON` feeds through `.set()`),\n * so both paths run the same checks. The second decode is the cost of validating\n * at a boundary; it happens once per inbound mutation.\n */\nfunction assertInboundDataValid(\n json: MutationNodeDataJSON,\n shape: NodeShapeData,\n mode: ValidationMode,\n): void {\n assertValid(shape, decodeNodeDataToRaw(json, shape), {mode});\n}\n\nexport function lowerMutationJSON(\n json: MutationJSON,\n): IRCreateQuery | IRUpdateQuery | IRDeleteQuery {\n assertWireVersion(json.v);\n switch (json.op) {\n case 'create': {\n const shape = requireShape(json.shape);\n assertInboundDataValid(json.data, shape, 'complete');\n return buildCanonicalCreateMutationIR({\n shape,\n description: decodeNodeData(json.data, shape),\n });\n }\n case 'upsert': {\n const shape = requireShape(json.shape);\n assertInboundDataValid(json.data, shape, 'partial');\n const updates = decodeNodeData(json.data, shape);\n const id = isContextRefJSON(json.targetId)\n ? resolveContextId(json.targetId['@ctx'], true)\n : json.targetId;\n if (!id) {\n throw new Error('upsert requires a targetId');\n }\n return buildCanonicalUpsertMutationIR({id, shape, updates});\n }\n case 'update': {\n const shape = requireShape(json.shape);\n assertInboundDataValid(json.data, shape, 'partial');\n const updates = decodeNodeData(json.data, shape);\n if (json.mode === 'for') {\n // A `{@ctx}` target resolves against the current context map; a mutation\n // must hit a concrete subject, so an unresolved context throws.\n const id = isContextRefJSON(json.targetId)\n ? resolveContextId(json.targetId['@ctx'], true)\n : json.targetId;\n if (!id) {\n throw new Error('update mode \"for\" requires a targetId');\n }\n return buildCanonicalUpdateMutationIR({id, shape, updates});\n }\n let where: IRExpression | undefined;\n let wherePatterns: IRGraphPattern[] | undefined;\n if (json.mode === 'where') {\n if (!json.where) throw new Error('update mode \"where\" requires a where clause');\n ({where, wherePatterns} = lowerWhere(shape, json.where));\n }\n return buildCanonicalUpdateWhereMutationIR({shape, updates, where, wherePatterns});\n }\n case 'delete': {\n const shape = requireShape(json.shape);\n if (json.mode === 'ids') {\n return buildCanonicalDeleteMutationIR({\n shape,\n // A `{@ctx}` id resolves against the live map; a delete must hit a\n // concrete node, so an unresolved context throws.\n ids: json.ids.map((id) =>\n isContextRefJSON(id) ? {id: resolveContextId(id['@ctx'], true)!} : {id},\n ),\n });\n }\n if (json.mode === 'all') {\n return buildCanonicalDeleteAllMutationIR({shape});\n }\n const {where, wherePatterns} = lowerWhere(shape, json.where);\n return buildCanonicalDeleteWhereMutationIR({shape, where, wherePatterns});\n }\n }\n}\n"]}
|
|
@@ -3,9 +3,9 @@ import { Shape } from './Shape.js';
|
|
|
3
3
|
* SHACL/RDF ordered-list cell shape (`rdf:List`).
|
|
4
4
|
*
|
|
5
5
|
* A list is a chain of cells: `first` holds the value, `rest` points to the next cell
|
|
6
|
-
* (or `rdf:nil`).
|
|
7
|
-
* a `contains` edge, so
|
|
8
|
-
*
|
|
6
|
+
* (or `rdf:nil`). `rest` is a `contains` edge, so deleting / replacing a list's owner deletes
|
|
7
|
+
* the whole spine (`rdf:rest*`) — while `first` is NOT a `contains` edge, so the list's
|
|
8
|
+
* *contents* (shared IRIs / values) are kept.
|
|
9
9
|
*
|
|
10
10
|
* This module holds the class only, and must never import `package.js`: `utils/Package.ts`
|
|
11
11
|
* imports it to register `List` by value (as it does NodeShape and PropertyShape) and to use
|
|
@@ -16,9 +16,9 @@ import { rdf } from '../ontologies/rdf.js';
|
|
|
16
16
|
* SHACL/RDF ordered-list cell shape (`rdf:List`).
|
|
17
17
|
*
|
|
18
18
|
* A list is a chain of cells: `first` holds the value, `rest` points to the next cell
|
|
19
|
-
* (or `rdf:nil`).
|
|
20
|
-
* a `contains` edge, so
|
|
21
|
-
*
|
|
19
|
+
* (or `rdf:nil`). `rest` is a `contains` edge, so deleting / replacing a list's owner deletes
|
|
20
|
+
* the whole spine (`rdf:rest*`) — while `first` is NOT a `contains` edge, so the list's
|
|
21
|
+
* *contents* (shared IRIs / values) are kept.
|
|
22
22
|
*
|
|
23
23
|
* This module holds the class only, and must never import `package.js`: `utils/Package.ts`
|
|
24
24
|
* imports it to register `List` by value (as it does NodeShape and PropertyShape) and to use
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"List.class.js","sourceRoot":"","sources":["../../../src/shapes/List.class.ts"],"names":[],"mappings":";;;;;;AAAA;;;;GAIG;AACH,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAC;AACjC,OAAO,EAAC,cAAc,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAC,GAAG,EAAC,MAAM,sBAAsB,CAAC;AAEzC;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,IAAkB,SAAQ,KAAK;IAI1C,IAAI,KAAK;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC;IACd,CAAC;;AAVM,gBAAW,GAAG,GAAG,CAAC,IAAI,CAAC;AAG9B;IADC,cAAc,CAAC,EAAC,IAAI,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAC,CAAC;iCAG9C;AAGD;IADC,cAAc,CAAC,EAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAC,CAAC;gCAG1E","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 */\nimport {Shape} from './Shape.js';\nimport {linkedProperty, objectProperty} from './SHACL.js';\nimport {rdf} from '../ontologies/rdf.js';\n\n/**\n * SHACL/RDF ordered-list cell shape (`rdf:List`).\n *\n * A list is a chain of cells: `first` holds the value, `rest` points to the next cell\n * (or `rdf:nil`).
|
|
1
|
+
{"version":3,"file":"List.class.js","sourceRoot":"","sources":["../../../src/shapes/List.class.ts"],"names":[],"mappings":";;;;;;AAAA;;;;GAIG;AACH,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAC;AACjC,OAAO,EAAC,cAAc,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAC,GAAG,EAAC,MAAM,sBAAsB,CAAC;AAEzC;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,IAAkB,SAAQ,KAAK;IAI1C,IAAI,KAAK;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC;IACd,CAAC;;AAVM,gBAAW,GAAG,GAAG,CAAC,IAAI,CAAC;AAG9B;IADC,cAAc,CAAC,EAAC,IAAI,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAC,CAAC;iCAG9C;AAGD;IADC,cAAc,CAAC,EAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAC,CAAC;gCAG1E","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 */\nimport {Shape} from './Shape.js';\nimport {linkedProperty, objectProperty} from './SHACL.js';\nimport {rdf} from '../ontologies/rdf.js';\n\n/**\n * SHACL/RDF ordered-list cell shape (`rdf:List`).\n *\n * A list is a chain of cells: `first` holds the value, `rest` points to the next cell\n * (or `rdf:nil`). `rest` is a `contains` edge, so deleting / replacing a list's owner deletes\n * the whole spine (`rdf:rest*`) — while `first` is NOT a `contains` edge, so the list's\n * *contents* (shared IRIs / values) are kept.\n *\n * This module holds the class only, and must never import `package.js`: `utils/Package.ts`\n * imports it to register `List` by value (as it does NodeShape and PropertyShape) and to use\n * it as the value shape of `PropertyShape.in`. Importing `package.js` from here would be a\n * cycle, with `corePackage` still uninitialised when this module evaluates. The public module\n * is `List.ts`, which loads the registration.\n */\nexport class List<T = unknown> extends Shape {\n static targetClass = rdf.List;\n\n @linkedProperty({path: rdf.first, maxCount: 1})\n get first(): T {\n return null;\n }\n\n @objectProperty({path: rdf.rest, maxCount: 1, shape: List, contains: true})\n get rest(): List<T> {\n return null;\n }\n}\n"]}
|
package/lib/esm/shapes/List.d.ts
CHANGED