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

resolveType factory is not compatible with Mercurius / graphql-jit #2067

Closed
2 of 4 tasks
wodCZ opened this issue Mar 8, 2022 · 2 comments
Closed
2 of 4 tasks

resolveType factory is not compatible with Mercurius / graphql-jit #2067

wodCZ opened this issue Mar 8, 2022 · 2 comments

Comments

@wodCZ
Copy link
Contributor

wodCZ commented Mar 8, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

The way the resolve-type.factory.ts is implemented breaks the compatibility with Mercurius' JIT feature.

The resolveType function is always converted to async, which is currently not supported by graphql-jit:

return async (...args) => {
const resolvedType = await resolveType(...args);
if (isString(resolvedType)) {
return resolvedType;
}
const typeDef =
this.typeDefinitionsStorage.getObjectTypeByTarget(resolvedType);
return typeDef?.type?.name;
};

This causes requests to fail on the following:

"Abstract type Shape must resolve to an Object type at runtime for field Query.shape. Either the Shape type should provide a \"resolveType\" function or each possible types should provide an \"isTypeOf\" function."

Minimum reproduction code

https://github.com/wodCZ/nestjs-graphql-union-reproduction

Steps to reproduce

No response

Expected behavior

The resolveType function of createUnionType should be kept synchronous when defined as synchronous.

Monkey-patching the resolve-type.factory.js from

    getResolveTypeFunction(resolveType) {
        return async (...args) => {
            var _a;
            const resolvedType = await resolveType(...args);
            if ((0, shared_utils_1.isString)(resolvedType)) {
                return resolvedType;
            }
            const typeDef = this.typeDefinitionsStorage.getObjectTypeByTarget(resolvedType);
            return (_a = typeDef === null || typeDef === void 0 ? void 0 : typeDef.type) === null || _a === void 0 ? void 0 : _a.name;
        };
    }

to (async/await removed)

    getResolveTypeFunction(resolveType) {
        return (...args) => {
            var _a;
            const resolvedType = resolveType(...args);
            if ((0, shared_utils_1.isString)(resolvedType)) {
                return resolvedType;
            }
            const typeDef = this.typeDefinitionsStorage.getObjectTypeByTarget(resolvedType);
            return (_a = typeDef === null || typeDef === void 0 ? void 0 : typeDef.type) === null || _a === void 0 ? void 0 : _a.name;
        };
    }

"fixes" the issue (of course breaking real asynchronous resolveType methods.

Package version

10.0.6

Graphql version

graphql: 16.3.0
@nestjs/mercurius: 10.0.6
mercurius: 9.3.3

NestJS version

8.0.0

Node.js version

17.6.0

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

@wodCZ
Copy link
Contributor Author

wodCZ commented Mar 8, 2022

It should be noted that removing resolveType function from createUnionType and returning the instance of the ObjectType directly works as expected.

(e.g. following the reproduction code):

@ObjectType()
class Square {
  @Field(() => Int)
  side: number;
}

@ObjectType()
class Circle {
  @Field(() => Int)
  radius: number;
}

const Shape = createUnionType({
  name: 'Shape',
  types: () => [Square, Circle] as const,
});

@Resolver(() => Shape)
export class AppResolver {
  @Query(() => Shape)
  shape() {
    return Object.assign(new Square(), { side: 10 });
  }
}

@kamilmysliwiec
Copy link
Member

Let's track this here #2069

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants