Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TS] Support ArrayLike in batch function and loadMany #214

Merged
merged 4 commits into from Nov 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/index.d.ts
Expand Up @@ -37,7 +37,7 @@ declare class DataLoader<K, V, C = K> {
* ]);
*
*/
loadMany(keys: K[]): Promise<V[]>;
loadMany(keys: ArrayLike<K>): Promise<V[]>;

/**
* Clears the value at `key` from the cache, if it exists. Returns itself for
Expand Down Expand Up @@ -70,7 +70,8 @@ declare namespace DataLoader {

// A Function, which when given an Array of keys, returns a Promise of an Array
// of values or Errors.
export type BatchLoadFn<K, V> = (keys: K[]) => PromiseLike<Array<V | Error>>;
export type BatchLoadFn<K, V> =
(keys: ArrayLike<K>) => PromiseLike<ArrayLike<V | Error>>;

// Optionally turn off batching or caching or provide a cache key function or a
// custom cache instance.
Expand Down
24 changes: 20 additions & 4 deletions src/index.js
Expand Up @@ -129,13 +129,18 @@ class DataLoader<K, V, C = K> {
*
*/
loadMany(keys: $ReadOnlyArray<K>): Promise<Array<V>> {
if (!Array.isArray(keys)) {
if (!isArrayLike(keys)) {
throw new TypeError(
'The loader.loadMany() function must be called with Array<key> ' +
`but got: ${keys}.`
`but got: ${(keys: any)}.`
);
}
return Promise.all(keys.map(key => this.load(key)));
// Support ArrayLike by using only minimal property access
const loadPromises = [];
for (let i = 0; i < keys.length; i++) {
loadPromises.push(this.load(keys[i]));
}
return Promise.all(loadPromises);
}

/**
Expand Down Expand Up @@ -266,7 +271,7 @@ function dispatchQueueBatch<K, V>(
batchPromise.then(values => {

// Assert the expected resolution from batchLoadFn.
if (!Array.isArray(values)) {
if (!isArrayLike(values)) {
throw new TypeError(
'DataLoader must be constructed with a function which accepts ' +
'Array<key> and returns Promise<Array<value>>, but the function did ' +
Expand Down Expand Up @@ -345,4 +350,15 @@ type LoaderQueue<K, V> = Array<{
reject: (error: Error) => void;
}>;

// Private
function isArrayLike(x: mixed): boolean {
return (
typeof x === 'object' &&
x !== null &&
typeof x.length === 'number' &&
(x.length === 0 ||
(x.length > 0 && Object.prototype.hasOwnProperty.call(x, x.length - 1)))
);
}

module.exports = DataLoader;