@_linked/core 2.34.0 → 2.36.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +54 -0
  3. package/lib/esm/index.d.ts +5 -1
  4. package/lib/esm/index.js +6 -0
  5. package/lib/esm/index.js.map +1 -1
  6. package/lib/esm/live/LiveQueryStore.d.ts +22 -0
  7. package/lib/esm/live/LiveQueryStore.js +88 -20
  8. package/lib/esm/live/LiveQueryStore.js.map +1 -1
  9. package/lib/esm/live/changes.d.ts +9 -1
  10. package/lib/esm/live/changes.js +7 -2
  11. package/lib/esm/live/changes.js.map +1 -1
  12. package/lib/esm/live/keys.d.ts +6 -0
  13. package/lib/esm/live/keys.js +10 -1
  14. package/lib/esm/live/keys.js.map +1 -1
  15. package/lib/esm/live/matcher.d.ts +4 -1
  16. package/lib/esm/live/matcher.js +10 -5
  17. package/lib/esm/live/matcher.js.map +1 -1
  18. package/lib/esm/queries/AskBuilder.d.ts +6 -0
  19. package/lib/esm/queries/AskBuilder.js +14 -0
  20. package/lib/esm/queries/AskBuilder.js.map +1 -1
  21. package/lib/esm/queries/CountBuilder.d.ts +6 -0
  22. package/lib/esm/queries/CountBuilder.js +14 -0
  23. package/lib/esm/queries/CountBuilder.js.map +1 -1
  24. package/lib/esm/queries/CreateBuilder.d.ts +4 -0
  25. package/lib/esm/queries/CreateBuilder.js +15 -1
  26. package/lib/esm/queries/CreateBuilder.js.map +1 -1
  27. package/lib/esm/queries/DeleteBuilder.d.ts +4 -0
  28. package/lib/esm/queries/DeleteBuilder.js +15 -1
  29. package/lib/esm/queries/DeleteBuilder.js.map +1 -1
  30. package/lib/esm/queries/FieldSet.d.ts +17 -0
  31. package/lib/esm/queries/FieldSet.js +110 -22
  32. package/lib/esm/queries/FieldSet.js.map +1 -1
  33. package/lib/esm/queries/IRLower.js +3 -2
  34. package/lib/esm/queries/IRLower.js.map +1 -1
  35. package/lib/esm/queries/IRMutation.js +15 -14
  36. package/lib/esm/queries/IRMutation.js.map +1 -1
  37. package/lib/esm/queries/MutationQuery.js +3 -2
  38. package/lib/esm/queries/MutationQuery.js.map +1 -1
  39. package/lib/esm/queries/MutationSerialization.js +2 -2
  40. package/lib/esm/queries/MutationSerialization.js.map +1 -1
  41. package/lib/esm/queries/PropertyPath.js +4 -3
  42. package/lib/esm/queries/PropertyPath.js.map +1 -1
  43. package/lib/esm/queries/QueryBuilder.d.ts +7 -0
  44. package/lib/esm/queries/QueryBuilder.js +42 -4
  45. package/lib/esm/queries/QueryBuilder.js.map +1 -1
  46. package/lib/esm/queries/QueryContext.js +2 -0
  47. package/lib/esm/queries/QueryContext.js.map +1 -1
  48. package/lib/esm/queries/SelectQuery.js +8 -3
  49. package/lib/esm/queries/SelectQuery.js.map +1 -1
  50. package/lib/esm/queries/UpdateBuilder.d.ts +4 -0
  51. package/lib/esm/queries/UpdateBuilder.js +15 -1
  52. package/lib/esm/queries/UpdateBuilder.js.map +1 -1
  53. package/lib/esm/queries/fromJSON.d.ts +12 -1
  54. package/lib/esm/queries/fromJSON.js +5 -1
  55. package/lib/esm/queries/fromJSON.js.map +1 -1
  56. package/lib/esm/queries/lower.js +12 -5
  57. package/lib/esm/queries/lower.js.map +1 -1
  58. package/lib/esm/queries/queryDependencies.js +14 -10
  59. package/lib/esm/queries/queryDependencies.js.map +1 -1
  60. package/lib/esm/queries/resolveShape.js +16 -3
  61. package/lib/esm/queries/resolveShape.js.map +1 -1
  62. package/lib/esm/shapes/Shape.js +2 -1
  63. package/lib/esm/shapes/Shape.js.map +1 -1
  64. package/lib/esm/shapes/nodeShapeData.js +7 -10
  65. package/lib/esm/shapes/nodeShapeData.js.map +1 -1
  66. package/lib/esm/shapes/registerRuntimeShape.js +3 -1
  67. package/lib/esm/shapes/registerRuntimeShape.js.map +1 -1
  68. package/lib/esm/shapes/syncShapes.d.ts +6 -2
  69. package/lib/esm/shapes/syncShapes.js +16 -9
  70. package/lib/esm/shapes/syncShapes.js.map +1 -1
  71. package/lib/esm/shapes/validation.js +10 -6
  72. package/lib/esm/shapes/validation.js.map +1 -1
  73. package/lib/esm/sparql/irToAlgebra.js +117 -52
  74. package/lib/esm/sparql/irToAlgebra.js.map +1 -1
  75. package/lib/esm/sparql/ownedLinkCheck.js +6 -1
  76. package/lib/esm/sparql/ownedLinkCheck.js.map +1 -1
  77. package/lib/esm/utils/LinkedStorage.d.ts +7 -0
  78. package/lib/esm/utils/LinkedStorage.js +39 -12
  79. package/lib/esm/utils/LinkedStorage.js.map +1 -1
  80. package/lib/esm/utils/ShapeCatalog.d.ts +57 -0
  81. package/lib/esm/utils/ShapeCatalog.js +86 -0
  82. package/lib/esm/utils/ShapeCatalog.js.map +1 -0
  83. package/lib/esm/utils/ShapeClass.d.ts +73 -8
  84. package/lib/esm/utils/ShapeClass.js +245 -66
  85. package/lib/esm/utils/ShapeClass.js.map +1 -1
  86. package/lib/esm/utils/linkedError.d.ts +35 -0
  87. package/lib/esm/utils/linkedError.js +52 -0
  88. package/lib/esm/utils/linkedError.js.map +1 -0
  89. package/lib/esm/utils/registryCache.d.ts +15 -0
  90. package/lib/esm/utils/registryCache.js +50 -0
  91. package/lib/esm/utils/registryCache.js.map +1 -0
  92. package/lib/esm/utils/sharedState.d.ts +25 -0
  93. package/lib/esm/utils/sharedState.js +34 -0
  94. package/lib/esm/utils/sharedState.js.map +1 -0
  95. package/lib/esm/utils/unresolvedShape.d.ts +42 -0
  96. package/lib/esm/utils/unresolvedShape.js +68 -0
  97. package/lib/esm/utils/unresolvedShape.js.map +1 -0
  98. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { isSetModificationValue, } from './QueryFactory.js';
2
2
  import { isExpressionNode, resolveExpressionRefs } from '../expressions/ExpressionNode.js';
3
3
  import { createTraversalResolver } from './IRLower.js';
4
+ import { attachCatalog } from '../utils/ShapeClass.js';
4
5
  /**
5
6
  * Throws if any field of an upsert carries an expression. Named per offending property so
6
7
  * the caller is not left decoding an unbound-variable mystery further down the pipeline.
@@ -88,19 +89,19 @@ const toNodeData = (description, collector) => {
88
89
  };
89
90
  /** Builds an IRCreateMutation from a create factory's internal description. */
90
91
  export const buildCanonicalCreateMutationIR = (query) => {
91
- return {
92
+ return attachCatalog({
92
93
  kind: 'create',
93
94
  shape: query.shape.id,
94
95
  data: toNodeData(query.description),
95
- };
96
+ });
96
97
  };
97
98
  /** Builds an IRUpdateMutation from an update factory's internal description. */
98
99
  export const buildCanonicalUpdateMutationIR = (query) => {
99
100
  const collector = createTraversalCollector();
100
101
  const data = toNodeData(query.updates, collector);
101
- return Object.assign({ kind: 'update', shape: query.shape.id, id: query.id, data }, (collector.patterns.length > 0
102
+ return attachCatalog(Object.assign({ kind: 'update', shape: query.shape.id, id: query.id, data }, (collector.patterns.length > 0
102
103
  ? { traversalPatterns: collector.patterns }
103
- : {}));
104
+ : {})));
104
105
  };
105
106
  /**
106
107
  * Builds an IRUpsertMutation — an update that also asserts the node's type, so it is
@@ -116,40 +117,40 @@ export const buildCanonicalUpsertMutationIR = (query) => {
116
117
  assertNoExpressionFields(query.updates, query.shape.id);
117
118
  const collector = createTraversalCollector();
118
119
  const data = toNodeData(query.updates, collector);
119
- return Object.assign({ kind: 'upsert', shape: query.shape.id, id: query.id, data }, (collector.patterns.length > 0
120
+ return attachCatalog(Object.assign({ kind: 'upsert', shape: query.shape.id, id: query.id, data }, (collector.patterns.length > 0
120
121
  ? { traversalPatterns: collector.patterns }
121
- : {}));
122
+ : {})));
122
123
  };
123
124
  /** Builds an IRDeleteMutation from a delete factory's internal description. */
124
125
  export const buildCanonicalDeleteMutationIR = (query) => {
125
- return {
126
+ return attachCatalog({
126
127
  kind: 'delete',
127
128
  shape: query.shape.id,
128
129
  ids: query.ids.map((id) => ({ id: id.id })),
129
- };
130
+ });
130
131
  };
131
132
  /** Builds an IRDeleteAllMutation — delete all instances of a shape type. */
132
133
  export const buildCanonicalDeleteAllMutationIR = (query) => {
133
- return {
134
+ return attachCatalog({
134
135
  kind: 'delete_all',
135
136
  shape: query.shape.id,
136
- };
137
+ });
137
138
  };
138
139
  /** Builds an IRDeleteWhereMutation — delete instances matching a condition. */
139
140
  export const buildCanonicalDeleteWhereMutationIR = (query) => {
140
- return {
141
+ return attachCatalog({
141
142
  kind: 'delete_where',
142
143
  shape: query.shape.id,
143
144
  where: query.where,
144
145
  wherePatterns: query.wherePatterns,
145
- };
146
+ });
146
147
  };
147
148
  /** Builds an IRUpdateWhereMutation — update instances matching a condition or all. */
148
149
  export const buildCanonicalUpdateWhereMutationIR = (query) => {
149
150
  const collector = createTraversalCollector();
150
151
  const data = toNodeData(query.updates, collector);
151
- return Object.assign({ kind: 'update_where', shape: query.shape.id, data, where: query.where, wherePatterns: query.wherePatterns }, (collector.patterns.length > 0
152
+ return attachCatalog(Object.assign({ kind: 'update_where', shape: query.shape.id, data, where: query.where, wherePatterns: query.wherePatterns }, (collector.patterns.length > 0
152
153
  ? { traversalPatterns: collector.patterns }
153
- : {}));
154
+ : {})));
154
155
  };
155
156
  //# sourceMappingURL=IRMutation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"IRMutation.js","sourceRoot":"","sources":["../../../src/queries/IRMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {NodeShapeData} from '../shapes/SHACL.js';\nimport {\n type NodeDescriptionValue,\n NodeReferenceValue,\n type PropUpdateValue,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n isSetModificationValue,\n} from './QueryFactory.js';\nimport {isExpressionNode, resolveExpressionRefs} from '../expressions/ExpressionNode.js';\nimport type {\n IRCreateMutation,\n IRDeleteMutation,\n IRDeleteAllMutation,\n IRDeleteWhereMutation,\n IRUpdateWhereMutation,\n IRFieldValue,\n IRNodeData,\n IRFieldUpdate,\n IRSetModificationValue,\n IRUpdateMutation,\n IRUpsertMutation,\n IRExpression,\n IRGraphPattern,\n IRTraversalPattern,\n} from './IntermediateRepresentation.js';\nimport {createTraversalResolver} from './IRLower.js';\n\ntype CreateMutationInput = {\n shape: NodeShapeData;\n description: NodeDescriptionValue;\n};\n\ntype UpdateMutationInput = {\n id: string;\n shape: NodeShapeData;\n updates: NodeDescriptionValue;\n};\n\ntype UpsertMutationInput = {\n id: string;\n shape: NodeShapeData;\n updates: NodeDescriptionValue;\n};\n\n/**\n * Throws if any field of an upsert carries an expression. Named per offending property so\n * the caller is not left decoding an unbound-variable mystery further down the pipeline.\n */\nconst assertNoExpressionFields = (\n updates: NodeDescriptionValue,\n shapeId: string,\n): void => {\n for (const field of updates?.fields ?? []) {\n // Mirrors how `toSingleFieldValue` recognises an expression, so the guard cannot\n // drift from the lowering it is protecting.\n if (isExpressionNode(field.val)) {\n throw new Error(\n `upsert does not support expression-valued fields (property \"${field.prop.id}\" of ${shapeId}). ` +\n `An expression reads the node's current value, which does not exist when upsert creates it, ` +\n `and the property would be silently skipped. Pass a concrete value, or use ` +\n `update().for({id}) if the node is known to exist.`,\n );\n }\n }\n};\n\ntype DeleteMutationInput = {\n shape: NodeShapeData;\n ids: NodeReferenceValue[];\n};\n\nconst toNodeReference = (value: NodeReferenceValue): NodeReferenceValue => ({\n id: value.id,\n});\n\nconst toSetModification = (value: SetModificationValue): IRSetModificationValue => {\n return {\n add: value.$add\n ? value.$add.map((item) => toFieldValue(item as unknown as PropUpdateValue))\n : undefined,\n remove: value.$remove ? value.$remove.map((item) => toNodeReference(item)) : undefined,\n };\n};\n\n/** Alias used as the mutation subject for expression ref resolution. */\nconst MUTATION_SUBJECT_ALIAS = '__mutation_subject__';\n\nexport type TraversalCollector = {\n resolve: (fromAlias: string, propertyShapeId: string) => string;\n patterns: IRTraversalPattern[];\n};\n\n/**\n * Create a traversal collector for mutation expressions. Uses `__trav_N__` alias\n * prefixes to avoid collision with query aliases (a0, a1...) and the mutation\n * subject placeholder. Delegates to the shared createTraversalResolver factory.\n */\nexport function createTraversalCollector(): TraversalCollector {\n let counter = 0;\n return createTraversalResolver(\n () => `__trav_${counter++}__`,\n (from, to, property): IRTraversalPattern => ({from, property, to}),\n );\n}\n\nconst toSingleFieldValue = (\n value: SinglePropertyUpdateValue,\n collector?: TraversalCollector,\n): IRFieldValue => {\n if (value === undefined) {\n return undefined;\n }\n\n // ExpressionNode → resolve refs and extract IRExpression\n if (isExpressionNode(value)) {\n return resolveExpressionRefs(\n value.ir,\n value._refs,\n MUTATION_SUBJECT_ALIAS,\n // In mutation context, all property segments are on the subject entity.\n // For single-segment refs (e.g. p.age), the property_expr already has the property as its .property.\n // For multi-segment refs (e.g. p.bestFriend.name), this creates intermediate traversals.\n collector\n ? collector.resolve\n : (_fromAlias, _propertyShapeId) => {\n // No collector provided — multi-segment traversals cannot be resolved.\n return MUTATION_SUBJECT_ALIAS;\n },\n );\n }\n\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value instanceof Date\n ) {\n return value;\n }\n\n if ('id' in (value as NodeReferenceValue)) {\n return toNodeReference(value as NodeReferenceValue);\n }\n\n return toNodeData(value as NodeDescriptionValue);\n};\n\nconst toFieldValue = (\n value: PropUpdateValue,\n collector?: TraversalCollector,\n): IRFieldValue => {\n if (Array.isArray(value)) {\n return value.map((item) => toSingleFieldValue(item, collector));\n }\n\n if (isSetModificationValue(value)) {\n return toSetModification(value);\n }\n\n return toSingleFieldValue(value, collector);\n};\n\nconst toFieldUpdate = (\n field: NodeDescriptionValue['fields'][number],\n collector?: TraversalCollector,\n): IRFieldUpdate => {\n return {\n property: field.prop.id,\n value: toFieldValue(field.val, collector),\n };\n};\n\nconst toNodeData = (\n description: NodeDescriptionValue,\n collector?: TraversalCollector,\n): IRNodeData => {\n return {\n shape: description.shape.id,\n fields: description.fields.map((f) => toFieldUpdate(f, collector)),\n ...(description.__id ? {id: description.__id} : {}),\n };\n};\n\n/** Builds an IRCreateMutation from a create factory's internal description. */\nexport const buildCanonicalCreateMutationIR = (\n query: CreateMutationInput,\n): IRCreateMutation => {\n return {\n kind: 'create',\n shape: query.shape.id,\n data: toNodeData(query.description),\n };\n};\n\n/** Builds an IRUpdateMutation from an update factory's internal description. */\nexport const buildCanonicalUpdateMutationIR = (\n query: UpdateMutationInput,\n): IRUpdateMutation => {\n const collector = createTraversalCollector();\n const data = toNodeData(query.updates, collector);\n return {\n kind: 'update',\n shape: query.shape.id,\n id: query.id,\n data,\n ...(collector.patterns.length > 0\n ? {traversalPatterns: collector.patterns}\n : {}),\n };\n};\n\n/**\n * Builds an IRUpsertMutation — an update that also asserts the node's type, so it is\n * correct whether or not the node exists.\n *\n * Rejects expression-valued fields. An expression such as `age: p.age.plus(1)` lowers to\n * a BIND over the node's current value; when the node does not exist that ref is unbound,\n * and SPARQL drops any INSERT triple containing an unbound variable. The write would\n * report success and store nothing for that property — precisely the silent-wrong-write\n * this primitive exists to remove, so it is refused rather than documented.\n */\nexport const buildCanonicalUpsertMutationIR = (\n query: UpsertMutationInput,\n): IRUpsertMutation => {\n assertNoExpressionFields(query.updates, query.shape.id);\n const collector = createTraversalCollector();\n const data = toNodeData(query.updates, collector);\n return {\n kind: 'upsert',\n shape: query.shape.id,\n id: query.id,\n data,\n ...(collector.patterns.length > 0\n ? {traversalPatterns: collector.patterns}\n : {}),\n };\n};\n\n/** Builds an IRDeleteMutation from a delete factory's internal description. */\nexport const buildCanonicalDeleteMutationIR = (\n query: DeleteMutationInput,\n): IRDeleteMutation => {\n return {\n kind: 'delete',\n shape: query.shape.id,\n ids: query.ids.map((id) => ({id: id.id})),\n };\n};\n\ntype DeleteAllMutationInput = {\n shape: NodeShapeData;\n};\n\n/** Builds an IRDeleteAllMutation — delete all instances of a shape type. */\nexport const buildCanonicalDeleteAllMutationIR = (\n query: DeleteAllMutationInput,\n): IRDeleteAllMutation => {\n return {\n kind: 'delete_all',\n shape: query.shape.id,\n };\n};\n\ntype DeleteWhereMutationInput = {\n shape: NodeShapeData;\n where: IRExpression;\n wherePatterns: IRGraphPattern[];\n};\n\n/** Builds an IRDeleteWhereMutation — delete instances matching a condition. */\nexport const buildCanonicalDeleteWhereMutationIR = (\n query: DeleteWhereMutationInput,\n): IRDeleteWhereMutation => {\n return {\n kind: 'delete_where',\n shape: query.shape.id,\n where: query.where,\n wherePatterns: query.wherePatterns,\n };\n};\n\ntype UpdateWhereMutationInput = {\n shape: NodeShapeData;\n updates: NodeDescriptionValue;\n where?: IRExpression;\n wherePatterns?: IRGraphPattern[];\n};\n\n/** Builds an IRUpdateWhereMutation — update instances matching a condition or all. */\nexport const buildCanonicalUpdateWhereMutationIR = (\n query: UpdateWhereMutationInput,\n): IRUpdateWhereMutation => {\n const collector = createTraversalCollector();\n const data = toNodeData(query.updates, collector);\n return {\n kind: 'update_where',\n shape: query.shape.id,\n data,\n where: query.where,\n wherePatterns: query.wherePatterns,\n ...(collector.patterns.length > 0\n ? {traversalPatterns: collector.patterns}\n : {}),\n };\n};\n"]}
1
+ {"version":3,"file":"IRMutation.js","sourceRoot":"","sources":["../../../src/queries/IRMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {NodeShapeData} from '../shapes/SHACL.js';\nimport {\n type NodeDescriptionValue,\n NodeReferenceValue,\n type PropUpdateValue,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n isSetModificationValue,\n} from './QueryFactory.js';\nimport {isExpressionNode, resolveExpressionRefs} from '../expressions/ExpressionNode.js';\nimport type {\n IRCreateMutation,\n IRDeleteMutation,\n IRDeleteAllMutation,\n IRDeleteWhereMutation,\n IRUpdateWhereMutation,\n IRFieldValue,\n IRNodeData,\n IRFieldUpdate,\n IRSetModificationValue,\n IRUpdateMutation,\n IRUpsertMutation,\n IRExpression,\n IRGraphPattern,\n IRTraversalPattern,\n} from './IntermediateRepresentation.js';\nimport {createTraversalResolver} from './IRLower.js';\nimport {attachCatalog} from '../utils/ShapeClass.js';\n\ntype CreateMutationInput = {\n shape: NodeShapeData;\n description: NodeDescriptionValue;\n};\n\ntype UpdateMutationInput = {\n id: string;\n shape: NodeShapeData;\n updates: NodeDescriptionValue;\n};\n\ntype UpsertMutationInput = {\n id: string;\n shape: NodeShapeData;\n updates: NodeDescriptionValue;\n};\n\n/**\n * Throws if any field of an upsert carries an expression. Named per offending property so\n * the caller is not left decoding an unbound-variable mystery further down the pipeline.\n */\nconst assertNoExpressionFields = (\n updates: NodeDescriptionValue,\n shapeId: string,\n): void => {\n for (const field of updates?.fields ?? []) {\n // Mirrors how `toSingleFieldValue` recognises an expression, so the guard cannot\n // drift from the lowering it is protecting.\n if (isExpressionNode(field.val)) {\n throw new Error(\n `upsert does not support expression-valued fields (property \"${field.prop.id}\" of ${shapeId}). ` +\n `An expression reads the node's current value, which does not exist when upsert creates it, ` +\n `and the property would be silently skipped. Pass a concrete value, or use ` +\n `update().for({id}) if the node is known to exist.`,\n );\n }\n }\n};\n\ntype DeleteMutationInput = {\n shape: NodeShapeData;\n ids: NodeReferenceValue[];\n};\n\nconst toNodeReference = (value: NodeReferenceValue): NodeReferenceValue => ({\n id: value.id,\n});\n\nconst toSetModification = (value: SetModificationValue): IRSetModificationValue => {\n return {\n add: value.$add\n ? value.$add.map((item) => toFieldValue(item as unknown as PropUpdateValue))\n : undefined,\n remove: value.$remove ? value.$remove.map((item) => toNodeReference(item)) : undefined,\n };\n};\n\n/** Alias used as the mutation subject for expression ref resolution. */\nconst MUTATION_SUBJECT_ALIAS = '__mutation_subject__';\n\nexport type TraversalCollector = {\n resolve: (fromAlias: string, propertyShapeId: string) => string;\n patterns: IRTraversalPattern[];\n};\n\n/**\n * Create a traversal collector for mutation expressions. Uses `__trav_N__` alias\n * prefixes to avoid collision with query aliases (a0, a1...) and the mutation\n * subject placeholder. Delegates to the shared createTraversalResolver factory.\n */\nexport function createTraversalCollector(): TraversalCollector {\n let counter = 0;\n return createTraversalResolver(\n () => `__trav_${counter++}__`,\n (from, to, property): IRTraversalPattern => ({from, property, to}),\n );\n}\n\nconst toSingleFieldValue = (\n value: SinglePropertyUpdateValue,\n collector?: TraversalCollector,\n): IRFieldValue => {\n if (value === undefined) {\n return undefined;\n }\n\n // ExpressionNode → resolve refs and extract IRExpression\n if (isExpressionNode(value)) {\n return resolveExpressionRefs(\n value.ir,\n value._refs,\n MUTATION_SUBJECT_ALIAS,\n // In mutation context, all property segments are on the subject entity.\n // For single-segment refs (e.g. p.age), the property_expr already has the property as its .property.\n // For multi-segment refs (e.g. p.bestFriend.name), this creates intermediate traversals.\n collector\n ? collector.resolve\n : (_fromAlias, _propertyShapeId) => {\n // No collector provided — multi-segment traversals cannot be resolved.\n return MUTATION_SUBJECT_ALIAS;\n },\n );\n }\n\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value instanceof Date\n ) {\n return value;\n }\n\n if ('id' in (value as NodeReferenceValue)) {\n return toNodeReference(value as NodeReferenceValue);\n }\n\n return toNodeData(value as NodeDescriptionValue);\n};\n\nconst toFieldValue = (\n value: PropUpdateValue,\n collector?: TraversalCollector,\n): IRFieldValue => {\n if (Array.isArray(value)) {\n return value.map((item) => toSingleFieldValue(item, collector));\n }\n\n if (isSetModificationValue(value)) {\n return toSetModification(value);\n }\n\n return toSingleFieldValue(value, collector);\n};\n\nconst toFieldUpdate = (\n field: NodeDescriptionValue['fields'][number],\n collector?: TraversalCollector,\n): IRFieldUpdate => {\n return {\n property: field.prop.id,\n value: toFieldValue(field.val, collector),\n };\n};\n\nconst toNodeData = (\n description: NodeDescriptionValue,\n collector?: TraversalCollector,\n): IRNodeData => {\n return {\n shape: description.shape.id,\n fields: description.fields.map((f) => toFieldUpdate(f, collector)),\n ...(description.__id ? {id: description.__id} : {}),\n };\n};\n\n/** Builds an IRCreateMutation from a create factory's internal description. */\nexport const buildCanonicalCreateMutationIR = (\n query: CreateMutationInput,\n): IRCreateMutation => {\n return attachCatalog({\n kind: 'create',\n shape: query.shape.id,\n data: toNodeData(query.description),\n });\n};\n\n/** Builds an IRUpdateMutation from an update factory's internal description. */\nexport const buildCanonicalUpdateMutationIR = (\n query: UpdateMutationInput,\n): IRUpdateMutation => {\n const collector = createTraversalCollector();\n const data = toNodeData(query.updates, collector);\n return attachCatalog({\n kind: 'update',\n shape: query.shape.id,\n id: query.id,\n data,\n ...(collector.patterns.length > 0\n ? {traversalPatterns: collector.patterns}\n : {}),\n });\n};\n\n/**\n * Builds an IRUpsertMutation — an update that also asserts the node's type, so it is\n * correct whether or not the node exists.\n *\n * Rejects expression-valued fields. An expression such as `age: p.age.plus(1)` lowers to\n * a BIND over the node's current value; when the node does not exist that ref is unbound,\n * and SPARQL drops any INSERT triple containing an unbound variable. The write would\n * report success and store nothing for that property — precisely the silent-wrong-write\n * this primitive exists to remove, so it is refused rather than documented.\n */\nexport const buildCanonicalUpsertMutationIR = (\n query: UpsertMutationInput,\n): IRUpsertMutation => {\n assertNoExpressionFields(query.updates, query.shape.id);\n const collector = createTraversalCollector();\n const data = toNodeData(query.updates, collector);\n return attachCatalog({\n kind: 'upsert',\n shape: query.shape.id,\n id: query.id,\n data,\n ...(collector.patterns.length > 0\n ? {traversalPatterns: collector.patterns}\n : {}),\n });\n};\n\n/** Builds an IRDeleteMutation from a delete factory's internal description. */\nexport const buildCanonicalDeleteMutationIR = (\n query: DeleteMutationInput,\n): IRDeleteMutation => {\n return attachCatalog({\n kind: 'delete',\n shape: query.shape.id,\n ids: query.ids.map((id) => ({id: id.id})),\n });\n};\n\ntype DeleteAllMutationInput = {\n shape: NodeShapeData;\n};\n\n/** Builds an IRDeleteAllMutation — delete all instances of a shape type. */\nexport const buildCanonicalDeleteAllMutationIR = (\n query: DeleteAllMutationInput,\n): IRDeleteAllMutation => {\n return attachCatalog({\n kind: 'delete_all',\n shape: query.shape.id,\n });\n};\n\ntype DeleteWhereMutationInput = {\n shape: NodeShapeData;\n where: IRExpression;\n wherePatterns: IRGraphPattern[];\n};\n\n/** Builds an IRDeleteWhereMutation — delete instances matching a condition. */\nexport const buildCanonicalDeleteWhereMutationIR = (\n query: DeleteWhereMutationInput,\n): IRDeleteWhereMutation => {\n return attachCatalog({\n kind: 'delete_where',\n shape: query.shape.id,\n where: query.where,\n wherePatterns: query.wherePatterns,\n });\n};\n\ntype UpdateWhereMutationInput = {\n shape: NodeShapeData;\n updates: NodeDescriptionValue;\n where?: IRExpression;\n wherePatterns?: IRGraphPattern[];\n};\n\n/** Builds an IRUpdateWhereMutation — update instances matching a condition or all. */\nexport const buildCanonicalUpdateWhereMutationIR = (\n query: UpdateWhereMutationInput,\n): IRUpdateWhereMutation => {\n const collector = createTraversalCollector();\n const data = toNodeData(query.updates, collector);\n return attachCatalog({\n kind: 'update_where',\n shape: query.shape.id,\n data,\n where: query.where,\n wherePatterns: query.wherePatterns,\n ...(collector.patterns.length > 0\n ? {traversalPatterns: collector.patterns}\n : {}),\n });\n};\n"]}
@@ -16,6 +16,7 @@ import { isExpressionNode } from '../expressions/ExpressionNode.js';
16
16
  import { createProxiedPathBuilder } from './ProxiedPathBuilder.js';
17
17
  import { asContextRef } from './QueryContext.js';
18
18
  import { assertValid, undeclaredPropertyMessage, } from '../shapes/validation.js';
19
+ import { topLevelDetails, unresolvedShapeError, unresolvedValueShapeError } from '../utils/unresolvedShape.js';
19
20
  export class MutationQueryFactory extends QueryFactory {
20
21
  /**
21
22
  * Normalize raw create/update data into a {@link NodeDescriptionValue} — the
@@ -50,7 +51,7 @@ export class MutationQueryFactory extends QueryFactory {
50
51
  // fail here with "Shape class not found".
51
52
  const shapeClass = shape.id ? resolveShapeConstructor(shape.id) : undefined;
52
53
  if (!shapeClass) {
53
- throw new Error(`Shape class not found for ${shape.id || 'unknown'}`);
54
+ throw unresolvedShapeError(`Shape class not found for ${shape.id || 'unknown'}`, topLevelDetails(shape.id || ''));
54
55
  }
55
56
  const proxy = createProxiedPathBuilder(shapeClass);
56
57
  const result = obj(proxy);
@@ -215,7 +216,7 @@ export class MutationQueryFactory extends QueryFactory {
215
216
  const shapeClass = resolveShapeConstructor(propShape.valueShape);
216
217
  valueShape = (shapeClass === null || shapeClass === void 0 ? void 0 : shapeClass.shape) || null;
217
218
  if (!valueShape) {
218
- throw new Error(`Shape class not found for ${propShape.valueShape.id}`);
219
+ throw unresolvedValueShapeError(`Shape class not found for ${propShape.valueShape.id}`, propShape);
219
220
  }
220
221
  }
221
222
  //pass the value shape of the property as the node shape of this value
@@ -1 +1 @@
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"]}
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';\nimport {topLevelDetails, unresolvedShapeError, unresolvedValueShapeError} from '../utils/unresolvedShape.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 unresolvedShapeError(\n `Shape class not found for ${shape.id || 'unknown'}`,\n topLevelDetails(shape.id || ''),\n );\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 unresolvedValueShapeError(\n `Shape class not found for ${propShape.valueShape.id}`,\n propShape,\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"]}
@@ -24,7 +24,7 @@ import { isSetModificationValue, } from './QueryFactory.js';
24
24
  import { getPropertyShape } from '../shapes/nodeShapeData.js';
25
25
  import { ExpressionNode, isExpressionNode } from '../expressions/ExpressionNode.js';
26
26
  import { PendingQueryContext } from './QueryContext.js';
27
- import { getShapeClass, resolveShapeConstructor } from '../utils/ShapeClass.js';
27
+ import { resolveShapeConstructor, getQueryShapeClass } from '../utils/ShapeClass.js';
28
28
  import { encodeValueExpr, decodeValueExpr, } from './DslJsonExpression.js';
29
29
  /** Reserved node-data keys (not property labels). */
30
30
  const NODE_ID_KEY = '__id';
@@ -36,7 +36,7 @@ const NODE_SHAPE_KEY = '__shape';
36
36
  export function valueShapeOf(prop) {
37
37
  var _a, _b;
38
38
  const id = (_a = prop === null || prop === void 0 ? void 0 : prop.valueShape) === null || _a === void 0 ? void 0 : _a.id;
39
- return id ? (_b = getShapeClass(id)) === null || _b === void 0 ? void 0 : _b.shape : undefined;
39
+ return id ? (_b = getQueryShapeClass(id)) === null || _b === void 0 ? void 0 : _b.shape : undefined;
40
40
  }
41
41
  /** Encode a single (non-array, non-setMod) property value. `prop` gives the nested-node shape. */
42
42
  function encodeSingleValue(value, prop) {
@@ -1 +1 @@
1
- {"version":3,"file":"MutationSerialization.js","sourceRoot":"","sources":["../../../src/queries/MutationSerialization.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAML,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AAGlF,OAAO,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAC,aAAa,EAAE,uBAAuB,EAAC,MAAM,wBAAwB,CAAC;AAG9E,OAAO,EACL,eAAe,EACf,eAAe,GAEhB,MAAM,wBAAwB,CAAC;AAsChC,qDAAqD;AACrD,MAAM,WAAW,GAAG,MAAM,CAAC;AAC3B,MAAM,cAAc,GAAG,SAAS,CAAC;AAmDjC,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF,6FAA6F;AAC7F,MAAM,UAAU,YAAY,CAAC,IAAwB;;IACnD,MAAM,EAAE,GAAG,MAAC,IAA+C,aAA/C,IAAI,uBAAJ,IAAI,CAA6C,UAAU,0CAAE,EAAE,CAAC;IAC5E,OAAO,EAAE,CAAC,CAAC,CAAC,MAAA,aAAa,CAAC,EAAE,CAAC,0CAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACnD,CAAC;AAED,kGAAkG;AAClG,SAAS,iBAAiB,CACxB,KAAgC,EAChC,IAAwB;IAExB,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC;IACjD,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,2EAA2E;QAC3E,OAAO,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,CAAsB,CAAC;IACrE,CAAC;IACD,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,EAAC,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,EAAC,CAAC;IACjE,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,SAAS,EAC1B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,yEAAyE;QACzE,oFAAoF;QACpF,IAAI,KAAK,YAAY,mBAAmB,EAAE,CAAC;YACzC,OAAO,EAAC,MAAM,EAAE,KAAK,CAAC,WAAW,EAAC,CAAC;QACrC,CAAC;QACD,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;YACtB,qFAAqF;YACrF,OAAO,cAAc,CAAC,KAA6B,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,IAAI,IAAI,KAAK;YAAE,OAAO,EAAC,KAAK,EAAG,KAA4B,CAAC,EAAE,EAAC,CAAC;IACtE,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,WAAW,CACzB,KAAsB,EACtB,IAAwB;IAExB,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAC,CAAC;IACjE,CAAC;IACD,IAAI,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,KAA6B,CAAC;QAC1C,MAAM,IAAI,GAAyD,EAAE,CAAC;QACtE,IAAI,GAAG,CAAC,IAAI;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAoB,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1F,IAAI,GAAG,CAAC,OAAO;YAAE,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,iBAAiB,CAAC,KAAkC,EAAE,IAAI,CAAC,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,IAA0B,EAC1B,aAA6B;IAE7B,MAAM,IAAI,GAAyB,EAAE,CAAC;IACtC,IAAI,IAAI,CAAC,IAAI;QAAE,IAAI,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;IAC7C,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,aAAa,CAAC,EAAE,EAAE,CAAC;QACzD,IAAI,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IACvC,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gFAAgF;AAChF,gEAAgE;AAChE,gFAAgF;AAEhF,iFAAiF;AACjF,sEAAsE;AACtE,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,IAAI,YAAY,GAAG,CAAC,CAAC;AAErB;;;;GAIG;AACH,SAAS,gBAAgB,CACvB,IAAuB,EACvB,YAAuC,EACvC,IAAwB;IAExB,IAAI,EAAE,YAAY,GAAG,gBAAgB,EAAE,CAAC;QACtC,YAAY,GAAG,CAAC,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,CAAC;QACH,OAAO,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;IACzD,CAAC;YAAS,CAAC;QACT,YAAY,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAuB,EACvB,YAAuC,EACvC,IAAwB;;IAExB,wBAAwB;IACxB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,EAAC,EAAE,EAAE,IAAI,EAAC,GAAG,eAAe,CAAC,IAAoB,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC;QAC5F,OAAO,IAAI,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,CAAC,sBAAsB;IACjE,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACpC,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAW,CAAC,CAAC;IACxD,yEAAyE;IACzE,sEAAsE;IACtE,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,IAAI,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAW,CAAC,CAAC;IACrE,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,EAAC,CAAC;IACtC,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,OAAQ,CAAC,CAAC,OAAO,CAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,MAAM,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAClC,8DAA8D;QAC9D,MAAM,GAAG,GAA+C,EAAE,CAAC;QAC3D,IAAI,CAAC,CAAC,MAAM,CAAC;YAAE,GAAG,CAAC,GAAG,GAAI,CAAC,CAAC,MAAM,CAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;QAChH,IAAI,CAAC,CAAC,SAAS,CAAC;YAAE,GAAG,CAAC,MAAM,GAAI,CAAC,CAAC,SAAS,CAAc,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,EAAE,EAAC,CAAC,CAAC,CAAC;QAC9E,OAAO,GAAG,CAAC;IACb,CAAC;IACD,qDAAqD;IACrD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,MAAM,EAAC,EAAE,EAAE,IAAI,EAAC,GAAG,eAAe,CAAC,IAAoB,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC;QAC5F,OAAO,IAAI,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,mDAAmD;IACnD,OAAO,yBAAyB,CAAC,CAAyB,EAAE,MAAA,YAAY,CAAC,IAAI,CAAC,mCAAI,YAAY,CAAC,CAAC;AAClG,CAAC;AAED;;;;;;GAMG;AACH;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,OAAe;IAC5C,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,UAAU,OAAO,qGAAqG,CACvH,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,yBAAyB,CAChC,IAA0B,EAC1B,KAAgC;IAEhC,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;IACrC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,GAAG,CAAC,KAAK,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC5E,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAgC;IAC3D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAA0B,EAC1B,KAAqB;IAErB,MAAM,SAAS,GACb,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,QAAQ;QACtC,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,cAAc,CAAW,CAAC,CAAC,KAAK;QAC7D,CAAC,CAAC,KAAK,CAAC;IACZ,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,IAAI,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,QAAQ;QAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;IACtE,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,cAAc,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QACjF,+DAA+D;QAC/D,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,WAAW;YAAE,SAAS;QAClF,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,GAAG,CAAC,GAAG,CAAC,GAAG,gBAAgB,CAAC,GAAwB,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n\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"]}
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 {resolveShapeConstructor, getQueryShapeClass} 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 ? getQueryShapeClass(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"]}
@@ -1,5 +1,6 @@
1
1
  import { getPropertyShape } from '../shapes/nodeShapeData.js';
2
- import { getShapeClass } from '../utils/ShapeClass.js';
2
+ import { getQueryShapeClass } from '../utils/ShapeClass.js';
3
+ import { unresolvedValueShapeError } from '../utils/unresolvedShape.js';
3
4
  /**
4
5
  * A value object representing a sequence of property traversals from a root shape.
5
6
  *
@@ -66,9 +67,9 @@ export function walkPropertyPath(shape, path) {
66
67
  if (!propertyShape.valueShape) {
67
68
  throw new Error(`Property '${label}' on shape '${currentShape.label || currentShape.id}' has no valueShape; cannot traverse further in path '${path}'`);
68
69
  }
69
- const shapeClass = getShapeClass(propertyShape.valueShape);
70
+ const shapeClass = getQueryShapeClass(propertyShape.valueShape);
70
71
  if (!shapeClass || !shapeClass.shape) {
71
- throw new Error(`Cannot resolve valueShape '${propertyShape.valueShape.id}' for property '${label}' in path '${path}'`);
72
+ throw unresolvedValueShapeError(`Cannot resolve valueShape '${propertyShape.valueShape.id}' for property '${label}' in path '${path}'`, propertyShape, currentShape);
72
73
  }
73
74
  currentShape = shapeClass.shape;
74
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PropertyPath.js","sourceRoot":"","sources":["../../../src/queries/PropertyPath.ts"],"names":[],"mappings":"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","sourcesContent":["import type {PropertyShapeData, NodeShapeData} from '../shapes/SHACL.js';\nimport {getPropertyShape} from '../shapes/nodeShapeData.js';\nimport {getShapeClass} from '../utils/ShapeClass.js';\n\n/**\n * A value object representing a sequence of property traversals from a root shape.\n *\n * Each segment is a PropertyShapeData representing one hop in the traversal.\n * For example, `friends.name` on PersonShape produces a PropertyPath with\n * two segments: [friendsPropertyShape, namePropertyShape].\n *\n * This is used by FieldSet and QueryBuilder to describe which properties\n * to select/filter, independent of proxy tracing.\n */\nexport class PropertyPath {\n constructor(\n readonly rootShape: NodeShapeData,\n readonly segments: readonly PropertyShapeData[],\n ) {}\n\n /** Append a property traversal hop, returning a new PropertyPath. */\n prop(property: PropertyShapeData): PropertyPath {\n return new PropertyPath(this.rootShape, [...this.segments, property]);\n }\n\n /** The terminal (leaf) property of this path. */\n get terminal(): PropertyShapeData | undefined {\n return this.segments[this.segments.length - 1];\n }\n\n /** The depth (number of hops) of this path. */\n get depth(): number {\n return this.segments.length;\n }\n\n /** String representation using property labels joined by dots. */\n toString(): string {\n return this.segments.map((s) => s.label).join('.');\n }\n\n /** Two PropertyPaths are equal if they have the same root shape and same segment sequence. */\n equals(other: PropertyPath): boolean {\n if (this.rootShape.id !== other.rootShape.id) return false;\n if (this.segments.length !== other.segments.length) return false;\n return this.segments.every((s, i) => s.id === other.segments[i].id);\n }\n}\n\n/**\n * Resolve a dot-separated property path string into a PropertyPath.\n *\n * Walks the shape's property shapes by label, following valueShape references\n * to traverse into nested shapes.\n *\n * Example: `walkPropertyPath(PersonShape, 'friends.name')` resolves\n * [friendsPropertyShape, namePropertyShape].\n *\n * @throws If any segment cannot be resolved.\n */\nexport function walkPropertyPath(shape: NodeShapeData, path: string): PropertyPath {\n const labels = path.split('.');\n const segments: PropertyShapeData[] = [];\n let currentShape = shape;\n\n for (const label of labels) {\n const propertyShape = getPropertyShape(currentShape, label);\n if (!propertyShape) {\n throw new Error(\n `Property '${label}' not found on shape '${currentShape.label || currentShape.id}' while resolving path '${path}'`,\n );\n }\n segments.push(propertyShape);\n\n // If there are more segments to resolve, follow the valueShape\n if (segments.length < labels.length) {\n if (!propertyShape.valueShape) {\n throw new Error(\n `Property '${label}' on shape '${currentShape.label || currentShape.id}' has no valueShape; cannot traverse further in path '${path}'`,\n );\n }\n const shapeClass = getShapeClass(propertyShape.valueShape);\n if (!shapeClass || !shapeClass.shape) {\n throw new Error(\n `Cannot resolve valueShape '${propertyShape.valueShape.id}' for property '${label}' in path '${path}'`,\n );\n }\n currentShape = shapeClass.shape;\n }\n }\n\n return new PropertyPath(shape, segments);\n}\n"]}
1
+ {"version":3,"file":"PropertyPath.js","sourceRoot":"","sources":["../../../src/queries/PropertyPath.ts"],"names":[],"mappings":"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","sourcesContent":["import type {PropertyShapeData, NodeShapeData} from '../shapes/SHACL.js';\nimport {getPropertyShape} from '../shapes/nodeShapeData.js';\nimport {getQueryShapeClass} from '../utils/ShapeClass.js';\nimport {unresolvedValueShapeError} from '../utils/unresolvedShape.js';\n\n/**\n * A value object representing a sequence of property traversals from a root shape.\n *\n * Each segment is a PropertyShapeData representing one hop in the traversal.\n * For example, `friends.name` on PersonShape produces a PropertyPath with\n * two segments: [friendsPropertyShape, namePropertyShape].\n *\n * This is used by FieldSet and QueryBuilder to describe which properties\n * to select/filter, independent of proxy tracing.\n */\nexport class PropertyPath {\n constructor(\n readonly rootShape: NodeShapeData,\n readonly segments: readonly PropertyShapeData[],\n ) {}\n\n /** Append a property traversal hop, returning a new PropertyPath. */\n prop(property: PropertyShapeData): PropertyPath {\n return new PropertyPath(this.rootShape, [...this.segments, property]);\n }\n\n /** The terminal (leaf) property of this path. */\n get terminal(): PropertyShapeData | undefined {\n return this.segments[this.segments.length - 1];\n }\n\n /** The depth (number of hops) of this path. */\n get depth(): number {\n return this.segments.length;\n }\n\n /** String representation using property labels joined by dots. */\n toString(): string {\n return this.segments.map((s) => s.label).join('.');\n }\n\n /** Two PropertyPaths are equal if they have the same root shape and same segment sequence. */\n equals(other: PropertyPath): boolean {\n if (this.rootShape.id !== other.rootShape.id) return false;\n if (this.segments.length !== other.segments.length) return false;\n return this.segments.every((s, i) => s.id === other.segments[i].id);\n }\n}\n\n/**\n * Resolve a dot-separated property path string into a PropertyPath.\n *\n * Walks the shape's property shapes by label, following valueShape references\n * to traverse into nested shapes.\n *\n * Example: `walkPropertyPath(PersonShape, 'friends.name')` resolves\n * [friendsPropertyShape, namePropertyShape].\n *\n * @throws If any segment cannot be resolved.\n */\nexport function walkPropertyPath(shape: NodeShapeData, path: string): PropertyPath {\n const labels = path.split('.');\n const segments: PropertyShapeData[] = [];\n let currentShape = shape;\n\n for (const label of labels) {\n const propertyShape = getPropertyShape(currentShape, label);\n if (!propertyShape) {\n throw new Error(\n `Property '${label}' not found on shape '${currentShape.label || currentShape.id}' while resolving path '${path}'`,\n );\n }\n segments.push(propertyShape);\n\n // If there are more segments to resolve, follow the valueShape\n if (segments.length < labels.length) {\n if (!propertyShape.valueShape) {\n throw new Error(\n `Property '${label}' on shape '${currentShape.label || currentShape.id}' has no valueShape; cannot traverse further in path '${path}'`,\n );\n }\n const shapeClass = getQueryShapeClass(propertyShape.valueShape);\n if (!shapeClass || !shapeClass.shape) {\n throw unresolvedValueShapeError(\n `Cannot resolve valueShape '${propertyShape.valueShape.id}' for property '${label}' in path '${path}'`,\n propertyShape,\n currentShape,\n );\n }\n currentShape = shapeClass.shape;\n }\n }\n\n return new PropertyPath(shape, segments);\n}\n"]}
@@ -9,6 +9,7 @@ import { FieldSet, type FieldSetFieldJSON } from './FieldSet.js';
9
9
  import { PendingQueryContext } from './QueryContext.js';
10
10
  import { type ContextRefJSON } from './ContextRef.js';
11
11
  import { type WherePathJSON, type SortByPathJSON, type RawMinusEntryJSON } from './QueryBuilderSerialization.js';
12
+ import type { ShapeCatalog } from '../utils/ShapeCatalog.js';
12
13
  import type { LiveListener, LiveQuery, LiveQueryOptions } from '../live/LiveQueryStore.js';
13
14
  /** JSON representation of a SelectBuilder. */
14
15
  export type QueryBuilderJSON = {
@@ -62,6 +63,7 @@ export declare class SelectBuilder<S extends Shape = Shape, R = any, Result = an
62
63
  private readonly _where?;
63
64
  private readonly _sortBy?;
64
65
  private readonly _rawMinusEntries?;
66
+ private readonly _catalog;
65
67
  private constructor();
66
68
  /** Create a shallow clone with overrides. */
67
69
  private clone;
@@ -307,6 +309,11 @@ export declare class SelectBuilder<S extends Shape = Shape, R = any, Result = an
307
309
  readonly __queryKind: "select";
308
310
  /** The shape this query targets — the routing key datasets/`LinkedStorage` use. */
309
311
  get shape(): NodeShapeData;
312
+ /**
313
+ * The catalog this builder resolves shapes in — captured when it was built, kept by
314
+ * every derived builder. Undefined = the global registry. Never serialized.
315
+ */
316
+ get catalog(): ShapeCatalog | undefined;
310
317
  /**
311
318
  * Execute the query and return results.
312
319
  *