@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 = `${
|
|
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
|
-
|
|
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 = `${
|
|
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
|
-
|
|
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.
|
|
415
|
-
where: this.getWhereByIdSchema(this.
|
|
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
|
|
422
|
-
return this.
|
|
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.
|
|
443
|
+
select: this.getSelectWithRelationsId(this.entityInstance),
|
|
427
444
|
where,
|
|
428
445
|
});
|
|
429
446
|
if (!data)
|
|
430
447
|
return null;
|
|
431
|
-
const
|
|
432
|
-
return this.
|
|
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.
|
|
455
|
+
select: this.getSelectWithRelationsId(this.entityInstance),
|
|
437
456
|
where,
|
|
438
457
|
});
|
|
439
458
|
if (!data)
|
|
440
459
|
return null;
|
|
441
|
-
const
|
|
442
|
-
return this.
|
|
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
|
+
}
|