grafast 0.1.1-beta.13 → 0.1.1-beta.15

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.
package/README.md CHANGED
@@ -53,6 +53,8 @@ And please give some love to our featured sponsors 🤩:
53
53
  <td align="center"><a href="https://dovetailapp.com/"><img src="https://graphile.org/images/sponsors/dovetail.png" width="90" height="90" alt="Dovetail" /><br />Dovetail</a> *</td>
54
54
  <td align="center"><a href="https://stellate.co/"><img src="https://graphile.org/images/sponsors/Stellate.png" width="90" height="90" alt="Stellate" /><br />Stellate</a> *</td>
55
55
  <td align="center"><a href="https://gosteelhead.com/"><img src="https://graphile.org/images/sponsors/steelhead.svg" width="90" height="90" alt="Steelhead" /><br />Steelhead</a> *</td>
56
+ </tr><tr>
57
+ <td align="center"><a href=""><img src="https://graphile.org/images/sponsors/latchbio.jpg" width="90" height="90" alt="LatchBio" /><br />LatchBio</a> *</td>
56
58
  </tr></table>
57
59
 
58
60
  <em>\* Sponsors the entire Graphile suite</em>
@@ -615,9 +615,7 @@ class OperationPlan {
615
615
  const rawPlanResolver = objectField.extensions?.grafast?.plan;
616
616
  if (rawPlanResolver) {
617
617
  resolverEmulation = false;
618
- }
619
- if (rawPlanResolver?.constructor?.name === "AsyncFunction") {
620
- throw new Error(`Plans must be synchronous, but this schema has an async function at '${objectType.name}.${fieldName}.plan': ${rawPlanResolver.toString()}`);
618
+ (0, utils_js_1.assertNotAsync)(rawPlanResolver, `${objectType.name}.${fieldName}.plan`);
621
619
  }
622
620
  const namedReturnType = getNamedType(fieldType);
623
621
  const resolvedResolver = objectField.resolve;
@@ -848,13 +846,12 @@ class OperationPlan {
848
846
  }
849
847
  else if (isScalarType(nullableFieldType)) {
850
848
  const scalarPlanResolver = nullableFieldType.extensions?.grafast?.plan;
851
- if (scalarPlanResolver?.constructor?.name === "AsyncFunction") {
852
- throw new Error(`Plans must be synchronous, but this schema has an async function at '${nullableFieldType.name}.plan': ${scalarPlanResolver.toString()}`);
853
- }
849
+ const fnDescription = `${nullableFieldType.name}.plan`;
850
+ (0, utils_js_1.assertNotAsync)(scalarPlanResolver, fnDescription);
854
851
  const $sideEffect = parentLayerPlan.latestSideEffectStep;
855
852
  try {
856
853
  const $leaf = typeof scalarPlanResolver === "function"
857
- ? (0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(parentLayerPlan, polymorphicPaths, scalarPlanResolver, null, $step, this.scalarPlanInfo)
854
+ ? (0, utils_js_1.assertNotPromise)((0, withGlobalLayerPlan_js_1.withGlobalLayerPlan)(parentLayerPlan, polymorphicPaths, scalarPlanResolver, null, $step, this.scalarPlanInfo), scalarPlanResolver, fnDescription)
858
855
  : $step;
859
856
  parentOutputPlan.addChild(parentObjectType, responseKey, {
860
857
  type: "outputPlan",
@@ -432,7 +432,7 @@ function executeBucket(bucket, requestContext) {
432
432
  }
433
433
  // End "f2b3b1b3" block
434
434
  }
435
- else {
435
+ else if (forceIndexValue === undefined) {
436
436
  const depVal = depExecutionVal.at(dataIndex);
437
437
  let depFlags;
438
438
  if ((bucket.flagUnion & interfaces_js_1.FLAG_ERROR) === interfaces_js_1.FLAG_ERROR &&
@@ -768,7 +768,7 @@ function executeBucket(bucket, requestContext) {
768
768
  }
769
769
  const result = needsFiltering
770
770
  ? reallyExecuteStepWithFiltering(step, dependencies, _rawForbiddenFlags, _rawOnReject, bucket.polymorphicPathList, extra)
771
- : reallyExecuteStepWithoutFiltering(step._isUnary ? 1 : size, step, dependencies, extra);
771
+ : reallyExecuteStepWithoutFiltering(step._isUnary ? 1 : size, step, $sideEffect ? dependencies.slice(0, depCount) : dependencies, extra);
772
772
  if ((0, utils_js_1.isPromiseLike)(result)) {
773
773
  return result.then(null, (error) => {
774
774
  // Don't need to do this here, it will be done where the
@@ -49,6 +49,12 @@ function evalDirectiveArgDirect(directive, argumentName, variableValuesStep, def
49
49
  case "IntValue": {
50
50
  return parseInt(value.value, 10);
51
51
  }
52
+ case "FloatValue": {
53
+ return parseFloat(value.value);
54
+ }
55
+ case "StringValue": {
56
+ return value.value;
57
+ }
52
58
  case "NullValue": {
53
59
  return null;
54
60
  }
package/dist/index.d.ts CHANGED
@@ -17,6 +17,8 @@ import { grafast, grafastSync } from "./grafastGraphql.js";
17
17
  import type { $$cacheByOperation, $$hooked, $$queryCache, CacheByOperationEntry, DataFromStep, EstablishOperationPlanEvent, ExecuteEvent, ExecuteStepEvent, GrafastExecutionArgs, GrafastTimeouts, ParseAndValidateEvent, PrepareArgsEvent, ScalarInputPlanResolver, StreamStepEvent, ValidateSchemaEvent } from "./interfaces.js";
18
18
  import { $$bypassGraphQL, $$eventEmitter, $$extensions, $$idempotent, $$verbatim, ArgumentApplyPlanResolver, ArgumentInputPlanResolver, BaseEventMap, BaseGraphQLArguments, BaseGraphQLRootValue, BaseGraphQLVariables, EnumValueApplyPlanResolver, EventCallback, EventMapKey, ExecutionDetails, ExecutionEventEmitter, ExecutionEventMap, ExecutionExtra, FieldArgs, FieldInfo, FieldPlanResolver, GrafastArgumentConfig, GrafastFieldConfig, GrafastFieldConfigArgumentMap, GrafastInputFieldConfig, GrafastPlanJSON, GrafastResultsList, GrafastResultStreamList, GrafastSubscriber, GrafastValuesList, InputObjectFieldApplyPlanResolver, InputObjectFieldInputPlanResolver, InputObjectTypeInputPlanResolver, InputStep, JSONArray, JSONObject, JSONValue, Maybe, NodeIdCodec, NodeIdHandler, OutputPlanForType, PolymorphicData, PromiseOrDirect, ScalarPlanResolver, StepOptimizeOptions, StepStreamOptions, TypedEventEmitter, UnbatchedExecutionExtra } from "./interfaces.js";
19
19
  import { getGrafastMiddleware } from "./middleware.js";
20
+ import type { Multistep, UnwrapMultistep } from "./multistep.js";
21
+ import { multistep } from "./multistep.js";
20
22
  import { polymorphicWrap } from "./polymorphic.js";
21
23
  import { assertExecutableStep, assertListCapableStep, assertModifierStep, BaseStep, ExecutableStep, isExecutableStep, isListCapableStep, isListLikeStep, isModifierStep, isObjectLikeStep, isStreamableStep, ListCapableStep, ListLikeStep, ModifierStep, ObjectLikeStep, PolymorphicStep, StreamableStep, UnbatchedExecutableStep } from "./step.js";
22
24
  import { __FlagStep, __InputListStep, __InputObjectStep, __InputObjectStepWithDollars, __InputStaticLeafStep, __ItemStep, __ListTransformStep, __TrackedValueStep, __TrackedValueStepWithDollars, __ValueStep, access, AccessStep, ActualKeyByDesiredKey, applyTransforms, ApplyTransformsStep, assertEdgeCapableStep, assertNotNull, assertPageInfoCapableStep, condition, ConditionStep, connection, ConnectionCapableStep, ConnectionStep, constant, ConstantStep, context, debugPlans, each, EdgeCapableStep, EdgeStep, error, ErrorStep, filter, FilterPlanMemo, first, FirstStep, GraphQLItemHandler, graphqlItemHandler, graphqlResolver, GraphQLResolverStep, groupBy, GroupByPlanMemo, inhibitOnNull, lambda, LambdaStep, last, LastStep, list, listen, ListenStep, ListStep, listTransform, ListTransformItemPlanCallback, ListTransformOptions, ListTransformReduce, LoadedRecordStep, loadMany, LoadManyCallback, loadManyCallback, loadOne, LoadOneCallback, loadOneCallback, LoadOptions, LoadStep, makeDecodeNodeId, node, nodeIdFromNode, NodeStep, object, ObjectPlanMeta, ObjectStep, operationPlan, PageInfoCapableStep, partitionByIndex, polymorphicBranch, PolymorphicBranchMatcher, PolymorphicBranchMatchers, PolymorphicBranchStep, proxy, ProxyStep, remapKeys, RemapKeysStep, reverse, reverseArray, ReverseStep, rootValue, setter, SetterCapableStep, SetterStep, sideEffect, SideEffectStep, specFromNodeId, trackedContext, trackedRootValue, trap, TRAP_ERROR, TRAP_ERROR_OR_INHIBITED, TRAP_INHIBITED } from "./steps/index.js";
@@ -25,7 +27,7 @@ import { stripAnsi } from "./stripAnsi.js";
25
27
  import { subscribe } from "./subscribe.js";
26
28
  import { arrayOfLength, arraysMatch, getEnumValueConfig, GrafastInputFieldConfigMap, GrafastInputObjectType, GrafastObjectType, inputObjectFieldSpec, InputObjectTypeSpec, isPromiseLike, newGrafastFieldConfigBuilder, newInputObjectTypeBuilder, newObjectTypeBuilder, objectFieldSpec, objectSpec, ObjectTypeFields, ObjectTypeSpec, stepADependsOnStepB, stepAMayDependOnStepB, stepsAreInSamePhase } from "./utils.js";
27
29
  export { isAsyncIterable } from "iterall";
28
- export { __FlagStep, __InputListStep, __InputObjectStep, __InputObjectStepWithDollars, __InputStaticLeafStep, __ItemStep, __ListTransformStep, __TrackedValueStep, __TrackedValueStepWithDollars, __ValueStep, $$bypassGraphQL, $$eventEmitter, $$extensions, $$idempotent, $$inhibit, $$verbatim, access, AccessStep, ActualKeyByDesiredKey, applyTransforms, ApplyTransformsStep, ArgumentApplyPlanResolver, ArgumentInputPlanResolver, arrayOfLength, arraysMatch, assertEdgeCapableStep, assertExecutableStep, assertListCapableStep, assertModifierStep, assertNotNull, assertPageInfoCapableStep, BaseEventMap, BaseGraphQLArguments, BaseGraphQLRootValue, BaseGraphQLVariables, BaseStep, condition, ConditionStep, connection, ConnectionCapableStep, ConnectionStep, constant, ConstantStep, context, DataFromObjectSteps, DataFromStep, debugPlans, defer, Deferred, each, EdgeCapableStep, EdgeStep, EnumPlans, EnumValueApplyPlanResolver, error, ErrorStep, EventCallback, EventMapKey, ExecutableStep, execute, ExecutionDetails, ExecutionEventEmitter, ExecutionEventMap, ExecutionExtra, exportAs, exportAsMany, FieldArgs, FieldInfo, FieldPlanResolver, FieldPlans, filter, FilterPlanMemo, first, FirstStep, flagError, getEnumValueConfig, getGrafastMiddleware, grafast, GrafastArgumentConfig, GrafastExecutionArgs, GrafastFieldConfig, GrafastFieldConfigArgumentMap, grafast as grafastGraphql, grafastSync as grafastGraphqlSync, GrafastInputFieldConfig, GrafastInputFieldConfigMap, GrafastInputObjectType, GrafastObjectType, GrafastPlanJSON, GrafastPlans, grafastPrint, GrafastResultsList, GrafastResultStreamList, GrafastSubscriber, grafastSync, GrafastValuesList, GraphQLItemHandler, graphqlItemHandler, graphqlResolver, GraphQLResolverStep, groupBy, GroupByPlanMemo, inhibitOnNull, InputObjectFieldApplyPlanResolver, InputObjectFieldInputPlanResolver, inputObjectFieldSpec, InputObjectPlans, InputObjectTypeInputPlanResolver, InputObjectTypeSpec, InputStep, InterfaceOrUnionPlans, isDev, isExecutableStep, isListCapableStep, isListLikeStep, isModifierStep, isObjectLikeStep, isPromiseLike, isSafeError, isStreamableStep, isUnaryStep, JSONArray, JSONObject, JSONValue, lambda, LambdaStep, last, LastStep, list, ListCapableStep, listen, ListenStep, ListLikeStep, ListStep, listTransform, ListTransformItemPlanCallback, ListTransformOptions, ListTransformReduce, LoadedRecordStep, loadMany, LoadManyCallback, loadManyCallback, loadOne, LoadOneCallback, loadOneCallback, LoadOptions, LoadStep, makeDecodeNodeId, makeGrafastSchema, Maybe, ModifierStep, newGrafastFieldConfigBuilder, newInputObjectTypeBuilder, newObjectTypeBuilder, node, NodeIdCodec, nodeIdFromNode, NodeIdHandler, NodeStep, noop, object, objectFieldSpec, ObjectLikeStep, ObjectPlanMeta, ObjectPlans, objectSpec, ObjectStep, ObjectTypeFields, ObjectTypeSpec, OperationPlan, operationPlan, OutputPlanForType, PageInfoCapableStep, partitionByIndex, polymorphicBranch, PolymorphicBranchMatcher, PolymorphicBranchMatchers, PolymorphicBranchStep, PolymorphicData, PolymorphicStep, polymorphicWrap, PromiseOrDirect, proxy, ProxyStep, remapKeys, RemapKeysStep, reverse, reverseArray, ReverseStep, rootValue, SafeError, ScalarPlanResolver, ScalarPlans, setter, SetterCapableStep, SetterStep, sideEffect, SideEffectStep, specFromNodeId, stepADependsOnStepB, stepAMayDependOnStepB, StepOptimizeOptions, stepsAreInSamePhase, StepStreamOptions, StreamableStep, stringifyPayload, stripAnsi, subscribe, trackedContext, trackedRootValue, trap, TRAP_ERROR, TRAP_ERROR_OR_INHIBITED, TRAP_INHIBITED, TypedEventEmitter, UnbatchedExecutableStep, UnbatchedExecutionExtra, };
30
+ export { __FlagStep, __InputListStep, __InputObjectStep, __InputObjectStepWithDollars, __InputStaticLeafStep, __ItemStep, __ListTransformStep, __TrackedValueStep, __TrackedValueStepWithDollars, __ValueStep, $$bypassGraphQL, $$eventEmitter, $$extensions, $$idempotent, $$inhibit, $$verbatim, access, AccessStep, ActualKeyByDesiredKey, applyTransforms, ApplyTransformsStep, ArgumentApplyPlanResolver, ArgumentInputPlanResolver, arrayOfLength, arraysMatch, assertEdgeCapableStep, assertExecutableStep, assertListCapableStep, assertModifierStep, assertNotNull, assertPageInfoCapableStep, BaseEventMap, BaseGraphQLArguments, BaseGraphQLRootValue, BaseGraphQLVariables, BaseStep, condition, ConditionStep, connection, ConnectionCapableStep, ConnectionStep, constant, ConstantStep, context, DataFromObjectSteps, DataFromStep, debugPlans, defer, Deferred, each, EdgeCapableStep, EdgeStep, EnumPlans, EnumValueApplyPlanResolver, error, ErrorStep, EventCallback, EventMapKey, ExecutableStep, execute, ExecutionDetails, ExecutionEventEmitter, ExecutionEventMap, ExecutionExtra, exportAs, exportAsMany, FieldArgs, FieldInfo, FieldPlanResolver, FieldPlans, filter, FilterPlanMemo, first, FirstStep, flagError, getEnumValueConfig, getGrafastMiddleware, grafast, GrafastArgumentConfig, GrafastExecutionArgs, GrafastFieldConfig, GrafastFieldConfigArgumentMap, grafast as grafastGraphql, grafastSync as grafastGraphqlSync, GrafastInputFieldConfig, GrafastInputFieldConfigMap, GrafastInputObjectType, GrafastObjectType, GrafastPlanJSON, GrafastPlans, grafastPrint, GrafastResultsList, GrafastResultStreamList, GrafastSubscriber, grafastSync, GrafastValuesList, GraphQLItemHandler, graphqlItemHandler, graphqlResolver, GraphQLResolverStep, groupBy, GroupByPlanMemo, inhibitOnNull, InputObjectFieldApplyPlanResolver, InputObjectFieldInputPlanResolver, inputObjectFieldSpec, InputObjectPlans, InputObjectTypeInputPlanResolver, InputObjectTypeSpec, InputStep, InterfaceOrUnionPlans, isDev, isExecutableStep, isListCapableStep, isListLikeStep, isModifierStep, isObjectLikeStep, isPromiseLike, isSafeError, isStreamableStep, isUnaryStep, JSONArray, JSONObject, JSONValue, lambda, LambdaStep, last, LastStep, list, ListCapableStep, listen, ListenStep, ListLikeStep, ListStep, listTransform, ListTransformItemPlanCallback, ListTransformOptions, ListTransformReduce, LoadedRecordStep, loadMany, LoadManyCallback, loadManyCallback, loadOne, LoadOneCallback, loadOneCallback, LoadOptions, LoadStep, makeDecodeNodeId, makeGrafastSchema, Maybe, ModifierStep, Multistep, multistep, newGrafastFieldConfigBuilder, newInputObjectTypeBuilder, newObjectTypeBuilder, node, NodeIdCodec, nodeIdFromNode, NodeIdHandler, NodeStep, noop, object, objectFieldSpec, ObjectLikeStep, ObjectPlanMeta, ObjectPlans, objectSpec, ObjectStep, ObjectTypeFields, ObjectTypeSpec, OperationPlan, operationPlan, OutputPlanForType, PageInfoCapableStep, partitionByIndex, polymorphicBranch, PolymorphicBranchMatcher, PolymorphicBranchMatchers, PolymorphicBranchStep, PolymorphicData, PolymorphicStep, polymorphicWrap, PromiseOrDirect, proxy, ProxyStep, remapKeys, RemapKeysStep, reverse, reverseArray, ReverseStep, rootValue, SafeError, ScalarPlanResolver, ScalarPlans, setter, SetterCapableStep, SetterStep, sideEffect, SideEffectStep, specFromNodeId, stepADependsOnStepB, stepAMayDependOnStepB, StepOptimizeOptions, stepsAreInSamePhase, StepStreamOptions, StreamableStep, stringifyPayload, stripAnsi, subscribe, trackedContext, trackedRootValue, trap, TRAP_ERROR, TRAP_ERROR_OR_INHIBITED, TRAP_INHIBITED, TypedEventEmitter, UnbatchedExecutableStep, UnbatchedExecutionExtra, UnwrapMultistep, };
29
31
  export { hookArgs } from "./args.js";
30
32
  export { version } from "./version.js";
31
33
  /** @deprecated Renamed to 'applyTransforms' */
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getEnumValueConfig = exports.flagError = exports.FirstStep = exports.first = exports.filter = exports.exportAsMany = exports.exportAs = exports.execute = exports.ExecutableStep = exports.ErrorStep = exports.error = exports.EdgeStep = exports.each = exports.defer = exports.debugPlans = exports.context = exports.ConstantStep = exports.constant = exports.ConnectionStep = exports.connection = exports.ConditionStep = exports.condition = exports.BaseStep = exports.assertPageInfoCapableStep = exports.assertNotNull = exports.assertModifierStep = exports.assertListCapableStep = exports.assertExecutableStep = exports.assertEdgeCapableStep = exports.arraysMatch = exports.arrayOfLength = exports.ApplyTransformsStep = exports.applyTransforms = exports.AccessStep = exports.access = exports.$$verbatim = exports.$$inhibit = exports.$$idempotent = exports.$$extensions = exports.$$eventEmitter = exports.$$bypassGraphQL = exports.__ValueStep = exports.__TrackedValueStep = exports.__ListTransformStep = exports.__ItemStep = exports.__InputStaticLeafStep = exports.__InputObjectStep = exports.__InputListStep = exports.__FlagStep = exports.isAsyncIterable = void 0;
4
- exports.objectFieldSpec = exports.object = exports.noop = exports.NodeStep = exports.nodeIdFromNode = exports.node = exports.newObjectTypeBuilder = exports.newInputObjectTypeBuilder = exports.newGrafastFieldConfigBuilder = exports.ModifierStep = exports.makeGrafastSchema = exports.makeDecodeNodeId = exports.LoadStep = exports.loadOneCallback = exports.loadOne = exports.loadManyCallback = exports.loadMany = exports.LoadedRecordStep = exports.listTransform = exports.ListStep = exports.ListenStep = exports.listen = exports.list = exports.LastStep = exports.last = exports.LambdaStep = exports.lambda = exports.isUnaryStep = exports.isStreamableStep = exports.isSafeError = exports.isPromiseLike = exports.isObjectLikeStep = exports.isModifierStep = exports.isListLikeStep = exports.isListCapableStep = exports.isExecutableStep = exports.isDev = exports.inputObjectFieldSpec = exports.inhibitOnNull = exports.groupBy = exports.GraphQLResolverStep = exports.graphqlResolver = exports.graphqlItemHandler = exports.GraphQLItemHandler = exports.grafastSync = exports.grafastPrint = exports.grafastGraphqlSync = exports.grafastGraphql = exports.grafast = exports.getGrafastMiddleware = void 0;
5
- exports.DeepEvalStep = exports.deepEval = exports.version = exports.hookArgs = exports.UnbatchedExecutableStep = exports.TRAP_INHIBITED = exports.TRAP_ERROR_OR_INHIBITED = exports.TRAP_ERROR = exports.trap = exports.trackedRootValue = exports.trackedContext = exports.subscribe = exports.stripAnsi = exports.stringifyPayload = exports.stepsAreInSamePhase = exports.stepAMayDependOnStepB = exports.stepADependsOnStepB = exports.specFromNodeId = exports.SideEffectStep = exports.sideEffect = exports.SetterStep = exports.setter = exports.SafeError = exports.rootValue = exports.ReverseStep = exports.reverseArray = exports.reverse = exports.RemapKeysStep = exports.remapKeys = exports.ProxyStep = exports.proxy = exports.polymorphicWrap = exports.PolymorphicBranchStep = exports.polymorphicBranch = exports.partitionByIndex = exports.operationPlan = exports.OperationPlan = exports.ObjectStep = exports.objectSpec = void 0;
4
+ exports.object = exports.noop = exports.NodeStep = exports.nodeIdFromNode = exports.node = exports.newObjectTypeBuilder = exports.newInputObjectTypeBuilder = exports.newGrafastFieldConfigBuilder = exports.multistep = exports.ModifierStep = exports.makeGrafastSchema = exports.makeDecodeNodeId = exports.LoadStep = exports.loadOneCallback = exports.loadOne = exports.loadManyCallback = exports.loadMany = exports.LoadedRecordStep = exports.listTransform = exports.ListStep = exports.ListenStep = exports.listen = exports.list = exports.LastStep = exports.last = exports.LambdaStep = exports.lambda = exports.isUnaryStep = exports.isStreamableStep = exports.isSafeError = exports.isPromiseLike = exports.isObjectLikeStep = exports.isModifierStep = exports.isListLikeStep = exports.isListCapableStep = exports.isExecutableStep = exports.isDev = exports.inputObjectFieldSpec = exports.inhibitOnNull = exports.groupBy = exports.GraphQLResolverStep = exports.graphqlResolver = exports.graphqlItemHandler = exports.GraphQLItemHandler = exports.grafastSync = exports.grafastPrint = exports.grafastGraphqlSync = exports.grafastGraphql = exports.grafast = exports.getGrafastMiddleware = void 0;
5
+ exports.DeepEvalStep = exports.deepEval = exports.version = exports.hookArgs = exports.UnbatchedExecutableStep = exports.TRAP_INHIBITED = exports.TRAP_ERROR_OR_INHIBITED = exports.TRAP_ERROR = exports.trap = exports.trackedRootValue = exports.trackedContext = exports.subscribe = exports.stripAnsi = exports.stringifyPayload = exports.stepsAreInSamePhase = exports.stepAMayDependOnStepB = exports.stepADependsOnStepB = exports.specFromNodeId = exports.SideEffectStep = exports.sideEffect = exports.SetterStep = exports.setter = exports.SafeError = exports.rootValue = exports.ReverseStep = exports.reverseArray = exports.reverse = exports.RemapKeysStep = exports.remapKeys = exports.ProxyStep = exports.proxy = exports.polymorphicWrap = exports.PolymorphicBranchStep = exports.polymorphicBranch = exports.partitionByIndex = exports.operationPlan = exports.OperationPlan = exports.ObjectStep = exports.objectSpec = exports.objectFieldSpec = void 0;
6
6
  const tslib_1 = require("tslib");
7
7
  require("./thereCanBeOnlyOne.js");
8
8
  const debug_1 = tslib_1.__importDefault(require("debug"));
@@ -45,6 +45,8 @@ Object.defineProperty(exports, "$$idempotent", { enumerable: true, get: function
45
45
  Object.defineProperty(exports, "$$verbatim", { enumerable: true, get: function () { return interfaces_js_1.$$verbatim; } });
46
46
  const middleware_js_1 = require("./middleware.js");
47
47
  Object.defineProperty(exports, "getGrafastMiddleware", { enumerable: true, get: function () { return middleware_js_1.getGrafastMiddleware; } });
48
+ const multistep_js_1 = require("./multistep.js");
49
+ Object.defineProperty(exports, "multistep", { enumerable: true, get: function () { return multistep_js_1.multistep; } });
48
50
  const polymorphic_js_1 = require("./polymorphic.js");
49
51
  Object.defineProperty(exports, "polymorphicWrap", { enumerable: true, get: function () { return polymorphic_js_1.polymorphicWrap; } });
50
52
  const step_js_1 = require("./step.js");
@@ -288,6 +290,7 @@ Object.defineProperty(exports, "isAsyncIterable", { enumerable: true, get: funct
288
290
  flagError: error_js_1.flagError,
289
291
  SafeError: error_js_1.SafeError,
290
292
  isUnaryStep: withGlobalLayerPlan_js_1.isUnaryStep,
293
+ multistep: multistep_js_1.multistep,
291
294
  });
292
295
  var args_js_1 = require("./args.js");
293
296
  Object.defineProperty(exports, "hookArgs", { enumerable: true, get: function () { return args_js_1.hookArgs; } });
@@ -0,0 +1,19 @@
1
+ import { ExecutableStep } from "./step.js";
2
+ /**
3
+ * When using this, always use `const`! Otherwise tuples will show up as arrays
4
+ * and break things.
5
+ */
6
+ export type Multistep = null | undefined | ExecutableStep | readonly [...(readonly ExecutableStep[])] | Record<string, ExecutableStep>;
7
+ export type UnwrapMultistep<TMultistepSpec extends Multistep> = TMultistepSpec extends null ? null : TMultistepSpec extends undefined ? undefined : TMultistepSpec extends ExecutableStep<infer U> ? U : TMultistepSpec extends readonly [...(readonly any[])] ? {
8
+ [index in keyof TMultistepSpec]: TMultistepSpec[index] extends ExecutableStep<infer V> ? V : never;
9
+ } : {
10
+ [key in keyof TMultistepSpec]: TMultistepSpec[key] extends ExecutableStep<infer V> ? V : never;
11
+ };
12
+ interface MultistepCacheConfig {
13
+ identifier: string;
14
+ cacheSize: number;
15
+ }
16
+ export declare function multistep<const TMultistepSpec extends Multistep>(spec: TMultistepSpec, stable?: string | true | MultistepCacheConfig): ExecutableStep<UnwrapMultistep<TMultistepSpec>>;
17
+ export declare function isMultistep<const TMultistepSpec extends Multistep>(spec: any): spec is TMultistepSpec;
18
+ export {};
19
+ //# sourceMappingURL=multistep.d.ts.map
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isMultistep = exports.multistep = void 0;
4
+ const step_js_1 = require("./step.js");
5
+ const constant_js_1 = require("./steps/constant.js");
6
+ const list_js_1 = require("./steps/list.js");
7
+ const object_js_1 = require("./steps/object.js");
8
+ const utils_js_1 = require("./utils.js");
9
+ function multistep(spec, stable) {
10
+ if (spec == null) {
11
+ return (0, constant_js_1.constant)(spec);
12
+ }
13
+ else if (spec instanceof step_js_1.ExecutableStep) {
14
+ return spec;
15
+ }
16
+ else if ((0, utils_js_1.isTuple)(spec)) {
17
+ const config = stable === true
18
+ ? { identifier: `multistep` }
19
+ : typeof stable === "string"
20
+ ? { identifier: stable }
21
+ : stable;
22
+ const $step = (0, list_js_1.list)(spec, config);
23
+ return $step;
24
+ }
25
+ else {
26
+ const config = stable === true
27
+ ? { identifier: `multistep` }
28
+ : typeof stable === "string"
29
+ ? { identifier: stable }
30
+ : stable;
31
+ const $step = (0, object_js_1.object)(spec, config);
32
+ return $step;
33
+ }
34
+ }
35
+ exports.multistep = multistep;
36
+ function isMultistep(spec) {
37
+ if (spec == null) {
38
+ return true;
39
+ }
40
+ else if (spec instanceof step_js_1.ExecutableStep) {
41
+ return true;
42
+ }
43
+ else if ((0, utils_js_1.isTuple)(spec) && spec.every((s) => s instanceof step_js_1.ExecutableStep)) {
44
+ return true;
45
+ }
46
+ else if (typeof spec === "object" &&
47
+ Object.values(spec).every((s) => s instanceof step_js_1.ExecutableStep)) {
48
+ return true;
49
+ }
50
+ else {
51
+ return false;
52
+ }
53
+ }
54
+ exports.isMultistep = isMultistep;
55
+ //# sourceMappingURL=multistep.js.map
@@ -6,7 +6,13 @@ const graphql = tslib_1.__importStar(require("graphql"));
6
6
  const constant_js_1 = require("./steps/constant.js");
7
7
  const list_js_1 = require("./steps/list.js");
8
8
  const object_js_1 = require("./steps/object.js");
9
+ const utils_js_1 = require("./utils.js");
9
10
  const { getNullableType, isEnumType, isInputObjectType, isListType, isScalarType, } = graphql;
11
+ function assertNotRuntime(operationPlan, description) {
12
+ if (operationPlan.phase === "ready") {
13
+ throw new Error(`${description} may only be called at planning time; however you have code that has attempted to call it during execution time. Please revisit your plan resolvers to locate the issue.`);
14
+ }
15
+ }
10
16
  function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAfterMode, callback) {
11
17
  if (operationPlan.loc !== null)
12
18
  operationPlan.loc.push(`withFieldArgsForArguments(${field.name})`);
@@ -20,6 +26,7 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
20
26
  let explicitlyApplied = false;
21
27
  const fieldArgs = {
22
28
  getRaw(path) {
29
+ assertNotRuntime(operationPlan, `fieldArgs.getRaw()`);
23
30
  if (typeof path === "string") {
24
31
  return $all.get(path);
25
32
  }
@@ -47,6 +54,7 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
47
54
  }
48
55
  },
49
56
  get(inPath) {
57
+ assertNotRuntime(operationPlan, `fieldArgs.get()`);
50
58
  const path = Array.isArray(inPath)
51
59
  ? inPath
52
60
  : inPath
@@ -111,21 +119,27 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
111
119
  if (rest.length === 0) {
112
120
  // Argument
113
121
  const arg = entity;
114
- result = arg.extensions.grafast?.inputPlan
115
- ? arg.extensions.grafast.inputPlan($parent, childFieldArgs, {
122
+ const argInputPlan = arg.extensions.grafast?.inputPlan;
123
+ const fnDescription = `???.${field.name}(${arg.name}:).inputPlan`;
124
+ (0, utils_js_1.assertNotAsync)(argInputPlan, fnDescription);
125
+ result = argInputPlan
126
+ ? (0, utils_js_1.assertNotPromise)(argInputPlan($parent, childFieldArgs, {
116
127
  schema,
117
128
  entity: arg,
118
- })
129
+ }), argInputPlan, fnDescription)
119
130
  : childFieldArgs.get();
120
131
  }
121
132
  else {
122
133
  // Input field
123
134
  const inputField = entity;
124
- result = inputField?.extensions.grafast?.inputPlan
125
- ? inputField.extensions.grafast.inputPlan(childFieldArgs, {
135
+ const inputFieldInputPlan = inputField?.extensions.grafast?.inputPlan;
136
+ const fnDescription = `???.${inputField?.name}.inputPlan`;
137
+ (0, utils_js_1.assertNotAsync)(inputFieldInputPlan, fnDescription);
138
+ result = inputFieldInputPlan
139
+ ? (0, utils_js_1.assertNotPromise)(inputFieldInputPlan(childFieldArgs, {
126
140
  schema,
127
141
  entity: inputField,
128
- })
142
+ }), inputFieldInputPlan, fnDescription)
129
143
  : childFieldArgs.get();
130
144
  }
131
145
  const nullableType = getNullableType(entityType);
@@ -136,6 +150,7 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
136
150
  }
137
151
  },
138
152
  apply(targetStepOrCallback, inPath) {
153
+ assertNotRuntime(operationPlan, `fieldArgs.apply()`);
139
154
  const path = Array.isArray(inPath) ? inPath : inPath ? [inPath] : [];
140
155
  const pathString = path.join(".");
141
156
  const $existing = applied.get(pathString);
@@ -197,21 +212,27 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
197
212
  if (rest.length === 0) {
198
213
  // Argument
199
214
  const arg = entity;
200
- result = arg.extensions.grafast?.applyPlan
201
- ? arg.extensions.grafast.applyPlan($parent, $target, childFieldArgs, {
215
+ const argApplyPlan = arg.extensions.grafast?.applyPlan;
216
+ const fnDescription = `???.${field.name}(${arg.name}:).applyPlan`;
217
+ (0, utils_js_1.assertNotAsync)(argApplyPlan, fnDescription);
218
+ result = argApplyPlan
219
+ ? (0, utils_js_1.assertNotPromise)(argApplyPlan($parent, $target, childFieldArgs, {
202
220
  schema,
203
221
  entity: arg,
204
- })
222
+ }), argApplyPlan, fnDescription)
205
223
  : undefined;
206
224
  }
207
225
  else if (entity) {
208
226
  // input field
209
227
  const inputField = entity;
210
- result = inputField.extensions.grafast?.applyPlan
211
- ? inputField.extensions.grafast.applyPlan($target, childFieldArgs, {
228
+ const inputFieldApplyPlan = inputField.extensions.grafast?.applyPlan;
229
+ const fnDescription = `???.${inputField.name}.applyPlan`;
230
+ (0, utils_js_1.assertNotAsync)(inputFieldApplyPlan, fnDescription);
231
+ result = inputFieldApplyPlan
232
+ ? (0, utils_js_1.assertNotPromise)(inputFieldApplyPlan($target, childFieldArgs, {
212
233
  schema,
213
234
  entity: inputField,
214
- })
235
+ }), inputFieldApplyPlan, fnDescription)
215
236
  : undefined;
216
237
  }
217
238
  else {
@@ -243,9 +264,11 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
243
264
  const nullableEntityType = getNullableType(entityType);
244
265
  const localFieldArgs = {
245
266
  getRaw(subpath) {
267
+ assertNotRuntime(operationPlan, `fieldArgs.getRaw()`);
246
268
  return fieldArgs.getRaw(concatPath(path, subpath));
247
269
  },
248
270
  get(subpath) {
271
+ assertNotRuntime(operationPlan, `fieldArgs.get()`);
249
272
  if (!subpath || (Array.isArray(subpath) && subpath.length === 0)) {
250
273
  if (isListType(nullableEntityType)) {
251
274
  if (!("evalLength" in $input)) {
@@ -265,10 +288,12 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
265
288
  else if (isInputObjectType(nullableEntityType)) {
266
289
  const typeResolver = nullableEntityType.extensions.grafast?.inputPlan ||
267
290
  defaultInputObjectTypeInputPlanResolver;
268
- const resolvedResult = typeResolver(getFieldArgsForPath(path, nullableEntityType, $input, "input"), {
291
+ const fnDescription = `${nullableEntityType}.inputPlan`;
292
+ (0, utils_js_1.assertNotAsync)(typeResolver, fnDescription);
293
+ const resolvedResult = (0, utils_js_1.assertNotPromise)(typeResolver(getFieldArgsForPath(path, nullableEntityType, $input, "input"), {
269
294
  schema,
270
295
  type: nullableEntityType,
271
- });
296
+ }), typeResolver, fnDescription);
272
297
  if (mode === "apply") {
273
298
  // NOTE: if mode === 'input' then `.get()` won't need a
274
299
  // `processAfter` since that will already have been handled in
@@ -279,11 +304,13 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
279
304
  }
280
305
  else if (isScalarType(nullableEntityType)) {
281
306
  const scalarResolver = nullableEntityType.extensions.grafast?.inputPlan;
307
+ const fnDescription = `${nullableEntityType}.inputPlan`;
308
+ (0, utils_js_1.assertNotAsync)(scalarResolver, fnDescription);
282
309
  if (scalarResolver !== undefined) {
283
- return scalarResolver($input, {
310
+ return (0, utils_js_1.assertNotPromise)(scalarResolver($input, {
284
311
  schema,
285
312
  type: nullableEntityType,
286
- });
313
+ }), scalarResolver, fnDescription);
287
314
  }
288
315
  else {
289
316
  return $input;
@@ -307,6 +334,7 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
307
334
  return fieldArgs.get(concatPath(path, subpath));
308
335
  },
309
336
  apply(targetStepOrCallback, subpath) {
337
+ assertNotRuntime(operationPlan, `fieldArgs.apply()`);
310
338
  if (mode === "apply" &&
311
339
  (!subpath || (Array.isArray(subpath) && subpath.length === 0))) {
312
340
  if (isInputObjectType(nullableEntityType)) {
@@ -349,12 +377,16 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
349
377
  const enumValue = nullableEntityType
350
378
  .getValues()
351
379
  .find((v) => v.value === value);
352
- const enumResolver = enumValue?.extensions.grafast?.applyPlan;
353
- if (enumResolver !== undefined) {
354
- const $target = typeof targetStepOrCallback === "function"
355
- ? targetStepOrCallback()
356
- : targetStepOrCallback;
357
- enumResolver($target);
380
+ if (enumValue) {
381
+ const enumResolver = enumValue.extensions.grafast?.applyPlan;
382
+ const fnDescription = `${nullableEntityType.name}.${enumValue.name}.applyPlan`;
383
+ (0, utils_js_1.assertNotAsync)(enumResolver, fnDescription);
384
+ if (enumResolver !== undefined) {
385
+ const $target = typeof targetStepOrCallback === "function"
386
+ ? targetStepOrCallback()
387
+ : targetStepOrCallback;
388
+ (0, utils_js_1.assertNotPromise)(enumResolver($target), enumResolver, fnDescription);
389
+ }
358
390
  }
359
391
  }
360
392
  else {
@@ -397,6 +429,7 @@ function withFieldArgsForArguments(operationPlan, $parent, $all, field, applyAft
397
429
  return localFieldArgs;
398
430
  }
399
431
  const result = callback(fieldArgs);
432
+ (0, utils_js_1.assertNotPromise)(result, callback, operationPlan.loc?.join(">") ?? "???");
400
433
  if (!explicitlyApplied) {
401
434
  processAfter(fieldArgs, [], result, args, applyAfterMode);
402
435
  }
package/dist/step.js CHANGED
@@ -225,6 +225,9 @@ class ExecutableStep extends BaseStep {
225
225
  const options = stepOrOptions instanceof ExecutableStep
226
226
  ? { step: stepOrOptions, skipDeduplication: false }
227
227
  : stepOrOptions;
228
+ if (options.step.layerPlan.id > this.layerPlan.id) {
229
+ throw new Error(`Cannot add dependency ${options.step} to ${this} since the former is in a deeper layerPlan (creates a catch-22)`);
230
+ }
228
231
  return this.operationPlan.stepTracker.addStepDependency(this, options);
229
232
  }
230
233
  /**
@@ -237,6 +240,9 @@ class ExecutableStep extends BaseStep {
237
240
  const options = stepOrOptions instanceof ExecutableStep
238
241
  ? { step: stepOrOptions }
239
242
  : stepOrOptions;
243
+ if (options.step.layerPlan.id > this.layerPlan.id) {
244
+ throw new Error(`Cannot add dependency ${options.step} to ${this} since the former is in a deeper layerPlan (creates a catch-22)`);
245
+ }
240
246
  return this.operationPlan.stepTracker.addStepUnaryDependency(this, options);
241
247
  }
242
248
  finalize() {
@@ -1,4 +1,5 @@
1
- import type { PromiseOrDirect, UnbatchedExecutionExtra, UnwrapPlanTuple } from "../interfaces.js";
1
+ import type { PromiseOrDirect, UnbatchedExecutionExtra } from "../interfaces.js";
2
+ import type { Multistep, UnwrapMultistep } from "../multistep.js";
2
3
  import type { ExecutableStep } from "../step.js";
3
4
  import { UnbatchedExecutableStep } from "../step.js";
4
5
  /**
@@ -23,7 +24,6 @@ export declare class LambdaStep<TIn, TOut> extends UnbatchedExecutableStep<TOut>
23
24
  * callback. Note: if you need to pass more than one value, pass a `ListStep`
24
25
  * as the `$plan` argument.
25
26
  */
26
- declare function lambda<const TIn extends readonly ExecutableStep[], TOut>(plans: TIn, fn: (value: UnwrapPlanTuple<TIn>) => PromiseOrDirect<TOut>, isSyncAndSafe?: boolean): LambdaStep<UnwrapPlanTuple<TIn>, TOut>;
27
- declare function lambda<const TIn, TOut>($plan: ExecutableStep<TIn> | null | undefined, fn: (value: TIn) => PromiseOrDirect<TOut>, isSyncAndSafe?: boolean): LambdaStep<TIn, TOut>;
27
+ declare function lambda<const TInMultistep extends Multistep, TOut>(spec: TInMultistep, fn: (value: UnwrapMultistep<TInMultistep>) => PromiseOrDirect<TOut>, isSyncAndSafe?: boolean): LambdaStep<UnwrapMultistep<TInMultistep>, TOut>;
28
28
  export { lambda };
29
29
  //# sourceMappingURL=lambda.d.ts.map
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.lambda = exports.LambdaStep = void 0;
4
+ const multistep_js_1 = require("../multistep.js");
4
5
  const step_js_1 = require("../step.js");
5
- const list_js_1 = require("./list.js");
6
6
  const sideEffect_js_1 = require("./sideEffect.js");
7
7
  /**
8
8
  * Calls the given lambda function for each tuple
@@ -40,16 +40,20 @@ class LambdaStep extends step_js_1.UnbatchedExecutableStep {
40
40
  }
41
41
  }
42
42
  exports.LambdaStep = LambdaStep;
43
- function lambda(planOrPlans, fn, isSyncAndSafe = false) {
43
+ /**
44
+ * A plan that takes the input `$plan` and feeds each value through the `fn`
45
+ * callback. Note: if you need to pass more than one value, pass a `ListStep`
46
+ * as the `$plan` argument.
47
+ */
48
+ function lambda(spec, fn, isSyncAndSafe = false) {
44
49
  if (fn.length > 1) {
45
50
  throw new Error("lambda callback should accept one argument, perhaps you forgot to destructure the arguments?");
46
51
  }
47
- const $lambda = Array.isArray(planOrPlans)
48
- ? new LambdaStep((0, list_js_1.list)(planOrPlans), fn)
49
- : new LambdaStep(planOrPlans, fn);
52
+ const $in = (0, multistep_js_1.multistep)(spec);
53
+ const $lambda = new LambdaStep($in, fn);
50
54
  if (fn.hasSideEffects) {
51
55
  console.trace(`You passed a function with \`hasSideEffects = true\` to \`lambda()\`, you should use \`sideEffect()\` instead (it has the same signature). We've automatically corrected this, but you should fix it in your code so the types are correct.`);
52
- return (0, sideEffect_js_1.sideEffect)(planOrPlans, fn);
56
+ return (0, sideEffect_js_1.sideEffect)(spec, fn);
53
57
  }
54
58
  if (isSyncAndSafe) {
55
59
  if (fn.constructor.name === "AsyncFunction") {
@@ -2,6 +2,10 @@ import type { ExecutionDetails, StepOptimizeOptions, UnbatchedExecutionExtra, Un
2
2
  import type { ExecutableStep } from "../step.js";
3
3
  import { UnbatchedExecutableStep } from "../step.js";
4
4
  import { ConstantStep } from "./constant.js";
5
+ interface ListStepCacheConfig {
6
+ identifier?: string;
7
+ cacheSize?: number;
8
+ }
5
9
  export declare class ListStep<const TPlanTuple extends readonly ExecutableStep[]> extends UnbatchedExecutableStep<UnwrapPlanTuple<TPlanTuple>> {
6
10
  static $$export: {
7
11
  moduleName: string;
@@ -10,12 +14,16 @@ export declare class ListStep<const TPlanTuple extends readonly ExecutableStep[]
10
14
  isSyncAndSafe: boolean;
11
15
  allowMultipleOptimizations: boolean;
12
16
  optimizeMetaKey: string;
13
- constructor(list: TPlanTuple);
17
+ private cacheSize;
18
+ private valueCount;
19
+ constructor(list: TPlanTuple, cacheConfig?: ListStepCacheConfig);
14
20
  toStringMeta(): string;
15
21
  execute({ indexMap, values }: ExecutionDetails): readonly UnwrapPlanTuple<TPlanTuple>[];
16
22
  unbatchedExecute(_extra: UnbatchedExecutionExtra, ...values: any[]): UnwrapPlanTuple<TPlanTuple>;
23
+ deduplicatedUnbatchedExecute({ meta: inMeta }: UnbatchedExecutionExtra, ...values: any[]): UnwrapPlanTuple<TPlanTuple>;
17
24
  deduplicate(peers: ListStep<TPlanTuple>[]): ListStep<TPlanTuple>[];
18
25
  optimize(opts: StepOptimizeOptions): this | ConstantStep<any[]>;
26
+ finalize(): void;
19
27
  /**
20
28
  * Get the original plan at the given index back again.
21
29
  */
@@ -27,5 +35,6 @@ export declare class ListStep<const TPlanTuple extends readonly ExecutableStep[]
27
35
  * Takes a list of plans and turns it into a single plan that represents the
28
36
  * list of their values.
29
37
  */
30
- export declare function list<const TPlanTuple extends readonly ExecutableStep[]>(list: TPlanTuple): ListStep<TPlanTuple>;
38
+ export declare function list<const TPlanTuple extends readonly ExecutableStep[]>(list: TPlanTuple, cacheConfig?: ListStepCacheConfig): ListStep<TPlanTuple>;
39
+ export {};
31
40
  //# sourceMappingURL=list.d.ts.map
@@ -3,16 +3,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.list = exports.ListStep = void 0;
4
4
  const step_js_1 = require("../step.js");
5
5
  const constant_js_1 = require("./constant.js");
6
+ const DEFAULT_CACHE_SIZE = 100;
6
7
  class ListStep extends step_js_1.UnbatchedExecutableStep {
7
8
  static { this.$$export = {
8
9
  moduleName: "grafast",
9
10
  exportName: "ListStep",
10
11
  }; }
11
- constructor(list) {
12
+ constructor(list, cacheConfig) {
12
13
  super();
13
14
  this.isSyncAndSafe = true;
14
15
  this.allowMultipleOptimizations = true;
15
16
  this.optimizeMetaKey = "ListStep";
17
+ this.valueCount = list.length;
18
+ this.cacheSize =
19
+ cacheConfig?.cacheSize ??
20
+ (cacheConfig?.identifier ? DEFAULT_CACHE_SIZE : 0);
21
+ this.metaKey =
22
+ this.cacheSize <= 0
23
+ ? undefined
24
+ : cacheConfig?.identifier
25
+ ? `list|${list.length}|${cacheConfig.identifier}`
26
+ : this.id;
16
27
  for (let i = 0, l = list.length; i < l; i++) {
17
28
  this.addDependency({ step: list[i], skipDeduplication: true });
18
29
  }
@@ -27,6 +38,30 @@ class ListStep extends step_js_1.UnbatchedExecutableStep {
27
38
  ) {
28
39
  return values;
29
40
  }
41
+ deduplicatedUnbatchedExecute({ meta: inMeta }, ...values //UnwrapPlanTuple<TPlanTuple>,
42
+ ) {
43
+ const meta = inMeta;
44
+ if (meta.nextIndex !== undefined) {
45
+ outer: for (let i = 0, l = meta.results.length; i < l; i++) {
46
+ const cachedValues = meta.results[i];
47
+ for (let j = 0, c = this.valueCount; j < c; j++) {
48
+ if (values[j] !== cachedValues[j]) {
49
+ continue outer;
50
+ }
51
+ }
52
+ return cachedValues;
53
+ }
54
+ }
55
+ else {
56
+ meta.nextIndex = 0;
57
+ meta.results = [];
58
+ }
59
+ meta.results[meta.nextIndex] = values;
60
+ // Only cache this.cacheSize results, use a round-robin
61
+ const maxIndex = this.cacheSize - 1;
62
+ meta.nextIndex = meta.nextIndex === maxIndex ? 0 : meta.nextIndex + 1;
63
+ return values;
64
+ }
30
65
  deduplicate(peers) {
31
66
  return peers;
32
67
  }
@@ -52,6 +87,12 @@ class ListStep extends step_js_1.UnbatchedExecutableStep {
52
87
  }
53
88
  return this;
54
89
  }
90
+ finalize() {
91
+ if (this.cacheSize > 0) {
92
+ this.unbatchedExecute = this.deduplicatedUnbatchedExecute;
93
+ }
94
+ super.finalize();
95
+ }
55
96
  /**
56
97
  * Get the original plan at the given index back again.
57
98
  */
@@ -70,8 +111,8 @@ exports.ListStep = ListStep;
70
111
  * Takes a list of plans and turns it into a single plan that represents the
71
112
  * list of their values.
72
113
  */
73
- function list(list) {
74
- return new ListStep(list);
114
+ function list(list, cacheConfig) {
115
+ return new ListStep(list, cacheConfig);
75
116
  }
76
117
  exports.list = list;
77
118
  //# sourceMappingURL=list.js.map
@@ -1,5 +1,6 @@
1
1
  import type { __ItemStep, ExecutionDetails } from "../index.js";
2
2
  import type { GrafastResultsList, Maybe, PromiseOrDirect } from "../interfaces.js";
3
+ import type { Multistep, UnwrapMultistep } from "../multistep.js";
3
4
  import { ExecutableStep } from "../step.js";
4
5
  export interface LoadOptions<TItem, TParams extends Record<string, any>, TUnarySpec = never> {
5
6
  unary: TUnarySpec;
@@ -25,7 +26,7 @@ export declare function loadManyCallback<TSpec, TItem, TParams extends Record<st
25
26
  /**
26
27
  * You shouldn't create instances of this yourself - use `loadOne` or `loadMany` instead.
27
28
  */
28
- export declare class LoadedRecordStep<TItem, TParams extends Record<string, any>> extends ExecutableStep<TItem> {
29
+ export declare class LoadedRecordStep<TItem, TParams extends Record<string, any> = Record<string, any>> extends ExecutableStep<TItem> {
29
30
  private isSingle;
30
31
  private sourceDescription;
31
32
  private ioEquivalence;
@@ -43,7 +44,7 @@ export declare class LoadedRecordStep<TItem, TParams extends Record<string, any>
43
44
  optimize(): ExecutableStep<any>;
44
45
  execute({ count, values: [values0], }: ExecutionDetails<[TItem]>): GrafastResultsList<TItem>;
45
46
  }
46
- export declare class LoadStep<TSpec, TItem, TData extends TItem | ReadonlyArray<TItem>, TParams extends Record<string, any>, TUnarySpec = never> extends ExecutableStep {
47
+ export declare class LoadStep<const TMultistep extends Multistep, TItem, TData extends TItem | ReadonlyArray<TItem>, TParams extends Record<string, any>, const TUnaryMultistep extends Multistep = never> extends ExecutableStep {
47
48
  private ioEquivalence;
48
49
  private load;
49
50
  static $$export: {
@@ -51,14 +52,12 @@ export declare class LoadStep<TSpec, TItem, TData extends TItem | ReadonlyArray<
51
52
  exportName: string;
52
53
  };
53
54
  isSyncAndSafe: boolean;
54
- loadOptions: Omit<LoadOptions<TItem, TParams, TUnarySpec>, "unary"> | null;
55
+ loadOptions: Omit<LoadOptions<TItem, TParams, UnwrapMultistep<TUnaryMultistep>>, "unary"> | null;
55
56
  loadOptionsKey: string;
56
57
  attributes: Set<keyof TItem>;
57
58
  params: Partial<TParams>;
58
59
  unaryDepId: number | null;
59
- constructor($spec: ExecutableStep<TSpec>, $unarySpec: ExecutableStep<TUnarySpec> | null, ioEquivalence: null | string | {
60
- [key in keyof TSpec]?: string | null;
61
- }, load: LoadCallback<TSpec, TItem, TData, TParams, TUnarySpec>);
60
+ constructor(spec: TMultistep, unarySpec: TUnaryMultistep | null, ioEquivalence: IOEquivalence<TMultistep>, load: LoadCallback<UnwrapMultistep<TMultistep>, TItem, TData, TParams, UnwrapMultistep<TUnaryMultistep>>);
62
61
  toStringMeta(): string;
63
62
  private makeAccessMap;
64
63
  listItem($item: __ItemStep<TItem>): LoadedRecordStep<TItem, TParams>;
@@ -66,27 +65,23 @@ export declare class LoadStep<TSpec, TItem, TData extends TItem | ReadonlyArray<
66
65
  setParam<TParamKey extends keyof TParams>(paramKey: TParamKey, value: TParams[TParamKey]): void;
67
66
  addAttributes(attributes: Set<keyof TItem>): void;
68
67
  finalize(): void;
69
- execute({ count, values: [values0, values1], extra, }: ExecutionDetails<[TSpec, TUnarySpec]>): PromiseOrDirect<GrafastResultsList<Maybe<TData>>>;
68
+ execute({ count, values: [values0, values1], extra, }: ExecutionDetails<[
69
+ UnwrapMultistep<TMultistep>,
70
+ UnwrapMultistep<TUnaryMultistep>
71
+ ]>): PromiseOrDirect<GrafastResultsList<Maybe<TData>>>;
70
72
  }
71
- export declare function loadMany<TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, TUnarySpec = never>($spec: ExecutableStep<TSpec>, loadCallback: LoadManyCallback<TSpec, TItem, TParams, TUnarySpec>): LoadStep<TSpec, TItem, ReadonlyArray<TItem>, TParams, TUnarySpec>;
72
- export declare function loadMany<TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, TUnarySpec = never>($spec: ExecutableStep<TSpec>, ioEquivalence: null | string | (TSpec extends [...any[]] ? {
73
- [key in keyof TSpec]: string | null;
74
- } : TSpec extends Record<string, any> ? {
75
- [key in keyof TSpec]?: string | null;
76
- } : never), loadCallback: LoadManyCallback<TSpec, TItem, TParams, TUnarySpec>): LoadStep<TSpec, TItem, ReadonlyArray<TItem>, TParams, TUnarySpec>;
77
- export declare function loadMany<TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, TUnarySpec = never>($spec: ExecutableStep<TSpec>, $unarySpec: ExecutableStep<TUnarySpec> | null, loadCallback: LoadManyCallback<TSpec, TItem, TParams, TUnarySpec>): LoadStep<TSpec, TItem, ReadonlyArray<TItem>, TParams, TUnarySpec>;
78
- export declare function loadMany<TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, TUnarySpec = never>($spec: ExecutableStep<TSpec>, $unarySpec: ExecutableStep<TUnarySpec> | null, ioEquivalence: null | string | (TSpec extends [...any[]] ? {
79
- [key in keyof TSpec]: string | null;
80
- } : TSpec extends Record<string, any> ? {
81
- [key in keyof TSpec]?: string | null;
82
- } : never), loadCallback: LoadManyCallback<TSpec, TItem, TParams, TUnarySpec>): LoadStep<TSpec, TItem, ReadonlyArray<TItem>, TParams, TUnarySpec>;
83
- export declare function loadOne<const TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, TUnarySpec = never>($spec: ExecutableStep<TSpec>, loadCallback: LoadOneCallback<TSpec, TItem, TParams, TUnarySpec>): LoadedRecordStep<TItem, TParams>;
84
- export declare function loadOne<const TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, TUnarySpec = never>($spec: ExecutableStep<TSpec>, ioEquivalence: null | string | {
85
- [key in keyof TSpec]?: string | null;
86
- }, loadCallback: LoadOneCallback<TSpec, TItem, TParams, TUnarySpec>): LoadedRecordStep<TItem, TParams>;
87
- export declare function loadOne<const TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnarySpec = never>($spec: ExecutableStep<TSpec>, $unarySpec: ExecutableStep<TUnarySpec> | null, loadCallback: LoadOneCallback<TSpec, TItem, TParams, TUnarySpec>): LoadedRecordStep<TItem, TParams>;
88
- export declare function loadOne<const TSpec, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnarySpec = never>($spec: ExecutableStep<TSpec>, $unarySpec: ExecutableStep<TUnarySpec> | null, ioEquivalence: null | string | {
89
- [key in keyof TSpec]?: string | null;
90
- }, loadCallback: LoadOneCallback<TSpec, TItem, TParams, TUnarySpec>): LoadedRecordStep<TItem, TParams>;
73
+ export declare function loadMany<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, loadCallback: LoadManyCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadStep<UnwrapMultistep<TMultistep>, TItem, ReadonlyArray<TItem>, TParams, UnwrapMultistep<TUnaryMultistep>>;
74
+ export declare function loadMany<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, ioEquivalence: IOEquivalence<TMultistep>, loadCallback: LoadManyCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadStep<UnwrapMultistep<TMultistep>, TItem, ReadonlyArray<TItem>, TParams, UnwrapMultistep<TUnaryMultistep>>;
75
+ export declare function loadMany<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, unarySpec: TUnaryMultistep | null, loadCallback: LoadManyCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadStep<UnwrapMultistep<TMultistep>, TItem, ReadonlyArray<TItem>, TParams, UnwrapMultistep<TUnaryMultistep>>;
76
+ export declare function loadMany<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, unarySpec: TUnaryMultistep | null, ioEquivalence: IOEquivalence<TMultistep>, loadCallback: LoadManyCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadStep<UnwrapMultistep<TMultistep>, TItem, ReadonlyArray<TItem>, TParams, UnwrapMultistep<TUnaryMultistep>>;
77
+ type IOEquivalence<TMultistep extends Multistep> = null | string | (UnwrapMultistep<TMultistep> extends readonly [...(readonly any[])] ? {
78
+ [key in Exclude<keyof UnwrapMultistep<TMultistep>, keyof any[]>]: string | null;
79
+ } : UnwrapMultistep<TMultistep> extends Record<string, any> ? {
80
+ [key in keyof UnwrapMultistep<TMultistep>]?: string | null;
81
+ } : never);
82
+ export declare function loadOne<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, loadCallback: LoadOneCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadedRecordStep<TItem, TParams>;
83
+ export declare function loadOne<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, ioEquivalence: IOEquivalence<TMultistep>, loadCallback: LoadOneCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadedRecordStep<TItem, TParams>;
84
+ export declare function loadOne<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, unarySpec: TUnaryMultistep | null, loadCallback: LoadOneCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadedRecordStep<TItem, TParams>;
85
+ export declare function loadOne<const TMultistep extends Multistep, TItem, TParams extends Record<string, any> = Record<string, any>, const TUnaryMultistep extends Multistep = never>(spec: TMultistep, unarySpec: TUnaryMultistep | null, ioEquivalence: IOEquivalence<TMultistep>, loadCallback: LoadOneCallback<UnwrapMultistep<TMultistep>, TItem, TParams, UnwrapMultistep<TUnaryMultistep>>): LoadedRecordStep<TItem, TParams>;
91
86
  export {};
92
87
  //# sourceMappingURL=load.d.ts.map
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.loadOne = exports.loadMany = exports.LoadStep = exports.LoadedRecordStep = exports.loadManyCallback = exports.loadOneCallback = void 0;
4
4
  const index_js_1 = require("../index.js");
5
+ const multistep_js_1 = require("../multistep.js");
5
6
  const step_js_1 = require("../step.js");
6
7
  const utils_js_1 = require("../utils.js");
7
8
  const access_js_1 = require("./access.js");
@@ -89,7 +90,7 @@ exports.LoadedRecordStep = LoadedRecordStep;
89
90
  class LoadStep extends step_js_1.ExecutableStep {
90
91
  /* implements ListCapableStep<TItem, LoadedRecordStep<TItem, TParams>> */
91
92
  static { this.$$export = { moduleName: "grafast", exportName: "LoadStep" }; }
92
- constructor($spec, $unarySpec, ioEquivalence, load) {
93
+ constructor(spec, unarySpec, ioEquivalence, load) {
93
94
  super();
94
95
  this.ioEquivalence = ioEquivalence;
95
96
  this.load = load;
@@ -99,7 +100,9 @@ class LoadStep extends step_js_1.ExecutableStep {
99
100
  this.attributes = new Set();
100
101
  this.params = Object.create(null);
101
102
  this.unaryDepId = null;
103
+ const $spec = (0, multistep_js_1.multistep)(spec, "load");
102
104
  this.addDependency($spec);
105
+ const $unarySpec = unarySpec == null ? null : (0, multistep_js_1.multistep)(unarySpec, "loadUnary");
103
106
  if ($unarySpec) {
104
107
  this.unaryDepId = this.addUnaryDependency($unarySpec);
105
108
  }
@@ -117,7 +120,7 @@ class LoadStep extends step_js_1.ExecutableStep {
117
120
  map[this.ioEquivalence] = $spec;
118
121
  return map;
119
122
  }
120
- else if (Array.isArray(this.ioEquivalence)) {
123
+ else if ((0, utils_js_1.isTuple)(this.ioEquivalence)) {
121
124
  for (let i = 0, l = this.ioEquivalence.length; i < l; i++) {
122
125
  const key = this.ioEquivalence[i];
123
126
  map[key] = (0, step_js_1.isListLikeStep)($spec) ? $spec.at(i) : (0, access_js_1.access)($spec, [i]);
@@ -296,41 +299,41 @@ async function executeBatches(loadBatches, load, loadOptions) {
296
299
  }
297
300
  }
298
301
  }
299
- function load($spec, $unarySpec, ioEquivalence, loadCallback) {
300
- return new LoadStep($spec, $unarySpec, ioEquivalence, loadCallback);
302
+ function load(spec, unarySpec, ioEquivalence, loadCallback) {
303
+ return new LoadStep(spec, unarySpec, ioEquivalence, loadCallback);
301
304
  }
302
- function loadMany($spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly) {
305
+ function loadMany(spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly) {
303
306
  if (loadCallbackOnly) {
304
- return load($spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly);
307
+ return load(spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly);
305
308
  }
306
309
  // At most 3 arguments
307
- else if ((0, index_js_1.isExecutableStep)(loadCallbackOrIoEquivalenceOrUnarySpec)) {
308
- return load($spec, loadCallbackOrIoEquivalenceOrUnarySpec, null, loadCallbackOrIoEquivalence);
310
+ else if ((0, multistep_js_1.isMultistep)(loadCallbackOrIoEquivalenceOrUnarySpec)) {
311
+ return load(spec, loadCallbackOrIoEquivalenceOrUnarySpec, null, loadCallbackOrIoEquivalence);
309
312
  }
310
313
  // Unary step is definitely null; 3 arguments
311
314
  else if (loadCallbackOrIoEquivalence) {
312
- return load($spec, null, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence);
315
+ return load(spec, null, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence);
313
316
  }
314
317
  // 2 arguments
315
318
  else {
316
- return load($spec, null, null, loadCallbackOrIoEquivalenceOrUnarySpec);
319
+ return load(spec, null, null, loadCallbackOrIoEquivalenceOrUnarySpec);
317
320
  }
318
321
  }
319
322
  exports.loadMany = loadMany;
320
- function loadOne($spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly) {
323
+ function loadOne(spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly) {
321
324
  if (loadCallbackOnly) {
322
- return load($spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly).single();
325
+ return load(spec, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence, loadCallbackOnly).single();
323
326
  }
324
327
  // At most 3 arguments
325
- else if ((0, index_js_1.isExecutableStep)(loadCallbackOrIoEquivalenceOrUnarySpec)) {
326
- return load($spec, loadCallbackOrIoEquivalenceOrUnarySpec, null, loadCallbackOrIoEquivalence).single();
328
+ else if ((0, multistep_js_1.isMultistep)(loadCallbackOrIoEquivalenceOrUnarySpec)) {
329
+ return load(spec, loadCallbackOrIoEquivalenceOrUnarySpec, null, loadCallbackOrIoEquivalence).single();
327
330
  }
328
331
  // Unary step is definitely null; 3 arguments
329
332
  else if (loadCallbackOrIoEquivalence) {
330
- return load($spec, null, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence).single();
333
+ return load(spec, null, loadCallbackOrIoEquivalenceOrUnarySpec, loadCallbackOrIoEquivalence).single();
331
334
  }
332
335
  else {
333
- return load($spec, null, null, loadCallbackOrIoEquivalenceOrUnarySpec).single();
336
+ return load(spec, null, null, loadCallbackOrIoEquivalenceOrUnarySpec).single();
334
337
  }
335
338
  }
336
339
  exports.loadOne = loadOne;
@@ -19,6 +19,10 @@ export interface ObjectPlanMeta<TSteps extends {
19
19
  }> {
20
20
  results: Results<TSteps>;
21
21
  }
22
+ interface ObjectStepCacheConfig {
23
+ identifier?: string;
24
+ cacheSize?: number;
25
+ }
22
26
  /**
23
27
  * A plan that represents an object using the keys given and the values being
24
28
  * the results of the associated plans.
@@ -36,7 +40,8 @@ export declare class ObjectStep<TPlans extends {
36
40
  allowMultipleOptimizations: boolean;
37
41
  private keys;
38
42
  optimizeMetaKey: string;
39
- constructor(obj: TPlans);
43
+ private cacheSize;
44
+ constructor(obj: TPlans, cacheConfig?: ObjectStepCacheConfig);
40
45
  /**
41
46
  * This key doesn't get typed, but it can be added later which can be quite
42
47
  * handy.
@@ -61,6 +66,6 @@ export declare class ObjectStep<TPlans extends {
61
66
  */
62
67
  export declare function object<TPlans extends {
63
68
  [key: string]: ExecutableStep;
64
- }>(obj: TPlans): ObjectStep<TPlans>;
69
+ }>(obj: TPlans, cacheConfig?: ObjectStepCacheConfig): ObjectStep<TPlans>;
65
70
  export {};
66
71
  //# sourceMappingURL=object.d.ts.map
@@ -6,6 +6,7 @@ const tslib_1 = require("tslib");
6
6
  const tamedevil_1 = tslib_1.__importStar(require("tamedevil"));
7
7
  const step_js_1 = require("../step.js");
8
8
  const constant_js_1 = require("./constant.js");
9
+ const DEFAULT_CACHE_SIZE = 100;
9
10
  const EMPTY_OBJECT = Object.freeze(Object.create(null));
10
11
  /**
11
12
  * A plan that represents an object using the keys given and the values being
@@ -16,13 +17,21 @@ class ObjectStep extends step_js_1.UnbatchedExecutableStep {
16
17
  moduleName: "grafast",
17
18
  exportName: "ObjectStep",
18
19
  }; }
19
- constructor(obj) {
20
+ constructor(obj, cacheConfig) {
20
21
  super();
21
22
  this.isSyncAndSafe = true;
22
23
  this.allowMultipleOptimizations = true;
23
24
  // Optimize needs the same 'meta' for all ObjectSteps
24
25
  this.optimizeMetaKey = "ObjectStep";
25
- this.metaKey = this.id;
26
+ this.cacheSize =
27
+ cacheConfig?.cacheSize ??
28
+ (cacheConfig?.identifier ? DEFAULT_CACHE_SIZE : 0);
29
+ this.metaKey =
30
+ this.cacheSize <= 0
31
+ ? undefined
32
+ : cacheConfig?.identifier
33
+ ? `object|${JSON.stringify(Object.keys(obj))}|${cacheConfig.identifier}`
34
+ : this.id;
26
35
  this.keys = Object.keys(obj);
27
36
  for (let i = 0, l = this.keys.length; i < l; i++) {
28
37
  this.addDependency({ step: obj[this.keys[i]], skipDeduplication: true });
@@ -102,9 +111,11 @@ ${tamedevil_1.default.join(this.keys.map((key, i) => (0, tamedevil_1.default) `
102
111
  const newObj = Object.create(null);
103
112
  ${tamedevil_1.default.join(this.keys.map((key, i) => (0, tamedevil_1.default) ` newObj${tamedevil_1.default.set(key, true)} = ${tamedevil_1.default.identifier(`val${i}`)};\n`), "")}\
104
113
  `;
105
- return tamedevil_1.default.runInBatch((0, tamedevil_1.default) `\
106
- (function ({ meta }, ${tamedevil_1.default.join(this.keys.map((_k, i) => tamedevil_1.default.identifier(`val${i}`)), ", ")}) {
107
- if (meta.nextIndex) {
114
+ const vals = tamedevil_1.default.join(this.keys.map((_k, i) => tamedevil_1.default.identifier(`val${i}`)), ", ");
115
+ if (this.cacheSize > 0) {
116
+ return tamedevil_1.default.runInBatch((0, tamedevil_1.default) `\
117
+ (function ({ meta }, ${vals}) {
118
+ if (meta.nextIndex != null) {
108
119
  for (let i = 0, l = meta.results.length; i < l; i++) {
109
120
  const [values, obj] = meta.results[i];
110
121
  if (${tamedevil_1.default.join(this.keys.map((_key, i) => (0, tamedevil_1.default) `values[${tamedevil_1.default.lit(i)}] === ${tamedevil_1.default.identifier(`val${i}`)}`), " && ")}) {
@@ -113,16 +124,22 @@ ${tamedevil_1.default.join(this.keys.map((key, i) => (0, tamedevil_1.default) `
113
124
  }
114
125
  } else {
115
126
  meta.nextIndex = 0;
116
- if (!meta.results) {
117
- meta.results = [];
118
- }
127
+ meta.results = [];
119
128
  }
120
129
  ${inner}
121
130
  meta.results[meta.nextIndex] = [[${tamedevil_1.default.join(this.keys.map((_key, i) => tamedevil_1.default.identifier(`val${i}`)), ",")}], newObj];
122
- // Only cache 10 results, use a round-robin
123
- meta.nextIndex = meta.nextIndex === 9 ? 0 : meta.nextIndex + 1;
131
+ // Only cache ${tamedevil_1.default.lit(this.cacheSize)} results, use a round-robin
132
+ meta.nextIndex = meta.nextIndex === ${tamedevil_1.default.lit(this.cacheSize - 1)} ? 0 : meta.nextIndex + 1;
133
+ return newObj;
134
+ })`, callback);
135
+ }
136
+ else {
137
+ return tamedevil_1.default.runInBatch((0, tamedevil_1.default) `\
138
+ (function (_, ${vals}) {
139
+ ${inner}
124
140
  return newObj;
125
141
  })`, callback);
142
+ }
126
143
  }
127
144
  finalize() {
128
145
  this.tupleToObjectJIT((fn) => {
@@ -184,8 +201,8 @@ exports.ObjectStep = ObjectStep;
184
201
  * A plan that represents an object using the keys given and the values being
185
202
  * the results of the associated plans.
186
203
  */
187
- function object(obj) {
188
- return new ObjectStep(obj);
204
+ function object(obj, cacheConfig) {
205
+ return new ObjectStep(obj, cacheConfig);
189
206
  }
190
207
  exports.object = object;
191
208
  //# sourceMappingURL=object.js.map
@@ -1,4 +1,5 @@
1
- import type { PromiseOrDirect, UnbatchedExecutionExtra, UnwrapPlanTuple } from "../interfaces.js";
1
+ import type { PromiseOrDirect, UnbatchedExecutionExtra } from "../interfaces.js";
2
+ import type { Multistep, UnwrapMultistep } from "../multistep.js";
2
3
  import type { ExecutableStep } from "../step.js";
3
4
  import { UnbatchedExecutableStep } from "../step.js";
4
5
  /**
@@ -22,7 +23,6 @@ export declare class SideEffectStep<TIn, TOut> extends UnbatchedExecutableStep<T
22
23
  * callback. Note: if you need to pass more than one value, pass a `ListStep`
23
24
  * as the `$plan` argument.
24
25
  */
25
- declare function sideEffect<const TIn extends readonly ExecutableStep[], TOut>(plans: TIn, fn: (value: UnwrapPlanTuple<TIn>) => PromiseOrDirect<TOut>): SideEffectStep<UnwrapPlanTuple<TIn>, TOut>;
26
- declare function sideEffect<const TIn, TOut>($plan: ExecutableStep<TIn> | null | undefined, fn: (value: TIn) => PromiseOrDirect<TOut>): SideEffectStep<TIn, TOut>;
26
+ declare function sideEffect<const TInMultistep extends Multistep, TOut>(spec: TInMultistep, fn: (value: UnwrapMultistep<TInMultistep>) => PromiseOrDirect<TOut>): SideEffectStep<UnwrapMultistep<TInMultistep>, TOut>;
27
27
  export { sideEffect };
28
28
  //# sourceMappingURL=sideEffect.d.ts.map
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.sideEffect = exports.SideEffectStep = void 0;
4
+ const multistep_js_1 = require("../multistep.js");
4
5
  const step_js_1 = require("../step.js");
5
- const list_js_1 = require("./list.js");
6
6
  /**
7
7
  * Calls the given callback function for each tuple
8
8
  */
@@ -27,13 +27,17 @@ class SideEffectStep extends step_js_1.UnbatchedExecutableStep {
27
27
  }
28
28
  }
29
29
  exports.SideEffectStep = SideEffectStep;
30
- function sideEffect(planOrPlans, fn) {
30
+ /**
31
+ * A plan that takes the input `$plan` and feeds each value through the `fn`
32
+ * callback. Note: if you need to pass more than one value, pass a `ListStep`
33
+ * as the `$plan` argument.
34
+ */
35
+ function sideEffect(spec, fn) {
31
36
  if (fn.length > 1) {
32
37
  throw new Error("sideEffect callback should accept one argument, perhaps you forgot to destructure the arguments?");
33
38
  }
34
- const $result = Array.isArray(planOrPlans)
35
- ? new SideEffectStep((0, list_js_1.list)(planOrPlans), fn)
36
- : new SideEffectStep(planOrPlans, fn);
39
+ const $in = (0, multistep_js_1.multistep)(spec);
40
+ const $result = new SideEffectStep($in, fn);
37
41
  return $result;
38
42
  }
39
43
  exports.sideEffect = sideEffect;
package/dist/utils.d.ts CHANGED
@@ -143,11 +143,13 @@ export declare function stepAMayDependOnStepB($a: ExecutableStep, $b: Executable
143
143
  export declare function stepsAreInSamePhase(ancestor: ExecutableStep, descendent: ExecutableStep): boolean;
144
144
  export declare const canonicalJSONStringify: (o: object) => string;
145
145
  export declare function assertNotAsync(fn: any, name: string): void;
146
+ export declare function assertNotPromise<TVal>(value: TVal, fn: any, name: string): TVal;
146
147
  export declare function hasItemPlan(step: ExecutableStep & {
147
148
  itemPlan?: ($item: ExecutableStep) => ExecutableStep;
148
149
  }): step is ExecutableStep & {
149
150
  itemPlan: ($item: ExecutableStep) => ExecutableStep;
150
151
  };
151
152
  export declare function exportNameHint(obj: any, nameHint: string): void;
153
+ export declare function isTuple<T extends readonly [...(readonly any[])]>(t: any | T): t is T;
152
154
  export {};
153
155
  //# sourceMappingURL=utils.d.ts.map
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.exportNameHint = exports.hasItemPlan = exports.assertNotAsync = exports.canonicalJSONStringify = exports.stepsAreInSamePhase = exports.stepAMayDependOnStepB = exports.stepADependsOnStepB = exports.writeableArray = exports.sudo = exports.isTypePlanned = exports.findVariableNamesUsed = exports.arrayOfLengthCb = exports.arrayOfLength = exports.stack = exports.sharedNull = exports.getEnumValueConfig = exports.inputObjectFieldSpec = exports.newInputObjectTypeBuilder = exports.newGrafastFieldConfigBuilder = exports.objectFieldSpec = exports.newObjectTypeBuilder = exports.objectSpec = exports.arraysMatch = exports.isDeferred = exports.isPromiseLike = exports.isPromise = exports.defaultValueToValueNode = exports.assertNullPrototype = exports.ROOT_VALUE_OBJECT = void 0;
3
+ exports.isTuple = exports.exportNameHint = exports.hasItemPlan = exports.assertNotPromise = exports.assertNotAsync = exports.canonicalJSONStringify = exports.stepsAreInSamePhase = exports.stepAMayDependOnStepB = exports.stepADependsOnStepB = exports.writeableArray = exports.sudo = exports.isTypePlanned = exports.findVariableNamesUsed = exports.arrayOfLengthCb = exports.arrayOfLength = exports.stack = exports.sharedNull = exports.getEnumValueConfig = exports.inputObjectFieldSpec = exports.newInputObjectTypeBuilder = exports.newGrafastFieldConfigBuilder = exports.objectFieldSpec = exports.newObjectTypeBuilder = exports.objectSpec = exports.arraysMatch = exports.isDeferred = exports.isPromiseLike = exports.isPromise = exports.defaultValueToValueNode = exports.assertNullPrototype = exports.ROOT_VALUE_OBJECT = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const graphql = tslib_1.__importStar(require("graphql"));
6
6
  const assert = tslib_1.__importStar(require("./assert.js"));
@@ -719,12 +719,21 @@ exports.stepsAreInSamePhase = stepsAreInSamePhase;
719
719
  // ENHANCE: implement this!
720
720
  const canonicalJSONStringify = (o) => JSON.stringify(o);
721
721
  exports.canonicalJSONStringify = canonicalJSONStringify;
722
+ // PERF: only do this if isDev; otherwise replace with NOOP?
722
723
  function assertNotAsync(fn, name) {
723
724
  if (fn?.constructor?.name === "AsyncFunction") {
724
725
  throw new Error(`Plans must be synchronous, but this schema has an async function at '${name}': ${fn.toString()}`);
725
726
  }
726
727
  }
727
728
  exports.assertNotAsync = assertNotAsync;
729
+ // PERF: only do this if isDev; otherwise replace with NOOP?
730
+ function assertNotPromise(value, fn, name) {
731
+ if (isPromiseLike(value)) {
732
+ throw new Error(`Plans must be synchronous, but this schema has an function at '${name}' that returned a promise-like object: ${fn.toString()}`);
733
+ }
734
+ return value;
735
+ }
736
+ exports.assertNotPromise = assertNotPromise;
728
737
  function hasItemPlan(step) {
729
738
  return "itemPlan" in step && typeof step.itemPlan === "function";
730
739
  }
@@ -743,4 +752,8 @@ function exportNameHint(obj, nameHint) {
743
752
  }
744
753
  }
745
754
  exports.exportNameHint = exportNameHint;
755
+ function isTuple(t) {
756
+ return Array.isArray(t);
757
+ }
758
+ exports.isTuple = isTuple;
746
759
  //# sourceMappingURL=utils.js.map
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "0.1.1-beta.13";
1
+ export declare const version = "0.1.1-beta.15";
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.13";
5
+ exports.version = "0.1.1-beta.15";
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.13",
3
+ "version": "0.1.1-beta.15",
4
4
  "description": "Cutting edge GraphQL planning and execution engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -59,6 +59,7 @@
59
59
  "chalk": "^4.1.2",
60
60
  "debug": "^4.3.4",
61
61
  "eventemitter3": "^5.0.1",
62
+ "graphile-config": "^0.0.1-beta.10",
62
63
  "graphql": "^16.1.0-experimental-stream-defer.6",
63
64
  "iterall": "^1.3.0",
64
65
  "tamedevil": "^0.0.0-beta.7",
@@ -66,16 +67,12 @@
66
67
  },
67
68
  "peerDependencies": {
68
69
  "@envelop/core": "^5.0.0",
69
- "graphile-config": "^0.0.1-beta.9",
70
70
  "graphql": "^16.1.0-experimental-stream-defer.6",
71
71
  "tamedevil": "^0.0.0-beta.7"
72
72
  },
73
73
  "peerDependenciesMeta": {
74
74
  "@envelop/core": {
75
75
  "optional": true
76
- },
77
- "graphile-config": {
78
- "optional": true
79
76
  }
80
77
  },
81
78
  "files": [