-
Notifications
You must be signed in to change notification settings - Fork 422
fix(graphql,apollo): ensures extensions are added to resolved fields #3779
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { GraphQLModule } from '@nestjs/graphql'; | ||
| import { ApolloDriver, ApolloDriverConfig } from '../../lib'; | ||
| import { UserModule } from './user/user.module'; | ||
| import { Module } from '@nestjs/common'; | ||
|
|
||
| /** | ||
| * Main application module for the code-first extensions example. | ||
| */ | ||
| @Module({ | ||
| imports: [ | ||
| GraphQLModule.forRoot<ApolloDriverConfig>({ | ||
| driver: ApolloDriver, | ||
| autoSchemaFile: true, | ||
| playground: false, | ||
| }), | ||
| UserModule, | ||
| ], | ||
| }) | ||
| export class AppModule {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { Extensions, Field, InputType } from '@nestjs/graphql'; | ||
|
|
||
| @InputType() | ||
| @Extensions({ exampleExtension: 'exampleValue' }) | ||
| export class CreateUserInput { | ||
| @Extensions({ fieldLevelExtension: 123 }) | ||
| @Field() | ||
| name!: string; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { ID, Field, ObjectType, Extensions } from '@nestjs/graphql'; | ||
|
|
||
| @ObjectType() | ||
| export class Status { | ||
| @Field(() => ID) | ||
| id!: string; | ||
|
|
||
| @Field() | ||
| @Extensions({ isPublic: true }) | ||
| code!: string; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { Extensions, Field, ID, ObjectType } from '@nestjs/graphql'; | ||
| import { Status } from './user-status.dto'; | ||
|
|
||
| @ObjectType() | ||
| export class User { | ||
| @Field(() => ID) | ||
| id!: string; | ||
|
|
||
| @Field() | ||
| name!: string; | ||
|
|
||
| @Extensions({ isPublic: true }) | ||
| @Field(() => Status, { nullable: true, description: 'DTO Description' }) | ||
| status?: Status; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { Module } from '@nestjs/common'; | ||
| import { UserResolver } from './user.resolver'; | ||
| import { UserService } from './user.service'; | ||
|
|
||
| @Module({ | ||
| providers: [UserResolver, UserService], | ||
| }) | ||
| export class UserModule {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { | ||
| Args, | ||
| Mutation, | ||
| Parent, | ||
| Query, | ||
| ResolveField, | ||
| Resolver, | ||
| } from '@nestjs/graphql'; | ||
| import { User } from './user.dto'; | ||
| import { UserService } from './user.service'; | ||
| import { CreateUserInput } from './create-user.input'; | ||
| import { Status } from './user-status.dto'; | ||
|
|
||
| @Resolver(() => User) | ||
| export class UserResolver { | ||
| constructor(private readonly userService: UserService) {} | ||
|
|
||
| @Query(() => [User], { name: 'users' }) | ||
| findAll(): User[] { | ||
| return this.userService.findAll(); | ||
| } | ||
|
|
||
| @Mutation(() => User) | ||
| createUser(@Args('createUserInput') createUserInput: CreateUserInput): User { | ||
| return this.userService.create(createUserInput); | ||
| } | ||
|
|
||
| @ResolveField('status', undefined, { | ||
| nullable: true, | ||
| description: 'Resolve Field Description', | ||
| }) | ||
| getStatus(@Parent() user: User): Status { | ||
| return { | ||
| id: 'status-id', | ||
| code: 'ACTIVE', | ||
| }; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { Injectable } from '@nestjs/common'; | ||
| import { User } from './user.dto'; | ||
| import { CreateUserInput } from './create-user.input'; | ||
|
|
||
| @Injectable() | ||
| export class UserService { | ||
| private users: User[] = []; | ||
| private idCounter = 1; | ||
|
|
||
| findAll(): User[] { | ||
| return this.users; | ||
| } | ||
|
|
||
| findOne(id: string): User | undefined { | ||
| return this.users.find((user) => user.id === id); | ||
| } | ||
|
|
||
| create(createUserInput: CreateUserInput): User { | ||
| const user: User = { | ||
| id: String(this.idCounter++), | ||
| name: createUserInput.name, | ||
| }; | ||
| this.users.push(user); | ||
| return user; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import { INestApplication } from '@nestjs/common'; | ||
| import { GraphQLSchemaHost } from '@nestjs/graphql'; | ||
| import { Test } from '@nestjs/testing'; | ||
| import * as assert from 'assert'; | ||
| import { GraphQLObjectType } from 'graphql'; | ||
| import { AppModule } from '../code-first-extensions/app.module'; | ||
|
|
||
| describe('Code-first extensions', () => { | ||
| let app: INestApplication; | ||
|
|
||
| beforeAll(async () => { | ||
| const moduleRef = await Test.createTestingModule({ | ||
| imports: [AppModule], | ||
| }).compile(); | ||
|
|
||
| app = moduleRef.createNestApplication(); | ||
| await app.init(); | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| await app.close(); | ||
| }); | ||
|
|
||
| it('Adds extensions to resolved field', async () => { | ||
| const { schema } = app.get(GraphQLSchemaHost); | ||
| const userObject = schema.getType('User') as GraphQLObjectType; | ||
| assert(userObject, 'User type not found in schema'); | ||
| const statusField = userObject.getFields().status; | ||
| assert(statusField, 'status field not found in User type'); | ||
|
|
||
| const extensions = statusField.extensions; | ||
|
|
||
| expect(extensions.isPublic).toBe(true); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -421,7 +421,7 @@ export class TypeMetadataStorageHost { | |
| } | ||
| let objectOrInterfaceTypeField = | ||
| objectOrInterfaceTypeMetadata.properties.find( | ||
| (fieldDef) => fieldDef.name === item.methodName, | ||
| (fieldDef) => fieldDef.schemaName === item.schemaName, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know why this didn't compare |
||
| ); | ||
| for ( | ||
| let _objectTypeRef = objectTypeRef; | ||
|
|
@@ -430,7 +430,7 @@ export class TypeMetadataStorageHost { | |
| ) { | ||
| const possibleTypeMetadata = getTypeMetadata(_objectTypeRef); | ||
| objectOrInterfaceTypeField = possibleTypeMetadata?.properties.find( | ||
| (fieldDef) => fieldDef.name === item.methodName, | ||
| (fieldDef) => fieldDef.schemaName === item.schemaName, | ||
| ); | ||
| if (objectOrInterfaceTypeField) { | ||
| objectTypeRef = _objectTypeRef; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,6 @@ import { GraphQLAstExplorer, GraphQLFactory } from '../lib'; | |
| import { GraphQLSchemaBuilder } from '../lib/graphql-schema.builder'; | ||
| import { ResolversExplorerService } from '../lib/services/resolvers-explorer.service'; | ||
| import { ScalarsExplorerService } from '../lib/services/scalars-explorer.service'; | ||
| import gql from 'graphql-tag'; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an unused import |
||
| import { GraphQLSchema } from 'graphql'; | ||
|
|
||
| describe('GraphQLFactory', () => { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I've asserted that this test fails without the changed I made to the type-metadata.storage