From b6f2bb76888cca568783d2e8ab75f666d558a8fe Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 25 Nov 2024 14:47:38 +1100 Subject: [PATCH 1/4] wip: add options to all services --- .../create-many-options.interface.ts | 3 +++ .../interfaces/create-one-options.interface.ts | 9 +++++++++ packages/core/src/interfaces/index.ts | 2 ++ .../src/services/assembler-query.service.ts | 10 ++++++---- .../core/src/services/noop-query.service.ts | 6 ++++-- .../core/src/services/proxy-query.service.ts | 10 ++++++---- packages/core/src/services/query.service.ts | 8 ++++++-- .../src/resolvers/create.resolver.ts | 10 ++++------ .../src/services/mongoose-query.service.ts | 13 ++++++++++--- .../src/services/sequelize-query.service.ts | 16 +++++++++++++--- .../src/services/typegoose-query-service.ts | 13 ++++++++++--- .../src/services/typeorm-query.service.ts | 18 +++++++++++------- 12 files changed, 84 insertions(+), 34 deletions(-) create mode 100644 packages/core/src/interfaces/create-many-options.interface.ts create mode 100644 packages/core/src/interfaces/create-one-options.interface.ts diff --git a/packages/core/src/interfaces/create-many-options.interface.ts b/packages/core/src/interfaces/create-many-options.interface.ts new file mode 100644 index 000000000..74224c015 --- /dev/null +++ b/packages/core/src/interfaces/create-many-options.interface.ts @@ -0,0 +1,3 @@ +import { CreateOneOptions } from './create-one-options.interface' + +export type CreateManyOptions = CreateOneOptions diff --git a/packages/core/src/interfaces/create-one-options.interface.ts b/packages/core/src/interfaces/create-one-options.interface.ts new file mode 100644 index 000000000..1156eb3b2 --- /dev/null +++ b/packages/core/src/interfaces/create-one-options.interface.ts @@ -0,0 +1,9 @@ +import { Filter } from './filter.interface' + +export interface CreateOneOptions { + /** + * Additional filter applied to the input dto before creation. This could be used to apply an additional filter to ensure + * that the entity being created belongs to a particular user. + */ + filter?: Filter +} diff --git a/packages/core/src/interfaces/index.ts b/packages/core/src/interfaces/index.ts index d47ab793b..7ccb00c40 100644 --- a/packages/core/src/interfaces/index.ts +++ b/packages/core/src/interfaces/index.ts @@ -2,6 +2,8 @@ export * from './aggregate-options.interface' export * from './aggregate-query.interface' export * from './aggregate-response.interface' export * from './count-options.interface' +export * from './create-many-options.interface' +export * from './create-one-options.interface' export * from './delete-many-options.interface' export * from './delete-many-response.interface' export * from './delete-one-options.interface' diff --git a/packages/core/src/services/assembler-query.service.ts b/packages/core/src/services/assembler-query.service.ts index 740200b56..e8e08c5a0 100644 --- a/packages/core/src/services/assembler-query.service.ts +++ b/packages/core/src/services/assembler-query.service.ts @@ -5,6 +5,8 @@ import { AggregateQuery, AggregateResponse, CountOptions, + CreateManyOptions, + CreateOneOptions, DeleteManyResponse, DeleteOneOptions, Filter, @@ -39,15 +41,15 @@ export class AssemblerQueryService, CE = DeepP ) } - public async createMany(items: C[]): Promise { + public async createMany(items: C[], opts?: CreateManyOptions): Promise { const { assembler } = this const converted = await assembler.convertToCreateEntities(items) - return this.assembler.convertToDTOs(await this.queryService.createMany(converted)) + return this.assembler.convertToDTOs(await this.queryService.createMany(converted, this.convertFilterable(opts))) } - public async createOne(item: C): Promise { + public async createOne(item: C, opts?: CreateOneOptions): Promise { const c = await this.assembler.convertToCreateEntity(item) - return this.assembler.convertToDTO(await this.queryService.createOne(c)) + return this.assembler.convertToDTO(await this.queryService.createOne(c, this.convertFilterable(opts))) } public async deleteMany(filter: Filter): Promise { diff --git a/packages/core/src/services/noop-query.service.ts b/packages/core/src/services/noop-query.service.ts index a5faa7bf2..ec0f679cb 100644 --- a/packages/core/src/services/noop-query.service.ts +++ b/packages/core/src/services/noop-query.service.ts @@ -7,6 +7,8 @@ import { AggregateQuery, AggregateResponse, CountOptions, + CreateManyOptions, + CreateOneOptions, DeleteManyOptions, DeleteManyResponse, DeleteOneOptions, @@ -43,11 +45,11 @@ export class NoOpQueryService, U = DeepPartial> i return Promise.reject(new NotImplementedException('addRelations is not implemented')) } - public createMany(items: C[]): Promise { + public createMany(items: C[], opts?: CreateManyOptions): Promise { return Promise.reject(new NotImplementedException('createMany is not implemented')) } - public createOne(item: C): Promise { + public createOne(item: C, opts?: CreateOneOptions): Promise { return Promise.reject(new NotImplementedException('createOne is not implemented')) } diff --git a/packages/core/src/services/proxy-query.service.ts b/packages/core/src/services/proxy-query.service.ts index 88f84cf67..258a5ec88 100644 --- a/packages/core/src/services/proxy-query.service.ts +++ b/packages/core/src/services/proxy-query.service.ts @@ -4,6 +4,8 @@ import { AggregateQuery, AggregateResponse, CountOptions, + CreateManyOptions, + CreateOneOptions, DeleteManyResponse, DeleteOneOptions, Filter, @@ -172,12 +174,12 @@ export class ProxyQueryService, U = DeepPartial> return this.proxied.findRelation(RelationClass, relationName, dto, opts) } - public createMany(items: C[]): Promise { - return this.proxied.createMany(items) + public createMany(items: C[], opts?: CreateManyOptions): Promise { + return this.proxied.createMany(items, opts) } - public createOne(item: C): Promise { - return this.proxied.createOne(item) + public createOne(item: C, opts?: CreateOneOptions): Promise { + return this.proxied.createOne(item, opts) } public async deleteMany(filter: Filter): Promise { diff --git a/packages/core/src/services/query.service.ts b/packages/core/src/services/query.service.ts index 5ff3952a5..677036f89 100644 --- a/packages/core/src/services/query.service.ts +++ b/packages/core/src/services/query.service.ts @@ -7,6 +7,8 @@ import { AggregateQuery, AggregateResponse, CountOptions, + CreateManyOptions, + CreateOneOptions, DeleteManyOptions, DeleteManyResponse, DeleteOneOptions, @@ -243,17 +245,19 @@ export interface QueryService, U = DeepPartial> { * Create a single record. * * @param item - the record to create. + * @param opts - Additional opts to apply when creating one entity. * @returns the created record. */ - createOne(item: C): Promise + createOne(item: C, opts?: CreateOneOptions): Promise /** * Creates a multiple record. * * @param items - the records to create. + * @param opts - Additional opts to apply when creating many entities. * @returns a created records. */ - createMany(items: C[]): Promise + createMany(items: C[], opts?: CreateManyOptions): Promise /** * Update one record. diff --git a/packages/query-graphql/src/resolvers/create.resolver.ts b/packages/query-graphql/src/resolvers/create.resolver.ts index 8d3b2f9b6..f6b3838d5 100644 --- a/packages/query-graphql/src/resolvers/create.resolver.ts +++ b/packages/query-graphql/src/resolvers/create.resolver.ts @@ -134,11 +134,10 @@ export const Creatable = @AuthorizerFilter({ operationGroup: OperationGroup.CREATE, many: false - }) // eslint-disable-next-line @typescript-eslint/no-unused-vars + }) authorizeFilter?: Filter ): Promise { - // Ignore `authorizeFilter` for now but give users the ability to throw an UnauthorizedException - const created = await this.service.createOne(input.input.input) + const created = await this.service.createOne(input.input.input, { filter: authorizeFilter ?? {} }) if (enableOneSubscriptions) { await this.publishCreatedEvent(created, authorizeFilter) } @@ -159,11 +158,10 @@ export const Creatable = @AuthorizerFilter({ operationGroup: OperationGroup.CREATE, many: true - }) // eslint-disable-next-line @typescript-eslint/no-unused-vars + }) authorizeFilter?: Filter ): Promise { - // Ignore `authorizeFilter` for now but give users the ability to throw an UnauthorizedException - const created = await this.service.createMany(input.input.input) + const created = await this.service.createMany(input.input.input, { filter: authorizeFilter ?? {} }) if (enableManySubscriptions) { await Promise.all(created.map((c) => this.publishCreatedEvent(c, authorizeFilter))) } diff --git a/packages/query-mongoose/src/services/mongoose-query.service.ts b/packages/query-mongoose/src/services/mongoose-query.service.ts index d38d44e82..628506453 100644 --- a/packages/query-mongoose/src/services/mongoose-query.service.ts +++ b/packages/query-mongoose/src/services/mongoose-query.service.ts @@ -3,6 +3,8 @@ import { NotFoundException } from '@nestjs/common' import { AggregateQuery, AggregateResponse, + applyFilter, + CreateOneOptions, DeepPartial, DeleteManyResponse, DeleteOneOptions, @@ -132,9 +134,13 @@ export class MongooseQueryService * const todoItem = await this.service.createOne({title: 'Todo Item', completed: false }); * ``` * @param record - The entity to create. + * @param opts - Additional options. */ - async createOne(record: DeepPartial): Promise { + async createOne(record: DeepPartial, opts?: CreateOneOptions): Promise { this.ensureIdIsNotPresent(record) + if (opts?.filter && !applyFilter(record as Entity, opts.filter)) { + throw new Error('Entity does not meet creation constraints') + } return this.Model.create(record) } @@ -149,10 +155,11 @@ export class MongooseQueryService * ]); * ``` * @param records - The entities to create. + * @param opts - Additional options. */ - public async createMany(records: DeepPartial[]): Promise { + public async createMany(records: DeepPartial[], opts?: CreateOneOptions): Promise { records.forEach((r) => this.ensureIdIsNotPresent(r)) - return this.Model.create(records) + return this.Model.create(opts?.filter ? applyFilter(records as Entity[], opts.filter) : records) } /** diff --git a/packages/query-sequelize/src/services/sequelize-query.service.ts b/packages/query-sequelize/src/services/sequelize-query.service.ts index b25069633..d28dc671f 100644 --- a/packages/query-sequelize/src/services/sequelize-query.service.ts +++ b/packages/query-sequelize/src/services/sequelize-query.service.ts @@ -2,6 +2,8 @@ import { NotFoundException } from '@nestjs/common' import { AggregateQuery, AggregateResponse, + applyFilter, + CreateOneOptions, DeepPartial, DeleteManyResponse, DeleteOneOptions, @@ -129,9 +131,13 @@ export class SequelizeQueryService> * const todoItem = await this.service.createOne({title: 'Todo Item', completed: false }); * ``` * @param record - The entity to create. + * @param opts - Additional options. */ - public async createOne(record: DeepPartial): Promise { + public async createOne(record: DeepPartial, opts?: CreateOneOptions): Promise { await this.ensureEntityDoesNotExist(record) + if (opts?.filter && !applyFilter(record as Entity, opts.filter)) { + throw new Error('Entity does not meet creation constraints') + } const changedValues = this.getChangedValues(record) return this.model.create(changedValues as MakeNullishOptional) } @@ -147,11 +153,15 @@ export class SequelizeQueryService> * ]); * ``` * @param records - The entities to create. + * @param opts - Additional options. */ - public async createMany(records: DeepPartial[]): Promise { + public async createMany(records: DeepPartial[], opts?: CreateOneOptions): Promise { await Promise.all(records.map((r) => this.ensureEntityDoesNotExist(r))) + const filteredRecords = opts?.filter ? applyFilter(records as Entity[], opts.filter) : records - return this.model.bulkCreate(records.map((r) => this.getChangedValues(r) as MakeNullishOptional)) + return this.model.bulkCreate( + filteredRecords.map((r) => this.getChangedValues(r as DeepPartial) as MakeNullishOptional) + ) } /** diff --git a/packages/query-typegoose/src/services/typegoose-query-service.ts b/packages/query-typegoose/src/services/typegoose-query-service.ts index b5b5b1d3c..5ba77a21a 100644 --- a/packages/query-typegoose/src/services/typegoose-query-service.ts +++ b/packages/query-typegoose/src/services/typegoose-query-service.ts @@ -2,6 +2,9 @@ import { NotFoundException } from '@nestjs/common' import { AggregateQuery, AggregateResponse, + applyFilter, + CreateManyOptions, + CreateOneOptions, DeepPartial, DeleteManyResponse, DeleteOneOptions, @@ -116,9 +119,13 @@ export class TypegooseQueryService extends ReferenceQuerySe * const todoItem = await this.service.createOne({title: 'Todo Item', completed: false }); * ``` * @param record - The entity to create. + * @param opts - Additional options. */ - async createOne(record: DeepPartial): Promise> { + async createOne(record: DeepPartial, opts?: CreateOneOptions): Promise> { this.ensureIdIsNotPresent(record) + if (opts?.filter && !applyFilter(record as Entity, opts.filter)) { + throw new Error('Entity does not meet creation constraints') + } const doc = await this.Model.create(record) return doc } @@ -135,9 +142,9 @@ export class TypegooseQueryService extends ReferenceQuerySe * ``` * @param records - The entities to create. */ - async createMany(records: DeepPartial[]): Promise[]> { + async createMany(records: DeepPartial[], opts?: CreateManyOptions): Promise[]> { records.forEach((r) => this.ensureIdIsNotPresent(r)) - const entities = await this.Model.create(records) + const entities = await this.Model.create(opts?.filter ? applyFilter(records as Entity[], opts.filter) : records) return entities } diff --git a/packages/query-typeorm/src/services/typeorm-query.service.ts b/packages/query-typeorm/src/services/typeorm-query.service.ts index 685e49491..e5e757386 100644 --- a/packages/query-typeorm/src/services/typeorm-query.service.ts +++ b/packages/query-typeorm/src/services/typeorm-query.service.ts @@ -3,8 +3,10 @@ import { AggregateOptions, AggregateQuery, AggregateResponse, + applyFilter, Class, CountOptions, + CreateOneOptions, DeepPartial, DeleteManyOptions, DeleteManyResponse, @@ -190,12 +192,15 @@ export class TypeOrmQueryService * const todoItem = await this.service.createOne({title: 'Todo Item', completed: false }); * ``` * @param record - The entity to create. + * @param opts - Additional options. */ - public async createOne(record: DeepPartial): Promise { + public async createOne(record: DeepPartial, opts?: CreateOneOptions): Promise { const entity = await this.ensureIsEntityAndDoesNotExist(record) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore + if (opts?.filter && !applyFilter(entity, opts.filter)) { + throw new Error('Entity does not meet creation constraints') + } + return this.repo.save(entity) } @@ -210,12 +215,11 @@ export class TypeOrmQueryService * ]); * ``` * @param records - The entities to create. + * @param opts - Additional options. */ - public async createMany(records: DeepPartial[]): Promise { + public async createMany(records: DeepPartial[], opts?: CreateOneOptions): Promise { const entities = await Promise.all(records.map((r) => this.ensureIsEntityAndDoesNotExist(r))) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return this.repo.save(entities) + return this.repo.save(opts?.filter ? applyFilter(entities, opts.filter) : entities) } /** From 89b5ba0615fd87c77456424aac399fd4b397ed11 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 26 Nov 2024 16:39:37 +1100 Subject: [PATCH 2/4] feat: Add `validateWithAuthFilter` config --- .../src/resolvers/create.resolver.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/query-graphql/src/resolvers/create.resolver.ts b/packages/query-graphql/src/resolvers/create.resolver.ts index f6b3838d5..b519264e2 100644 --- a/packages/query-graphql/src/resolvers/create.resolver.ts +++ b/packages/query-graphql/src/resolvers/create.resolver.ts @@ -25,7 +25,14 @@ import { BaseServiceResolver, ResolverClass, ServiceResolver, SubscriptionResolv export type CreatedEvent = { [eventName: string]: DTO } -export interface CreateResolverOpts> extends SubscriptionResolverOpts { +interface AuthValidationOps { + /** + * Determines whether the auth filter should be passed into the query service + */ + validateWithAuthFilter?: boolean +} + +export interface CreateResolverOpts> extends SubscriptionResolverOpts, AuthValidationOps { /** * The Input DTO that should be used to create records. */ @@ -41,6 +48,9 @@ export interface CreateResolverOpts> extends Subscript createOneMutationName?: string createManyMutationName?: string + + one?: SubscriptionResolverOpts['one'] & AuthValidationOps + many?: SubscriptionResolverOpts['many'] & AuthValidationOps } export interface CreateResolver> extends ServiceResolver { @@ -137,7 +147,9 @@ export const Creatable = }) authorizeFilter?: Filter ): Promise { - const created = await this.service.createOne(input.input.input, { filter: authorizeFilter ?? {} }) + const createOneOpts = + opts?.validateWithAuthFilter || opts?.one?.validateWithAuthFilter ? { filter: authorizeFilter ?? {} } : undefined + const created = await this.service.createOne(input.input.input, createOneOpts) if (enableOneSubscriptions) { await this.publishCreatedEvent(created, authorizeFilter) } @@ -161,7 +173,9 @@ export const Creatable = }) authorizeFilter?: Filter ): Promise { - const created = await this.service.createMany(input.input.input, { filter: authorizeFilter ?? {} }) + const createManyOpts = + opts.validateWithAuthFilter || opts.many?.validateWithAuthFilter ? { filter: authorizeFilter ?? {} } : undefined + const created = await this.service.createMany(input.input.input, createManyOpts) if (enableManySubscriptions) { await Promise.all(created.map((c) => this.publishCreatedEvent(c, authorizeFilter))) } From 07f3ae9550a7b259b822c8e0f2be86456399ef99 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 26 Nov 2024 16:40:24 +1100 Subject: [PATCH 3/4] fixup! feat: Add `validateWithAuthFilter` config --- packages/query-graphql/src/resolvers/create.resolver.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/query-graphql/src/resolvers/create.resolver.ts b/packages/query-graphql/src/resolvers/create.resolver.ts index b519264e2..ae380f9fb 100644 --- a/packages/query-graphql/src/resolvers/create.resolver.ts +++ b/packages/query-graphql/src/resolvers/create.resolver.ts @@ -25,14 +25,14 @@ import { BaseServiceResolver, ResolverClass, ServiceResolver, SubscriptionResolv export type CreatedEvent = { [eventName: string]: DTO } -interface AuthValidationOps { +interface AuthValidationOpts { /** * Determines whether the auth filter should be passed into the query service */ validateWithAuthFilter?: boolean } -export interface CreateResolverOpts> extends SubscriptionResolverOpts, AuthValidationOps { +export interface CreateResolverOpts> extends SubscriptionResolverOpts, AuthValidationOpts { /** * The Input DTO that should be used to create records. */ @@ -49,8 +49,8 @@ export interface CreateResolverOpts> extends Subscript createOneMutationName?: string createManyMutationName?: string - one?: SubscriptionResolverOpts['one'] & AuthValidationOps - many?: SubscriptionResolverOpts['many'] & AuthValidationOps + one?: SubscriptionResolverOpts['one'] & AuthValidationOpts + many?: SubscriptionResolverOpts['many'] & AuthValidationOpts } export interface CreateResolver> extends ServiceResolver { From 4d0e472d128d542ed7486300b16eba87a1d333db Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 29 Nov 2024 16:45:32 +1100 Subject: [PATCH 4/4] fix: existing test mocks --- .../services/assembler-query.service.spec.ts | 4 ++-- .../services/proxy-query.service.spec.ts | 4 ++-- .../resolvers/create.resolver.spec.ts | 20 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/core/__tests__/services/assembler-query.service.spec.ts b/packages/core/__tests__/services/assembler-query.service.spec.ts index 4031e9ccc..a4ba32d18 100644 --- a/packages/core/__tests__/services/assembler-query.service.spec.ts +++ b/packages/core/__tests__/services/assembler-query.service.spec.ts @@ -445,7 +445,7 @@ describe('AssemblerQueryService', () => { it('should transform the results for a single entity', () => { const mockQueryService = mock>() const assemblerService = new AssemblerQueryService(new TestAssembler(), instance(mockQueryService)) - when(mockQueryService.createOne(objectContaining({ bar: 'baz' }))).thenResolve({ + when(mockQueryService.createOne(objectContaining({ bar: 'baz' }), undefined)).thenResolve({ bar: 'baz' }) @@ -457,7 +457,7 @@ describe('AssemblerQueryService', () => { it('should transform the results for a single entity', () => { const mockQueryService = mock>() const assemblerService = new AssemblerQueryService(new TestAssembler(), instance(mockQueryService)) - when(mockQueryService.createMany(deepEqual([{ bar: 'baz' }]))).thenResolve([{ bar: 'baz' }]) + when(mockQueryService.createMany(deepEqual([{ bar: 'baz' }]), undefined)).thenResolve([{ bar: 'baz' }]) return expect(assemblerService.createMany([{ foo: 'baz' }])).resolves.toEqual([{ foo: 'baz' }]) }) diff --git a/packages/core/__tests__/services/proxy-query.service.spec.ts b/packages/core/__tests__/services/proxy-query.service.spec.ts index ff3c3f05a..69edbf14c 100644 --- a/packages/core/__tests__/services/proxy-query.service.spec.ts +++ b/packages/core/__tests__/services/proxy-query.service.spec.ts @@ -23,12 +23,12 @@ describe('ProxyQueryService', () => { }) it('should proxy to the underlying service when calling createMany', () => { const entities = [{ foo: 'bar' }] - when(mockQueryService.createMany(entities)).thenResolve(entities) + when(mockQueryService.createMany(entities, undefined)).thenResolve(entities) return expect(queryService.createMany(entities)).resolves.toBe(entities) }) it('should proxy to the underlying service when calling createOne', () => { const entity = { foo: 'bar' } - when(mockQueryService.createOne(entity)).thenResolve(entity) + when(mockQueryService.createOne(entity, undefined)).thenResolve(entity) return expect(queryService.createOne(entity)).resolves.toBe(entity) }) it('should proxy to the underlying service when calling deleteMany', () => { diff --git a/packages/query-graphql/__tests__/resolvers/create.resolver.spec.ts b/packages/query-graphql/__tests__/resolvers/create.resolver.spec.ts index 355a8b62a..181ec45fe 100644 --- a/packages/query-graphql/__tests__/resolvers/create.resolver.spec.ts +++ b/packages/query-graphql/__tests__/resolvers/create.resolver.spec.ts @@ -78,7 +78,7 @@ describe('CreateResolver', () => { id: 'id-1', stringField: 'foo' } - when(mockService.createOne(objectContaining(args.input))).thenResolve(output) + when(mockService.createOne(objectContaining(args.input), undefined)).thenResolve(output) const result = await resolver.createOne({ input: args }) return expect(result).toEqual(output) }) @@ -109,7 +109,7 @@ describe('CreateResolver', () => { stringField: 'foo' } ] - when(mockService.createMany(objectContaining(args.input))).thenResolve(output) + when(mockService.createMany(objectContaining(args.input), undefined)).thenResolve(output) const result = await resolver.createMany({ input: args }) return expect(result).toEqual(output) }) @@ -134,7 +134,7 @@ describe('CreateResolver', () => { } const eventName = getDTOEventName(EventType.CREATED, TestResolverDTO) const event = { [eventName]: output } - when(mockService.createOne(objectContaining(args.input))).thenResolve(output) + when(mockService.createOne(objectContaining(args.input), undefined)).thenResolve(output) when(mockPubSub.publish(eventName, deepEqual(event))).thenResolve() const result = await resolver.createOne({ input: args }) verify(mockPubSub.publish(eventName, deepEqual(event))).once() @@ -154,7 +154,7 @@ describe('CreateResolver', () => { } const eventName = getDTOEventName(EventType.CREATED, TestResolverDTO) const event = { [eventName]: output } - when(mockService.createOne(objectContaining(args.input))).thenResolve(output) + when(mockService.createOne(objectContaining(args.input), undefined)).thenResolve(output) when(mockPubSub.publish(eventName, deepEqual(event))).thenResolve() const result = await resolver.createOne({ input: args }) verify(mockPubSub.publish(eventName, deepEqual(event))).once() @@ -172,7 +172,7 @@ describe('CreateResolver', () => { id: 'id-1', stringField: 'foo' } - when(mockService.createOne(objectContaining(args.input))).thenResolve(output) + when(mockService.createOne(objectContaining(args.input), undefined)).thenResolve(output) const result = await resolver.createOne({ input: args }) verify(mockPubSub.publish(anything(), anything())).never() return expect(result).toEqual(output) @@ -192,7 +192,7 @@ describe('CreateResolver', () => { id: 'id-1', stringField: 'foo' } - when(mockService.createOne(objectContaining(args.input))).thenResolve(output) + when(mockService.createOne(objectContaining(args.input), undefined)).thenResolve(output) const result = await resolver.createOne({ input: args }) verify(mockPubSub.publish(anything(), anything())).never() return expect(result).toEqual(output) @@ -217,7 +217,7 @@ describe('CreateResolver', () => { ] const eventName = getDTOEventName(EventType.CREATED, TestResolverDTO) const events = output.map((o) => ({ [eventName]: o })) - when(mockService.createMany(objectContaining(args.input))).thenResolve(output) + when(mockService.createMany(objectContaining(args.input), undefined)).thenResolve(output) events.forEach((e) => when(mockPubSub.publish(eventName, deepEqual(e))).thenResolve()) const result = await resolver.createMany({ input: args }) events.forEach((e) => verify(mockPubSub.publish(eventName, deepEqual(e))).once()) @@ -241,7 +241,7 @@ describe('CreateResolver', () => { ] const eventName = getDTOEventName(EventType.CREATED, TestResolverDTO) const events = output.map((o) => ({ [eventName]: o })) - when(mockService.createMany(objectContaining(args.input))).thenResolve(output) + when(mockService.createMany(objectContaining(args.input), undefined)).thenResolve(output) events.forEach((e) => when(mockPubSub.publish(eventName, deepEqual(e))).thenResolve()) const result = await resolver.createMany({ input: args }) events.forEach((e) => verify(mockPubSub.publish(eventName, deepEqual(e))).once()) @@ -263,7 +263,7 @@ describe('CreateResolver', () => { stringField: 'foo' } ] - when(mockService.createMany(objectContaining(args.input))).thenResolve(output) + when(mockService.createMany(objectContaining(args.input), undefined)).thenResolve(output) const result = await resolver.createMany({ input: args }) verify(mockPubSub.publish(anything(), anything())).never() return expect(result).toEqual(output) @@ -287,7 +287,7 @@ describe('CreateResolver', () => { stringField: 'foo' } ] - when(mockService.createMany(objectContaining(args.input))).thenResolve(output) + when(mockService.createMany(objectContaining(args.input), undefined)).thenResolve(output) const result = await resolver.createMany({ input: args }) verify(mockPubSub.publish(anything(), anything())).never() return expect(result).toEqual(output)