@_linked/core 1.2.1 → 2.0.0-next.20260310082533

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 (169) hide show
  1. package/CHANGELOG.md +117 -6
  2. package/README.md +209 -14
  3. package/lib/cjs/index.d.ts +10 -2
  4. package/lib/cjs/index.js +33 -8
  5. package/lib/cjs/index.js.map +1 -1
  6. package/lib/cjs/interfaces/IQuadStore.d.ts +1 -1
  7. package/lib/cjs/package.d.ts +1 -1
  8. package/lib/cjs/queries/CreateBuilder.d.ts +38 -0
  9. package/lib/cjs/queries/CreateBuilder.js +100 -0
  10. package/lib/cjs/queries/CreateBuilder.js.map +1 -0
  11. package/lib/cjs/queries/CreateQuery.d.ts +3 -3
  12. package/lib/cjs/queries/CreateQuery.js.map +1 -1
  13. package/lib/cjs/queries/DeleteBuilder.d.ts +39 -0
  14. package/lib/cjs/queries/DeleteBuilder.js +85 -0
  15. package/lib/cjs/queries/DeleteBuilder.js.map +1 -0
  16. package/lib/cjs/queries/DeleteQuery.d.ts +3 -3
  17. package/lib/cjs/queries/DeleteQuery.js.map +1 -1
  18. package/lib/cjs/queries/FieldSet.d.ts +203 -0
  19. package/lib/cjs/queries/FieldSet.js +533 -0
  20. package/lib/cjs/queries/FieldSet.js.map +1 -0
  21. package/lib/cjs/queries/IRDesugar.d.ts +13 -8
  22. package/lib/cjs/queries/IRDesugar.js +143 -132
  23. package/lib/cjs/queries/IRDesugar.js.map +1 -1
  24. package/lib/cjs/queries/IRLower.js +1 -0
  25. package/lib/cjs/queries/IRLower.js.map +1 -1
  26. package/lib/cjs/queries/IntermediateRepresentation.d.ts +1 -0
  27. package/lib/cjs/queries/MutationQuery.d.ts +1 -1
  28. package/lib/cjs/queries/MutationQuery.js +1 -6
  29. package/lib/cjs/queries/MutationQuery.js.map +1 -1
  30. package/lib/cjs/queries/PropertyPath.d.ts +38 -0
  31. package/lib/cjs/queries/PropertyPath.js +82 -0
  32. package/lib/cjs/queries/PropertyPath.js.map +1 -0
  33. package/lib/cjs/queries/ProxiedPathBuilder.d.ts +14 -0
  34. package/lib/cjs/queries/ProxiedPathBuilder.js +29 -0
  35. package/lib/cjs/queries/ProxiedPathBuilder.js.map +1 -0
  36. package/lib/cjs/queries/QueryBuilder.d.ts +141 -0
  37. package/lib/cjs/queries/QueryBuilder.js +334 -0
  38. package/lib/cjs/queries/QueryBuilder.js.map +1 -0
  39. package/lib/cjs/queries/SelectQuery.d.ts +60 -134
  40. package/lib/cjs/queries/SelectQuery.js +67 -526
  41. package/lib/cjs/queries/SelectQuery.js.map +1 -1
  42. package/lib/cjs/queries/UpdateBuilder.d.ts +37 -0
  43. package/lib/cjs/queries/UpdateBuilder.js +84 -0
  44. package/lib/cjs/queries/UpdateBuilder.js.map +1 -0
  45. package/lib/cjs/queries/UpdateQuery.d.ts +3 -3
  46. package/lib/cjs/queries/UpdateQuery.js.map +1 -1
  47. package/lib/cjs/queries/WhereCondition.d.ts +18 -0
  48. package/lib/cjs/queries/WhereCondition.js +3 -0
  49. package/lib/cjs/queries/WhereCondition.js.map +1 -0
  50. package/lib/cjs/queries/queryDispatch.d.ts +20 -0
  51. package/lib/cjs/queries/queryDispatch.js +15 -0
  52. package/lib/cjs/queries/queryDispatch.js.map +1 -0
  53. package/lib/cjs/queries/resolveShape.d.ts +10 -0
  54. package/lib/cjs/queries/resolveShape.js +23 -0
  55. package/lib/cjs/queries/resolveShape.js.map +1 -0
  56. package/lib/cjs/shapes/SHACL.js +7 -5
  57. package/lib/cjs/shapes/SHACL.js.map +1 -1
  58. package/lib/cjs/shapes/Shape.d.ts +33 -52
  59. package/lib/cjs/shapes/Shape.js +36 -50
  60. package/lib/cjs/shapes/Shape.js.map +1 -1
  61. package/lib/cjs/sparql/SparqlAlgebra.d.ts +6 -1
  62. package/lib/cjs/sparql/algebraToString.js +10 -0
  63. package/lib/cjs/sparql/algebraToString.js.map +1 -1
  64. package/lib/cjs/sparql/irToAlgebra.js +6 -2
  65. package/lib/cjs/sparql/irToAlgebra.js.map +1 -1
  66. package/lib/cjs/test-helpers/query-capture-store.d.ts +8 -2
  67. package/lib/cjs/test-helpers/query-capture-store.js +80 -34
  68. package/lib/cjs/test-helpers/query-capture-store.js.map +1 -1
  69. package/lib/cjs/test-helpers/query-fixtures.d.ts +564 -3045
  70. package/lib/cjs/test-helpers/query-fixtures.js +59 -18
  71. package/lib/cjs/test-helpers/query-fixtures.js.map +1 -1
  72. package/lib/cjs/test-helpers/test-utils.d.ts +18 -0
  73. package/lib/cjs/test-helpers/test-utils.js +47 -0
  74. package/lib/cjs/test-helpers/test-utils.js.map +1 -0
  75. package/lib/cjs/utils/LinkedStorage.d.ts +3 -4
  76. package/lib/cjs/utils/LinkedStorage.js +12 -6
  77. package/lib/cjs/utils/LinkedStorage.js.map +1 -1
  78. package/lib/cjs/utils/Package.d.ts +8 -8
  79. package/lib/cjs/utils/Package.js.map +1 -1
  80. package/lib/cjs/utils/ShapeClass.d.ts +2 -2
  81. package/lib/cjs/utils/ShapeClass.js +4 -22
  82. package/lib/cjs/utils/ShapeClass.js.map +1 -1
  83. package/lib/esm/index.d.ts +10 -2
  84. package/lib/esm/index.js +25 -4
  85. package/lib/esm/index.js.map +1 -1
  86. package/lib/esm/interfaces/IQuadStore.d.ts +1 -1
  87. package/lib/esm/package.d.ts +1 -1
  88. package/lib/esm/queries/CreateBuilder.d.ts +38 -0
  89. package/lib/esm/queries/CreateBuilder.js +96 -0
  90. package/lib/esm/queries/CreateBuilder.js.map +1 -0
  91. package/lib/esm/queries/CreateQuery.d.ts +3 -3
  92. package/lib/esm/queries/CreateQuery.js.map +1 -1
  93. package/lib/esm/queries/DeleteBuilder.d.ts +39 -0
  94. package/lib/esm/queries/DeleteBuilder.js +81 -0
  95. package/lib/esm/queries/DeleteBuilder.js.map +1 -0
  96. package/lib/esm/queries/DeleteQuery.d.ts +3 -3
  97. package/lib/esm/queries/DeleteQuery.js.map +1 -1
  98. package/lib/esm/queries/FieldSet.d.ts +203 -0
  99. package/lib/esm/queries/FieldSet.js +529 -0
  100. package/lib/esm/queries/FieldSet.js.map +1 -0
  101. package/lib/esm/queries/IRDesugar.d.ts +13 -8
  102. package/lib/esm/queries/IRDesugar.js +143 -132
  103. package/lib/esm/queries/IRDesugar.js.map +1 -1
  104. package/lib/esm/queries/IRLower.js +1 -0
  105. package/lib/esm/queries/IRLower.js.map +1 -1
  106. package/lib/esm/queries/IntermediateRepresentation.d.ts +1 -0
  107. package/lib/esm/queries/MutationQuery.d.ts +1 -1
  108. package/lib/esm/queries/MutationQuery.js +1 -6
  109. package/lib/esm/queries/MutationQuery.js.map +1 -1
  110. package/lib/esm/queries/PropertyPath.d.ts +38 -0
  111. package/lib/esm/queries/PropertyPath.js +77 -0
  112. package/lib/esm/queries/PropertyPath.js.map +1 -0
  113. package/lib/esm/queries/ProxiedPathBuilder.d.ts +14 -0
  114. package/lib/esm/queries/ProxiedPathBuilder.js +26 -0
  115. package/lib/esm/queries/ProxiedPathBuilder.js.map +1 -0
  116. package/lib/esm/queries/QueryBuilder.d.ts +141 -0
  117. package/lib/esm/queries/QueryBuilder.js +330 -0
  118. package/lib/esm/queries/QueryBuilder.js.map +1 -0
  119. package/lib/esm/queries/SelectQuery.d.ts +60 -134
  120. package/lib/esm/queries/SelectQuery.js +61 -515
  121. package/lib/esm/queries/SelectQuery.js.map +1 -1
  122. package/lib/esm/queries/UpdateBuilder.d.ts +37 -0
  123. package/lib/esm/queries/UpdateBuilder.js +80 -0
  124. package/lib/esm/queries/UpdateBuilder.js.map +1 -0
  125. package/lib/esm/queries/UpdateQuery.d.ts +3 -3
  126. package/lib/esm/queries/UpdateQuery.js.map +1 -1
  127. package/lib/esm/queries/WhereCondition.d.ts +18 -0
  128. package/lib/esm/queries/WhereCondition.js +2 -0
  129. package/lib/esm/queries/WhereCondition.js.map +1 -0
  130. package/lib/esm/queries/queryDispatch.d.ts +20 -0
  131. package/lib/esm/queries/queryDispatch.js +11 -0
  132. package/lib/esm/queries/queryDispatch.js.map +1 -0
  133. package/lib/esm/queries/resolveShape.d.ts +10 -0
  134. package/lib/esm/queries/resolveShape.js +20 -0
  135. package/lib/esm/queries/resolveShape.js.map +1 -0
  136. package/lib/esm/shapes/SHACL.js +7 -5
  137. package/lib/esm/shapes/SHACL.js.map +1 -1
  138. package/lib/esm/shapes/Shape.d.ts +33 -52
  139. package/lib/esm/shapes/Shape.js +36 -47
  140. package/lib/esm/shapes/Shape.js.map +1 -1
  141. package/lib/esm/sparql/SparqlAlgebra.d.ts +6 -1
  142. package/lib/esm/sparql/algebraToString.js +10 -0
  143. package/lib/esm/sparql/algebraToString.js.map +1 -1
  144. package/lib/esm/sparql/irToAlgebra.js +6 -2
  145. package/lib/esm/sparql/irToAlgebra.js.map +1 -1
  146. package/lib/esm/test-helpers/query-capture-store.d.ts +8 -2
  147. package/lib/esm/test-helpers/query-capture-store.js +45 -33
  148. package/lib/esm/test-helpers/query-capture-store.js.map +1 -1
  149. package/lib/esm/test-helpers/query-fixtures.d.ts +564 -3045
  150. package/lib/esm/test-helpers/query-fixtures.js +59 -18
  151. package/lib/esm/test-helpers/query-fixtures.js.map +1 -1
  152. package/lib/esm/test-helpers/test-utils.d.ts +18 -0
  153. package/lib/esm/test-helpers/test-utils.js +41 -0
  154. package/lib/esm/test-helpers/test-utils.js.map +1 -0
  155. package/lib/esm/utils/LinkedStorage.d.ts +3 -4
  156. package/lib/esm/utils/LinkedStorage.js +12 -6
  157. package/lib/esm/utils/LinkedStorage.js.map +1 -1
  158. package/lib/esm/utils/Package.d.ts +8 -8
  159. package/lib/esm/utils/Package.js.map +1 -1
  160. package/lib/esm/utils/ShapeClass.d.ts +2 -2
  161. package/lib/esm/utils/ShapeClass.js +4 -22
  162. package/lib/esm/utils/ShapeClass.js.map +1 -1
  163. package/package.json +1 -1
  164. package/lib/cjs/queries/QueryParser.d.ts +0 -17
  165. package/lib/cjs/queries/QueryParser.js +0 -55
  166. package/lib/cjs/queries/QueryParser.js.map +0 -1
  167. package/lib/esm/queries/QueryParser.d.ts +0 -17
  168. package/lib/esm/queries/QueryParser.js +0 -51
  169. package/lib/esm/queries/QueryParser.js.map +0 -1
@@ -3,10 +3,10 @@ import { ShapeSet } from '../collections/ShapeSet.js';
3
3
  import { shacl } from '../ontologies/shacl.js';
4
4
  import { CoreSet } from '../collections/CoreSet.js';
5
5
  import { getPropertyShapeByLabel, getShapeClass } from '../utils/ShapeClass.js';
6
- import { QueryFactory } from './QueryFactory.js';
7
6
  import { xsd } from '../ontologies/xsd.js';
8
- import { buildSelectQuery, } from './IRPipeline.js';
9
- import { QueryParser } from './QueryParser.js';
7
+ import { createProxiedPathBuilder } from './ProxiedPathBuilder.js';
8
+ import { FieldSet } from './FieldSet.js';
9
+ import { PropertyPath } from './PropertyPath.js';
10
10
  const isSameRef = (a, b) => !!a && !!b && a.id === b.id;
11
11
  export var WhereMethods;
12
12
  (function (WhereMethods) {
@@ -43,16 +43,16 @@ export class QueryBuilderObject {
43
43
  return QueryShapeSet.create(originalValue, property, subject);
44
44
  }
45
45
  else if (typeof originalValue === 'string') {
46
- return new QueryString(originalValue, property, subject);
46
+ return new QueryPrimitive(originalValue, property, subject);
47
47
  }
48
48
  else if (typeof originalValue === 'number') {
49
- return new QueryNumber(originalValue, property, subject);
49
+ return new QueryPrimitive(originalValue, property, subject);
50
50
  }
51
51
  else if (typeof originalValue === 'boolean') {
52
- return new QueryBoolean(originalValue, property, subject);
52
+ return new QueryPrimitive(originalValue, property, subject);
53
53
  }
54
54
  else if (originalValue instanceof Date) {
55
- return new QueryDate(originalValue, property, subject);
55
+ return new QueryPrimitive(originalValue, property, subject);
56
56
  }
57
57
  else if (Array.isArray(originalValue)) {
58
58
  return new QueryPrimitiveSet(originalValue, property, subject);
@@ -91,23 +91,23 @@ export class QueryBuilderObject {
91
91
  if (datatype) {
92
92
  if (singleValue) {
93
93
  if (isSameRef(datatype, xsd.integer)) {
94
- return new QueryNumber(0, property, subject);
94
+ return new QueryPrimitive(0, property, subject);
95
95
  }
96
96
  else if (isSameRef(datatype, xsd.boolean)) {
97
- return new QueryBoolean(false, property, subject);
97
+ return new QueryPrimitive(false, property, subject);
98
98
  }
99
99
  else if (isSameRef(datatype, xsd.dateTime) ||
100
100
  isSameRef(datatype, xsd.date)) {
101
- return new QueryDate(new Date(), property, subject);
101
+ return new QueryPrimitive(new Date(), property, subject);
102
102
  }
103
103
  else if (isSameRef(datatype, xsd.string)) {
104
- return new QueryString('', property, subject);
104
+ return new QueryPrimitive('', property, subject);
105
105
  }
106
106
  }
107
107
  else {
108
108
  //TODO review this, do we need property & subject in both of these? currently yes, but why
109
109
  return new QueryPrimitiveSet([''], property, subject, [
110
- new QueryString('', property, subject),
110
+ new QueryPrimitive('', property, subject),
111
111
  ]);
112
112
  }
113
113
  }
@@ -134,30 +134,17 @@ export class QueryBuilderObject {
134
134
  isSameRef(property.nodeKind, shacl.BlankNodeOrLiteral)) {
135
135
  if (singleValue) {
136
136
  //default to string if no datatype is set
137
- return new QueryString('', property, subject);
137
+ return new QueryPrimitive('', property, subject);
138
138
  }
139
139
  else {
140
140
  //TODO review this, do we need property & subject in both of these? currently yes, but why
141
141
  return new QueryPrimitiveSet([''], property, subject, [
142
- new QueryString('', property, subject),
142
+ new QueryPrimitive('', property, subject),
143
143
  ]);
144
144
  }
145
145
  }
146
146
  //if an object is expected and no value shape is set, then warn
147
147
  throw Error(`No shape set for objectProperty ${property.parentNodeShape.label}.${property.label}`);
148
- // //and use a generic shape
149
- // const shapeValue = new (Shape as any)(new TestNode(path));
150
- // if (singleValue) {
151
- // return QueryShape.create(shapeValue, property, subject);
152
- // } else {
153
- // //check if shapeValue is iterable
154
- // if (!(Symbol.iterator in Object(shapeValue))) {
155
- // throw new Error(
156
- // `Property ${property.parentNodeShape.label}.${property.label} is not marked as single value (maxCount:1), but the value is not iterable`,
157
- // );
158
- // }
159
- // return QueryShapeSet.create(new ShapeSet(shapeValue), property, subject);
160
- // }
161
148
  }
162
149
  static getOriginalSource(endValue) {
163
150
  if (typeof endValue === 'undefined')
@@ -165,7 +152,7 @@ export class QueryBuilderObject {
165
152
  if (endValue instanceof QueryPrimitiveSet) {
166
153
  return new ShapeSet(endValue.contents.map((endValue) => this.getOriginalSource(endValue)));
167
154
  }
168
- if (endValue instanceof QueryString) {
155
+ if (endValue instanceof QueryPrimitive) {
169
156
  return endValue.subject
170
157
  ? this.getOriginalSource(endValue.subject)
171
158
  : endValue.originalValue;
@@ -199,7 +186,6 @@ export class QueryBuilderObject {
199
186
  return new BoundComponent(component, this);
200
187
  }
201
188
  limit(lim) {
202
- console.log(lim);
203
189
  }
204
190
  /**
205
191
  * Returns the path of properties that were requested to reach this value
@@ -227,45 +213,6 @@ export class BoundComponent extends QueryBuilderObject {
227
213
  this.originalValue = originalValue;
228
214
  this.source = source;
229
215
  }
230
- getParentQueryFactory() {
231
- let parentQuery = this.originalValue.query;
232
- if (parentQuery instanceof SelectQueryFactory) {
233
- return parentQuery;
234
- }
235
- if (typeof parentQuery === 'object') {
236
- if (Object.keys(parentQuery).length > 1) {
237
- throw new Error('Only one key is allowed to map a query to a property for linkedSetComponents');
238
- }
239
- for (let key in parentQuery) {
240
- if (parentQuery[key] instanceof SelectQueryFactory) {
241
- return parentQuery[key];
242
- }
243
- throw new Error('Unknown value type for query object. Keep to this format: {propName: Shape.query(s => ...)}');
244
- }
245
- }
246
- throw new Error('Unknown data query type. Expected a SelectQueryFactory (from Shape.query()) or an object with 1 key whose value is a SelectQueryFactory');
247
- }
248
- getPropertyPath() {
249
- let sourcePath = this.source.getPropertyPath();
250
- let requestQuery = this.getParentQueryFactory();
251
- let compSelectQuery = requestQuery.getQueryPaths();
252
- if (Array.isArray(sourcePath)) {
253
- if (Array.isArray(compSelectQuery)) {
254
- // QueryPath[] — unwrap single-element arrays for compact representation
255
- const unwrapped = compSelectQuery.length === 1
256
- ? Array.isArray(compSelectQuery[0]) && compSelectQuery[0].length === 1
257
- ? compSelectQuery[0][0]
258
- : compSelectQuery[0]
259
- : compSelectQuery;
260
- sourcePath.push(unwrapped);
261
- }
262
- else {
263
- // CustomQueryObject
264
- sourcePath.push(compSelectQuery);
265
- }
266
- }
267
- return sourcePath;
268
- }
269
216
  }
270
217
  /**
271
218
  * Converts query context to a ShapeReferenceValue
@@ -278,17 +225,40 @@ const convertQueryContext = (shape) => {
278
225
  },
279
226
  };
280
227
  };
281
- const processWhereClause = (validation, shape) => {
228
+ export const processWhereClause = (validation, shape) => {
282
229
  if (validation instanceof Function) {
283
230
  if (!shape) {
284
231
  throw new Error('Cannot process where clause without shape');
285
232
  }
286
- return new LinkedWhereQuery(shape, validation).getWherePath();
233
+ const proxy = createProxiedPathBuilder(shape);
234
+ const evaluation = validation(proxy);
235
+ return evaluation.getWherePath();
287
236
  }
288
237
  else {
289
238
  return validation.getWherePath();
290
239
  }
291
240
  };
241
+ /**
242
+ * Evaluate a sort callback through the proxy and extract a SortByPath.
243
+ * This is a standalone helper that replaces the need for the former SelectQueryFactory.sortBy().
244
+ */
245
+ export const evaluateSortCallback = (shape, sortFn, direction = 'ASC') => {
246
+ const proxy = createProxiedPathBuilder(shape);
247
+ const response = sortFn(proxy);
248
+ const nodeShape = shape.shape;
249
+ const paths = [];
250
+ if (response instanceof QueryBuilderObject || response instanceof QueryPrimitiveSet) {
251
+ paths.push(new PropertyPath(nodeShape, FieldSet.collectPropertySegments(response)));
252
+ }
253
+ else if (Array.isArray(response)) {
254
+ for (const item of response) {
255
+ if (item instanceof QueryBuilderObject) {
256
+ paths.push(new PropertyPath(nodeShape, FieldSet.collectPropertySegments(item)));
257
+ }
258
+ }
259
+ }
260
+ return { paths, direction };
261
+ };
292
262
  export class QueryShapeSet extends QueryBuilderObject {
293
263
  constructor(_originalValue, property, subject) {
294
264
  super(property, subject);
@@ -344,8 +314,6 @@ export class QueryShapeSet extends QueryBuilderObject {
344
314
  return originalShapeSet[key].bind(originalShapeSet);
345
315
  }
346
316
  else if (key !== 'then' && key !== '$$typeof') {
347
- //TODO: there is a strange bug with "then" being called, only for queries that access ShapeSets (multi value props), but I'm not sure where it comes from
348
- //hiding the warning for now in that case as it doesn't seem to affect the results
349
317
  console.warn('Could not find property shape for key ' +
350
318
  key +
351
319
  ' on shape ' +
@@ -452,10 +420,10 @@ export class QueryShapeSet extends QueryBuilderObject {
452
420
  return this.proxy;
453
421
  }
454
422
  select(subQueryFn) {
455
- let leastSpecificShape = this.getOriginalValue().getLeastSpecificShape();
456
- let subQuery = new SelectQueryFactory(leastSpecificShape, subQueryFn);
457
- subQuery.parentQueryPath = this.getPropertyPath();
458
- return subQuery;
423
+ const leastSpecificShape = this.getOriginalValue().getLeastSpecificShape();
424
+ const parentSegments = FieldSet.collectPropertySegments(this);
425
+ const fs = FieldSet.forSubSelect(leastSpecificShape, subQueryFn, parentSegments);
426
+ return fs;
459
427
  }
460
428
  selectAll() {
461
429
  let leastSpecificShape = this.getOriginalValue().getLeastSpecificShape();
@@ -487,12 +455,6 @@ export class QueryShape extends QueryBuilderObject {
487
455
  return (this.originalValue.__queryContextId ||
488
456
  this.originalValue['id']);
489
457
  }
490
- // where(validation: WhereClause<S>): this {
491
- // let nodeShape = this.originalValue.nodeShape;
492
- // this.wherePath = processWhereClause(validation, nodeShape);
493
- // //return this because after Shape.friends.where() we can call other methods of Shape.friends
494
- // return this.proxy;
495
- // }
496
458
  static create(original, property, subject) {
497
459
  let instance = new QueryShape(original, property, subject);
498
460
  let proxy = this.proxifyQueryShape(instance);
@@ -517,27 +479,9 @@ export class QueryShape extends QueryBuilderObject {
517
479
  //if not, then a method/accessor of the original shape was called
518
480
  //then check if we have indexed any property shapes with that name for this shapes NodeShape
519
481
  //NOTE: this will only work with a @linkedProperty decorator
520
- // let propertyShape = originalShape.nodeShape
521
- // .getPropertyShapes()
522
- // .find((propertyShape) => propertyShape.label === key);
523
482
  let propertyShape = getPropertyShapeByLabel(originalShape.constructor, key);
524
483
  if (propertyShape) {
525
- //generate the query shape based on the property shape
526
- // let nodeValue;
527
- // if(propertyShape.maxCount <= 1) {
528
- // nodeValue = new TestNode(propertyShape.path);
529
- // } else {
530
- // nodeValue = new NodeSet(new TestNode(propertyShape.path));
531
- // }
532
484
  return QueryBuilderObject.generatePathValue(propertyShape, target);
533
- //get the value of the property from the original shape
534
- // let value = originalShape[key];
535
- // //convert the value into a query value
536
- // return QueryBuilderObject.convertOriginal(
537
- // value,
538
- // propertyShape,
539
- // queryShape,
540
- // );
541
485
  }
542
486
  }
543
487
  if (key !== 'then' && key !== '$$typeof') {
@@ -547,8 +491,6 @@ export class QueryShape extends QueryBuilderObject {
547
491
  //https://stackoverflow.com/a/49725198/977206
548
492
  const stackLines = stack.split('\n').slice(1); //remove the "Error" line
549
493
  console.warn(`${originalShape.constructor.name}.${key.toString()} is accessed in a query, but it does not have a @linkedProperty decorator. Queries can only access decorated get/set methods. ${stackLines.join('\n')}`);
550
- // } else {
551
- // console.error('Proxy is accessed like a promise');
552
494
  }
553
495
  return originalShape[key];
554
496
  },
@@ -564,18 +506,16 @@ export class QueryShape extends QueryBuilderObject {
564
506
  }
565
507
  return QueryShape.create(newOriginal, this.property, this.subject);
566
508
  }
567
- // else return this
568
509
  return this;
569
- // return this.proxy;
570
510
  }
571
511
  equals(otherValue) {
572
512
  return new Evaluation(this, WhereMethods.EQUALS, [otherValue]);
573
513
  }
574
514
  select(subQueryFn) {
575
- let leastSpecificShape = getShapeClass(this.getOriginalValue().nodeShape.id);
576
- let subQuery = new SelectQueryFactory(leastSpecificShape, subQueryFn);
577
- subQuery.parentQueryPath = this.getPropertyPath();
578
- return subQuery;
515
+ const leastSpecificShape = getShapeClass(this.getOriginalValue().nodeShape.id);
516
+ const parentSegments = FieldSet.collectPropertySegments(this);
517
+ const fs = FieldSet.forSubSelect(leastSpecificShape, subQueryFn, parentSegments);
518
+ return fs;
579
519
  }
580
520
  selectAll() {
581
521
  let leastSpecificShape = getShapeClass(this.getOriginalValue().nodeShape.id);
@@ -651,8 +591,11 @@ export class Evaluation {
651
591
  class SetEvaluation extends Evaluation {
652
592
  }
653
593
  /**
654
- * The class that is used for when JS primitives are converted to a QueryValue
655
- * This is extended by QueryString, QueryNumber, QueryBoolean, etc
594
+ * Concrete query wrapper for JS primitive values (string, number, boolean, Date).
595
+ *
596
+ * Replaces the former abstract class + subclasses (QueryString, QueryNumber,
597
+ * QueryBoolean, QueryDate) — the type parameter T carries the primitive type,
598
+ * so separate subclasses are unnecessary.
656
599
  */
657
600
  export class QueryPrimitive extends QueryBuilderObject {
658
601
  constructor(originalValue, property, subject) {
@@ -667,21 +610,11 @@ export class QueryPrimitive extends QueryBuilderObject {
667
610
  }
668
611
  where(validation) {
669
612
  // let nodeShape = this.subject.getOriginalValue().nodeShape;
670
- this.wherePath = processWhereClause(validation, new QueryString(''));
613
+ this.wherePath = processWhereClause(validation, new QueryPrimitive(''));
671
614
  //return this because after Shape.friends.where() we can call other methods of Shape.friends
672
615
  return this;
673
616
  }
674
617
  }
675
- //@TODO: QueryString, QueryNumber, QueryBoolean, QueryDate can all be replaced with QueryPrimitive, and we can infer the original type, no need for these extra classes
676
- //UPDATE some of this has started. Query response to result conversion is using QueryPrimitive only
677
- export class QueryString extends QueryPrimitive {
678
- }
679
- export class QueryDate extends QueryPrimitive {
680
- }
681
- export class QueryNumber extends QueryPrimitive {
682
- }
683
- export class QueryBoolean extends QueryPrimitive {
684
- }
685
618
  export class QueryPrimitiveSet extends QueryBuilderObject {
686
619
  constructor(originalValue, property, subject, items) {
687
620
  super(property, subject);
@@ -700,7 +633,7 @@ export class QueryPrimitiveSet extends QueryBuilderObject {
700
633
  createNew(...args) {
701
634
  return new this.constructor(this.property, this.subject, ...args);
702
635
  }
703
- //TODO: see if we can merge these methods of QueryString and QueryPrimitiveSet and soon other things like QueryNumber
636
+ //TODO: see if we can merge these methods of QueryPrimitive and QueryPrimitiveSet
704
637
  // so that they're only defined once
705
638
  equals(other) {
706
639
  return new Evaluation(this, WhereMethods.EQUALS, [other]);
@@ -735,358 +668,7 @@ export class QueryPrimitiveSet extends QueryBuilderObject {
735
668
  //countable, resultKey
736
669
  }
737
670
  }
738
- let documentLoaded = false;
739
- let callbackStack = [];
740
- const docReady = () => {
741
- documentLoaded = true;
742
- callbackStack.forEach((callback) => callback());
743
- callbackStack = [];
744
- };
745
- if (typeof document === 'undefined' || document.readyState !== 'loading') {
746
- docReady();
747
- }
748
- else {
749
- documentLoaded = false;
750
- document.addEventListener('DOMContentLoaded', () => () => {
751
- docReady();
752
- });
753
- setTimeout(() => {
754
- if (!documentLoaded) {
755
- console.warn('⚠️ Forcing init after timeout');
756
- docReady();
757
- }
758
- }, 3500);
759
- }
760
- //only continue to parse the query if the document is ready, and all shapes from initial bundles are loaded
761
- export var onQueriesReady = (callback) => {
762
- if (!documentLoaded) {
763
- callbackStack.push(callback);
764
- }
765
- else {
766
- callback();
767
- }
768
- };
769
- export class SelectQueryFactory extends QueryFactory {
770
- constructor(shape, queryBuildFn, subject) {
771
- super();
772
- this.shape = shape;
773
- this.queryBuildFn = queryBuildFn;
774
- this.subject = subject;
775
- let promise, resolve, reject;
776
- promise = new Promise((res, rej) => {
777
- resolve = res;
778
- reject = rej;
779
- });
780
- this.initPromise = { promise, resolve, reject, complete: false };
781
- //only continue to parse the query if the document is ready, and all shapes from initial bundles are loaded
782
- if (typeof document === 'undefined' || document.readyState !== 'loading') {
783
- this.init();
784
- }
785
- else {
786
- document.addEventListener('DOMContentLoaded', () => this.init());
787
- setTimeout(() => {
788
- if (!this.initPromise.complete) {
789
- console.warn('⚠️ Forcing init after timeout');
790
- this.init();
791
- }
792
- }, 3500);
793
- }
794
- }
795
- setLimit(limit) {
796
- this.limit = limit;
797
- }
798
- getLimit() {
799
- return this.limit;
800
- }
801
- setOffset(offset) {
802
- this.offset = offset;
803
- }
804
- getOffset() {
805
- return this.offset;
806
- }
807
- setSubject(subject) {
808
- this.subject = subject;
809
- return this;
810
- }
811
- where(validation) {
812
- this.wherePath = processWhereClause(validation, this.shape);
813
- return this;
814
- }
815
- exec() {
816
- return QueryParser.selectQuery(this);
817
- }
818
- /**
819
- * Returns the raw pipeline input for this query.
820
- * Used internally by build() and by test helpers that need
821
- * to feed factory state into individual pipeline stages.
822
- */
823
- toRawInput() {
824
- const input = {
825
- select: this.getQueryPaths(),
826
- subject: this.getSubject(),
827
- limit: this.limit,
828
- offset: this.offset,
829
- shape: this.shape,
830
- sortBy: this.getSortByPath(),
831
- singleResult: this.singleResult ||
832
- !!(this.subject &&
833
- ('id' in this.subject || 'id' in this.subject)),
834
- };
835
- if (this.wherePath) {
836
- input.where = this.wherePath;
837
- }
838
- return input;
839
- }
840
- build() {
841
- return buildSelectQuery(this.toRawInput());
842
- }
843
- getSubject() {
844
- var _a, _b;
845
- //if the subject is a QueryShape which comes from query context
846
- //then it will carry a query context id and we convert it to a node reference
847
- //NOTE: its important to access originalValue instead of .node directly because QueryShape.node may be undefined
848
- if ((_b = (_a = this.subject) === null || _a === void 0 ? void 0 : _a.originalValue) === null || _b === void 0 ? void 0 : _b.__queryContextId) {
849
- return convertQueryContext(this.subject);
850
- }
851
- // }
852
- return this.subject;
853
- }
854
- /**
855
- * Returns an array of query paths
856
- * A single query can request multiple things in multiple "query paths" (For example this is using 2 paths: Shape.select(p => [p.name, p.friends.name]))
857
- * Each query path is returned as array of the property paths requested, with potential where clauses (together called a QueryStep)
858
- */
859
- getQueryPaths(response = this.traceResponse) {
860
- let queryPaths = [];
861
- let queryObject;
862
- //if the trace response is an array, then multiple paths were requested
863
- if (response instanceof QueryBuilderObject ||
864
- response instanceof QueryPrimitiveSet) {
865
- //if it's a single value, then only one path was requested, and we can add it directly
866
- queryPaths.push(response.getPropertyPath());
867
- }
868
- else if (Array.isArray(response) || response instanceof Set) {
869
- response.forEach((endValue) => {
870
- if (endValue instanceof QueryBuilderObject) {
871
- queryPaths.push(endValue.getPropertyPath());
872
- }
873
- else if (endValue instanceof SelectQueryFactory) {
874
- queryPaths.push(endValue.getQueryPaths());
875
- }
876
- });
877
- }
878
- else if (response instanceof Evaluation) {
879
- queryPaths.push(response.getWherePath());
880
- }
881
- else if (response instanceof SelectQueryFactory) {
882
- queryPaths.push(response.getQueryPaths());
883
- }
884
- else if (!response) {
885
- //that's totally fine. For example Person.select().where(p => p.name.equals('John'))
886
- //will return all persons with the name John, but no properties are selected for these persons
887
- }
888
- //if it's an object
889
- else if (typeof response === 'object') {
890
- queryObject = {};
891
- //then loop over all the keys
892
- Object.getOwnPropertyNames(response).forEach((key) => {
893
- //and add the property paths for each key
894
- const value = response[key];
895
- //TODO: we could potentially make Evaluation extend QueryValue, and rename getPropertyPath to something more generic,
896
- //that way we can simplify the code perhaps? Or would we loose type clarity? (QueryStep is the generic one for QueryValue, and Evaluation can just return WherePath right?)
897
- if (value instanceof QueryBuilderObject ||
898
- value instanceof QueryPrimitiveSet) {
899
- queryObject[key] = value.getPropertyPath();
900
- }
901
- else if (value instanceof Evaluation) {
902
- queryObject[key] = value.getWherePath();
903
- }
904
- else {
905
- throw Error('Unknown trace response type for key ' + key);
906
- }
907
- });
908
- }
909
- else {
910
- throw Error('Unknown trace response type');
911
- }
912
- if (this.parentQueryPath) {
913
- queryPaths = this.parentQueryPath.concat([
914
- queryObject || queryPaths,
915
- ]);
916
- //reset the variable so it doesn't get used again below
917
- queryObject = null;
918
- }
919
- return queryObject || queryPaths;
920
- }
921
- isValidSetResult(qResults) {
922
- return qResults.every((qResult) => {
923
- return this.isValidResult(qResult);
924
- });
925
- }
926
- isValidResult(qResult) {
927
- let select = this.getQueryPaths();
928
- if (Array.isArray(select)) {
929
- return this.isValidQueryPathsResult(qResult, select);
930
- }
931
- else if (typeof select === 'object') {
932
- return this.isValidCustomObjectResult(qResult, select);
933
- }
934
- }
935
- clone() {
936
- return new SelectQueryFactory(this.shape, this.queryBuildFn, this.subject);
937
- }
938
- /**
939
- * Makes a clone of the query template, sets the subject and executes the query
940
- * @param subject
941
- */
942
- execFor(subject) {
943
- //TODO: Differentiate between the result of Shape.query and the internal query in Shape.select?
944
- // so that Shape.query can never be executed. Its just a template
945
- return this.clone().setSubject(subject).exec();
946
- }
947
- patchResultPromise(p) {
948
- let pAdjusted = p;
949
- p['where'] = (validation) => {
950
- // preventExec();
951
- this.where(validation);
952
- return pAdjusted;
953
- };
954
- p['limit'] = (lim) => {
955
- this.setLimit(lim);
956
- return pAdjusted;
957
- };
958
- p['sortBy'] = (sortFn, direction = 'ASC') => {
959
- this.sortBy(sortFn, direction);
960
- return pAdjusted;
961
- };
962
- p['one'] = () => {
963
- this.setLimit(1);
964
- this.singleResult = true;
965
- return pAdjusted;
966
- };
967
- return p;
968
- }
969
- sortBy(sortFn, direction) {
970
- let queryShape = this.getQueryShape();
971
- if (sortFn) {
972
- this.sortResponse = sortFn(queryShape, this);
973
- this.sortDirection = direction;
974
- }
975
- return this;
976
- }
977
- init() {
978
- let queryShape = this.getQueryShape();
979
- if (this.queryBuildFn) {
980
- let queryResponse = this.queryBuildFn(queryShape, this);
981
- this.traceResponse = queryResponse;
982
- }
983
- this.initPromise.resolve(this.traceResponse);
984
- this.initPromise.complete = true;
985
- }
986
- initialized() {
987
- return this.initPromise.promise;
988
- }
989
- /**
990
- * Returns the dummy shape instance who's properties can be accessed freely inside a queryBuildFn
991
- * It is used to trace the properties that are accessed in the queryBuildFn
992
- * @private
993
- */
994
- getQueryShape() {
995
- let queryShape;
996
- //if the given class already extends QueryValue
997
- if (this.shape instanceof QueryBuilderObject) {
998
- //then we're likely dealing with QueryPrimitives (end values like strings)
999
- //and we can use the given query value directly for the query evaluation
1000
- queryShape = this.shape;
1001
- }
1002
- else {
1003
- //else a shape class is given, and we need to create a dummy node to apply and trace the query
1004
- let dummyShape = new this.shape();
1005
- queryShape = QueryShape.create(dummyShape);
1006
- }
1007
- return queryShape;
1008
- }
1009
- getSortByPath() {
1010
- if (!this.sortResponse)
1011
- return null;
1012
- //TODO: we should put more restrictions on sortBy and getting query paths from the response
1013
- // currently it reuses much of the select logic, but for example using .where() should probably not be allowed in a sortBy function?
1014
- return {
1015
- paths: this.getQueryPaths(this.sortResponse),
1016
- direction: this.sortDirection,
1017
- };
1018
- }
1019
- isValidQueryPathsResult(qResult, select) {
1020
- return select.every((path) => {
1021
- return this.isValidQueryPathResult(qResult, path);
1022
- });
1023
- }
1024
- isValidQueryPathResult(qResult, path, nameOverwrite) {
1025
- if (Array.isArray(path)) {
1026
- return this.isValidQueryStepResult(qResult, path[0], path.splice(1), nameOverwrite);
1027
- }
1028
- else {
1029
- if (path.firstPath) {
1030
- return this.isValidQueryPathResult(qResult, path.firstPath);
1031
- }
1032
- else if (path.path) {
1033
- return this.isValidQueryPathResult(qResult, path.path);
1034
- }
1035
- }
1036
- }
1037
- isValidQueryStepResult(qResult, step, restPath = [], nameOverwrite) {
1038
- if (!qResult) {
1039
- return false;
1040
- }
1041
- if (step.property) {
1042
- //if a name overwrite is given we check if that key exists instead of the property label
1043
- //this happens with custom objects: for the first property step, the named key will be the accessKey used in the result instead of the first property label.
1044
- //e.g. {title:item.name} in a query will result in a "title" key in the result, not "name"
1045
- const accessKey = nameOverwrite || step.property.label;
1046
- //also check if this property needs to have a value (minCount > 0), if not it can be empty and undefined
1047
- // if (!qResult.hasOwnProperty(accessKey) && (step as PropertyQueryStep).property.minCount > 0) {
1048
- //the key must be in the object. If there is no value then it should be null (or undefined, but null works better with JSON.stringify, as it keeps the key. Whilst undefined keys get removed)
1049
- if (!qResult.hasOwnProperty(accessKey)) {
1050
- return false;
1051
- }
1052
- if (restPath.length > 0) {
1053
- return this.isValidQueryStepResult(qResult[accessKey], restPath[0], restPath.splice(1));
1054
- }
1055
- return true;
1056
- }
1057
- else if (step.count) {
1058
- return this.isValidQueryStepResult(qResult, step.count[0]);
1059
- }
1060
- else if (Array.isArray(step)) {
1061
- return step.every((subStep) => {
1062
- return this.isValidQueryPathResult(qResult, subStep);
1063
- });
1064
- }
1065
- else if (typeof step === 'object') {
1066
- if (Array.isArray(qResult)) {
1067
- return qResult.every((singleResult) => {
1068
- return this.isValidQueryStepResult(singleResult, step);
1069
- });
1070
- }
1071
- return this.isValidCustomObjectResult(qResult, step);
1072
- }
1073
- }
1074
- isValidCustomObjectResult(qResult, step) {
1075
- //for custom objects, all keys need to be defined, even if the value is undefined
1076
- for (let key in step) {
1077
- if (!qResult.hasOwnProperty(key)) {
1078
- return false;
1079
- }
1080
- let path = step[key];
1081
- if (!this.isValidQueryPathResult(qResult, path, key)) {
1082
- return false;
1083
- }
1084
- // return this.isValidQueryPathResult(qResult[key], path);
1085
- }
1086
- return true;
1087
- }
1088
- }
1089
- export class SetSize extends QueryNumber {
671
+ export class SetSize extends QueryPrimitive {
1090
672
  constructor(subject, countable, label) {
1091
673
  super();
1092
674
  this.subject = subject;
@@ -1098,57 +680,21 @@ export class SetSize extends QueryNumber {
1098
680
  return this;
1099
681
  }
1100
682
  getPropertyPath() {
1101
- //if a countable argument was given
1102
- // if (this.countable) {
1103
- //then creating the count step is straightforward
1104
- // let countablePath = this.countable.getPropertyPath();
1105
- // if (countablePath.some((step) => Array.isArray(step))) {
1106
- // throw new Error(
1107
- // 'Cannot count a diverging path. Provide one path of properties to count',
1108
- // );
1109
- // }
1110
- // let self: CountStep = {
1111
- // count: this.countable?.getPropertyPath(),
1112
- // label: this.label,
1113
- // };
1114
- // //and we can add the count step to the path of the subject
1115
- // let parent = this.subject.getPropertyPath();
1116
- // parent.push(self);
1117
- // return parent;
1118
- // } else {
1119
- //if nothing to count was given as an argument,
1120
- //then we just count the last property in the path
1121
- //also, we use the label of the last property as the label of the count step
683
+ //count the last property in the path
684
+ //use the label of the last property as the label of the count step
1122
685
  let countable = this.subject.getPropertyStep();
1123
686
  let self = {
1124
687
  count: [countable],
1125
- label: this.label || this.subject.property.label, //the default is property name + 'Size', i.e., friendsSize
1126
- //numFriends
1127
- // label: this.label || 'num'+this.subject.property.label[0].toUpperCase()+this.subject.property.label.slice(1),//the default is property name + 'Size', i.e., friendsSize
688
+ label: this.label || this.subject.property.label,
1128
689
  };
1129
- //in that case we request the path of the subject of the subject (the parent of the parent)
1130
- //and add the CountStep to that path
1131
- //since we already used the subject as the thing that's counted.
690
+ //request the path of the subject's subject (the parent of the parent)
691
+ //and add the SizeStep to that path, since we already used the subject as the thing that's counted
1132
692
  if (this.subject.subject) {
1133
693
  let path = this.subject.subject.getPropertyPath();
1134
694
  path.push(self);
1135
695
  return path;
1136
696
  }
1137
- //if there is no parent of a parent, then we just return the count step as the whole path
1138
697
  return [self];
1139
- // }
1140
- }
1141
- }
1142
- /**
1143
- * A sub query that is used to filter results
1144
- * i.e p.friends.where(f => //LinkedWhereQuery here)
1145
- */
1146
- export class LinkedWhereQuery extends SelectQueryFactory {
1147
- getResponse() {
1148
- return this.traceResponse;
1149
- }
1150
- getWherePath() {
1151
- return this.traceResponse.getWherePath();
1152
698
  }
1153
699
  }
1154
700
  //# sourceMappingURL=SelectQuery.js.map