graphql-tools: Stacked object merges fail in v7 (regression)

Upgrading to v7, my API test suite shows an outstanding failure possibly similar to https://github.com/ardatan/graphql-tools/issues/2137, though distinct. While https://github.com/ardatan/graphql-tools/issues/2137 was a newly-discovered issue that existed in v6, this is demonstrably a regression that worked in v6 and is failing in v7.

In this scenario, objects merging atop other merged objects now appear to fail. Here’s another three-part test that demonstrates:

  • Test 1: two versions of Post merge together with unique fields from each service. This works fine.
  • Test 2: Post.network in Posts service merges with Network from Layouts service. This also works fine.
  • Test 3: now the merge patterns from tests 1&2 are combined, at which time they fail when requested together.

Of note, I’m running the alpha stitching branch from https://github.com/ardatan/graphql-tools/pull/2154. The test suite had several failures with 7.0.0, though running with that fix has brought it down to just this one (so significant progress!)

cc @yaacovCR @DrewML

import { makeExecutableSchema } from '@graphql-tools/schema';
import { stitchSchemas } from '@graphql-tools/stitch';
import { graphql } from 'graphql';

describe('Merged associations', () => {
  const layoutSchema = makeExecutableSchema({
    typeDefs: `
      type Network {
        id: ID!
        domain: String!
      }
      type Post {
        id: ID!
        sections: [String]!
      }
      type Query {
        networks(ids: [ID!]!): [Network]!
        _posts(ids: [ID!]!): [Post]!
      }
    `,
    resolvers: {
      Query: {
        networks: (root, { ids }) => ids.map(id => ({ id, domain: `network${id}.com` })),
        _posts: (root, { ids }) => ids.map(id => ({
          id,
          sections: ['News']
        })),
      }
    }
  });

  const postsSchema = makeExecutableSchema({
    typeDefs: `
      type Network {
        id: ID!
      }
      type Post {
        id: ID!
        title: String!
        network: Network
      }
      type Query {
        posts(ids: [ID!]!): [Post]!
      }
    `,
    resolvers: {
      Query: {
        posts: (root, { ids }) => ids.map(id => ({
          id,
          title: `Post ${id}`,
          network: { id: Number(id)+2 }
        })),
      }
    }
  });

  const gatewaySchema = stitchSchemas({
    subschemas: [
      {
        schema: layoutSchema,
        merge: {
          Network: {
            selectionSet: '{ id }',
            fieldName: 'networks',
            key: ({ id }) => id,
            argsFromKeys: (ids) => ({ ids }),
          },
          Post: {
            selectionSet: '{ id }',
            fieldName: '_posts',
            key: ({ id }) => id,
            argsFromKeys: (ids) => ({ ids }),
          },
        },
      },
      {
        schema: postsSchema,
        merge: {
          Post: {
            selectionSet: '{ id }',
            fieldName: 'posts',
            key: ({ id }) => id,
            argsFromKeys: (ids) => ({ ids }),
          },
        },
      },
    ]
  });

  it('merges object with own remote type', async () => {
    const { data, errors } = await graphql(gatewaySchema, `
      query {
        posts(ids: [55]) {
          title
          sections
        }
      }
    `);

    expect(data.posts).toEqual([{
      title: 'Post 55',
      sections: ['News']
    }]);
  });

  it('merges object association with associated remote type', async () => {
    const { data, errors } = await graphql(gatewaySchema, `
      query {
        posts(ids: [55]) {
          title
          network { domain }
        }
      }
    `);

    expect(data.posts).toEqual([{
      title: 'Post 55',
      network: { domain: 'network57.com' },
    }]);
  });

  it('merges object with own remote type and association with associated remote type', async () => {
    const { data } = await graphql(gatewaySchema, `
      query {
        posts(ids: [55]) {
          title
          network { domain }
          sections
        }
      }
    `);

    expect(data.posts).toEqual([{
      title: 'Post 55',
      network: { domain: 'network57.com' },
      sections: ['News']
    }]);
  });
});

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 15 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Actually that code needs a lot of improvement but I just did a quick refactor and was able to fix locally. Well hopefully get a fix out this afternoon