Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
ardatan committed Aug 1, 2024
1 parent d25452d commit 521691e
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 127 deletions.
24 changes: 21 additions & 3 deletions packages/batch-delegate/src/getLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import DataLoader from 'dataloader';
import { getNamedType, GraphQLList, GraphQLSchema, print } from 'graphql';
import { ValueOrPromise } from 'value-or-promise';
import { delegateToSchema, getActualFieldNodes, SubschemaConfig } from '@graphql-tools/delegate';
import { memoize1, memoize2, relocatedError } from '@graphql-tools/utils';
import { inspect, memoize1, memoize2, relocatedError } from '@graphql-tools/utils';
import { BatchDelegateOptions } from './types.js';

function createBatchFn<K = any>(options: BatchDelegateOptions) {
Expand Down Expand Up @@ -38,13 +38,31 @@ function createBatchFn<K = any>(options: BatchDelegateOptions) {
...(lazyOptionsFn == null ? options : lazyOptionsFn(options, keys)),
}),
).then(results => {
if (results instanceof AggregateError && keys.length === results.errors.length) {
return results.errors;
}
if (results instanceof Error) {
return keys.map(() => results);
}

const values = valuesFromResults == null ? results : valuesFromResults(results, keys);

return Array.isArray(values) ? values : keys.map(() => values);
if (Array.isArray(values)) {
if (values.length !== keys.length) {
return keys.map(
key =>
new Error(`The batch delegation failed for the field "${fieldName}" and the key "${inspect(key)}".
Returned results have ${results.length} items, but ${keys.length} were expected.
Possible solutions;
- Ensure that defined "fieldName" returns an array with the same length as the keys.
- Map the results to the keys using the "valuesFromResults" option.
- Disable the batch delegation for the defined "fieldName".
`),
);
}
return values;
}

return keys.map(() => values);
});
};
}
Expand Down
167 changes: 43 additions & 124 deletions packages/batch-delegate/tests/arrayBatchMerge.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { parse, print } from 'graphql';
import { execute, isIncrementalResult } from '@graphql-tools/executor';
import { parse } from 'graphql';
import { normalizedExecutor } from '@graphql-tools/executor';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { stitchSchemas } from '@graphql-tools/stitch';
import '../../testing/to-be-similar-gql-doc';

describe('batch delegation', () => {
test('works with mismatching array length', async () => {
const booksWithTitle = [
{ id: '1', title: 'Book 1' },
{ id: '2', title: 'Book 2' },
{ id: '3', title: 'Book 3' },
{ id: '4', title: 'Book 4' },
];
const booksWithIsbn = [
{ id: '2', isbn: 456 },
{ id: '4', isbn: 101 },
];
const titleSchema = makeExecutableSchema({
typeDefs: /* GraphQL */ `
type Book {
Expand All @@ -13,14 +22,13 @@ describe('batch delegation', () => {
}
type Query {
book(id: ID!): Book
booksWithTitle(ids: [ID!]!): [Book]
}
`,
resolvers: {
Query: {
book: (_obj, _args, _ctx, info) => {
logSelectionsMade(info, 'titleSchema');
return { id: '1', title: 'Book 1' };
booksWithTitle: (_obj, args, _ctx, info) => {

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 3 Products

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Type Check on GraphQL v15

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 10 Products

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 50 Products

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Type Check on GraphQL v16

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 100 Products

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 1000 Products

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Type Check on GraphQL v17.0.0-alpha.1

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / ESM Test

'info' is declared but its value is never read.

Check failure on line 30 in packages/batch-delegate/tests/arrayBatchMerge.test.ts

View workflow job for this annotation

GitHub Actions / Browser Test

'info' is declared but its value is never read.
return booksWithTitle.filter(book => args.ids.includes(book.id));
},
},
},
Expand All @@ -34,67 +42,30 @@ describe('batch delegation', () => {
}
type Query {
books(id: [ID!]!): [Book]
booksWithIsbn(ids: [ID!]!): [Book]
}
`,
resolvers: {
Query: {
books: (_obj, _args, _ctx, info) => {
logSelectionsMade(info, 'isbnSchema');
return [{ id: '1', isbn: 123 }];
booksWithIsbn: (_obj, args, _ctx) => {
return booksWithIsbn.filter(book => args.ids.includes(book.id));
},
},
},
});

const queriesMade = {
titleSchema: [],
isbnSchema: [],
};

const logSelectionsMade = (info: any, schema: string) => {
queriesMade[schema].push(print(info.operation));
};

const stitchedSchemaWithValuesFromResults = stitchSchemas({
const stitchedSchema = stitchSchemas({
subschemas: [
{
schema: titleSchema,
merge: {
Book: {
selectionSet: '{ id }',
fieldName: 'book',
},
},
},
{
schema: isbnSchema,
merge: {
Book: {
selectionSet: '{ id }',
fieldName: 'books',
fieldName: 'booksWithTitle',
key: ({ id }) => id,
argsFromKeys: ids => ({ id: ids }),
valuesFromResults: ({ results }, keys) => {
const response = Object.fromEntries(results.map((r: any) => [r.id, r]));

return keys.map(key => response[key] ?? { id: key });
},
},
},
},
],
mergeTypes: true,
});

const stitchedSchemaWithoutValuesFromResults = stitchSchemas({
subschemas: [
{
schema: titleSchema,
merge: {
Book: {
selectionSet: '{ id }',
fieldName: 'book',
argsFromKeys: ids => ({ ids }),
valuesFromResults: (results: any[], keys: readonly string[]) =>
keys.map(key => results.find(result => result.id === key)),
},
},
},
Expand All @@ -103,90 +74,38 @@ describe('batch delegation', () => {
merge: {
Book: {
selectionSet: '{ id }',
fieldName: 'books',
fieldName: 'booksWithIsbn',
key: ({ id }) => id,
argsFromKeys: ids => ({ id: ids }),
argsFromKeys: ids => ({ ids }),
valuesFromResults: (results: any[], keys: readonly string[]) =>
keys.map(key => results.find(result => result.id === key)),
},
},
},
],
mergeTypes: true,
});

const query = /* GraphQL */ `
query {
book(id: "1") {
id
title
isbn
}
}
`;

test('works with merged types and array batching', async () => {
const goodResult = await execute({
schema: stitchedSchemaWithoutValuesFromResults,
document: parse(query),
});

if (isIncrementalResult(goodResult)) throw Error('result is incremental');

expect(goodResult.data).toEqual({
book: {
id: '1',
title: 'Book 1',
isbn: 123,
},
});
});

test('does not work with valuesFromResults', async () => {
const badResult = await execute({
schema: stitchedSchemaWithValuesFromResults,
document: parse(query),
});

if (isIncrementalResult(badResult)) throw Error('result is incremental');

expect(badResult.data).toEqual({
book: {
id: '1',
title: 'Book 1',
isbn: 123,
},
});
});

test('it makes the right selections', async () => {
queriesMade.titleSchema = [];
queriesMade.isbnSchema = [];

await execute({
schema: stitchedSchemaWithValuesFromResults,
document: parse(query),
});

const expectedTitleQuery = /* GraphQL */ `
const result = await normalizedExecutor({
schema: stitchedSchema,
document: parse(/* GraphQL */ `
query {
__typename
book(id: "1") {
booksWithTitle(ids: ["1", "2", "3", "4"]) {
id
title
__typename
}
}
`;
const expectedIsbnQuery = /* GraphQL */ `
query ($_v0_id: [ID!]!) {
__typename
books(id: $_v0_id) {
id
isbn
}
}
`;
`),
});

expect(queriesMade.isbnSchema[0]).toBeSimilarGqlDoc(expectedIsbnQuery);
expect(queriesMade.titleSchema[0]).toBeSimilarGqlDoc(expectedTitleQuery);
expect(result).toEqual({
data: {
booksWithTitle: [
{ id: '1', title: 'Book 1', isbn: null },
{ id: '2', title: 'Book 2', isbn: 456 },
{ id: '3', title: 'Book 3', isbn: null },
{ id: '4', title: 'Book 4', isbn: 101 },
],
},
});
});

0 comments on commit 521691e

Please sign in to comment.