-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(graphql): Add support for auto-generated federations
* Added @reference decorator * Added federated auto-generated resolvers
- Loading branch information
1 parent
d654388
commit 238f641
Showing
18 changed files
with
416 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
packages/query-graphql/__tests__/resolvers/federation/federation.resolver.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { ObjectType, Field } from '@nestjs/graphql'; | ||
import { FederationResolver, Relation } from '../../../src'; | ||
import * as relations from '../../../src/resolvers/relations'; | ||
|
||
describe('FederationResolver', () => { | ||
const readRelation = jest.spyOn(relations, 'ReadRelationsResolver'); | ||
@ObjectType() | ||
class TestFederatedRelationDTO { | ||
@Field() | ||
id!: string; | ||
} | ||
|
||
it('should create a federated resolver with relations from metadata', () => { | ||
@ObjectType() | ||
@Relation('test', () => TestFederatedRelationDTO) | ||
class TestFederatedDTO { | ||
@Field() | ||
id!: string; | ||
} | ||
FederationResolver(TestFederatedDTO); | ||
expect(readRelation).toBeCalledWith(TestFederatedDTO, { | ||
many: {}, | ||
one: { | ||
test: { DTO: TestFederatedRelationDTO }, | ||
}, | ||
}); | ||
}); | ||
|
||
it('should create a federated resolver with provided relations', () => { | ||
@ObjectType() | ||
class TestFederatedDTO { | ||
@Field() | ||
id!: string; | ||
} | ||
FederationResolver(TestFederatedDTO, { | ||
one: { | ||
test: { DTO: TestFederatedRelationDTO }, | ||
}, | ||
}); | ||
expect(readRelation).toBeCalledWith(TestFederatedDTO, { | ||
many: {}, | ||
one: { | ||
test: { DTO: TestFederatedRelationDTO }, | ||
}, | ||
}); | ||
}); | ||
}); |
79 changes: 79 additions & 0 deletions
79
packages/query-graphql/__tests__/resolvers/reference.resolver.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import 'reflect-metadata'; | ||
import * as nestGraphql from '@nestjs/graphql'; | ||
import { instance, mock, when } from 'ts-mockito'; | ||
import { QueryService } from '@nestjs-query/core'; | ||
import * as decorators from '../../src/decorators'; | ||
import { ReferenceResolver } from '../../src'; | ||
|
||
const { ID, ObjectType } = nestGraphql; | ||
|
||
@ObjectType('TestReference') | ||
class TestReferenceDTO { | ||
@decorators.FilterableField(() => ID) | ||
id!: string; | ||
|
||
@decorators.FilterableField() | ||
stringField!: string; | ||
} | ||
|
||
describe('ReferenceResolver', () => { | ||
const resolveReferenceSpy = jest.spyOn(nestGraphql, 'ResolveReference'); | ||
|
||
beforeEach(() => jest.clearAllMocks()); | ||
|
||
class TestResolver extends ReferenceResolver(TestReferenceDTO, { key: 'id' }) { | ||
constructor(service: QueryService<TestReferenceDTO>) { | ||
super(service); | ||
} | ||
} | ||
|
||
function asserResolveReferenceCall() { | ||
expect(resolveReferenceSpy).toBeCalledTimes(1); | ||
expect(resolveReferenceSpy).toBeCalledWith(); | ||
} | ||
|
||
it('should create a new resolver with a resolveReference method', () => { | ||
jest.clearAllMocks(); // reset | ||
const Resolver = ReferenceResolver(TestReferenceDTO, { key: 'id' }); | ||
asserResolveReferenceCall(); | ||
expect(Resolver.prototype.resolveReference).toBeInstanceOf(Function); | ||
}); | ||
|
||
it('should return the original resolver if key is not provided', () => { | ||
jest.clearAllMocks(); // reset | ||
const Resolver = ReferenceResolver(TestReferenceDTO); | ||
expect(resolveReferenceSpy).not.toBeCalled(); | ||
expect(Resolver.prototype.resolveReference).toBeUndefined(); | ||
}); | ||
|
||
describe('#resolveReference', () => { | ||
it('should call the service getById with the provided input', async () => { | ||
const mockService = mock<QueryService<TestReferenceDTO>>(); | ||
const id = 'id-1'; | ||
const output: TestReferenceDTO = { | ||
id, | ||
stringField: 'foo', | ||
}; | ||
const resolver = new TestResolver(instance(mockService)); | ||
when(mockService.getById(id)).thenResolve(output); | ||
// @ts-ignore | ||
const result = await resolver.resolveReference({ __type: 'TestReference', id }); | ||
return expect(result).toEqual(output); | ||
}); | ||
|
||
it('should reject if the id is not found', async () => { | ||
const mockService = mock<QueryService<TestReferenceDTO>>(); | ||
const id = 'id-1'; | ||
const output: TestReferenceDTO = { | ||
id, | ||
stringField: 'foo', | ||
}; | ||
const resolver = new TestResolver(instance(mockService)); | ||
when(mockService.getById(id)).thenResolve(output); | ||
// @ts-ignore | ||
return expect(resolver.resolveReference({ __type: 'TestReference' })).rejects.toThrow( | ||
'Unable to resolve reference, missing required key id for TestReference', | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
packages/query-graphql/src/decorators/reference.decorator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Class } from '@nestjs-query/core'; | ||
import { getMetadataStorage } from '../metadata'; | ||
import { ResolverRelationReference } from '../resolvers/relations'; | ||
import { ReferencesKeys } from '../resolvers/relations/relations.interface'; | ||
|
||
export type ReferenceDecoratorOpts<DTO, Relation> = Omit<ResolverRelationReference<DTO, Relation>, 'DTO'>; | ||
export type ReferenceTypeFunc<Relation> = () => Class<Relation>; | ||
|
||
export function Reference<DTO, Reference>( | ||
name: string, | ||
relationTypeFunction: ReferenceTypeFunc<Reference>, | ||
keys: ReferencesKeys<any, Reference>, | ||
options?: ReferenceDecoratorOpts<DTO, Reference>, | ||
) { | ||
return <Cls extends Class<DTO>>(DTOClass: Cls): Cls | void => { | ||
getMetadataStorage().addReference(DTOClass, name, { | ||
name, | ||
keys, | ||
relationOpts: options, | ||
relationTypeFunc: relationTypeFunction, | ||
}); | ||
return DTOClass; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.