-
-
Notifications
You must be signed in to change notification settings - Fork 796
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(batchDelegate): simplify batch delegation (#1855)
= allow createBatchDelegateFn to take an options object that can prespecify any option if desired = introduces batchDelegateToSchema in which all arguments including key and result mapping are deferred to runtime = updates schema stitching type merging to allow configuration of result mapping
- Loading branch information
Showing
7 changed files
with
137 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { BatchDelegateOptions, DataLoaderCache } from './types'; | ||
|
||
import { getLoader } from './getLoader'; | ||
|
||
export function batchDelegateToSchema<K = any, V = any, C = K>(options: BatchDelegateOptions): any { | ||
let cache: DataLoaderCache<K, V, C>; | ||
|
||
const loader = getLoader(cache, options); | ||
return loader.load(options.key); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,40 @@ | ||
import { FieldNode, getNamedType, GraphQLOutputType, GraphQLList } from 'graphql'; | ||
|
||
import DataLoader from 'dataloader'; | ||
|
||
import { delegateToSchema } from '@graphql-tools/delegate'; | ||
import { | ||
CreateBatchDelegateFnOptions, | ||
BatchDelegateOptionsFn, | ||
BatchDelegateFn, | ||
BatchDelegateArgsFn, | ||
BatchDelegateResultsFn, | ||
DataLoaderCache, | ||
} from './types'; | ||
|
||
import { BatchDelegateOptionsFn, BatchDelegateFn, BatchDelegateOptions } from './types'; | ||
import { getLoader } from './getLoader'; | ||
|
||
export function createBatchDelegateFn<K = any, V = any, C = K>( | ||
argFn: (args: ReadonlyArray<K>) => Record<string, any>, | ||
batchDelegateOptionsFn: BatchDelegateOptionsFn, | ||
optionsOrArgsFn: CreateBatchDelegateFnOptions | BatchDelegateArgsFn, | ||
optionsFn?: BatchDelegateOptionsFn, | ||
dataLoaderOptions?: DataLoader.Options<K, V, C>, | ||
resultsFn?: (results: any, keys: ReadonlyArray<K>) => V[] | ||
resultsFn?: BatchDelegateResultsFn | ||
): BatchDelegateFn<K> { | ||
let cache: WeakMap<ReadonlyArray<FieldNode>, DataLoader<K, V, C>>; | ||
|
||
function createBatchFn(options: BatchDelegateOptions) { | ||
return async (keys: ReadonlyArray<K>) => { | ||
let results = await delegateToSchema({ | ||
returnType: new GraphQLList(getNamedType(options.info.returnType) as GraphQLOutputType), | ||
args: argFn(keys), | ||
...batchDelegateOptionsFn(options), | ||
}); | ||
results = resultsFn ? resultsFn(results, keys) : results; | ||
return Array.isArray(results) ? results : keys.map(() => results); | ||
}; | ||
} | ||
|
||
function getLoader(options: BatchDelegateOptions) { | ||
if (!cache) { | ||
cache = new WeakMap(); | ||
const batchFn = createBatchFn(options); | ||
const newValue = new DataLoader<K, V, C>(keys => batchFn(keys), dataLoaderOptions); | ||
cache.set(options.info.fieldNodes, newValue); | ||
return newValue; | ||
} | ||
|
||
const cachedValue = cache.get(options.info.fieldNodes); | ||
if (cachedValue === undefined) { | ||
const batchFn = createBatchFn(options); | ||
const newValue = new DataLoader<K, V, C>(keys => batchFn(keys), dataLoaderOptions); | ||
cache.set(options.info.fieldNodes, newValue); | ||
return newValue; | ||
} | ||
return typeof optionsOrArgsFn === 'function' | ||
? createBatchDelegateFnImpl({ | ||
argsFn: optionsOrArgsFn, | ||
optionsFn, | ||
dataLoaderOptions, | ||
resultsFn, | ||
}) | ||
: createBatchDelegateFnImpl(optionsOrArgsFn); | ||
} | ||
|
||
return cachedValue; | ||
} | ||
function createBatchDelegateFnImpl<K = any, V = any, C = K>(options: CreateBatchDelegateFnOptions): BatchDelegateFn<K> { | ||
let cache: DataLoaderCache<K, V, C>; | ||
|
||
return options => { | ||
const loader = getLoader(options); | ||
return loader.load(options.key); | ||
return batchDelegateOptions => { | ||
const loader = getLoader(cache, { | ||
...options, | ||
...batchDelegateOptions, | ||
}); | ||
return loader.load(batchDelegateOptions.key); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { getNamedType, GraphQLOutputType, GraphQLList } from 'graphql'; | ||
|
||
import DataLoader from 'dataloader'; | ||
|
||
import { delegateToSchema } from '@graphql-tools/delegate'; | ||
|
||
import { BatchDelegateOptions, DataLoaderCache } from './types'; | ||
|
||
function createBatchFn<K = any>(options: BatchDelegateOptions) { | ||
const argsFn = options.argsFn ?? ((keys: ReadonlyArray<K>) => ({ ids: keys })); | ||
const { resultsFn, optionsFn } = options; | ||
|
||
return async (keys: ReadonlyArray<K>) => { | ||
let results = await delegateToSchema({ | ||
returnType: new GraphQLList(getNamedType(options.info.returnType) as GraphQLOutputType), | ||
args: argsFn(keys), | ||
...(optionsFn != null ? optionsFn(options) : options), | ||
}); | ||
|
||
if (resultsFn != null) { | ||
results = resultsFn(results, keys); | ||
} | ||
|
||
return Array.isArray(results) ? results : keys.map(() => results); | ||
}; | ||
} | ||
|
||
function createLoader<K = any, V = any, C = K>( | ||
cache: DataLoaderCache, | ||
options: BatchDelegateOptions | ||
): DataLoader<K, V, C> { | ||
const batchFn = createBatchFn(options); | ||
const newValue = new DataLoader<K, V, C>(keys => batchFn(keys), options.dataLoaderOptions); | ||
cache.set(options.info.fieldNodes, newValue); | ||
return newValue; | ||
} | ||
|
||
export function getLoader<K = any, V = any, C = K>( | ||
cache: DataLoaderCache, | ||
options: BatchDelegateOptions | ||
): DataLoader<K, V, C> { | ||
if (!cache) { | ||
cache = new WeakMap(); | ||
return createLoader(cache, options); | ||
} | ||
|
||
const cachedValue = cache.get(options.info.fieldNodes); | ||
if (cachedValue === undefined) { | ||
return createLoader(cache, options); | ||
} | ||
|
||
return cachedValue; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { createBatchDelegateFn } from './createBatchDelegateFn'; | ||
export * from './batchDelegateToSchema'; | ||
export * from './createBatchDelegateFn'; | ||
|
||
export * from './types'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters