@soda-gql/core 0.3.0 → 0.4.1

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 (32) hide show
  1. package/README.md +29 -9
  2. package/dist/adapter.d.cts +2 -2
  3. package/dist/adapter.d.ts +2 -2
  4. package/dist/{index-DH3lMepk.d.cts → index-C-evbm4T.d.ts} +47 -21
  5. package/dist/index-C-evbm4T.d.ts.map +1 -0
  6. package/dist/{index-WU6aMZjg.d.ts → index-IYiti5xq.d.cts} +47 -21
  7. package/dist/index-IYiti5xq.d.cts.map +1 -0
  8. package/dist/index.cjs +154 -21
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +4 -4
  11. package/dist/index.d.ts +4 -4
  12. package/dist/index.js +154 -22
  13. package/dist/index.js.map +1 -1
  14. package/dist/runtime.cjs +1 -1
  15. package/dist/runtime.cjs.map +1 -1
  16. package/dist/runtime.d.cts +2 -2
  17. package/dist/runtime.d.ts +2 -2
  18. package/dist/runtime.js +1 -1
  19. package/dist/runtime.js.map +1 -1
  20. package/dist/{schema-C7q047S0.d.ts → schema-D88zIxYO.d.cts} +79 -16
  21. package/dist/schema-D88zIxYO.d.cts.map +1 -0
  22. package/dist/{schema-BElqa12z.d.cts → schema-DgHZfIVa.d.ts} +79 -16
  23. package/dist/schema-DgHZfIVa.d.ts.map +1 -0
  24. package/dist/{schema-builder-DDfulXP3.d.cts → schema-builder-DWYlI1oI.d.cts} +2 -2
  25. package/dist/{schema-builder-DDfulXP3.d.cts.map → schema-builder-DWYlI1oI.d.cts.map} +1 -1
  26. package/dist/{schema-builder-DfyTaFMt.d.ts → schema-builder-XjFwbmSc.d.ts} +2 -2
  27. package/dist/{schema-builder-DfyTaFMt.d.ts.map → schema-builder-XjFwbmSc.d.ts.map} +1 -1
  28. package/package.json +1 -1
  29. package/dist/index-DH3lMepk.d.cts.map +0 -1
  30. package/dist/index-WU6aMZjg.d.ts.map +0 -1
  31. package/dist/schema-BElqa12z.d.cts.map +0 -1
  32. package/dist/schema-C7q047S0.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -13,15 +13,25 @@ var VarRef = class {
13
13
  const isVarRef = (value) => {
14
14
  return typeof value === "object" && value !== null && value instanceof VarRef;
15
15
  };
16
+ /**
17
+ * Recursively checks if a NestedValue contains any VarRef.
18
+ * Used by getVarRefValue to determine if it's safe to return as ConstValue.
19
+ */
20
+ const hasVarRefInside = (value) => {
21
+ if (isVarRef(value)) return true;
22
+ if (Array.isArray(value)) return value.some(hasVarRefInside);
23
+ if (typeof value === "object" && value !== null) return Object.values(value).some(hasVarRefInside);
24
+ return false;
25
+ };
16
26
  const createVarRefFromVariable = (name) => {
17
27
  return new VarRef({
18
28
  type: "variable",
19
29
  name
20
30
  });
21
31
  };
22
- const createVarRefFromConstValue = (value) => {
32
+ const createVarRefFromNestedValue = (value) => {
23
33
  return new VarRef({
24
- type: "const-value",
34
+ type: "nested-value",
25
35
  value
26
36
  });
27
37
  };
@@ -30,22 +40,117 @@ const getVarRefInner = (varRef) => {
30
40
  };
31
41
  /**
32
42
  * Get the variable name from a VarRef.
33
- * Throws if the VarRef contains a const-value instead of a variable reference.
43
+ * Throws if the VarRef contains a nested-value instead of a variable reference.
34
44
  */
35
45
  const getVarRefName = (varRef) => {
36
46
  const inner = VarRef.getInner(varRef);
37
- if (inner.type !== "variable") throw new Error("Expected variable reference, got const-value");
47
+ if (inner.type !== "variable") throw new Error("Expected variable reference, got nested-value");
38
48
  return inner.name;
39
49
  };
40
50
  /**
41
51
  * Get the const value from a VarRef.
42
- * Throws if the VarRef contains a variable reference instead of a const-value.
52
+ * Throws if the VarRef contains a variable reference instead of a nested-value,
53
+ * or if the nested-value contains any VarRef inside.
43
54
  */
44
55
  const getVarRefValue = (varRef) => {
45
56
  const inner = VarRef.getInner(varRef);
46
- if (inner.type !== "const-value") throw new Error("Expected const-value, got variable reference");
57
+ if (inner.type !== "nested-value") throw new Error("Expected nested-value, got variable reference");
58
+ if (hasVarRefInside(inner.value)) throw new Error("Cannot get const value: nested-value contains VarRef");
47
59
  return inner.value;
48
60
  };
61
+ const SelectableProxyInnerRegistry = /* @__PURE__ */ new WeakMap();
62
+ const getSelectableProxyInner = (proxy) => {
63
+ const inner = SelectableProxyInnerRegistry.get(proxy);
64
+ if (!inner) throw new Error(`Proxy inner not found`);
65
+ return inner;
66
+ };
67
+ const createSelectableProxy = (current) => {
68
+ const proxy = new Proxy(Object.create(null), { get(_, property) {
69
+ if (typeof property === "symbol") throw new Error(`Prohibited property access: ${String(property)}`);
70
+ const nextSegments = [...current.segments, property];
71
+ if (current.varInner.type === "virtual") return createSelectableProxy({
72
+ varInner: current.varInner,
73
+ segments: nextSegments
74
+ });
75
+ if (current.varInner.type === "variable") return createSelectableProxy({
76
+ varInner: {
77
+ type: "virtual",
78
+ varName: current.varInner.name,
79
+ varSegments: nextSegments
80
+ },
81
+ segments: nextSegments
82
+ });
83
+ if (typeof current.varInner.value === "object" && current.varInner.value !== null) {
84
+ const value = current.varInner.value[property];
85
+ return createSelectableProxy({
86
+ varInner: isVarRef(value) ? getVarRefInner(value) : {
87
+ type: "nested-value",
88
+ value
89
+ },
90
+ segments: nextSegments
91
+ });
92
+ }
93
+ throw new Error(`Cannot access children of primitive value at path [${current.segments.join(".")}]`);
94
+ } });
95
+ SelectableProxyInnerRegistry.set(proxy, current);
96
+ return proxy;
97
+ };
98
+ /**
99
+ * Get the variable name from a VarRef at a specific path.
100
+ *
101
+ * @param varRef - The VarRef containing a nested-value
102
+ * @param selector - Path builder function, e.g., p => p.user.age
103
+ * @returns The variable name at the specified path
104
+ * @throws If path doesn't lead to a VarRef with type "variable"
105
+ *
106
+ * @example
107
+ * const ref = createVarRefFromNestedValue({
108
+ * user: { age: someVariableRef }
109
+ * });
110
+ * getNameAt(ref, p => p.user.age); // returns the variable name
111
+ */
112
+ const getNameAt = (varRef, selector) => {
113
+ const inner = getSelectableProxyInner(selector(createSelectableProxy({
114
+ varInner: VarRef.getInner(varRef),
115
+ segments: []
116
+ })));
117
+ if (inner.varInner.type === "virtual") throw new Error(`Value at path [${inner.segments.join(".")}] is inside a variable`);
118
+ if (inner.varInner.type !== "variable") throw new Error(`Value at path [${inner.segments.join(".")}] is not a variable`);
119
+ return inner.varInner.name;
120
+ };
121
+ /**
122
+ * Get the const value from a nested-value VarRef at a specific path.
123
+ *
124
+ * @param varRef - The VarRef containing a nested-value
125
+ * @param pathFn - Path builder function, e.g., p => p.user.name
126
+ * @returns The const value at the specified path
127
+ * @throws If path leads to a VarRef or if value contains VarRef inside
128
+ *
129
+ * @example
130
+ * const ref = createVarRefFromNestedValue({
131
+ * user: { name: "Alice", age: someVariableRef }
132
+ * });
133
+ * getValueAt(ref, p => p.user.name); // returns "Alice"
134
+ */
135
+ const getValueAt = (varRef, selector) => {
136
+ const inner = getSelectableProxyInner(selector(createSelectableProxy({
137
+ varInner: VarRef.getInner(varRef),
138
+ segments: []
139
+ })));
140
+ if (inner.varInner.type === "virtual") throw new Error(`Value at path [${inner.segments.join(".")}] is inside a variable`);
141
+ if (inner.varInner.type !== "nested-value") throw new Error(`Value at path [${inner.segments.join(".")}] is not a nested-value`);
142
+ if (hasVarRefInside(inner.varInner.value)) throw new Error(`Value at path [${inner.segments.join(".")}] contains nested VarRef`);
143
+ return inner.varInner.value;
144
+ };
145
+ const getVariablePath = (varRef, selector) => {
146
+ const inner = getSelectableProxyInner(selector(createSelectableProxy({
147
+ varInner: VarRef.getInner(varRef),
148
+ segments: []
149
+ })));
150
+ if (inner.varInner.type === "virtual") return [`$${inner.varInner.varName}`, ...inner.segments.slice(inner.varInner.varSegments.length)];
151
+ if (inner.varInner.type === "variable") return [`$${inner.varInner.name}`];
152
+ throw new Error(`Value at path [${inner.segments.join(".")}] is not a variable or inside a variable`);
153
+ };
49
154
 
50
155
  //#endregion
51
156
  //#region packages/core/src/composer/build-document.ts
@@ -61,7 +166,7 @@ const buildArgumentValue = (value) => {
61
166
  value: inner.name
62
167
  }
63
168
  };
64
- if (inner.type === "const-value") return buildConstValueNode(inner.value);
169
+ if (inner.type === "nested-value") return buildArgumentValue(inner.value);
65
170
  throw new Error(`Unknown var ref type: ${inner}`);
66
171
  }
67
172
  if (Array.isArray(value)) return {
@@ -297,8 +402,8 @@ const buildDocument = (options) => {
297
402
  * query.operation({
298
403
  * name: "GetData",
299
404
  * fields: ({ $ }) => $colocate({
300
- * userCard: userCardFragment.embed({ userId: $.userId }),
301
- * posts: postsFragment.embed({ userId: $.userId }),
405
+ * userCard: userCardFragment.spread({ userId: $.userId }),
406
+ * posts: postsFragment.spread({ userId: $.userId }),
302
407
  * }),
303
408
  * });
304
409
  *
@@ -335,7 +440,7 @@ const fieldPathContext = { current: null };
335
440
  * ```typescript
336
441
  * import { getCurrentFieldPath } from '@soda-gql/core';
337
442
  *
338
- * // Inside a field builder or model embed:
443
+ * // Inside a field builder or model spread:
339
444
  * const path = getCurrentFieldPath();
340
445
  * console.log(path?.full); // "$.user.posts[].author"
341
446
  * ```
@@ -569,8 +674,8 @@ var Fragment = class Fragment extends GqlElement {
569
674
  get typename() {
570
675
  return GqlElement.get(this).typename;
571
676
  }
572
- get embed() {
573
- return GqlElement.get(this).embed;
677
+ get spread() {
678
+ return GqlElement.get(this).spread;
574
679
  }
575
680
  static create(define$1) {
576
681
  return new Fragment(define$1);
@@ -633,7 +738,7 @@ const withFragmentUsageCollection = (fn) => {
633
738
  }
634
739
  };
635
740
  /**
636
- * Record a fragment usage. Called when fragment.embed() is invoked.
741
+ * Record a fragment usage. Called when fragment.spread() is invoked.
637
742
  * No-op if not in a collection context.
638
743
  *
639
744
  * @internal
@@ -647,10 +752,10 @@ const recordFragmentUsage = (record) => {
647
752
  const createVarAssignments = (definitions, providedValues) => {
648
753
  return mapValues(definitions, (_definition, key) => {
649
754
  const varName = key;
650
- if (!providedValues || providedValues[varName] === void 0) return createVarRefFromConstValue(void 0);
755
+ if (!providedValues || providedValues[varName] === void 0) return createVarRefFromNestedValue(void 0);
651
756
  const provided = providedValues[varName];
652
757
  if (isVarRef(provided)) return provided;
653
- return createVarRefFromConstValue(provided);
758
+ return createVarRefFromNestedValue(provided);
654
759
  });
655
760
  };
656
761
  const createVarRefs = (definitions) => mapValues(definitions, (_ref, name) => createVarRefFromVariable(name));
@@ -664,7 +769,7 @@ const createGqlFragmentComposers = (schema, _adapter) => {
664
769
  const { metadata, fields } = options;
665
770
  return Fragment.create(() => ({
666
771
  typename,
667
- embed: (variables) => {
772
+ spread: (variables) => {
668
773
  const f = createFieldFactories(schema, typename);
669
774
  const $ = createVarAssignments(varDefinitions, variables);
670
775
  recordFragmentUsage({
@@ -758,6 +863,8 @@ const createOperationComposerFactory = (schema, adapter) => {
758
863
  /**
759
864
  * Creates a variable method for a specific input type.
760
865
  * This is used by codegen to generate type-specific variable methods.
866
+ *
867
+ * @deprecated Use createVarMethodFactory instead for proper type inference with nested input objects.
761
868
  */
762
869
  const createVarMethod = (kind, typeName) => {
763
870
  return (modifier, extras) => ({
@@ -769,6 +876,30 @@ const createVarMethod = (kind, typeName) => {
769
876
  });
770
877
  };
771
878
  /**
879
+ * Creates a factory function for generating schema-scoped variable methods.
880
+ * This ensures proper type inference for nested input objects by binding the schema type upfront.
881
+ *
882
+ * @example
883
+ * ```typescript
884
+ * const createMethod = createVarMethodFactory<typeof schema>();
885
+ * const inputTypeMethods = {
886
+ * Boolean: createMethod("scalar", "Boolean"),
887
+ * user_bool_exp: createMethod("input", "user_bool_exp"),
888
+ * } satisfies InputTypeMethods<typeof schema>;
889
+ * ```
890
+ */
891
+ const createVarMethodFactory = () => {
892
+ return (kind, typeName) => {
893
+ return ((modifier, extras) => ({
894
+ kind,
895
+ name: typeName,
896
+ modifier,
897
+ defaultValue: extras?.default ? { default: extras.default() } : null,
898
+ directives: extras?.directives ?? {}
899
+ }));
900
+ };
901
+ };
902
+ /**
772
903
  * Creates a variable builder that uses injected input type methods.
773
904
  */
774
905
  const createVarBuilder = (inputTypeMethods) => {
@@ -784,6 +915,9 @@ const createVarBuilder = (inputTypeMethods) => {
784
915
  varBuilder.getName = getVarRefName;
785
916
  varBuilder.getValue = getVarRefValue;
786
917
  varBuilder.getInner = getVarRefInner;
918
+ varBuilder.getNameAt = getNameAt;
919
+ varBuilder.getValueAt = getValueAt;
920
+ varBuilder.getVariablePath = getVariablePath;
787
921
  return varBuilder;
788
922
  };
789
923
 
@@ -795,21 +929,19 @@ const createGqlElementComposer = (schema, options) => {
795
929
  const metadataAdapter = adapter?.metadata;
796
930
  const fragment = createGqlFragmentComposers(schema, metadataAdapter);
797
931
  const createOperationComposer = createOperationComposerFactory(schema, metadataAdapter);
798
- const composers = {
932
+ const context = {
799
933
  fragment,
800
934
  query: { operation: createOperationComposer("query") },
801
935
  mutation: { operation: createOperationComposer("mutation") },
802
- subscription: { operation: createOperationComposer("subscription") }
803
- };
804
- const helper = {
936
+ subscription: { operation: createOperationComposer("subscription") },
805
937
  $var: createVarBuilder(inputTypeMethods),
806
938
  $colocate: createColocateHelper(),
807
939
  ...helpers ?? {}
808
940
  };
809
- const elementComposer = (composeElement) => composeElement(composers, helper);
941
+ const elementComposer = (composeElement) => composeElement(context);
810
942
  return elementComposer;
811
943
  };
812
944
 
813
945
  //#endregion
814
- export { Fragment, GqlElement, Operation, appendToPath, buildArgumentValue, buildConstValueNode, buildDocument, buildOperationTypeNode, buildWithTypeModifier, createColocateHelper, createDefaultAdapter, createFieldFactories, createGqlElementComposer, createGqlFragmentComposers, createOperationComposerFactory, createVarAssignments, createVarBuilder, createVarMethod, createVarRefs, defaultMetadataAdapter, define, defineOperationRoots, defineScalar, getCurrentFieldPath, getVarRefInner, getVarRefName, getVarRefValue, isListType, recordFragmentUsage, unsafeInputType, unsafeOutputType, withFieldPath, withFragmentUsageCollection };
946
+ export { Fragment, GqlElement, Operation, appendToPath, buildArgumentValue, buildConstValueNode, buildDocument, buildOperationTypeNode, buildWithTypeModifier, createColocateHelper, createDefaultAdapter, createFieldFactories, createGqlElementComposer, createGqlFragmentComposers, createOperationComposerFactory, createVarAssignments, createVarBuilder, createVarMethod, createVarMethodFactory, createVarRefs, defaultMetadataAdapter, define, defineOperationRoots, defineScalar, getCurrentFieldPath, getVarRefInner, getVarRefName, getVarRefValue, isListType, recordFragmentUsage, unsafeInputType, unsafeOutputType, withFieldPath, withFragmentUsageCollection };
815
947
  //# sourceMappingURL=index.js.map