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

Nested Computed Fields Edge Case #6437

Merged
merged 2 commits into from
Aug 14, 2024
Merged

Nested Computed Fields Edge Case #6437

merged 2 commits into from
Aug 14, 2024

Conversation

ardatan
Copy link
Owner

@ardatan ardatan commented Aug 14, 2024

Fix the bug happens when a merged field is a computed field requires another computed field requires a field from the initial subschema.

In the following test case, totalOrdersPrices needs userOrders which needs lastName from initial Query.user.
So the bug was skipping the dependencies of userOrders because it assumed lastName already there by mistake.

    const schema1 = makeExecutableSchema({
      typeDefs: /* GraphQL */ `
        type User {
          id: ID!
          firstName: String!
          lastName: String!
          address: String
        }

        type Query {
          user: User
        }
      `,
      resolvers: {
        Query: {
          user: () => {
            return {
              id: 1,
              firstName: 'Jake',
              lastName: 'Dawkins',
              address: 'everywhere',
            };
          },
        },
      },
    });
    const schema2 = makeExecutableSchema({
      typeDefs: /* GraphQL */ `
        type UserOrder {
          id: ID!
        }

        type User {
          id: ID!
          totalOrdersPrices: Int
          aggregatedOrdersByStatus: Int
        }

        type Query {
          userWithOrderDetails(userId: ID!, userOrderIds: [ID]): User
        }
      `,
      resolvers: {
        Query: {
          userWithOrderDetails: (_root, { userId, userOrderIds }) => {
            return {
              id: userId,
              userOrders: userOrderIds?.map((userOrderId: string) => ({ id: userOrderId })),
            };
          },
        },
        User: {
          totalOrdersPrices(user) {
            if (user.userOrders instanceof Error) {
              return user.userOrders;
            }
            if (!user.userOrders) {
              throw new Error('UserOrders is required');
            }
            return 0;
          },
          aggregatedOrdersByStatus(user) {
            if (user.userOrders instanceof Error) {
              return user.userOrders;
            }
            if (!user.userOrders) {
              throw new Error('UserOrders is required');
            }
            return 1;
          },
        },
      },
    });
    const schema3 = makeExecutableSchema({
      typeDefs: /* GraphQL */ `
        type User {
          id: ID!
          userOrders: [UserOrder!]
        }

        type UserOrder {
          id: ID!
        }

        type Query {
          userWithOrders(id: ID!, lastName: String): User
        }
      `,
      resolvers: {
        Query: {
          userWithOrders: (_root, { id, lastName }) => {
            return {
              id,
              lastName,
            };
          },
        },
        User: {
          userOrders(user) {
            if (!user.lastName) {
              throw new Error('LastName is required');
            }
            return [
              {
                id: `${user.lastName}1`,
              },
            ];
          },
        },
      },
    });
    const stitchedSchema = stitchSchemas({
      subschemas: [
        {
          schema: schema1,
        },
        {
          schema: schema2,
          merge: {
            User: {
              selectionSet: '{ id }',
              fieldName: 'userWithOrderDetails',
              args: ({ id, userOrders }: { id: string; userOrders: any[] }) => ({
                userId: id,
                userOrderIds: userOrders?.map?.(({ id }: { id: string }) => id),
              }),
              fields: {
                totalOrdersPrices: {
                  selectionSet: '{ userOrders { id } }',
                  computed: true,
                },
                aggregatedOrdersByStatus: {
                  selectionSet: '{ userOrders { id } }',
                  computed: true,
                },
              },
            },
          },
        },
        {
          schema: schema3,
          merge: {
            User: {
              selectionSet: '{ id }',
              fieldName: 'userWithOrders',
              args: ({ id, lastName }: { id: string; lastName: string }) => ({
                id,
                lastName,
              }),
              fields: {
                userOrders: {
                  selectionSet: '{ lastName }',
                  computed: true,
                },
              },
            },
          },
        },
      ],
    });
    const res = await normalizedExecutor({
      schema: stitchedSchema,
      document: parse(/* GraphQL */ `
        query User {
          user {
            aggregatedOrdersByStatus
            totalOrdersPrices
          }
        }
      `),
    });
    expect(res).toEqual({
      data: {
        user: {
          aggregatedOrdersByStatus: 1,
          totalOrdersPrices: 0,
        },
      },
    });

Copy link

changeset-bot bot commented Aug 14, 2024

🦋 Changeset detected

Latest commit: e1f7976

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@graphql-tools/federation Patch
@graphql-tools/delegate Patch
federation-benchmark Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@theguild-bot
Copy link
Collaborator

theguild-bot commented Aug 14, 2024

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
@graphql-tools/delegate 10.0.19-alpha-20240814092043-e1f7976c0ab9122da7b71c9ca741f261d3028bb8 npm ↗︎ unpkg ↗︎
@graphql-tools/federation 2.2.7-alpha-20240814092043-e1f7976c0ab9122da7b71c9ca741f261d3028bb8 npm ↗︎ unpkg ↗︎

Copy link
Contributor

github-actions bot commented Aug 14, 2024

✅ Benchmark Results

     ✓ no_errors
     ✓ expected_result

     checks.........................: 100.00% ✓ 326       ✗ 0  
     data_received..................: 38 MB   3.8 MB/s
     data_sent......................: 140 kB  14 kB/s
     http_req_blocked...............: avg=4.06µs   min=2.14µs   med=2.72µs   max=169.73µs p(90)=4.12µs   p(95)=4.59µs  
     http_req_connecting............: avg=680ns    min=0s       med=0s       max=110.88µs p(90)=0s       p(95)=0s      
     http_req_duration..............: avg=56.68ms  min=48.65ms  med=53.45ms  max=147.35ms p(90)=63.56ms  p(95)=84.63ms 
       { expected_response:true }...: avg=56.68ms  min=48.65ms  med=53.45ms  max=147.35ms p(90)=63.56ms  p(95)=84.63ms 
     http_req_failed................: 0.00%   ✓ 0         ✗ 163
     http_req_receiving.............: avg=148.69µs min=104.22µs med=136.48µs max=1.05ms   p(90)=163.32µs p(95)=209.83µs
     http_req_sending...............: avg=26.08µs  min=19.79µs  med=25.49µs  max=68.73µs  p(90)=30.57µs  p(95)=36.49µs 
     http_req_tls_handshaking.......: avg=0s       min=0s       med=0s       max=0s       p(90)=0s       p(95)=0s      
     http_req_waiting...............: avg=56.51ms  min=48.48ms  med=53.27ms  max=146.92ms p(90)=63.38ms  p(95)=84.46ms 
     http_reqs......................: 163     16.285866/s
     iteration_duration.............: avg=61.38ms  min=52.79ms  med=57.81ms  max=151.49ms p(90)=73.51ms  p(95)=88.36ms 
     iterations.....................: 163     16.285866/s
     vus............................: 1       min=1       max=1
     vus_max........................: 1       min=1       max=1

Copy link
Contributor

github-actions bot commented Aug 14, 2024

💻 Website Preview

The latest changes are available as preview in: https://344f6ea1.graphql-tools.pages.dev

@ardatan ardatan changed the title Nested Computed Fields Nested Computed Fields Edge Case Aug 14, 2024
@ardatan ardatan merged commit 3188051 into master Aug 14, 2024
29 checks passed
@ardatan ardatan deleted the nested-nested-requires branch August 14, 2024 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants