@_linked/core 2.36.0 → 2.36.2

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 (73) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +19 -0
  3. package/lib/esm/collections/CoreSet.js +2 -0
  4. package/lib/esm/collections/CoreSet.js.map +1 -1
  5. package/lib/esm/collections/ShapeSet.js +2 -0
  6. package/lib/esm/collections/ShapeSet.js.map +1 -1
  7. package/lib/esm/expressions/Expr.js +3 -2
  8. package/lib/esm/expressions/Expr.js.map +1 -1
  9. package/lib/esm/expressions/ExpressionNode.js +10 -7
  10. package/lib/esm/expressions/ExpressionNode.js.map +1 -1
  11. package/lib/esm/index.d.ts +1 -1
  12. package/lib/esm/index.js +1 -1
  13. package/lib/esm/index.js.map +1 -1
  14. package/lib/esm/queries/AskBuilder.js +5 -3
  15. package/lib/esm/queries/AskBuilder.js.map +1 -1
  16. package/lib/esm/queries/CountBuilder.js +4 -2
  17. package/lib/esm/queries/CountBuilder.js.map +1 -1
  18. package/lib/esm/queries/CreateBuilder.js +2 -0
  19. package/lib/esm/queries/CreateBuilder.js.map +1 -1
  20. package/lib/esm/queries/DeleteBuilder.js +3 -1
  21. package/lib/esm/queries/DeleteBuilder.js.map +1 -1
  22. package/lib/esm/queries/DslJsonExpression.js +7 -6
  23. package/lib/esm/queries/DslJsonExpression.js.map +1 -1
  24. package/lib/esm/queries/FieldSet.js +10 -8
  25. package/lib/esm/queries/FieldSet.js.map +1 -1
  26. package/lib/esm/queries/IRLower.js +2 -1
  27. package/lib/esm/queries/IRLower.js.map +1 -1
  28. package/lib/esm/queries/MutationSerialization.js +2 -1
  29. package/lib/esm/queries/MutationSerialization.js.map +1 -1
  30. package/lib/esm/queries/PropertyPath.js +2 -0
  31. package/lib/esm/queries/PropertyPath.js.map +1 -1
  32. package/lib/esm/queries/ProxiedPathBuilder.js +2 -1
  33. package/lib/esm/queries/ProxiedPathBuilder.js.map +1 -1
  34. package/lib/esm/queries/QueryBuilder.js +5 -4
  35. package/lib/esm/queries/QueryBuilder.js.map +1 -1
  36. package/lib/esm/queries/QueryContext.js +17 -6
  37. package/lib/esm/queries/QueryContext.js.map +1 -1
  38. package/lib/esm/queries/SelectQuery.js +18 -12
  39. package/lib/esm/queries/SelectQuery.js.map +1 -1
  40. package/lib/esm/queries/UpdateBuilder.js +3 -1
  41. package/lib/esm/queries/UpdateBuilder.js.map +1 -1
  42. package/lib/esm/queries/lower.js +5 -4
  43. package/lib/esm/queries/lower.js.map +1 -1
  44. package/lib/esm/shapes/SHACL.js +6 -3
  45. package/lib/esm/shapes/SHACL.js.map +1 -1
  46. package/lib/esm/shapes/Shape.d.ts +3 -1
  47. package/lib/esm/shapes/Shape.js +20 -2
  48. package/lib/esm/shapes/Shape.js.map +1 -1
  49. package/lib/esm/shapes/validation.js +3 -2
  50. package/lib/esm/shapes/validation.js.map +1 -1
  51. package/lib/esm/utils/LinkedErrorLogging.d.ts +2 -1
  52. package/lib/esm/utils/LinkedErrorLogging.js +11 -0
  53. package/lib/esm/utils/LinkedErrorLogging.js.map +1 -1
  54. package/lib/esm/utils/LinkedFileStorage.d.ts +6 -4
  55. package/lib/esm/utils/LinkedFileStorage.js +34 -4
  56. package/lib/esm/utils/LinkedFileStorage.js.map +1 -1
  57. package/lib/esm/utils/Package.d.ts +6 -0
  58. package/lib/esm/utils/Package.js +35 -7
  59. package/lib/esm/utils/Package.js.map +1 -1
  60. package/lib/esm/utils/Prefix.d.ts +4 -2
  61. package/lib/esm/utils/Prefix.js +18 -2
  62. package/lib/esm/utils/Prefix.js.map +1 -1
  63. package/lib/esm/utils/ShapeClass.js +11 -6
  64. package/lib/esm/utils/ShapeClass.js.map +1 -1
  65. package/lib/esm/utils/cached.js +2 -1
  66. package/lib/esm/utils/cached.js.map +1 -1
  67. package/lib/esm/utils/linkedError.d.ts +32 -0
  68. package/lib/esm/utils/linkedError.js +40 -0
  69. package/lib/esm/utils/linkedError.js.map +1 -1
  70. package/lib/esm/utils/unresolvedShape.d.ts +8 -4
  71. package/lib/esm/utils/unresolvedShape.js +14 -10
  72. package/lib/esm/utils/unresolvedShape.js.map +1 -1
  73. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"QueryContext.js","sourceRoot":"","sources":["../../../src/queries/QueryContext.ts"],"names":[],"mappings":"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","sourcesContent":["import {type QShape, QueryShape} from './SelectQuery.js';\nimport {Shape, createShapeTarget} from '../shapes/Shape.js';\nimport {brandLinkedError} from '../utils/linkedError.js';\n\nconst queryContext = new Map<string, QShape<any, any, any>>();\n\n/**\n * A live reference returned by getQueryContext when the context hasn't been set yet.\n * Its `id` getter resolves lazily from the global context map, so queries built with\n * a PendingQueryContext will pick up the value once it's set (e.g. after auth completes).\n */\nexport class PendingQueryContext {\n constructor(public readonly contextName: string) {}\n\n get id(): string | undefined {\n return queryContext.get(this.contextName)?.id;\n }\n}\n\n/**\n * Thrown when a query carrying a context reference is lowered but the context\n * isn't set in the current process. A context ref is carried in DSL-JSON and\n * resolves at lowering time against whatever context map is available (e.g.\n * server-side auth); if it can't resolve, lowering throws this rather than\n * silently producing a subject-less query.\n */\nexport class UnresolvedContextError extends Error {\n constructor(public readonly contextName: string) {\n super(\n `Query context \"${contextName}\" is not set and could not be resolved at lowering time.`,\n );\n this.name = 'UnresolvedContextError';\n }\n}\nbrandLinkedError(UnresolvedContextError, '@_linked/core', 'UnresolvedContextError');\n\n/** Listener notified (with the changed context name) whenever a context is set or cleared. */\nexport type QueryContextListener = (name: string) => void;\nconst contextListeners = new Set<QueryContextListener>();\n\n/**\n * Subscribe to query-context changes. Returns an unsubscribe function.\n *\n * This is the primitive that makes context resolution reactive: a consuming layer\n * (e.g. React components) subscribes and re-runs affected queries when the context\n * lands — so a query that resolved to `null` while the context was unset simply\n * re-runs and resolves once it's available (\"waiting\"), and re-runs again on any\n * later change (\"auto re-resolve\"). Core only emits the change; re-execution is the\n * consumer's responsibility.\n */\nexport function subscribeQueryContext(listener: QueryContextListener): () => void {\n contextListeners.add(listener);\n return () => contextListeners.delete(listener);\n}\n\nfunction notifyContextChange(name: string): void {\n // Snapshot so a listener that (un)subscribes or re-sets a context during\n // notification can't mutate the set mid-iteration.\n for (const listener of [...contextListeners]) {\n try {\n listener(name);\n } catch (err) {\n // A listener must never break setQueryContext for the others.\n console.error('[linked] query context listener failed', err);\n }\n }\n}\n\n/**\n * Normalize any query-context value to a {@link PendingQueryContext} carrying its name,\n * or return `undefined` if the value is not a context reference.\n *\n * A context appears in two runtime forms: a `PendingQueryContext` (the context was unset\n * when `getQueryContext()` was called) or a resolved `QueryShape` stamped with\n * `__queryContextName` (it was already set). Both must be treated as the same `{@ctx}`\n * reference wherever a node value/id is accepted (mutation field values, delete ids), so\n * that context-bound mutations behave identically whether the context is set or unset at\n * build time — resolution always happens at lowering.\n */\nexport function asContextRef(value: unknown): PendingQueryContext | undefined {\n if (value instanceof PendingQueryContext) return value;\n if (!value || typeof value !== 'object') return undefined;\n // A resolved context is a QueryShape proxy wrapping a Shape stamped with\n // `__queryContextName`. Read it via `originalValue` (a known QueryShape field)\n // so we don't trip the proxy's \"undecorated property\" guard (it now throws);\n // a bare Shape\n // carries the stamp directly.\n const v = value as {originalValue?: {__queryContextName?: unknown}; __queryContextName?: unknown};\n const source = v.originalValue ?? v;\n const name = (source as {__queryContextName?: unknown}).__queryContextName;\n if (typeof name === 'string') return new PendingQueryContext(name);\n return undefined;\n}\n\nexport function getQueryContext<T extends Shape>(name: string): QShape<T> {\n if (queryContext.has(name)) {\n return queryContext.get(name);\n }\n // Return a live reference that resolves lazily when the context is set.\n // This avoids the timing issue where module-level queries capture null\n // because the context hasn't been set yet (e.g. useEffect hasn't fired).\n return new PendingQueryContext(name) as any;\n}\n\nexport function setQueryContext(name: string, value: any, shapeType?) {\n // Clearing a context entry\n if (!value) {\n queryContext.delete(name);\n notifyContextChange(name);\n return;\n }\n\n // Already a QShape — stamp the underlying shape and store as-is. (Checked before\n // the plain-`{id}` branch below: a QueryShape's `.id` getter is also a string, so\n // testing for `{id}` first would wrongly require a shapeType and no-op.)\n if (value instanceof QueryShape) {\n const orig = (value as any).originalValue;\n if (orig) {\n orig.__queryContextName = name;\n if (typeof orig.id === 'string') orig.__queryContextId = orig.id;\n }\n queryContext.set(name, value as any);\n notifyContextChange(name);\n return;\n }\n\n // A Shape-shaped value (e.g. a `createShapeTarget` proxy target) — stamp it and\n // wrap as a QShape. Needs no shapeType (it already carries its shape class).\n if (value instanceof Shape) {\n value.__queryContextName = name;\n if (typeof value.id === 'string') value.__queryContextId = value.id;\n queryContext.set(name, new QueryShape(value) as any);\n notifyContextChange(name);\n return;\n }\n\n // A plain QResult `{id}` — materialize a shape (requires shapeType).\n if (typeof value.id === 'string') {\n if (!shapeType) {\n // A silent no-op here is a trap: the context never sets and the caller\n // gets no signal. A `{id}` value cannot be materialized without its shape.\n throw new Error(\n `setQueryContext('${name}'): a {id} value requires a shapeType so the shape can be materialized. Pass the Shape class as the third argument.`,\n );\n }\n const shape = createShapeTarget(shapeType as any, value.id);\n shape.__queryContextId = value.id;\n shape.__queryContextName = name;\n queryContext.set(name, QueryShape.create(shape) as any);\n notifyContextChange(name);\n return;\n }\n\n throw new Error(\n `setQueryContext('${name}'): value is not a QueryShape, Shape, or {id} result. Got ${typeof value}. Pass a Shape instance, a query-context shape, or a {id} result (with its shapeType).`,\n );\n}\n"]}
1
+ {"version":3,"file":"QueryContext.js","sourceRoot":"","sources":["../../../src/queries/QueryContext.ts"],"names":[],"mappings":"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","sourcesContent":["import {type QShape, QueryShape} from './SelectQuery.js';\nimport {Shape, createShapeTarget} from '../shapes/Shape.js';\nimport {brandLinkedClass, brandLinkedError, isLinkedInstance} from '../utils/linkedError.js';\nimport {sharedState} from '../utils/sharedState.js';\n\n/**\n * The context map and its listeners, shared by every copy of core in the runtime: a context\n * the app sets through one copy must resolve for a query lowered by the other, and a React\n * layer subscribed through one copy must hear a change made through the other.\n */\nconst contextState = sharedState('@_linked/core', 'QueryContext', () => ({\n contexts: new Map<string, QShape<any, any, any>>(),\n listeners: new Set<QueryContextListener>(),\n}));\nconst queryContext = contextState.contexts;\n\n/**\n * A live reference returned by getQueryContext when the context hasn't been set yet.\n * Its `id` getter resolves lazily from the global context map, so queries built with\n * a PendingQueryContext will pick up the value once it's set (e.g. after auth completes).\n */\nexport class PendingQueryContext {\n constructor(public readonly contextName: string) {}\n\n get id(): string | undefined {\n return queryContext.get(this.contextName)?.id;\n }\n}\nbrandLinkedClass(PendingQueryContext, '@_linked/core', 'PendingQueryContext');\n\n\n/**\n * Thrown when a query carrying a context reference is lowered but the context\n * isn't set in the current process. A context ref is carried in DSL-JSON and\n * resolves at lowering time against whatever context map is available (e.g.\n * server-side auth); if it can't resolve, lowering throws this rather than\n * silently producing a subject-less query.\n */\nexport class UnresolvedContextError extends Error {\n constructor(public readonly contextName: string) {\n super(\n `Query context \"${contextName}\" is not set and could not be resolved at lowering time.`,\n );\n this.name = 'UnresolvedContextError';\n }\n}\nbrandLinkedError(UnresolvedContextError, '@_linked/core', 'UnresolvedContextError');\n\n/** Listener notified (with the changed context name) whenever a context is set or cleared. */\nexport type QueryContextListener = (name: string) => void;\nconst contextListeners = contextState.listeners;\n\n/**\n * Subscribe to query-context changes. Returns an unsubscribe function.\n *\n * This is the primitive that makes context resolution reactive: a consuming layer\n * (e.g. React components) subscribes and re-runs affected queries when the context\n * lands — so a query that resolved to `null` while the context was unset simply\n * re-runs and resolves once it's available (\"waiting\"), and re-runs again on any\n * later change (\"auto re-resolve\"). Core only emits the change; re-execution is the\n * consumer's responsibility.\n */\nexport function subscribeQueryContext(listener: QueryContextListener): () => void {\n contextListeners.add(listener);\n return () => contextListeners.delete(listener);\n}\n\nfunction notifyContextChange(name: string): void {\n // Snapshot so a listener that (un)subscribes or re-sets a context during\n // notification can't mutate the set mid-iteration.\n for (const listener of [...contextListeners]) {\n try {\n listener(name);\n } catch (err) {\n // A listener must never break setQueryContext for the others.\n console.error('[linked] query context listener failed', err);\n }\n }\n}\n\n/**\n * Normalize any query-context value to a {@link PendingQueryContext} carrying its name,\n * or return `undefined` if the value is not a context reference.\n *\n * A context appears in two runtime forms: a `PendingQueryContext` (the context was unset\n * when `getQueryContext()` was called) or a resolved `QueryShape` stamped with\n * `__queryContextName` (it was already set). Both must be treated as the same `{@ctx}`\n * reference wherever a node value/id is accepted (mutation field values, delete ids), so\n * that context-bound mutations behave identically whether the context is set or unset at\n * build time — resolution always happens at lowering.\n */\nexport function asContextRef(value: unknown): PendingQueryContext | undefined {\n if (isLinkedInstance(value, PendingQueryContext)) return value;\n if (!value || typeof value !== 'object') return undefined;\n // A resolved context is a QueryShape proxy wrapping a Shape stamped with\n // `__queryContextName`. Read it via `originalValue` (a known QueryShape field)\n // so we don't trip the proxy's \"undecorated property\" guard (it now throws);\n // a bare Shape\n // carries the stamp directly.\n const v = value as {originalValue?: {__queryContextName?: unknown}; __queryContextName?: unknown};\n const source = v.originalValue ?? v;\n const name = (source as {__queryContextName?: unknown}).__queryContextName;\n if (typeof name === 'string') return new PendingQueryContext(name);\n return undefined;\n}\n\nexport function getQueryContext<T extends Shape>(name: string): QShape<T> {\n if (queryContext.has(name)) {\n return queryContext.get(name);\n }\n // Return a live reference that resolves lazily when the context is set.\n // This avoids the timing issue where module-level queries capture null\n // because the context hasn't been set yet (e.g. useEffect hasn't fired).\n return new PendingQueryContext(name) as any;\n}\n\nexport function setQueryContext(name: string, value: any, shapeType?) {\n // Clearing a context entry\n if (!value) {\n queryContext.delete(name);\n notifyContextChange(name);\n return;\n }\n\n // Already a QShape — stamp the underlying shape and store as-is. (Checked before\n // the plain-`{id}` branch below: a QueryShape's `.id` getter is also a string, so\n // testing for `{id}` first would wrongly require a shapeType and no-op.)\n if (isLinkedInstance(value, QueryShape)) {\n const orig = (value as any).originalValue;\n if (orig) {\n orig.__queryContextName = name;\n if (typeof orig.id === 'string') orig.__queryContextId = orig.id;\n }\n queryContext.set(name, value as any);\n notifyContextChange(name);\n return;\n }\n\n // A Shape-shaped value (e.g. a `createShapeTarget` proxy target) — stamp it and\n // wrap as a QShape. Needs no shapeType (it already carries its shape class).\n if (isLinkedInstance(value, Shape)) {\n value.__queryContextName = name;\n if (typeof value.id === 'string') value.__queryContextId = value.id;\n queryContext.set(name, new QueryShape(value) as any);\n notifyContextChange(name);\n return;\n }\n\n // A plain QResult `{id}` — materialize a shape (requires shapeType).\n if (typeof value.id === 'string') {\n if (!shapeType) {\n // A silent no-op here is a trap: the context never sets and the caller\n // gets no signal. A `{id}` value cannot be materialized without its shape.\n throw new Error(\n `setQueryContext('${name}'): a {id} value requires a shapeType so the shape can be materialized. Pass the Shape class as the third argument.`,\n );\n }\n const shape = createShapeTarget(shapeType as any, value.id);\n shape.__queryContextId = value.id;\n shape.__queryContextName = name;\n queryContext.set(name, QueryShape.create(shape) as any);\n notifyContextChange(name);\n return;\n }\n\n throw new Error(\n `setQueryContext('${name}'): value is not a QueryShape, Shape, or {id} result. Got ${typeof value}. Pass a Shape instance, a query-context shape, or a {id} result (with its shapeType).`,\n );\n}\n"]}
@@ -11,6 +11,7 @@ import { PropertyPath } from './PropertyPath.js';
11
11
  import { ExpressionNode, ExistsCondition, isExpressionNode, isExistsCondition, tracedPropertyExpression, tracedAliasExpression } from '../expressions/ExpressionNode.js';
12
12
  import { PendingQueryContext } from './QueryContext.js';
13
13
  import { unresolvedValueShapeError } from '../utils/unresolvedShape.js';
14
+ import { brandLinkedClass, isLinkedInstance } from '../utils/linkedError.js';
14
15
  /**
15
16
  * String keys the query-shape proxy must let through *without* treating them as
16
17
  * a property access — promise-awaiting (`then`), React (`$$typeof`), and common
@@ -169,6 +170,7 @@ export class QueryBuilderObject {
169
170
  return path;
170
171
  }
171
172
  }
173
+ brandLinkedClass(QueryBuilderObject, '@_linked/core', 'QueryBuilderObject');
172
174
  export class BoundComponent extends QueryBuilderObject {
173
175
  constructor(originalValue, source) {
174
176
  super(null, null);
@@ -261,7 +263,7 @@ function findContextName(qbo) {
261
263
  var _a;
262
264
  let current = qbo;
263
265
  while (current) {
264
- if (current instanceof QueryShape && ((_a = current.originalValue) === null || _a === void 0 ? void 0 : _a.__queryContextName)) {
266
+ if (isLinkedInstance(current, QueryShape) && ((_a = current.originalValue) === null || _a === void 0 ? void 0 : _a.__queryContextName)) {
265
267
  return current.originalValue.__queryContextName;
266
268
  }
267
269
  current = current.subject;
@@ -303,7 +305,7 @@ function wrapWithExpressionProxy(qp) {
303
305
  const baseNode = toExpressionNode(target);
304
306
  return (...args) => {
305
307
  // Convert QueryBuilderObject arguments to ExpressionNode
306
- const convertedArgs = args.map((arg) => { var _a; return arg instanceof QueryBuilderObject ? ((_a = toExpressionNode(arg)) !== null && _a !== void 0 ? _a : arg) : arg; });
308
+ const convertedArgs = args.map((arg) => { var _a; return isLinkedInstance(arg, QueryBuilderObject) ? ((_a = toExpressionNode(arg)) !== null && _a !== void 0 ? _a : arg) : arg; });
307
309
  return baseNode[key](...convertedArgs);
308
310
  };
309
311
  }
@@ -321,12 +323,12 @@ export const evaluateSortCallback = (shape, sortFn, direction = 'ASC') => {
321
323
  const response = sortFn(proxy);
322
324
  const nodeShape = shape.shape;
323
325
  const paths = [];
324
- if (response instanceof QueryBuilderObject || response instanceof QueryPrimitiveSet) {
326
+ if (isLinkedInstance(response, QueryBuilderObject) || isLinkedInstance(response, QueryPrimitiveSet)) {
325
327
  paths.push(new PropertyPath(nodeShape, FieldSet.collectPropertySegments(response)));
326
328
  }
327
329
  else if (Array.isArray(response)) {
328
330
  for (const item of response) {
329
- if (item instanceof QueryBuilderObject) {
331
+ if (isLinkedInstance(item, QueryBuilderObject)) {
330
332
  paths.push(new PropertyPath(nodeShape, FieldSet.collectPropertySegments(item)));
331
333
  }
332
334
  }
@@ -427,7 +429,7 @@ export class QueryShapeSet extends QueryBuilderObject {
427
429
  }
428
430
  concat(other) {
429
431
  if (other) {
430
- if (other instanceof QueryShapeSet) {
432
+ if (isLinkedInstance(other, QueryShapeSet)) {
431
433
  other.queryShapes.forEach(this.queryShapes.add.bind(this.queryShapes));
432
434
  }
433
435
  else {
@@ -534,6 +536,7 @@ export class QueryShapeSet extends QueryBuilderObject {
534
536
  throw new Error('Expected a callback or ExpressionNode for some/every/none');
535
537
  }
536
538
  }
539
+ brandLinkedClass(QueryShapeSet, '@_linked/core', 'QueryShapeSet');
537
540
  export class QueryShape extends QueryBuilderObject {
538
541
  constructor(originalValue, property, subject) {
539
542
  super(property, subject);
@@ -597,23 +600,23 @@ export class QueryShape extends QueryBuilderObject {
597
600
  const self = toExpressionNode(this);
598
601
  // An unresolved query-context reference (`getQueryContext('user')` before it
599
602
  // is set) carries no `.id` yet — keep it as a `{@ctx}` ref, resolved at lower.
600
- if (otherValue instanceof PendingQueryContext) {
603
+ if (isLinkedInstance(otherValue, PendingQueryContext)) {
601
604
  return self.eq(otherValue);
602
605
  }
603
606
  //validate the value is formed correctly
604
607
  if (!otherValue.id) {
605
608
  throw Error(`Invalid value for .equals(). ${JSON.stringify(otherValue)}`);
606
609
  }
607
- const arg = otherValue instanceof QueryBuilderObject
610
+ const arg = isLinkedInstance(otherValue, QueryBuilderObject)
608
611
  ? toExpressionNode(otherValue)
609
612
  : otherValue;
610
613
  return self.eq(arg);
611
614
  }
612
615
  oneOf(values) {
613
- return toExpressionNode(this).oneOf(values.map((v) => (v instanceof QueryBuilderObject ? toExpressionNode(v) : v)));
616
+ return toExpressionNode(this).oneOf(values.map((v) => (isLinkedInstance(v, QueryBuilderObject) ? toExpressionNode(v) : v)));
614
617
  }
615
618
  notOneOf(values) {
616
- return toExpressionNode(this).notOneOf(values.map((v) => (v instanceof QueryBuilderObject ? toExpressionNode(v) : v)));
619
+ return toExpressionNode(this).notOneOf(values.map((v) => (isLinkedInstance(v, QueryBuilderObject) ? toExpressionNode(v) : v)));
617
620
  }
618
621
  select(subQueryFn) {
619
622
  // A sub-select on a project-authored value shape has no authored class, so fall
@@ -640,6 +643,7 @@ export class QueryShape extends QueryBuilderObject {
640
643
  return this.select((shape) => propertyLabels.map((label) => shape[label]));
641
644
  }
642
645
  }
646
+ brandLinkedClass(QueryShape, '@_linked/core', 'QueryShape');
643
647
  /**
644
648
  * Concrete query wrapper for JS primitive values (string, number, boolean, Date).
645
649
  *
@@ -656,16 +660,16 @@ export class QueryPrimitive extends QueryBuilderObject {
656
660
  }
657
661
  equals(otherValue) {
658
662
  const self = toExpressionNode(this);
659
- const arg = otherValue instanceof QueryBuilderObject
663
+ const arg = isLinkedInstance(otherValue, QueryBuilderObject)
660
664
  ? toExpressionNode(otherValue)
661
665
  : otherValue;
662
666
  return self.eq(arg);
663
667
  }
664
668
  oneOf(values) {
665
- return toExpressionNode(this).oneOf(values.map((v) => (v instanceof QueryBuilderObject ? toExpressionNode(v) : v)));
669
+ return toExpressionNode(this).oneOf(values.map((v) => (isLinkedInstance(v, QueryBuilderObject) ? toExpressionNode(v) : v)));
666
670
  }
667
671
  notOneOf(values) {
668
- return toExpressionNode(this).notOneOf(values.map((v) => (v instanceof QueryBuilderObject ? toExpressionNode(v) : v)));
672
+ return toExpressionNode(this).notOneOf(values.map((v) => (isLinkedInstance(v, QueryBuilderObject) ? toExpressionNode(v) : v)));
669
673
  }
670
674
  where(validation) {
671
675
  // For inline where on a primitive (p.hobby.where(h => h.equals(...))),
@@ -677,6 +681,7 @@ export class QueryPrimitive extends QueryBuilderObject {
677
681
  return this;
678
682
  }
679
683
  }
684
+ brandLinkedClass(QueryPrimitive, '@_linked/core', 'QueryPrimitive');
680
685
  export class QueryPrimitiveSet extends QueryBuilderObject {
681
686
  constructor(originalValue, property, subject, items) {
682
687
  super(property, subject);
@@ -730,6 +735,7 @@ export class QueryPrimitiveSet extends QueryBuilderObject {
730
735
  //countable, resultKey
731
736
  }
732
737
  }
738
+ brandLinkedClass(QueryPrimitiveSet, '@_linked/core', 'QueryPrimitiveSet');
733
739
  export class SetSize extends QueryPrimitive {
734
740
  constructor(subject, countable, label) {
735
741
  super();