@koalarx/nest 3.1.28 → 3.1.30
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.
- package/core/database/entity.base.d.ts +2 -1
- package/core/database/entity.base.js +11 -9
- package/core/database/entity.decorator.d.ts +1 -1
- package/core/database/repository.base.d.ts +2 -0
- package/core/database/repository.base.js +43 -22
- package/core/mapping/auto-mapping.service.d.ts +6 -0
- package/core/mapping/auto-mapping.service.js +108 -51
- package/core/utils/automap-cycle-context.d.ts +6 -0
- package/core/utils/automap-cycle-context.js +26 -0
- package/core/utils/hydrate-entity-from-cache.d.ts +22 -0
- package/core/utils/hydrate-entity-from-cache.js +76 -0
- package/package.json +1 -1
- package/tsconfig.lib.tsbuildinfo +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Overwrite } from '..';
|
|
2
|
+
import { AutomapContext } from '../utils/automap-cycle-context';
|
|
2
3
|
import { IComparable, IComparableId } from '../utils/interfaces/icomparable';
|
|
3
4
|
export declare enum EntityActionType {
|
|
4
5
|
create = 1,
|
|
@@ -15,6 +16,6 @@ export declare abstract class EntityBase<T extends IComparable<T>> implements IC
|
|
|
15
16
|
_id: IComparableId;
|
|
16
17
|
_action: EntityActionType;
|
|
17
18
|
constructor(props?: EntityProps<T>);
|
|
18
|
-
automap(props?: EntityProps<T
|
|
19
|
+
automap(props?: EntityProps<T>, context?: AutomapContext): void;
|
|
19
20
|
equals(obj: EntityBase<T>): boolean;
|
|
20
21
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.EntityBase = exports.EntityActionType = void 0;
|
|
4
4
|
const utils_1 = require("@koalarx/utils");
|
|
5
5
|
const auto_mapping_list_1 = require("../mapping/auto-mapping-list");
|
|
6
|
+
const automap_cycle_context_1 = require("../utils/automap-cycle-context");
|
|
6
7
|
const list_1 = require("../utils/list");
|
|
7
8
|
var EntityActionType;
|
|
8
9
|
(function (EntityActionType) {
|
|
@@ -17,8 +18,15 @@ class EntityBase {
|
|
|
17
18
|
this.automap(props);
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
|
-
automap(props) {
|
|
21
|
+
automap(props, context = (0, automap_cycle_context_1.createAutomapContext)()) {
|
|
21
22
|
if (props) {
|
|
23
|
+
if (typeof props === 'object' && props !== null) {
|
|
24
|
+
const cachedInstance = context.references.get(props);
|
|
25
|
+
if (cachedInstance && cachedInstance !== this) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
context.references.set(props, this);
|
|
29
|
+
}
|
|
22
30
|
for (const key of Object.keys(props)) {
|
|
23
31
|
if (props[key] === undefined) {
|
|
24
32
|
continue;
|
|
@@ -29,10 +37,7 @@ class EntityBase {
|
|
|
29
37
|
let value = props[key];
|
|
30
38
|
if (this[key].entityType) {
|
|
31
39
|
value = value.map((item) => {
|
|
32
|
-
|
|
33
|
-
entity._action = this._action;
|
|
34
|
-
entity.automap(item);
|
|
35
|
-
return entity;
|
|
40
|
+
return (0, automap_cycle_context_1.mapEntityReference)(item, this[key].entityType, context, this._action);
|
|
36
41
|
});
|
|
37
42
|
}
|
|
38
43
|
this[key].setList(value);
|
|
@@ -51,10 +56,7 @@ class EntityBase {
|
|
|
51
56
|
}
|
|
52
57
|
else if (EntityOnPropKey) {
|
|
53
58
|
if (props[key]) {
|
|
54
|
-
|
|
55
|
-
entity._action = this._action;
|
|
56
|
-
entity.automap(props[key]);
|
|
57
|
-
this[key] = entity;
|
|
59
|
+
this[key] = (0, automap_cycle_context_1.mapEntityReference)(props[key], EntityOnPropKey, context, this._action);
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
else if (propDefinitions) {
|
|
@@ -12,7 +12,7 @@ export declare function Entity<T extends new (...args: any[]) => EntityBase<any>
|
|
|
12
12
|
new (...args: any[]): {
|
|
13
13
|
_id: import("../utils/interfaces/icomparable").IComparableId;
|
|
14
14
|
_action: import("./entity.base").EntityActionType;
|
|
15
|
-
automap(props?: import("./entity.base").EntityProps<any> | undefined): void;
|
|
15
|
+
automap(props?: import("./entity.base").EntityProps<any> | undefined, context?: import("../utils/automap-cycle-context").AutomapContext): void;
|
|
16
16
|
equals(obj: EntityBase<any>): boolean;
|
|
17
17
|
};
|
|
18
18
|
} & T;
|
|
@@ -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()
|
|
@@ -2,9 +2,15 @@ import { Type } from '@nestjs/common';
|
|
|
2
2
|
import { AutoMappingProfile } from './auto-mapping-profile';
|
|
3
3
|
export declare class AutoMappingService {
|
|
4
4
|
private readonly _contextList;
|
|
5
|
+
private readonly _circularCutPolicy;
|
|
6
|
+
private createMapContext;
|
|
5
7
|
constructor(automappingProfile: AutoMappingProfile);
|
|
6
8
|
private getInstanceType;
|
|
7
9
|
map<S, T>(data: any, source: Type<S>, target: Type<T>): T;
|
|
10
|
+
private getIdOnlyValue;
|
|
11
|
+
private shouldCutCircularMapping;
|
|
12
|
+
private getCutValue;
|
|
13
|
+
private mapWithContext;
|
|
8
14
|
private getTarget;
|
|
9
15
|
private mapNestedProp;
|
|
10
16
|
private mapListToArray;
|
|
@@ -17,6 +17,15 @@ const auto_mapping_list_1 = require("./auto-mapping-list");
|
|
|
17
17
|
const auto_mapping_profile_1 = require("./auto-mapping-profile");
|
|
18
18
|
let AutoMappingService = class AutoMappingService {
|
|
19
19
|
_contextList = auto_mapping_list_1.AutoMappingList;
|
|
20
|
+
_circularCutPolicy = {
|
|
21
|
+
onCut: 'id-only',
|
|
22
|
+
};
|
|
23
|
+
createMapContext() {
|
|
24
|
+
return {
|
|
25
|
+
references: new WeakMap(),
|
|
26
|
+
targetPath: [],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
20
29
|
constructor(automappingProfile) {
|
|
21
30
|
automappingProfile.profile();
|
|
22
31
|
}
|
|
@@ -29,57 +38,105 @@ let AutoMappingService = class AutoMappingService {
|
|
|
29
38
|
}
|
|
30
39
|
}
|
|
31
40
|
map(data, source, target) {
|
|
41
|
+
return this.mapWithContext(data, source, target, this.createMapContext());
|
|
42
|
+
}
|
|
43
|
+
getIdOnlyValue(data) {
|
|
44
|
+
if (!data || typeof data !== 'object') {
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
const id = data.id ?? data._id;
|
|
48
|
+
if (id !== undefined) {
|
|
49
|
+
return { id };
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
shouldCutCircularMapping(target, context) {
|
|
54
|
+
return context.targetPath.some((targetOnPath) => targetOnPath === target);
|
|
55
|
+
}
|
|
56
|
+
getCutValue(data) {
|
|
57
|
+
const onCut = this._circularCutPolicy.onCut;
|
|
58
|
+
if (onCut === 'null') {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (onCut === 'omit') {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return this.getIdOnlyValue(data);
|
|
65
|
+
}
|
|
66
|
+
mapWithContext(data, source, target, context) {
|
|
67
|
+
if (!data || this.isPrimitiveType(data)) {
|
|
68
|
+
return data;
|
|
69
|
+
}
|
|
70
|
+
if (this.shouldCutCircularMapping(target, context)) {
|
|
71
|
+
return this.getCutValue(data);
|
|
72
|
+
}
|
|
73
|
+
const cachedByTarget = context.references.get(data);
|
|
74
|
+
const cachedTarget = cachedByTarget?.get(target);
|
|
75
|
+
if (cachedTarget) {
|
|
76
|
+
return cachedTarget;
|
|
77
|
+
}
|
|
32
78
|
const { mapContext, propSourceContext, propTargetContext } = this._contextList.get(source, target);
|
|
33
79
|
if (!mapContext) {
|
|
34
80
|
throw new Error(`No mapping context found for ${source.name} to ${target.name}`);
|
|
35
81
|
}
|
|
36
82
|
const mappedTarget = new target.prototype.constructor();
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
if (typeof data === 'object') {
|
|
84
|
+
const cachedTargets = context.references.get(data) ?? new Map();
|
|
85
|
+
cachedTargets.set(target, mappedTarget);
|
|
86
|
+
context.references.set(data, cachedTargets);
|
|
87
|
+
}
|
|
88
|
+
context.targetPath.push(target);
|
|
89
|
+
try {
|
|
90
|
+
propSourceContext?.props.forEach((propSource) => {
|
|
91
|
+
const value = data[propSource.name];
|
|
92
|
+
const compositionType = propSource.compositionType;
|
|
93
|
+
const compositionAction = propSource.compositionAction;
|
|
94
|
+
if (value !== undefined) {
|
|
95
|
+
const targetProp = propTargetContext?.props.find((tp) => tp.name === propSource.name);
|
|
96
|
+
if (targetProp) {
|
|
97
|
+
const typeSource = (0, get_type_by_prop_1.getTypeByProp)(propSource);
|
|
98
|
+
const typeTarget = (0, get_type_by_prop_1.getTypeByProp)(targetProp);
|
|
99
|
+
const listToArray = typeSource === list_1.List.name &&
|
|
100
|
+
typeTarget === Array.name &&
|
|
101
|
+
value instanceof list_1.List;
|
|
102
|
+
const arrayToList = typeSource === Array.name &&
|
|
103
|
+
typeTarget === list_1.List.name &&
|
|
104
|
+
value instanceof Array &&
|
|
105
|
+
!!compositionType;
|
|
106
|
+
const arrayToArray = typeSource === Array.name &&
|
|
107
|
+
typeTarget === Array.name &&
|
|
108
|
+
value instanceof Array &&
|
|
109
|
+
!!compositionType;
|
|
110
|
+
let mappedValue = value;
|
|
111
|
+
if (listToArray) {
|
|
112
|
+
mappedValue = this.mapListToArray(value, context);
|
|
113
|
+
}
|
|
114
|
+
else if (arrayToList) {
|
|
115
|
+
mappedValue = this.mapArrayToList(value, this.getInstanceType(compositionType), context, compositionAction === 'onlySet');
|
|
116
|
+
}
|
|
117
|
+
else if (arrayToArray) {
|
|
118
|
+
mappedValue = this.mapArrayToArray(value, this.getInstanceType(compositionType), context);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const propSourceInstance = this._contextList.getSourceByName(typeSource);
|
|
122
|
+
if (propSourceInstance) {
|
|
123
|
+
mappedValue = this.mapNestedProp(value, propSourceInstance, context);
|
|
124
|
+
}
|
|
71
125
|
}
|
|
126
|
+
mappedTarget[targetProp.name] = mappedValue;
|
|
72
127
|
}
|
|
73
|
-
mappedTarget[targetProp.name] = mappedValue;
|
|
74
128
|
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
}
|
|
129
|
+
});
|
|
130
|
+
propTargetContext?.props.forEach((prop) => {
|
|
131
|
+
const formMemberDefinition = mapContext.forMemberDifinitions?.find((def) => def[prop.name])?.[prop.name];
|
|
132
|
+
if (formMemberDefinition) {
|
|
133
|
+
mappedTarget[prop.name] = formMemberDefinition(data);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
context.targetPath.pop();
|
|
139
|
+
}
|
|
83
140
|
return mappedTarget;
|
|
84
141
|
}
|
|
85
142
|
getTarget(data, source) {
|
|
@@ -92,21 +149,21 @@ let AutoMappingService = class AutoMappingService {
|
|
|
92
149
|
}
|
|
93
150
|
return targets[0];
|
|
94
151
|
}
|
|
95
|
-
mapNestedProp(data, source) {
|
|
96
|
-
return this.
|
|
152
|
+
mapNestedProp(data, source, context) {
|
|
153
|
+
return this.mapWithContext(data, source.prototype.constructor, this.getTarget(data, source), context);
|
|
97
154
|
}
|
|
98
|
-
mapListToArray(value) {
|
|
155
|
+
mapListToArray(value, context) {
|
|
99
156
|
return value.toArray().map((item) => {
|
|
100
157
|
const entityOnList = value.entityType?.prototype.constructor;
|
|
101
158
|
if (entityOnList) {
|
|
102
|
-
return this.mapNestedProp(item, entityOnList) ?? {};
|
|
159
|
+
return this.mapNestedProp(item, entityOnList, context) ?? {};
|
|
103
160
|
}
|
|
104
161
|
return {};
|
|
105
162
|
});
|
|
106
163
|
}
|
|
107
|
-
mapArrayToList(value, compositionType, onlySet = true) {
|
|
164
|
+
mapArrayToList(value, compositionType, context, onlySet = true) {
|
|
108
165
|
const list = new list_1.List(this.getTarget(value, compositionType.prototype.constructor));
|
|
109
|
-
const mappedValue = value.map((item) => this.mapNestedProp(item, compositionType.prototype.constructor) ?? {});
|
|
166
|
+
const mappedValue = value.map((item) => this.mapNestedProp(item, compositionType.prototype.constructor, context) ?? {});
|
|
110
167
|
if (onlySet) {
|
|
111
168
|
list.setList(mappedValue);
|
|
112
169
|
}
|
|
@@ -115,8 +172,8 @@ let AutoMappingService = class AutoMappingService {
|
|
|
115
172
|
}
|
|
116
173
|
return list;
|
|
117
174
|
}
|
|
118
|
-
mapArrayToArray(value, compositionType) {
|
|
119
|
-
return value.map((item) => this.mapNestedProp(item, compositionType.prototype.constructor) ?? {});
|
|
175
|
+
mapArrayToArray(value, compositionType, context) {
|
|
176
|
+
return value.map((item) => this.mapNestedProp(item, compositionType.prototype.constructor, context) ?? {});
|
|
120
177
|
}
|
|
121
178
|
isPrimitiveType(value) {
|
|
122
179
|
switch (typeof value) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
export interface AutomapContext {
|
|
3
|
+
references: WeakMap<object, any>;
|
|
4
|
+
}
|
|
5
|
+
export declare function createAutomapContext(): AutomapContext;
|
|
6
|
+
export declare function mapEntityReference(value: any, EntityOnPropKey: Type<any>, context: AutomapContext, action: number): any;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAutomapContext = createAutomapContext;
|
|
4
|
+
exports.mapEntityReference = mapEntityReference;
|
|
5
|
+
function createAutomapContext() {
|
|
6
|
+
return {
|
|
7
|
+
references: new WeakMap(),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function mapEntityReference(value, EntityOnPropKey, context, action) {
|
|
11
|
+
if (!value || typeof value !== 'object') {
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
const cachedEntity = context.references.get(value);
|
|
15
|
+
if (cachedEntity) {
|
|
16
|
+
return cachedEntity;
|
|
17
|
+
}
|
|
18
|
+
const entity = new EntityOnPropKey();
|
|
19
|
+
if (entity && typeof entity.automap === 'function') {
|
|
20
|
+
;
|
|
21
|
+
entity._action = action;
|
|
22
|
+
context.references.set(value, entity);
|
|
23
|
+
entity.automap(value, context);
|
|
24
|
+
}
|
|
25
|
+
return entity;
|
|
26
|
+
}
|
|
@@ -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
|
+
}
|