Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions API_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,20 +176,20 @@ Describes the shape and behaviour of the resources object you will pass to `getL

#### `resources` Parameters

| Key | Value Description |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isBatchResource` | Is this a batch resource? (Can you pass it a list of keys and get a list of results back?) |
| `docsLink` | The URL for the documentation of the resource. Useful for others to verify information is correct, and may be used in stack traces. |
| `batchKey` | The argument to the resource that represents the list of entities we want to fetch. (e.g. 'user_ids') |
| `newKey` | The argument we'll replace the batchKey with - should be a singular version of the `batchKey` (e.g. 'user_id') |
| `reorderResultsByKey` | (Optional) If the resource itself does not guarantee ordering, use this to specify which key in the response objects corresponds to an element in `batchKey`. Transforms and re-order the response to the same order as requested from the DataLoaders. |
| `nestedPath` | (Optional) If the resource returns the list of results in a nested path (e.g. `{ results: [ 1, 2, 3 ] }`), this tells the DataLoader where in the response to find the results. (e.g. 'results'). |
| `commaSeparatedBatchKey` | (Optional) Set to true if the interface of the resource takes the batch key as a comma separated list (rather than an array of IDs, as is more common). Default: false |
| `isResponseDictionary` | (Optional) Set to true if the batch resource returns the results as a dictionary with key mapped to values (instead of a list of items). If this option is supplied `reorderResultsByKey` should not be. Default: false |
| `isBatchKeyASet` | (Optional) Set to true if the interface of the resource takes the batch key as a set (rather than an array). For example, when using a generated clientlib based on swagger where `uniqueItems: true` is set for the batchKey parameter. Default: false. |
| `propertyBatchKey` | (Optional) The argument to the resource that represents the optional properties we want to fetch. (e.g. usually 'properties' or 'features'). |
| `maxBatchSize` | (Optional) Limits the number of items that can be batched together in a single request. When more items are requested than this limit, multiple requests will be made. This can help prevent hitting URI length limits or timeouts for large batches. |
| `responseKey` | (Non-optional when propertyBatchKey is used) The key in the response objects corresponds to `batchKey`. This should be the only field that are marked as required in your swagger endpoint response, except nestedPath. |
| Key | Value Description |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isBatchResource` | Is this a batch resource? (Can you pass it a list of keys and get a list of results back?) |
| `docsLink` | The URL for the documentation of the resource. Useful for others to verify information is correct, and may be used in stack traces. |
| `batchKey` | The argument to the resource that represents the list of entities we want to fetch. (e.g. 'user_ids') |
| `newKey` | The argument we'll replace the batchKey with - should be a singular version of the `batchKey` (e.g. 'user_id') |
| `reorderResultsByKey` | (Optional) If the resource itself does not guarantee ordering, use this to specify which key in the response objects corresponds to an element in `batchKey`. Transforms and re-order the response to the same order as requested from the DataLoaders. Can be a dot separated nested path. |
| `nestedPath` | (Optional) If the resource returns the list of results in a nested path (e.g. `{ results: [ 1, 2, 3 ] }`), this tells the DataLoader where in the response to find the results. (e.g. 'results'). |
| `commaSeparatedBatchKey` | (Optional) Set to true if the interface of the resource takes the batch key as a comma separated list (rather than an array of IDs, as is more common). Default: false |
| `isResponseDictionary` | (Optional) Set to true if the batch resource returns the results as a dictionary with key mapped to values (instead of a list of items). If this option is supplied `reorderResultsByKey` should not be. Default: false |
| `isBatchKeyASet` | (Optional) Set to true if the interface of the resource takes the batch key as a set (rather than an array). For example, when using a generated clientlib based on swagger where `uniqueItems: true` is set for the batchKey parameter. Default: false. |
| `propertyBatchKey` | (Optional) The argument to the resource that represents the optional properties we want to fetch. (e.g. usually 'properties' or 'features'). |
| `maxBatchSize` | (Optional) Limits the number of items that can be batched together in a single request. When more items are requested than this limit, multiple requests will be made. This can help prevent hitting URI length limits or timeouts for large batches. |
| `responseKey` | (Non-optional when propertyBatchKey is used) The key in the response objects corresponds to `batchKey`. This should be the only field that are marked as required in your swagger endpoint response, except nestedPath. |

### `typings`

Expand Down
36 changes: 36 additions & 0 deletions __tests__/implementation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,42 @@ test('batch endpoint (with reorderResultsByKey)', async () => {
});
});

test('batch endpoint (with nested reorderResultsByKey path)', async () => {
const config = {
resources: {
foo: {
isBatchResource: true,
docsLink: 'example.com/docs/bar',
batchKey: 'foo_ids',
newKey: 'foo_id',
reorderResultsByKey: 'nested.foo_id',
},
},
};

const resources = {
foo: ({ foo_ids }) => {
expect(foo_ids).toEqual([1, 2, 3]);
return Promise.resolve([
{ nested: { foo_id: 2, foo_value: 'world' } },
{ nested: { foo_id: 1, foo_value: 'hello' } },
{ nested: { foo_id: 3, foo_value: '!' } },
]);
},
};

await createDataLoaders(config, async (getLoaders) => {
const loaders = getLoaders(resources);

const results = await loaders.foo.loadMany([{ foo_id: 1 }, { foo_id: 2 }, { foo_id: 3 }]);
expect(results).toEqual([
{ nested: { foo_id: 1, foo_value: 'hello' } },
{ nested: { foo_id: 2, foo_value: 'world' } },
{ nested: { foo_id: 3, foo_value: '!' } },
]);
});
});

test('batch endpoint (with nestedPath)', async () => {
const config = {
resources: {
Expand Down
2 changes: 1 addition & 1 deletion schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
},
"reorderResultsByKey": {
"type": "string",
"description": "(Optional) If the resource itself does not guarantee ordering, this key specifies which key in the response objects corresponds to an element in `batchKey`. We use this to transfrom and re-order the response to the same order as in batchKey."
"description": "(Optional) If the resource itself does not guarantee ordering, this key specifies which key in the response objects corresponds to an element in `batchKey`. We use this to transfrom and re-order the response to the same order as in batchKey. Can be a dot separated nested path."
},
"nestedPath": {
"type": "string",
Expand Down
9 changes: 4 additions & 5 deletions src/runtimeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export function sortByKeys<V>({
items,
/** The IDs we originally requested from the endpoint */
keys,
/** The attribute of each element in `items` that maps it to an element in `keys`. */
/** The attribute of each element in `items` that maps it to an element in `keys`. Can be a dot-separated nested path. */
prop,
/** Some path that indicates what resource this is being used on. Used for stack traces. */
resourcePath,
Expand Down Expand Up @@ -212,10 +212,9 @@ export function sortByKeys<V>({

itemsMap.set(String(reorderResultsByValue), item);
} else {
// @ts-ignore: TODO: Work how to tell typescript item[prop] exists
invariant(item[prop] != null, `${errorPrefix(resourcePath)} Could not find property "${prop}" in item`);
// @ts-ignore: TODO: Work how to tell typescript item[prop] exists
itemsMap.set(String(item[prop]), item);
const sortKey = _.get(item, prop);
invariant(sortKey != null, `${errorPrefix(resourcePath)} Could not find property "${prop}" in item`);
itemsMap.set(String(sortKey), item);
}
});

Expand Down