@koalarx/nest 3.1.12 → 3.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,13 @@ import { EntityBase } from './entity.base';
2
2
  type EntityProps<T> = Omit<{
3
3
  [K in keyof T as T[K] extends Function ? never : K]: T[K];
4
4
  }, '_id' | '_action'>;
5
- export declare function Entity<T extends new (...args: any[]) => EntityBase<any>>(id?: keyof EntityProps<InstanceType<T>>): (target: T) => {
5
+ export type CompositeId = readonly (string | number)[];
6
+ export interface IdConfig<T extends EntityProps<any>> {
7
+ single?: keyof T;
8
+ composite?: readonly (keyof T)[];
9
+ custom?: (props: T) => string | number | CompositeId;
10
+ }
11
+ export declare function Entity<T extends new (...args: any[]) => EntityBase<any>>(id?: keyof EntityProps<InstanceType<T>> | IdConfig<EntityProps<InstanceType<T>>>): (target: T) => {
6
12
  new (...args: any[]): {
7
13
  _id: import("../utils/interfaces/icomparable").IComparableId;
8
14
  _action: import("./entity.base").EntityActionType;
@@ -1,6 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Entity = Entity;
4
+ function normalizeIdConfig(id) {
5
+ if (!id)
6
+ return undefined;
7
+ if (typeof id === 'string' || typeof id === 'symbol') {
8
+ return { single: id };
9
+ }
10
+ return id;
11
+ }
4
12
  function Entity(id) {
5
13
  return function (target) {
6
14
  class NewConstructor extends target {
@@ -17,7 +25,8 @@ function Entity(id) {
17
25
  value: target.name,
18
26
  writable: false,
19
27
  });
20
- Reflect.defineMetadata('entity:id', id, NewConstructor.prototype);
28
+ const idConfig = normalizeIdConfig(id);
29
+ Reflect.defineMetadata('entity:id', idConfig, NewConstructor.prototype);
21
30
  return NewConstructor;
22
31
  };
23
32
  }
@@ -15,7 +15,9 @@ export declare abstract class RepositoryBase<TEntity extends EntityBase<TEntity>
15
15
  private readonly _includeFindMany?;
16
16
  constructor({ context, modelName }: RepositoryInitProps<TEntity, TContext>);
17
17
  private getIdPropName;
18
+ private getWhereByIdSchema;
18
19
  private getConnectPrismaSchemaForRelation;
20
+ private checkIdHasValue;
19
21
  private getSelectRootPrismaSchema;
20
22
  private getSelectWithRelationsId;
21
23
  private getPropNameFromEntitySource;
@@ -26,6 +28,7 @@ export declare abstract class RepositoryBase<TEntity extends EntityBase<TEntity>
26
28
  private findManySchema;
27
29
  private createEntity;
28
30
  private orphanRemoval;
31
+ private getIdOnEntity;
29
32
  private loadRelationForEntity;
30
33
  private enrichEntityWithRelations;
31
34
  private persistRelations;
@@ -22,16 +22,40 @@ class RepositoryBase {
22
22
  });
23
23
  }
24
24
  getIdPropName(entity) {
25
- return (Reflect.getMetadata('entity:id', entity ? entity.constructor.prototype : this._modelName.prototype) ?? 'id');
25
+ const idConfig = Reflect.getMetadata('entity:id', entity ? entity.constructor.prototype : this._modelName.prototype);
26
+ if (idConfig) {
27
+ if (idConfig.single) {
28
+ return idConfig.single;
29
+ }
30
+ else if (idConfig.composite) {
31
+ return idConfig.composite;
32
+ }
33
+ }
34
+ return 'id';
26
35
  }
27
- getConnectPrismaSchemaForRelation(entity, data) {
36
+ getWhereByIdSchema(entity, value) {
28
37
  const propIdName = this.getIdPropName(entity);
38
+ if (Array.isArray(propIdName)) {
39
+ const whereSchema = {};
40
+ propIdName.forEach((propName) => {
41
+ whereSchema[propName] =
42
+ typeof value === 'object' ? value[propName] : value;
43
+ });
44
+ return whereSchema;
45
+ }
29
46
  return {
30
- connect: {
31
- [propIdName]: (data ?? entity)[propIdName],
32
- },
47
+ [propIdName]: typeof value === 'object' ? value[propIdName] : value,
33
48
  };
34
49
  }
50
+ getConnectPrismaSchemaForRelation(entity, data) {
51
+ return {
52
+ connect: this.getWhereByIdSchema(entity, data ?? entity),
53
+ };
54
+ }
55
+ checkIdHasValue(entity, value) {
56
+ const result = this.getWhereByIdSchema(entity, value);
57
+ return Object.values(result).every((val) => val !== undefined && val !== null);
58
+ }
35
59
  getSelectRootPrismaSchema(entity) {
36
60
  const selectSchema = {};
37
61
  Object.keys(entity)
@@ -62,18 +86,14 @@ class RepositoryBase {
62
86
  }
63
87
  if (instance instanceof entity_base_1.EntityBase) {
64
88
  selectSchema[prop.name] = {
65
- select: {
66
- [this.getIdPropName(entity[prop.name])]: true,
67
- },
89
+ select: this.getWhereByIdSchema(instance, true),
68
90
  };
69
91
  }
70
92
  else if (instance instanceof list_1.List) {
71
93
  const list = new entity()[prop.name];
72
94
  const entityInstance = list.entityType;
73
95
  selectSchema[prop.name] = {
74
- select: {
75
- [this.getIdPropName(entityInstance)]: true,
76
- },
96
+ select: this.getWhereByIdSchema(new entityInstance(), true),
77
97
  };
78
98
  }
79
99
  else {
@@ -174,12 +194,10 @@ class RepositoryBase {
174
194
  .forEach((key) => {
175
195
  if (entity[key] instanceof entity_base_1.EntityBase) {
176
196
  if (entity[key]._action === entity_base_1.EntityActionType.create) {
177
- if (entity[key][this.getIdPropName(entity)]) {
197
+ if (entity[key] && this.checkIdHasValue(entity, entity[key])) {
178
198
  prismaSchema[key] = {
179
199
  connectOrCreate: {
180
- where: {
181
- [this.getIdPropName(entity)]: entity[key][this.getIdPropName(entity)],
182
- },
200
+ where: this.getWhereByIdSchema(entity[key].constructor, entity[key]),
183
201
  create: this.entityToPrisma(entity[key]),
184
202
  },
185
203
  };
@@ -237,15 +255,28 @@ class RepositoryBase {
237
255
  .forEach((key) => (where[key] = entity[key]));
238
256
  return client[(0, KlString_1.toCamelCase)(entity.constructor.name)].delete({ where });
239
257
  }
240
- async loadRelationForEntity(where, entity) {
258
+ getIdOnEntity(entity, data) {
259
+ const propIdName = this.getIdPropName(entity);
260
+ if (Array.isArray(propIdName)) {
261
+ const idValues = [];
262
+ propIdName.forEach((propName) => {
263
+ idValues.push(data[propName]);
264
+ });
265
+ return idValues.join('-');
266
+ }
267
+ return data[propIdName];
268
+ }
269
+ async loadRelationForEntity(where, entity, cache) {
241
270
  return this._context[(0, KlString_1.toCamelCase)((0, KlString_1.toCamelCase)(entity.name))]
242
- .findUnique({
271
+ .findFirst({
243
272
  select: this.getSelectWithRelationsId(entity),
244
273
  where,
245
274
  })
246
- .then((data) => this.enrichEntityWithRelations(entity, data));
275
+ .then((data) => this.enrichEntityWithRelations(entity, data, cache));
247
276
  }
248
- async enrichEntityWithRelations(entity, data) {
277
+ async enrichEntityWithRelations(entity, data, cache = new Map()) {
278
+ if (!data)
279
+ return data;
249
280
  const relationQueries = [];
250
281
  const relationKeys = [];
251
282
  const allProps = auto_mapping_list_1.AutoMappingList.getAllProps(entity);
@@ -258,17 +289,27 @@ class RepositoryBase {
258
289
  relationKeys.push(propName);
259
290
  const items = [];
260
291
  data[propName].forEach((item) => {
261
- items.push(this.loadRelationForEntity(item, entityInstance));
292
+ const cacheKey = `${entity.constructor.name}-${propName}-${this.getIdOnEntity(new entityInstance(), item)}`;
293
+ if (cache.has(cacheKey)) {
294
+ items.push(Promise.resolve(cache.get(cacheKey)));
295
+ return;
296
+ }
297
+ cache.set(cacheKey, item);
298
+ items.push(this.loadRelationForEntity(item, entityInstance, cache));
262
299
  });
263
300
  relationQueries.push(Promise.all(items));
264
301
  return;
265
302
  }
266
303
  const relationEntity = auto_mapping_list_1.AutoMappingList.getSourceByName(propDef?.type ?? '');
267
- if (relationEntity) {
304
+ if (relationEntity && data[propName]) {
305
+ const cacheKey = `${entity.constructor.name}-${propName}-${this.getIdOnEntity(new relationEntity(), data[propName])}`;
306
+ if (cache.has(cacheKey)) {
307
+ data[propName] = cache.get(cacheKey);
308
+ return;
309
+ }
310
+ cache.set(cacheKey, data[propName]);
268
311
  relationKeys.push(propName);
269
- relationQueries.push(this.loadRelationForEntity({
270
- [this.getIdPropName(relationEntity)]: data[propName][this.getIdPropName(relationEntity)],
271
- }, relationEntity));
312
+ relationQueries.push(this.loadRelationForEntity(this.getWhereByIdSchema(relationEntity, data[propName]), relationEntity, cache));
272
313
  }
273
314
  });
274
315
  if (relationQueries.length > 0) {
@@ -285,6 +326,9 @@ class RepositoryBase {
285
326
  ...relationCreates.map((relationCreate) => transaction[relationCreate.modelName]
286
327
  .create(relationCreate.schema)
287
328
  .then((response) => {
329
+ if (relationCreate.relations.length === 0) {
330
+ return Promise.all([]);
331
+ }
288
332
  return Promise.all(relationCreate.relations.map((relation) => {
289
333
  const relationPropName = this.getPropNameFromEntitySource(relation, relationCreate.entityInstance);
290
334
  if (relationPropName &&
@@ -298,8 +342,15 @@ class RepositoryBase {
298
342
  select: this.getSelectRootPrismaSchema(relation),
299
343
  })
300
344
  .then((response) => {
301
- relation[this.getIdPropName(relation)] =
302
- response[this.getIdPropName(relation)];
345
+ const idPropName = this.getIdPropName(relation);
346
+ if (!Array.isArray(idPropName)) {
347
+ relation[idPropName] = response[idPropName];
348
+ }
349
+ else {
350
+ idPropName.forEach((propName) => {
351
+ relation[propName] = response[propName];
352
+ });
353
+ }
303
354
  return this.persistRelations(transaction, relation);
304
355
  });
305
356
  }));
@@ -321,11 +372,13 @@ class RepositoryBase {
321
372
  async findById(id) {
322
373
  const data = await this.context().findFirst({
323
374
  select: this.getSelectWithRelationsId(this._modelName.prototype.constructor),
324
- where: { [this.getIdPropName()]: id },
375
+ where: this.getWhereByIdSchema(this._modelName.prototype.constructor, {
376
+ id,
377
+ }),
325
378
  });
326
379
  if (!data)
327
380
  return null;
328
- const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, data);
381
+ const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, { ...data });
329
382
  return this.createEntity(enrichedEntity);
330
383
  }
331
384
  async findFirst(where) {
@@ -335,7 +388,7 @@ class RepositoryBase {
335
388
  });
336
389
  if (!data)
337
390
  return null;
338
- const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, data);
391
+ const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, { ...data });
339
392
  return this.createEntity(enrichedEntity);
340
393
  }
341
394
  async findUnique(where) {
@@ -345,7 +398,7 @@ class RepositoryBase {
345
398
  });
346
399
  if (!data)
347
400
  return null;
348
- const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, data);
401
+ const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, { ...data });
349
402
  return this.createEntity(enrichedEntity);
350
403
  }
351
404
  async findMany(where, pagination) {
@@ -370,7 +423,15 @@ class RepositoryBase {
370
423
  include: this.getInclude(),
371
424
  })
372
425
  .then((response) => {
373
- entity[this.getIdPropName()] = response[this.getIdPropName()];
426
+ const idPropName = this.getIdPropName(entity);
427
+ if (!Array.isArray(idPropName)) {
428
+ entity[idPropName] = response[idPropName];
429
+ }
430
+ else {
431
+ idPropName.forEach((propName) => {
432
+ entity[propName] = response[propName];
433
+ });
434
+ }
374
435
  return this.persistRelations(client, entity).then(() => entity);
375
436
  }));
376
437
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koalarx/nest",
3
- "version": "3.1.12",
3
+ "version": "3.1.14",
4
4
  "description": "",
5
5
  "author": "Igor D. Rangel",
6
6
  "license": "MIT",