Skip to content
This repository was archived by the owner on Jul 10, 2019. It is now read-only.
This repository was archived by the owner on Jul 10, 2019. It is now read-only.

Resolvers should look for a custom resolver first, but this would break the mixed @client / server query #226

@PCreations

Description

@PCreations

When resolving a field, the resolve function should first look for a custom resolver, thus simulating the same behavior as on a server :

const query = gql`
query {
  messages {
    content
    user {
      username
    }
  }
}
`;
const resolvers = {
  Message: {
    user: ({ user }) => ({
      ...db.getUserById(user),
      __typename: 'User',
    }),
  },
  Query: {
    messages: () => [{ id: "m1", content: "message 1", user: "u1",  __typename: "Message" }]
  }
}

With apollo-link-state, due to this statement stating that if there is a field in the root value, it's because the server already sent something. It's not true, this statement should be valid only if we are at the Query level.

Here is a failing test :

it('runs resolvers for nested client queries', done => {
  const nestedQuery = gql`
    query NestedQuery {
      foo @client {
        bar
        nestedBar {
          baz
        }
      }
    }
  `;
  const getNestedBarById = id => id === '42' ? {
    baz: true,
  } : null;

  const client = withClientState({
    resolvers: {
      Foo: {
        nestedBar: ({ nestedBar }) => getNestedBarById(nestedBar),
      },
      Query: {
        foo: () => ({ bar: true, nestedBar: '42', __typename: 'Foo' }),
      },
    }
  });
  execute(client, { query: nestedQuery }).subscribe(({ data }) => {
    expect(data).toEqual({ foo: { bar: true, nestedBar: { baz: true } } });
    done();
  }, done.fail);
});
// TypeError: Cannot read property 'baz' of undefined

Quick edit (to be refactored) to make all the tests pass (this one included) :
in index.js

const resolver = (fieldName, rootValue = {}, args, context, info) => {

  //resultKey is where data under the field name is ultimately returned by the server
  //https://github.com/apollographql/apollo-client/tree/master/packages/graphql-anywhere#resolver-info
  const fieldValue = rootValue[info.resultKey];

  //If fieldValue is defined and we are at the Query level, server returned a value
  if (fieldValue !== undefined && (((rootValue as any).__typename || type) == 'Query')) {
    return fieldValue;
  }

  // Look for the field in the custom resolver map
  const resolverMap = resolvers[(rootValue as any).__typename || type];
  if (resolverMap) {
    const resolve = resolverMap[fieldName];
    if (resolve) return resolve(rootValue, args, context, info);
    if (fieldValue !== undefined) return fieldValue;
  }
  if (fieldValue !== undefined) {
    return fieldValue;
  }

  //TODO: the proper thing to do here is throw an error saying to
  //add `client.onResetStore(link.writeDefaults);`
  //waiting on https://github.com/apollographql/apollo-client/pull/3010
  //Currently with nested fields, this sort of return does not work

  return defaults[fieldName];
};

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions