Skip to content

Commit a50bdf7

Browse files
authored
feat: Make assemblers convert* methods async (#216)
BREAKING CHANGE: All `convert*` methods are now async. `convertAsyncTo*` methods are dropped in favor of async `convertTo`. Fixes #215
2 parents bab9a8c + ae7c3fb commit a50bdf7

File tree

6 files changed

+79
-145
lines changed

6 files changed

+79
-145
lines changed

packages/core/__tests__/assemblers/abstract.assembler.spec.ts

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -93,44 +93,16 @@ describe('ClassTransformerAssembler', () => {
9393
})
9494

9595
describe('convertToDTOs', () => {
96-
it('should call the convertToDTO implementation', () => {
96+
it('should call the convertToDTO implementation', async () => {
9797
const assembler = new TestAssembler()
98-
expect(assembler.convertToDTOs([testEntity])).toEqual([testDTO])
99-
})
100-
})
101-
102-
describe('convertAsyncToDTO', () => {
103-
it('should call the convertToDTO implementation with the resolved value', () => {
104-
const assembler = new TestAssembler()
105-
return expect(assembler.convertAsyncToDTO(Promise.resolve(testEntity))).resolves.toEqual(testDTO)
106-
})
107-
})
108-
109-
describe('convertAsyncToDTOs', () => {
110-
it('should call the convertToDTO implementation with the resolved value', () => {
111-
const assembler = new TestAssembler()
112-
return expect(assembler.convertAsyncToDTOs(Promise.resolve([testEntity]))).resolves.toEqual([testDTO])
98+
expect(await assembler.convertToDTOs([testEntity])).toEqual([testDTO])
11399
})
114100
})
115101

116102
describe('convertToEntities', () => {
117-
it('should call the convertToEntity implementation', () => {
118-
const assembler = new TestAssembler()
119-
expect(assembler.convertToEntities([testDTO])).toEqual([testEntity])
120-
})
121-
})
122-
123-
describe('convertAsyncToEntity', () => {
124-
it('should call the convertToEntity implementation with the resolved value', () => {
125-
const assembler = new TestAssembler()
126-
return expect(assembler.convertAsyncToEntity(Promise.resolve(testDTO))).resolves.toEqual(testEntity)
127-
})
128-
})
129-
130-
describe('convertAsyncToEntities', () => {
131-
it('should call the convertToEntity implementation with the resolved value', () => {
103+
it('should call the convertToEntity implementation', async () => {
132104
const assembler = new TestAssembler()
133-
return expect(assembler.convertAsyncToEntities(Promise.resolve([testDTO]))).resolves.toEqual([testEntity])
105+
expect(await assembler.convertToEntities([testDTO])).toEqual([testEntity])
134106
})
135107
})
136108
})

packages/core/src/assemblers/abstract.assembler.ts

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,49 +34,29 @@ export abstract class AbstractAssembler<DTO, Entity, C = DeepPartial<DTO>, CE =
3434
this.EntityClass = EntityClas
3535
}
3636

37-
abstract convertToDTO(entity: Entity): DTO
37+
public abstract convertToDTO(entity: Entity): Promise<DTO> | DTO
3838

39-
abstract convertToEntity(dto: DTO): Entity
39+
public abstract convertToEntity(dto: DTO): Promise<Entity> | Entity
4040

41-
abstract convertQuery(query: Query<DTO>): Query<Entity>
41+
public abstract convertQuery(query: Query<DTO>): Query<Entity>
4242

43-
abstract convertAggregateQuery(aggregate: AggregateQuery<DTO>): AggregateQuery<Entity>
43+
public abstract convertAggregateQuery(aggregate: AggregateQuery<DTO>): AggregateQuery<Entity>
4444

45-
abstract convertAggregateResponse(aggregate: AggregateResponse<Entity>): AggregateResponse<DTO>
45+
public abstract convertAggregateResponse(aggregate: AggregateResponse<Entity>): AggregateResponse<DTO>
4646

47-
abstract convertToCreateEntity(create: C): CE
47+
public abstract convertToCreateEntity(create: C): Promise<CE> | CE
4848

49-
abstract convertToUpdateEntity(update: U): UE
49+
public abstract convertToUpdateEntity(update: U): Promise<UE> | UE
5050

51-
convertToDTOs(entities: Entity[]): DTO[] {
52-
return entities.map((e) => this.convertToDTO(e))
51+
public convertToDTOs(entities: Entity[]): Promise<DTO[]> {
52+
return Promise.all(entities.map((e) => this.convertToDTO(e)))
5353
}
5454

55-
convertToEntities(dtos: DTO[]): Entity[] {
56-
return dtos.map((dto) => this.convertToEntity(dto))
55+
public convertToEntities(dtos: DTO[]): Promise<Entity[]> {
56+
return Promise.all(dtos.map((dto) => this.convertToEntity(dto)))
5757
}
5858

59-
convertToCreateEntities(createDtos: C[]): CE[] {
60-
return createDtos.map((c) => this.convertToCreateEntity(c))
61-
}
62-
63-
async convertAsyncToDTO(entity: Promise<Entity>): Promise<DTO> {
64-
const e = await entity
65-
return this.convertToDTO(e)
66-
}
67-
68-
async convertAsyncToDTOs(entities: Promise<Entity[]>): Promise<DTO[]> {
69-
const es = await entities
70-
return this.convertToDTOs(es)
71-
}
72-
73-
async convertAsyncToEntity(dto: Promise<DTO>): Promise<Entity> {
74-
const d = await dto
75-
return this.convertToEntity(d)
76-
}
77-
78-
async convertAsyncToEntities(dtos: Promise<DTO[]>): Promise<Entity[]> {
79-
const ds = await dtos
80-
return this.convertToEntities(ds)
59+
public convertToCreateEntities(createDtos: C[]): Promise<CE[]> {
60+
return Promise.all(createDtos.map((c) => this.convertToCreateEntity(c)))
8161
}
8262
}

packages/core/src/assemblers/assembler.ts

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ export interface Assembler<
1414
* Convert an entity to a DTO
1515
* @param entity - the entity to convert
1616
*/
17-
convertToDTO(entity: Entity): DTO
17+
convertToDTO(entity: Entity): Promise<DTO> | DTO
1818

1919
/**
2020
* Convert a DTO to an entity.
2121
* @param dto - The dto to convert.
2222
*/
23-
convertToEntity(dto: DTO): Entity
23+
convertToEntity(dto: DTO): Promise<Entity> | Entity
2424

2525
/**
2626
* Convert a DTO query to an entity query.
@@ -44,55 +44,31 @@ export interface Assembler<
4444
* Convert a create dto input to the equivalent create entity type
4545
* @param createDTO
4646
*/
47-
convertToCreateEntity(createDTO: CreateDTO): CreateEntity
47+
convertToCreateEntity(createDTO: CreateDTO): Promise<CreateEntity> | CreateEntity
4848

4949
/**
5050
* Convert a update dto input to the equivalent update entity type
5151
* @param createDTO
5252
*/
53-
convertToUpdateEntity(createDTO: UpdateDTO): UpdateEntity
53+
convertToUpdateEntity(createDTO: UpdateDTO): Promise<UpdateEntity> | UpdateEntity
5454

5555
/**
5656
* Convert an array of entities to a an of DTOs
5757
* @param entities - the entities to convert.
5858
*/
59-
convertToDTOs(entities: Entity[]): DTO[]
59+
convertToDTOs(entities: Entity[]): Promise<DTO[]>
6060

6161
/**
6262
* Convert an array of DTOs to an array of entities.
6363
* @param dtos - the dtos to convert.
6464
*/
65-
convertToEntities(dtos: DTO[]): Entity[]
66-
67-
/**
68-
* Convert an entity to a DTO.
69-
* @param entity - the promise that should resolve with the entity.
70-
*/
71-
convertAsyncToDTO(entity: Promise<Entity>): Promise<DTO>
72-
73-
/**
74-
* Convert an array of entities to an array of DTOs.
75-
* @param entities - the promise that should resolve with the entity array.
76-
*/
77-
convertAsyncToDTOs(entities: Promise<Entity[]>): Promise<DTO[]>
78-
79-
/**
80-
* Convert a DTO to an entity.
81-
* @param dto - the promise that should resolve with the DTO.
82-
*/
83-
convertAsyncToEntity(dto: Promise<DTO>): Promise<Entity>
84-
85-
/**
86-
* Convert an array of DTOs to an array of entities.
87-
* @param dtos - the promise that should resolve with the dtos.
88-
*/
89-
convertAsyncToEntities(dtos: Promise<DTO[]>): Promise<Entity[]>
65+
convertToEntities(dtos: DTO[]): Promise<Entity[]>
9066

9167
/**
9268
* Convert an array of create DTOs to an array of create entities
9369
* @param createDtos
9470
*/
95-
convertToCreateEntities(createDtos: CreateDTO[]): CreateEntity[]
71+
convertToCreateEntities(createDtos: CreateDTO[]): Promise<CreateEntity[]>
9672
}
9773

9874
const assemblerReflector = new ValueReflector(ASSEMBLER_CLASSES_KEY)

packages/core/src/services/assembler-query.service.ts

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,35 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
2828
readonly queryService: QueryService<Entity, CE, UE>
2929
) {}
3030

31-
public addRelations<Relation>(
31+
public async addRelations<Relation>(
3232
relationName: string,
3333
id: string | number,
3434
relationIds: (string | number)[],
3535
opts?: ModifyRelationOptions<DTO, Relation>
3636
): Promise<DTO> {
37-
return this.assembler.convertAsyncToDTO(
38-
this.queryService.addRelations(relationName, id, relationIds, this.convertModifyRelationsOptions(opts))
37+
return this.assembler.convertToDTO(
38+
await this.queryService.addRelations(relationName, id, relationIds, this.convertModifyRelationsOptions(opts))
3939
)
4040
}
4141

42-
public createMany(items: C[]): Promise<DTO[]> {
42+
public async createMany(items: C[]): Promise<DTO[]> {
4343
const { assembler } = this
44-
const converted = assembler.convertToCreateEntities(items)
45-
return this.assembler.convertAsyncToDTOs(this.queryService.createMany(converted))
44+
const converted = await assembler.convertToCreateEntities(items)
45+
return this.assembler.convertToDTOs(await this.queryService.createMany(converted))
4646
}
4747

48-
public createOne(item: C): Promise<DTO> {
49-
const c = this.assembler.convertToCreateEntity(item)
50-
return this.assembler.convertAsyncToDTO(this.queryService.createOne(c))
48+
public async createOne(item: C): Promise<DTO> {
49+
const c = await this.assembler.convertToCreateEntity(item)
50+
return this.assembler.convertToDTO(await this.queryService.createOne(c))
5151
}
5252

5353
public async deleteMany(filter: Filter<DTO>): Promise<DeleteManyResponse> {
5454
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
5555
return this.queryService.deleteMany(this.assembler.convertQuery({ filter }).filter)
5656
}
5757

58-
public deleteOne(id: number | string, opts?: DeleteOneOptions<DTO>): Promise<DTO> {
59-
return this.assembler.convertAsyncToDTO(this.queryService.deleteOne(id, this.convertFilterable(opts)))
58+
public async deleteOne(id: number | string, opts?: DeleteOneOptions<DTO>): Promise<DTO> {
59+
return this.assembler.convertToDTO(await this.queryService.deleteOne(id, this.convertFilterable(opts)))
6060
}
6161

6262
public async findById(id: string | number, opts?: FindByIdOptions<DTO>): Promise<DTO | undefined> {
@@ -67,12 +67,12 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
6767
return this.assembler.convertToDTO(entity)
6868
}
6969

70-
public getById(id: string | number, opts?: GetByIdOptions<DTO>): Promise<DTO> {
71-
return this.assembler.convertAsyncToDTO(this.queryService.getById(id, this.convertFilterable(opts)))
70+
public async getById(id: string | number, opts?: GetByIdOptions<DTO>): Promise<DTO> {
71+
return this.assembler.convertToDTO(await this.queryService.getById(id, this.convertFilterable(opts)))
7272
}
7373

74-
public query(query: Query<DTO>, opts?: QueryOptions<DTO>): Promise<DTO[]> {
75-
return this.assembler.convertAsyncToDTOs(this.queryService.query(this.assembler.convertQuery(query), opts as never))
74+
public async query(query: Query<DTO>, opts?: QueryOptions<DTO>): Promise<DTO[]> {
75+
return this.assembler.convertToDTOs(await this.queryService.query(this.assembler.convertQuery(query), opts as never))
7676
}
7777

7878
public async aggregate(
@@ -128,7 +128,7 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
128128
query: Query<Relation>
129129
): Promise<Relation[] | Map<DTO, Relation[]>> {
130130
if (Array.isArray(dto)) {
131-
const entities = this.assembler.convertToEntities(dto)
131+
const entities = await this.assembler.convertToEntities(dto)
132132
const relationMap = await this.queryService.queryRelations(RelationClass, relationName, entities, query)
133133

134134
return entities.reduce((map, e, index) => {
@@ -140,7 +140,7 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
140140
}, new Map<DTO, Relation[]>())
141141
}
142142

143-
return this.queryService.queryRelations(RelationClass, relationName, this.assembler.convertToEntity(dto), query)
143+
return this.queryService.queryRelations(RelationClass, relationName, await this.assembler.convertToEntity(dto), query)
144144
}
145145

146146
public countRelations<Relation>(
@@ -164,15 +164,15 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
164164
filter: Filter<Relation>
165165
): Promise<number | Map<DTO, number>> {
166166
if (Array.isArray(dto)) {
167-
const entities = this.assembler.convertToEntities(dto)
167+
const entities = await this.assembler.convertToEntities(dto)
168168
const relationMap = await this.queryService.countRelations(RelationClass, relationName, entities, filter)
169169
return entities.reduce((map, e, index) => {
170170
const entry = relationMap.get(e) ?? 0
171171
map.set(dto[index], entry)
172172
return map
173173
}, new Map<DTO, number>())
174174
}
175-
return this.queryService.countRelations(RelationClass, relationName, this.assembler.convertToEntity(dto), filter)
175+
return this.queryService.countRelations(RelationClass, relationName, await this.assembler.convertToEntity(dto), filter)
176176
}
177177

178178
/**
@@ -210,71 +210,71 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
210210
opts?: FindRelationOptions<Relation>
211211
): Promise<(Relation | undefined) | Map<DTO, Relation | undefined>> {
212212
if (Array.isArray(dto)) {
213-
const entities = this.assembler.convertToEntities(dto)
213+
const entities = await this.assembler.convertToEntities(dto)
214214
const relationMap = await this.queryService.findRelation(RelationClass, relationName, entities, opts)
215215
return entities.reduce((map, e, index) => {
216216
map.set(dto[index], relationMap.get(e))
217217
return map
218218
}, new Map<DTO, Relation | undefined>())
219219
}
220-
return this.queryService.findRelation(RelationClass, relationName, this.assembler.convertToEntity(dto))
220+
return this.queryService.findRelation(RelationClass, relationName, await this.assembler.convertToEntity(dto))
221221
}
222222

223-
public removeRelation<Relation>(
223+
public async removeRelation<Relation>(
224224
relationName: string,
225225
id: string | number,
226226
relationId: string | number,
227227
opts?: ModifyRelationOptions<DTO, Relation>
228228
): Promise<DTO> {
229-
return this.assembler.convertAsyncToDTO(
230-
this.queryService.removeRelation(relationName, id, relationId, this.convertModifyRelationsOptions(opts))
229+
return this.assembler.convertToDTO(
230+
await this.queryService.removeRelation(relationName, id, relationId, this.convertModifyRelationsOptions(opts))
231231
)
232232
}
233233

234-
public removeRelations<Relation>(
234+
public async removeRelations<Relation>(
235235
relationName: string,
236236
id: string | number,
237237
relationIds: (string | number)[],
238238
opts?: ModifyRelationOptions<DTO, Relation>
239239
): Promise<DTO> {
240-
return this.assembler.convertAsyncToDTO(
241-
this.queryService.removeRelations(relationName, id, relationIds, this.convertModifyRelationsOptions(opts))
240+
return this.assembler.convertToDTO(
241+
await this.queryService.removeRelations(relationName, id, relationIds, this.convertModifyRelationsOptions(opts))
242242
)
243243
}
244244

245-
public setRelations<Relation>(
245+
public async setRelations<Relation>(
246246
relationName: string,
247247
id: string | number,
248248
relationIds: (string | number)[],
249249
opts?: ModifyRelationOptions<DTO, Relation>
250250
): Promise<DTO> {
251-
return this.assembler.convertAsyncToDTO(
252-
this.queryService.setRelations(relationName, id, relationIds, this.convertModifyRelationsOptions(opts))
251+
return this.assembler.convertToDTO(
252+
await this.queryService.setRelations(relationName, id, relationIds, this.convertModifyRelationsOptions(opts))
253253
)
254254
}
255255

256-
public setRelation<Relation>(
256+
public async setRelation<Relation>(
257257
relationName: string,
258258
id: string | number,
259259
relationId: string | number,
260260
opts?: ModifyRelationOptions<DTO, Relation>
261261
): Promise<DTO> {
262-
return this.assembler.convertAsyncToDTO(
263-
this.queryService.setRelation(relationName, id, relationId, this.convertModifyRelationsOptions(opts))
262+
return this.assembler.convertToDTO(
263+
await this.queryService.setRelation(relationName, id, relationId, this.convertModifyRelationsOptions(opts))
264264
)
265265
}
266266

267-
public updateMany(update: U, filter: Filter<DTO>): Promise<UpdateManyResponse> {
267+
public async updateMany(update: U, filter: Filter<DTO>): Promise<UpdateManyResponse> {
268268
return this.queryService.updateMany(
269-
this.assembler.convertToUpdateEntity(update),
269+
await this.assembler.convertToUpdateEntity(update),
270270
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
271271
this.assembler.convertQuery({ filter }).filter
272272
)
273273
}
274274

275-
public updateOne(id: string | number, update: U, opts?: UpdateOneOptions<DTO>): Promise<DTO> {
276-
return this.assembler.convertAsyncToDTO(
277-
this.queryService.updateOne(id, this.assembler.convertToUpdateEntity(update), this.convertFilterable(opts))
275+
public async updateOne(id: string | number, update: U, opts?: UpdateOneOptions<DTO>): Promise<DTO> {
276+
return this.assembler.convertToDTO(
277+
await this.queryService.updateOne(id, await this.assembler.convertToUpdateEntity(update), this.convertFilterable(opts))
278278
)
279279
}
280280

@@ -300,7 +300,7 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
300300
aggregate: AggregateQuery<Relation>
301301
): Promise<AggregateResponse<Relation>[] | Map<DTO, AggregateResponse<Relation>[]>> {
302302
if (Array.isArray(dto)) {
303-
const entities = this.assembler.convertToEntities(dto)
303+
const entities = await this.assembler.convertToEntities(dto)
304304
const relationMap = await this.queryService.aggregateRelations(RelationClass, relationName, entities, filter, aggregate)
305305
return entities.reduce((map, e, index) => {
306306
const entry = relationMap.get(e) ?? []
@@ -311,7 +311,7 @@ export class AssemblerQueryService<DTO, Entity, C = DeepPartial<DTO>, CE = DeepP
311311
return this.queryService.aggregateRelations(
312312
RelationClass,
313313
relationName,
314-
this.assembler.convertToEntity(dto),
314+
await this.assembler.convertToEntity(dto),
315315
filter,
316316
aggregate
317317
)

0 commit comments

Comments
 (0)