grafast 0.1.1-beta.11 → 0.1.1-beta.13

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 (41) hide show
  1. package/README.md +0 -3
  2. package/dist/args.js +8 -2
  3. package/dist/constraints.d.ts +15 -1
  4. package/dist/constraints.js +40 -1
  5. package/dist/engine/LayerPlan.d.ts +1 -0
  6. package/dist/engine/LayerPlan.js +62 -9
  7. package/dist/engine/OperationPlan.js +372 -274
  8. package/dist/engine/OutputPlan.d.ts +6 -5
  9. package/dist/engine/OutputPlan.js +423 -444
  10. package/dist/engine/executeBucket.js +36 -77
  11. package/dist/error.d.ts +13 -0
  12. package/dist/grafastGraphql.d.ts +5 -5
  13. package/dist/graphqlCollectFields.d.ts +6 -0
  14. package/dist/graphqlCollectFields.js +14 -8
  15. package/dist/interfaces.d.ts +18 -0
  16. package/dist/interfaces.js +0 -2
  17. package/dist/mermaid.js +20 -11
  18. package/dist/operationPlan-input.js +8 -1
  19. package/dist/planJSONInterfaces.d.ts +2 -0
  20. package/dist/prepare.js +3 -3
  21. package/dist/step.d.ts +5 -5
  22. package/dist/step.js +53 -2
  23. package/dist/steps/__flag.d.ts +3 -2
  24. package/dist/steps/__inputObject.d.ts +1 -0
  25. package/dist/steps/__inputObject.js +36 -0
  26. package/dist/steps/__item.d.ts +3 -3
  27. package/dist/steps/__trackedValue.d.ts +8 -0
  28. package/dist/steps/__trackedValue.js +40 -0
  29. package/dist/steps/__value.d.ts +2 -1
  30. package/dist/steps/constant.d.ts +2 -0
  31. package/dist/steps/constant.js +12 -0
  32. package/dist/steps/graphqlResolver.js +8 -5
  33. package/dist/steps/listen.d.ts +2 -2
  34. package/dist/steps/object.d.ts +1 -1
  35. package/dist/steps/sideEffect.d.ts +0 -1
  36. package/dist/thereCanBeOnlyOne.js +1 -1
  37. package/dist/utils.d.ts +4 -0
  38. package/dist/utils.js +7 -0
  39. package/dist/version.d.ts +1 -1
  40. package/dist/version.js +1 -1
  41. package/package.json +1 -1
@@ -2,11 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.__InputObjectStep = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const graphql = tslib_1.__importStar(require("graphql"));
5
6
  const tamedevil_1 = tslib_1.__importDefault(require("tamedevil"));
6
7
  const input_js_1 = require("../input.js");
7
8
  const step_js_1 = require("../step.js");
8
9
  const utils_js_1 = require("../utils.js");
9
10
  const constant_js_1 = require("./constant.js");
11
+ const { Kind } = graphql;
10
12
  /**
11
13
  * Implements `InputObjectStep`
12
14
  */
@@ -123,6 +125,40 @@ class __InputObjectStep extends step_js_1.UnbatchedExecutableStep {
123
125
  }
124
126
  return !this.inputFields[attrName].step.evalIs(undefined);
125
127
  }
128
+ evalKeys() {
129
+ if (this.inputValues === undefined) {
130
+ return null;
131
+ }
132
+ else if (this.inputValues.kind === Kind.NULL) {
133
+ return null;
134
+ }
135
+ else if (this.inputValues.kind !== Kind.OBJECT) {
136
+ throw new Error("evalKeys must only be called for object types");
137
+ }
138
+ const keys = [];
139
+ const inputFieldKeys = Object.keys(this.inputFields);
140
+ for (let i = 0; i < inputFieldKeys.length; i++) {
141
+ const key = inputFieldKeys[i];
142
+ const inputFieldPlan = this.inputFields[key].step;
143
+ // This evalIs() is required. With __inputObject we know that it's an
144
+ // explicit input object (not variable) in the GraphQL document, but the
145
+ // values of each key may still be undefined if they're a variable that
146
+ // isn't supplied and has no default. In these cases we do not wish to
147
+ // return these keys (since the input object is not seen as having those
148
+ // keys set), but that will differ on an operation-to-operation basis,
149
+ // and thus we must evaluate whether or not they are undefined. Note that
150
+ // this implicitly adds constraints for these values; we do not need to
151
+ // explicitly add any constraint for the object itself because the
152
+ // document itself guarantees it will always be present.
153
+ //
154
+ // PERF: We should not need to .evalIs(undefined) for any input field
155
+ // that is declared as non-nullable, I think?
156
+ if (!inputFieldPlan.evalIs(undefined)) {
157
+ keys.push(key);
158
+ }
159
+ }
160
+ return keys;
161
+ }
126
162
  }
127
163
  exports.__InputObjectStep = __InputObjectStep;
128
164
  //# sourceMappingURL=__inputObject.js.map
@@ -1,4 +1,4 @@
1
- import type { JSONValue } from "../index.js";
1
+ import type { GrafastResultsList, JSONValue } from "../index.js";
2
2
  import { $$deepDepSkip } from "../interfaces.js";
3
3
  import type { ExecutableStep } from "../step.js";
4
4
  import { $$noExec, UnbatchedExecutableStep } from "../step.js";
@@ -20,8 +20,8 @@ export declare class __ItemStep<TData> extends UnbatchedExecutableStep<TData> {
20
20
  planJSONExtra(): Record<string, JSONValue | undefined> | undefined;
21
21
  getParentStep(): ExecutableStep;
22
22
  [$$deepDepSkip](): ExecutableStep;
23
- execute(): never;
24
- unbatchedExecute(): never;
23
+ execute(): GrafastResultsList<TData>;
24
+ unbatchedExecute(): TData;
25
25
  finalize(): void;
26
26
  }
27
27
  //# sourceMappingURL=__item.d.ts.map
@@ -83,6 +83,14 @@ export declare class __TrackedValueStep<TData = any, TInputType extends GraphQLI
83
83
  * **WARNING**: avoid using this where possible, it causes OpPlans to split.
84
84
  */
85
85
  evalHas(key: string): boolean;
86
+ /**
87
+ * Evaluates the keys of the current value, and adds a
88
+ * constraint to the OpPlan to ensure that all future evaluations of this
89
+ * check will always return the same result.
90
+ *
91
+ * **WARNING**: avoid using this where possible, it causes OpPlans to split.
92
+ */
93
+ evalKeys(): ReadonlyArray<keyof TData & string> | null;
86
94
  /**
87
95
  * Evaluates the length of the current value (assumed to be an array), and
88
96
  * adds a constraint to the OpPlan to ensure that all future values will have
@@ -231,6 +231,46 @@ class __TrackedValueStep extends step_js_1.UnbatchedExecutableStep {
231
231
  });
232
232
  return exists;
233
233
  }
234
+ /**
235
+ * Evaluates the keys of the current value, and adds a
236
+ * constraint to the OpPlan to ensure that all future evaluations of this
237
+ * check will always return the same result.
238
+ *
239
+ * **WARNING**: avoid using this where possible, it causes OpPlans to split.
240
+ */
241
+ evalKeys() {
242
+ const { value, path } = this;
243
+ if (!(0, graphql_1.isInputObjectType)(this.nullableGraphQLType)) {
244
+ throw new Error("evalKeys must only be called for object types");
245
+ }
246
+ if (value == null) {
247
+ this.constraints.push({
248
+ type: "keys",
249
+ path,
250
+ keys: null,
251
+ });
252
+ return null;
253
+ }
254
+ const keys = [];
255
+ const keysOfType = Object.keys(this.nullableGraphQLType.getFields());
256
+ // NOTE: it's important that we loop through the fields in their defined
257
+ // order, this ensures the `keys` array always has consistent ordering.
258
+ for (let i = 0; i < keysOfType.length; i++) {
259
+ const key = keysOfType[i];
260
+ // NOTE: `key in value` would be more performant here, but we cannot trust
261
+ // users not to pass `{foo: undefined}` so we must do the more expensive
262
+ // `value[key] !== undefined` check.
263
+ if (value[key] !== undefined) {
264
+ keys.push(key);
265
+ }
266
+ }
267
+ this.constraints.push({
268
+ type: "keys",
269
+ path,
270
+ keys,
271
+ });
272
+ return keys;
273
+ }
234
274
  /**
235
275
  * Evaluates the length of the current value (assumed to be an array), and
236
276
  * adds a constraint to the OpPlan to ensure that all future values will have
@@ -1,3 +1,4 @@
1
+ import type { GrafastResultsList } from "../index.js";
1
2
  import { $$noExec, ExecutableStep } from "../step.js";
2
3
  import type { AccessStep } from "./access.js";
3
4
  /**
@@ -14,7 +15,7 @@ export declare class __ValueStep<TData> extends ExecutableStep<TData> {
14
15
  [$$noExec]: boolean;
15
16
  constructor();
16
17
  toStringMeta(): string | null;
17
- execute(): never;
18
+ execute(): GrafastResultsList<TData>;
18
19
  get<TAttr extends keyof TData>(attrName: TAttr): AccessStep<TData[TAttr]>;
19
20
  at<TIndex extends keyof TData>(index: TIndex): AccessStep<TData[TIndex]>;
20
21
  }
@@ -18,6 +18,8 @@ export declare class ConstantStep<TData> extends UnbatchedExecutableStep<TData>
18
18
  eval(): TData;
19
19
  evalIs(value: any): boolean;
20
20
  evalIsEmpty(): boolean;
21
+ evalLength(): number | null;
22
+ evalKeys(): ReadonlyArray<keyof TData & string> | null;
21
23
  unbatchedExecute(): TData;
22
24
  isNull(): boolean;
23
25
  isUndefined(): boolean;
@@ -43,6 +43,18 @@ class ConstantStep extends step_js_1.UnbatchedExecutableStep {
43
43
  this.data !== null &&
44
44
  Object.keys(this.data).length === 0);
45
45
  }
46
+ evalLength() {
47
+ return Array.isArray(this.data) ? this.data.length : null;
48
+ }
49
+ evalKeys() {
50
+ if (this.data == null || typeof this.data !== "object") {
51
+ return null;
52
+ }
53
+ else {
54
+ const data = this.data;
55
+ return Object.keys(data).filter((k) => data[k] !== undefined);
56
+ }
57
+ }
46
58
  unbatchedExecute() {
47
59
  return this.data;
48
60
  }
@@ -8,7 +8,7 @@ const index_js_1 = require("../index.js");
8
8
  const polymorphic_js_1 = require("../polymorphic.js");
9
9
  const step_js_1 = require("../step.js");
10
10
  const utils_js_1 = require("../utils.js");
11
- const { defaultTypeResolver, getNamedType, getNullableType, isAbstractType, isListType, } = graphql;
11
+ const { defaultTypeResolver, getNamedType, getNullableType, isAbstractType, isListType, isNonNullType, } = graphql;
12
12
  function dcr(data, // but not a promise
13
13
  context, resolveInfo) {
14
14
  if (data == null) {
@@ -69,9 +69,6 @@ class GraphQLResolverStep extends step_js_1.UnbatchedExecutableStep {
69
69
  this.subscriber?.name ||
70
70
  null);
71
71
  }
72
- deduplicate(peers) {
73
- return peers.filter((peer) => peer.resolver === this.resolver && peer.subscriber === this.subscriber);
74
- }
75
72
  unbatchedExecute(_extra, source, args, context, variableValues, rootValue) {
76
73
  if (this.isNotRoot && source == null) {
77
74
  return source;
@@ -142,7 +139,13 @@ class GraphQLItemHandler extends step_js_1.ExecutableStep {
142
139
  this.isSyncAndSafe = false;
143
140
  this.addDependency($parent);
144
141
  if (isListType(nullableType)) {
145
- this.nullableInnerType = nullableType.ofType;
142
+ const innerType = nullableType.ofType;
143
+ if (isNonNullType(innerType)) {
144
+ this.nullableInnerType = innerType.ofType;
145
+ }
146
+ else {
147
+ this.nullableInnerType = innerType;
148
+ }
146
149
  }
147
150
  else {
148
151
  if (!isAbstractType(nullableType)) {
@@ -1,4 +1,4 @@
1
- import type { GrafastResultStreamList, GrafastSubscriber, StreamDetails } from "../interfaces.js";
1
+ import type { GrafastResultsList, GrafastResultStreamList, GrafastSubscriber, StreamDetails } from "../interfaces.js";
2
2
  import type { StreamableStep } from "../step.js";
3
3
  import { ExecutableStep } from "../step.js";
4
4
  import type { __ItemStep } from "./__item.js";
@@ -25,7 +25,7 @@ export declare class ListenStep<TTopics extends {
25
25
  */
26
26
  private topicDep;
27
27
  constructor(pubsubOrPlan: ExecutableStep<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: ExecutableStep<TTopic> | string, itemPlan?: (itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep);
28
- execute(): never;
28
+ execute(): GrafastResultsList<TTopics[TTopic]>;
29
29
  stream({ indexMap, values, }: StreamDetails<readonly [GrafastSubscriber<TTopics>, TTopic]>): GrafastResultStreamList<TTopics[TTopic]>;
30
30
  }
31
31
  /**
@@ -49,7 +49,7 @@ export declare class ObjectStep<TPlans extends {
49
49
  execute({ indexMap, values, extra, }: ExecutionDetails<Array<DataFromObjectSteps<TPlans>[keyof TPlans]>>): ReadonlyArray<DataFromObjectSteps<TPlans>>;
50
50
  unbatchedExecute(_extra: UnbatchedExecutionExtra, ..._values: any[]): any;
51
51
  deduplicate(peers: ObjectStep<any>[]): ObjectStep<TPlans>[];
52
- optimize(opts: StepOptimizeOptions): ConstantStep<any> | this;
52
+ optimize(opts: StepOptimizeOptions): ConstantStep<any> | this | ConstantStep<Record<string, any>>;
53
53
  /**
54
54
  * Get the original plan with the given key back again.
55
55
  */
@@ -12,7 +12,6 @@ export declare class SideEffectStep<TIn, TOut> extends UnbatchedExecutableStep<T
12
12
  };
13
13
  isSyncAndSafe: boolean;
14
14
  allowMultipleOptimizations: boolean;
15
- hasSideEffects: boolean;
16
15
  private planDep;
17
16
  constructor($plan: ExecutableStep<TIn> | null | undefined, fn: (value: TIn) => PromiseOrDirect<TOut>);
18
17
  toStringMeta(): any;
@@ -6,7 +6,7 @@ if (globalAny[$$grafast] === true) {
6
6
  // Already warned
7
7
  }
8
8
  else if (globalAny[$$grafast]) {
9
- console.trace(`WARNING: more than one version of the 'grafast' module has been instantiated - you must ensure there is exactly one grafast (e.g. using yarn "resolutions" or similar techniques). Try clearing your package lockfile and reinstalling. ${globalAny[$$grafast].stack}`);
9
+ console.trace(`WARNING: more than one version of the 'grafast' module has been instantiated - you must ensure there is exactly one grafast (e.g. using yarn "resolutions" or similar techniques). Try clearing your package lockfile and reinstalling.\n ${String(globalAny[$$grafast].stack).replace(/\n/g, "\n ")}`);
10
10
  globalAny[$$grafast] = true;
11
11
  }
12
12
  else {
package/dist/utils.d.ts CHANGED
@@ -103,6 +103,10 @@ export declare function arrayOfLength(length: number, fill?: any): any[];
103
103
  */
104
104
  export declare function findVariableNamesUsed(operationPlan: OperationPlan, field: FieldNode): string[];
105
105
  export declare function isTypePlanned(schema: GraphQLSchema, namedType: GraphQLNamedType): boolean;
106
+ /**
107
+ * Returns `true` if the first argument depends on the second argument either
108
+ * directly or indirectly (via a chain of dependencies).
109
+ */
106
110
  export declare function stepADependsOnStepB(stepA: ExecutableStep, stepB: ExecutableStep): boolean;
107
111
  /**
108
112
  * Returns true if stepA is allowed to depend on stepB, false otherwise. (This
package/dist/utils.js CHANGED
@@ -605,10 +605,17 @@ function writeableArray(a) {
605
605
  return a;
606
606
  }
607
607
  exports.writeableArray = writeableArray;
608
+ /**
609
+ * Returns `true` if the first argument depends on the second argument either
610
+ * directly or indirectly (via a chain of dependencies).
611
+ */
608
612
  function stepADependsOnStepB(stepA, stepB) {
609
613
  if (stepA === stepB) {
610
614
  throw new Error("Invalid call to stepADependsOnStepB");
611
615
  }
616
+ // PERF: bredth-first might be better.
617
+ // PERF: we can stop looking once we pass a certain layerPlan boundary.
618
+ // PERF: maybe some form of caching here would be sensible?
612
619
  // Depth-first search for match
613
620
  for (const dep of sudo(stepA).dependencies) {
614
621
  if (dep === stepB) {
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "0.1.1-beta.11";
1
+ export declare const version = "0.1.1-beta.13";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
4
  // This file is autogenerated by /scripts/postversion.mjs
5
- exports.version = "0.1.1-beta.11";
5
+ exports.version = "0.1.1-beta.13";
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grafast",
3
- "version": "0.1.1-beta.11",
3
+ "version": "0.1.1-beta.13",
4
4
  "description": "Cutting edge GraphQL planning and execution engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",