@koalarx/nest 3.1.28 → 3.1.29

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.
@@ -14,6 +14,7 @@ export declare abstract class RepositoryBase<TEntity extends EntityBase<TEntity>
14
14
  private readonly _modelName;
15
15
  private readonly _includeFindMany?;
16
16
  constructor({ context, modelName }: RepositoryInitProps<TEntity, TContext>);
17
+ private get entityInstance();
17
18
  private getIdPropName;
18
19
  private getWhereByIdSchema;
19
20
  private getConnectPrismaSchemaForRelation;
@@ -30,6 +31,7 @@ export declare abstract class RepositoryBase<TEntity extends EntityBase<TEntity>
30
31
  private orphanRemoval;
31
32
  private getIdOnEntity;
32
33
  private loadRelationForEntity;
34
+ private loadEntityFromCache;
33
35
  private enrichEntityWithRelations;
34
36
  private persistRelations;
35
37
  protected context(transactionalClient?: TContext): TContext[TModelKey];
@@ -6,9 +6,10 @@ const pagination_dto_1 = require("../dtos/pagination.dto");
6
6
  const koala_global_vars_1 = require("../koala-global-vars");
7
7
  const auto_mapping_list_1 = require("../mapping/auto-mapping-list");
8
8
  const generate_prisma_include_schema_1 = require("../utils/generate-prisma-include-schema");
9
+ const hydrate_entity_from_cache_1 = require("../utils/hydrate-entity-from-cache");
9
10
  const list_1 = require("../utils/list");
10
- const entity_base_1 = require("./entity.base");
11
11
  const proxy_1 = require("../utils/proxy");
12
+ const entity_base_1 = require("./entity.base");
12
13
  class RepositoryBase {
13
14
  _context;
14
15
  _modelName;
@@ -22,6 +23,9 @@ class RepositoryBase {
22
23
  entity: this._modelName,
23
24
  });
24
25
  }
26
+ get entityInstance() {
27
+ return this._modelName.prototype.constructor;
28
+ }
25
29
  getIdPropName(entity) {
26
30
  const idConfig = Reflect.getMetadata('entity:id', entity ? entity.constructor.prototype : this._modelName.prototype);
27
31
  if (idConfig) {
@@ -310,6 +314,24 @@ class RepositoryBase {
310
314
  })
311
315
  .then((data) => this.enrichEntityWithRelations(entity, (0, proxy_1.createProxy)(data), cache));
312
316
  }
317
+ loadEntityFromCache(entity, data, cache) {
318
+ return (0, hydrate_entity_from_cache_1.hydrateEntityFromCache)({
319
+ entity: entity,
320
+ data,
321
+ cache,
322
+ dependencies: {
323
+ getAllProps: (sourceEntity) => auto_mapping_list_1.AutoMappingList.getAllProps(sourceEntity),
324
+ getPropDefinitions: (sourceEntity, propName) => auto_mapping_list_1.AutoMappingList.getPropDefinitions(sourceEntity, propName),
325
+ getSourceByName: (sourceName) => auto_mapping_list_1.AutoMappingList.getSourceByName(sourceName),
326
+ getListEntityType: (sourceEntity, propName) => {
327
+ const list = new sourceEntity()[propName];
328
+ return list.entityType;
329
+ },
330
+ getIdOnEntity: (currentEntity, value) => this.getIdOnEntity(currentEntity, value),
331
+ createEntity: (sourceEntity) => new sourceEntity(),
332
+ },
333
+ });
334
+ }
313
335
  async enrichEntityWithRelations(entity, data, cache = new Map()) {
314
336
  if (!data) {
315
337
  return null;
@@ -321,31 +343,24 @@ class RepositoryBase {
321
343
  if (propDef?.type === list_1.List.name) {
322
344
  const list = new entity()[prop.name];
323
345
  const entityInstance = list.entityType;
324
- const items = [];
325
346
  for (const item of data[propName] || []) {
326
- const cacheKey = `${entity.name}-${this.getIdOnEntity(new entityInstance(), item)}`;
347
+ const cacheKey = `${entityInstance.name}-${this.getIdOnEntity(new entityInstance(), item)}`;
327
348
  if (cache.has(cacheKey)) {
328
- items.push(cache.get(cacheKey));
329
349
  continue;
330
350
  }
331
351
  cache.set(cacheKey, item);
332
- const enrichedItem = await this.loadRelationForEntity(this.getWhereByIdSchema(new entityInstance(), item), entityInstance, cache);
333
- cache.set(cacheKey, enrichedItem);
334
- items.push(enrichedItem);
352
+ await this.loadRelationForEntity(this.getWhereByIdSchema(new entityInstance(), item), entityInstance, cache).then((response) => cache.set(cacheKey, response));
335
353
  }
336
- data[propName] = items;
337
354
  continue;
338
355
  }
339
356
  const relationEntity = auto_mapping_list_1.AutoMappingList.getSourceByName(propDef?.type ?? '');
340
357
  if (relationEntity && data[propName]) {
341
- const cacheKey = `${entity.name}-${this.getIdOnEntity(new relationEntity(), data[propName])}`;
358
+ const cacheKey = `${relationEntity.name}-${this.getIdOnEntity(new relationEntity(), data[propName])}`;
342
359
  if (cache.has(cacheKey)) {
343
- data[propName] = cache.get(cacheKey);
344
360
  continue;
345
361
  }
346
362
  cache.set(cacheKey, data[propName]);
347
- data[propName] = await this.loadRelationForEntity(this.getWhereByIdSchema(new relationEntity(), data[propName]), relationEntity, cache);
348
- cache.set(cacheKey, data[propName]);
363
+ await this.loadRelationForEntity(this.getWhereByIdSchema(new relationEntity(), data[propName]), relationEntity, cache).then((response) => cache.set(cacheKey, response));
349
364
  }
350
365
  }
351
366
  return data;
@@ -411,35 +426,41 @@ class RepositoryBase {
411
426
  }
412
427
  async findById(id) {
413
428
  const data = await this.context().findFirst({
414
- select: this.getSelectWithRelationsId(this._modelName.prototype.constructor),
415
- where: this.getWhereByIdSchema(this._modelName.prototype.constructor, {
429
+ select: this.getSelectWithRelationsId(this.entityInstance),
430
+ where: this.getWhereByIdSchema(this.entityInstance, {
416
431
  id,
417
432
  }),
418
433
  });
419
434
  if (!data)
420
435
  return null;
421
- const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, (0, proxy_1.createProxy)(data));
422
- return this.createEntity(enrichedEntity);
436
+ const cache = new Map();
437
+ return this.enrichEntityWithRelations(this.entityInstance, (0, proxy_1.createProxy)(data), cache)
438
+ .then((response) => this.loadEntityFromCache(this.entityInstance, response, cache))
439
+ .then((response) => this.createEntity(response));
423
440
  }
424
441
  async findFirst(where) {
425
442
  const data = await this.context().findFirst({
426
- select: this.getSelectWithRelationsId(this._modelName.prototype.constructor),
443
+ select: this.getSelectWithRelationsId(this.entityInstance),
427
444
  where,
428
445
  });
429
446
  if (!data)
430
447
  return null;
431
- const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, (0, proxy_1.createProxy)(data));
432
- return this.createEntity(enrichedEntity);
448
+ const cache = new Map();
449
+ return this.enrichEntityWithRelations(this.entityInstance, (0, proxy_1.createProxy)(data), cache)
450
+ .then((response) => this.loadEntityFromCache(this.entityInstance, response, cache))
451
+ .then((response) => this.createEntity(response));
433
452
  }
434
453
  async findUnique(where) {
435
454
  const data = await this.context().findUnique({
436
- select: this.getSelectWithRelationsId(this._modelName.prototype.constructor),
455
+ select: this.getSelectWithRelationsId(this.entityInstance),
437
456
  where,
438
457
  });
439
458
  if (!data)
440
459
  return null;
441
- const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, (0, proxy_1.createProxy)(data));
442
- return this.createEntity(enrichedEntity);
460
+ const cache = new Map();
461
+ return this.enrichEntityWithRelations(this.entityInstance, (0, proxy_1.createProxy)(data), cache)
462
+ .then((response) => this.loadEntityFromCache(this.entityInstance, response, cache))
463
+ .then((response) => this.createEntity(response));
443
464
  }
444
465
  async findMany(where, pagination) {
445
466
  return this.context()
@@ -0,0 +1,22 @@
1
+ import { Type } from '@nestjs/common';
2
+ export type GraphVisitState = 'loading' | 'loaded';
3
+ export interface HydrateEntityFromCacheDependencies {
4
+ getAllProps(entity: Type<any>): Array<{
5
+ name: string;
6
+ }>;
7
+ getPropDefinitions(entity: Type<any>, propName: string): {
8
+ type?: string;
9
+ } | undefined;
10
+ getSourceByName(sourceName: string): Type<any> | undefined;
11
+ getListEntityType(entity: Type<any>, propName: string): Type<any> | undefined;
12
+ getIdOnEntity(entity: any, data: any): string;
13
+ createEntity(entity: Type<any>): any;
14
+ }
15
+ export interface HydrateEntityFromCacheParams {
16
+ entity: Type<any>;
17
+ data: any;
18
+ cache: Map<string, any>;
19
+ dependencies: HydrateEntityFromCacheDependencies;
20
+ visitState?: Map<string, GraphVisitState>;
21
+ }
22
+ export declare function hydrateEntityFromCache({ entity, data, cache, dependencies, visitState, }: HydrateEntityFromCacheParams): any;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hydrateEntityFromCache = hydrateEntityFromCache;
4
+ function mergeScalarProps(target, source) {
5
+ Object.keys(source || {}).forEach((key) => {
6
+ const value = source[key];
7
+ if (value === undefined) {
8
+ return;
9
+ }
10
+ if (Array.isArray(value)) {
11
+ return;
12
+ }
13
+ if (value !== null && typeof value === 'object') {
14
+ return;
15
+ }
16
+ target[key] = value;
17
+ });
18
+ }
19
+ function getCacheKey(entity, data, dependencies) {
20
+ const entityId = dependencies.getIdOnEntity(dependencies.createEntity(entity), data);
21
+ return `${entity.name}-${entityId}`;
22
+ }
23
+ function hydrateEntityFromCache({ entity, data, cache, dependencies, visitState = new Map(), }) {
24
+ if (!data) {
25
+ return data;
26
+ }
27
+ const cacheKey = getCacheKey(entity, data, dependencies);
28
+ const sourceData = cache.get(cacheKey) ?? data;
29
+ let canonicalEntity = cache.get(cacheKey);
30
+ if (!canonicalEntity) {
31
+ canonicalEntity = sourceData;
32
+ cache.set(cacheKey, canonicalEntity);
33
+ }
34
+ mergeScalarProps(canonicalEntity, sourceData);
35
+ if (visitState.get(cacheKey) === 'loading') {
36
+ return canonicalEntity;
37
+ }
38
+ visitState.set(cacheKey, 'loading');
39
+ const allProps = dependencies.getAllProps(entity);
40
+ for (const prop of allProps) {
41
+ const propName = prop.name;
42
+ const propDefinition = dependencies.getPropDefinitions(entity, propName);
43
+ const sourcePropValue = sourceData[propName] ?? canonicalEntity[propName];
44
+ if (Array.isArray(sourcePropValue)) {
45
+ const listEntity = dependencies.getListEntityType(entity, propName);
46
+ if (!listEntity) {
47
+ canonicalEntity[propName] = sourcePropValue;
48
+ continue;
49
+ }
50
+ canonicalEntity[propName] = sourcePropValue.map((item) => hydrateEntityFromCache({
51
+ entity: listEntity,
52
+ data: item,
53
+ cache,
54
+ dependencies,
55
+ visitState,
56
+ }));
57
+ continue;
58
+ }
59
+ const relationEntity = dependencies.getSourceByName(propDefinition?.type ?? '');
60
+ if (relationEntity && sourcePropValue) {
61
+ canonicalEntity[propName] = hydrateEntityFromCache({
62
+ entity: relationEntity,
63
+ data: sourcePropValue,
64
+ cache,
65
+ dependencies,
66
+ visitState,
67
+ });
68
+ continue;
69
+ }
70
+ if (sourcePropValue !== undefined) {
71
+ canonicalEntity[propName] = sourcePropValue;
72
+ }
73
+ }
74
+ visitState.set(cacheKey, 'loaded');
75
+ return canonicalEntity;
76
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koalarx/nest",
3
- "version": "3.1.28",
3
+ "version": "3.1.29",
4
4
  "description": "",
5
5
  "author": "Igor D. Rangel",
6
6
  "license": "MIT",