@rws-framework/db 3.0.1 → 3.1.0
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/dist/decorators/InverseRelation.js +30 -2
- package/dist/helper/DbHelper.d.ts +1 -0
- package/dist/helper/DbHelper.js +6 -0
- package/dist/helper/db/schema-generator.js +4 -1
- package/dist/helper/db/utils.d.ts +1 -1
- package/dist/helper/db/utils.js +11 -13
- package/dist/models/core/RWSModel.d.ts +4 -2
- package/dist/models/core/RWSModel.js +5 -67
- package/dist/models/utils/HydrateUtils.d.ts +13 -0
- package/dist/models/utils/HydrateUtils.js +81 -0
- package/package.json +1 -1
- package/src/decorators/InverseRelation.ts +43 -2
- package/src/helper/DbHelper.ts +9 -0
- package/src/helper/db/schema-generator.ts +6 -2
- package/src/helper/db/utils.ts +15 -15
- package/src/models/core/RWSModel.ts +11 -86
- package/src/models/utils/HydrateUtils.ts +102 -0
|
@@ -1,16 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
require("reflect-metadata");
|
|
4
|
+
const ModelUtils_1 = require("../models/utils/ModelUtils");
|
|
5
|
+
function guessForeignKey(inversionModel, bindingModel, decoratorsData) {
|
|
6
|
+
var _a;
|
|
7
|
+
let key = null;
|
|
8
|
+
let defaultKey = `${bindingModel._collection}_id`;
|
|
9
|
+
const relDecorators = {};
|
|
10
|
+
const trackDecorators = {};
|
|
11
|
+
if (Object.keys(trackDecorators).includes(key)) {
|
|
12
|
+
return key;
|
|
13
|
+
}
|
|
14
|
+
for (const decKey of Object.keys(decoratorsData)) {
|
|
15
|
+
const dec = decoratorsData[decKey];
|
|
16
|
+
if (dec.annotationType === 'Relation') {
|
|
17
|
+
relDecorators[decKey] = dec;
|
|
18
|
+
}
|
|
19
|
+
if (dec.annotationType === 'TrackType') {
|
|
20
|
+
trackDecorators[decKey] = dec;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const relKey of Object.keys(relDecorators)) {
|
|
24
|
+
const prodMeta = (_a = relDecorators[relKey]) === null || _a === void 0 ? void 0 : _a.metadata;
|
|
25
|
+
if (prodMeta && prodMeta.relatedTo._collection === bindingModel._collection) {
|
|
26
|
+
return prodMeta.relationField;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return key;
|
|
30
|
+
}
|
|
4
31
|
function InverseRelation(inversionModel, sourceModel, relationOptions = null) {
|
|
5
32
|
return function (target, key) {
|
|
6
|
-
const metadataPromise = Promise.resolve().then(() => {
|
|
33
|
+
const metadataPromise = Promise.resolve().then(async () => {
|
|
7
34
|
const model = inversionModel();
|
|
8
35
|
const source = sourceModel();
|
|
36
|
+
const decoratorsData = await ModelUtils_1.ModelUtils.getModelAnnotations(model);
|
|
9
37
|
const metaOpts = {
|
|
10
38
|
...relationOptions,
|
|
11
39
|
key,
|
|
12
40
|
inversionModel: model,
|
|
13
|
-
foreignKey: relationOptions && relationOptions.foreignKey ? relationOptions.foreignKey :
|
|
41
|
+
foreignKey: relationOptions && relationOptions.foreignKey ? relationOptions.foreignKey : guessForeignKey(model, source, decoratorsData),
|
|
14
42
|
// Generate a unique relation name if one is not provided
|
|
15
43
|
relationName: relationOptions && relationOptions.relationName ?
|
|
16
44
|
relationOptions.relationName.toLowerCase() :
|
|
@@ -27,6 +27,7 @@ export declare class DbHelper {
|
|
|
27
27
|
* @param leaveFile Whether to leave the schema file after generation
|
|
28
28
|
*/
|
|
29
29
|
static pushDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile?: boolean): Promise<void>;
|
|
30
|
+
static migrateDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile?: boolean): Promise<void>;
|
|
30
31
|
/**
|
|
31
32
|
* Generate model sections for the schema
|
|
32
33
|
* @param model The model to generate a section for
|
package/dist/helper/DbHelper.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DbHelper = void 0;
|
|
4
|
+
const console_1 = require("@rws-framework/console");
|
|
4
5
|
const db_1 = require("./db");
|
|
5
6
|
/**
|
|
6
7
|
* Database helper class
|
|
@@ -27,6 +28,11 @@ class DbHelper {
|
|
|
27
28
|
static async pushDBModels(configService, dbService, leaveFile = false) {
|
|
28
29
|
return db_1.SchemaGenerator.pushDBModels(configService, dbService, leaveFile);
|
|
29
30
|
}
|
|
31
|
+
static async migrateDBModels(configService, dbService, leaveFile = false) {
|
|
32
|
+
process.env = { ...process.env, [this.dbUrlVarName]: configService.get('db_url') };
|
|
33
|
+
const [_, schemaPath] = db_1.DbUtils.getSchemaDir();
|
|
34
|
+
await console_1.rwsShell.runCommand(`${db_1.DbUtils.detectInstaller()} prisma migrate dev --create-only --schema=${schemaPath}`, process.cwd());
|
|
35
|
+
}
|
|
30
36
|
/**
|
|
31
37
|
* Generate model sections for the schema
|
|
32
38
|
* @param model The model to generate a section for
|
|
@@ -47,7 +47,7 @@ datasource db {
|
|
|
47
47
|
const modelName = model._collection;
|
|
48
48
|
section += `model ${modelName} {\n`;
|
|
49
49
|
if (!model._NO_ID) {
|
|
50
|
-
section += `\t${utils_1.DbUtils.generateId(dbType, modelMetadatas
|
|
50
|
+
section += `\t${utils_1.DbUtils.generateId(dbType, modelMetadatas)}\n`;
|
|
51
51
|
}
|
|
52
52
|
for (const key in modelMetadatas) {
|
|
53
53
|
const modelMetadata = modelMetadatas[key].metadata;
|
|
@@ -81,6 +81,9 @@ datasource db {
|
|
|
81
81
|
const relationFieldName = modelMetadata.relationField ? modelMetadata.relationField : key.toLowerCase() + '_' + modelMetadata.relationField.toLowerCase();
|
|
82
82
|
const relatedToField = modelMetadata.relatedToField || 'id';
|
|
83
83
|
const bindingFieldExists = !!modelMetadatas[relationFieldName];
|
|
84
|
+
if (modelMetadata.required === false) {
|
|
85
|
+
requiredString = '?';
|
|
86
|
+
}
|
|
84
87
|
if (isMany) {
|
|
85
88
|
// Add an inverse field to the related model if it doesn't exist
|
|
86
89
|
section += `\t${key} ${relatedModel._collection}[] @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}", ${cascadeOpts.join(', ')})\n`;
|
|
@@ -18,7 +18,7 @@ export declare class DbUtils {
|
|
|
18
18
|
static generateId(dbType: IDbConfigParams['db_type'], modelMeta: Record<string, {
|
|
19
19
|
annotationType: string;
|
|
20
20
|
metadata: IIdMetaOpts;
|
|
21
|
-
}>,
|
|
21
|
+
}>, optional?: boolean): string;
|
|
22
22
|
}
|
|
23
23
|
export declare const workspaceRootPath: string;
|
|
24
24
|
export declare const moduleDirPath: string;
|
package/dist/helper/db/utils.js
CHANGED
|
@@ -34,7 +34,7 @@ class DbUtils {
|
|
|
34
34
|
/**
|
|
35
35
|
* Generate an ID field based on the database type
|
|
36
36
|
*/
|
|
37
|
-
static generateId(dbType, modelMeta,
|
|
37
|
+
static generateId(dbType, modelMeta, optional = false) {
|
|
38
38
|
var _a, _b, _c, _d;
|
|
39
39
|
let useUuid = false;
|
|
40
40
|
let field = 'id';
|
|
@@ -46,9 +46,6 @@ class DbUtils {
|
|
|
46
46
|
if (annotationType == 'IdType') {
|
|
47
47
|
const dbSpecificTags = type_converter_1.TypeConverter.processTypeOptions({ tags: [], dbOptions: modelMetadata.dbOptions }, dbType);
|
|
48
48
|
tags.push(...dbSpecificTags);
|
|
49
|
-
if (debug) {
|
|
50
|
-
console.log({ modelMetadata: modelMetadata.dbOptions });
|
|
51
|
-
}
|
|
52
49
|
field = key;
|
|
53
50
|
if ((_b = (_a = modelMetadata.dbOptions) === null || _a === void 0 ? void 0 : _a.mysql) === null || _b === void 0 ? void 0 : _b.useUuid) {
|
|
54
51
|
useUuid = true;
|
|
@@ -63,23 +60,27 @@ class DbUtils {
|
|
|
63
60
|
}
|
|
64
61
|
}
|
|
65
62
|
let idString;
|
|
63
|
+
let reqStr = '';
|
|
64
|
+
if (optional) {
|
|
65
|
+
reqStr = '?';
|
|
66
|
+
}
|
|
66
67
|
switch (dbType) {
|
|
67
68
|
case 'mongodb':
|
|
68
|
-
idString = `${field} String @id @default(auto()) @map("_id") @db.ObjectId`;
|
|
69
|
+
idString = `${field} String${reqStr} @id @default(auto()) @map("_id") @db.ObjectId`;
|
|
69
70
|
break;
|
|
70
71
|
case 'mysql':
|
|
71
72
|
idString = useUuid
|
|
72
|
-
? `${field} String @id @default(uuid())`
|
|
73
|
-
: `${field} Int @id @default(autoincrement())`;
|
|
73
|
+
? `${field} String${reqStr} @id @default(uuid())`
|
|
74
|
+
: `${field} Int${reqStr} @id @default(autoincrement())`;
|
|
74
75
|
break;
|
|
75
76
|
case 'postgresql':
|
|
76
77
|
case 'postgres':
|
|
77
78
|
idString = useUuid
|
|
78
|
-
? `${field} String @id @default(uuid())`
|
|
79
|
-
: `${field} Int @id @default(autoincrement())`;
|
|
79
|
+
? `${field} String${reqStr} @id @default(uuid())`
|
|
80
|
+
: `${field} Int${reqStr} @id @default(autoincrement())`;
|
|
80
81
|
break;
|
|
81
82
|
case 'sqlite':
|
|
82
|
-
idString = `${field} Int @id @default(autoincrement())`;
|
|
83
|
+
idString = `${field} Int${reqStr} @id @default(autoincrement())`;
|
|
83
84
|
break;
|
|
84
85
|
}
|
|
85
86
|
if (tags.length) {
|
|
@@ -88,9 +89,6 @@ class DbUtils {
|
|
|
88
89
|
if (!idString) {
|
|
89
90
|
throw new Error(`DB type "${dbType}" is not supported!`);
|
|
90
91
|
}
|
|
91
|
-
if (debug) {
|
|
92
|
-
console.log({ idString, useUuid });
|
|
93
|
-
}
|
|
94
92
|
return idString;
|
|
95
93
|
}
|
|
96
94
|
}
|
|
@@ -4,6 +4,8 @@ import { OpModelType } from '../interfaces/OpModelType';
|
|
|
4
4
|
import { FindByType, IPaginationParams } from '../../types/FindParams';
|
|
5
5
|
import { DBService } from '../../services/DBService';
|
|
6
6
|
import { ISuperTagData } from '../../decorators/RWSCollection';
|
|
7
|
+
import { RelManyMetaType, RelOneMetaType } from '../types/RelationTypes';
|
|
8
|
+
import { IRWSModel } from '../../types/IRWSModel';
|
|
7
9
|
declare class RWSModel<T> implements IModel {
|
|
8
10
|
static services: IRWSModelServices;
|
|
9
11
|
[key: string]: any;
|
|
@@ -30,9 +32,9 @@ declare class RWSModel<T> implements IModel {
|
|
|
30
32
|
_asyncFill(data: any, fullDataMode?: boolean, allowRelations?: boolean): Promise<T>;
|
|
31
33
|
private getModelScalarFields;
|
|
32
34
|
private getRelationOneMeta;
|
|
33
|
-
static getRelationOneMeta(model: any, classFields: string[]): Promise<
|
|
35
|
+
static getRelationOneMeta(model: any, classFields: string[]): Promise<RelOneMetaType<IRWSModel>>;
|
|
34
36
|
private getRelationManyMeta;
|
|
35
|
-
static getRelationManyMeta(model: any, classFields: string[]): Promise<
|
|
37
|
+
static getRelationManyMeta(model: any, classFields: string[]): Promise<RelManyMetaType<IRWSModel>>;
|
|
36
38
|
static paginate<T extends RWSModel<T>>(this: OpModelType<T>, paginateParams: IPaginationParams, findParams?: FindByType): Promise<T[]>;
|
|
37
39
|
toMongo(): Promise<any>;
|
|
38
40
|
getCollection(): string | null;
|
|
@@ -15,6 +15,7 @@ const FieldsHelper_1 = require("../../helper/FieldsHelper");
|
|
|
15
15
|
const RelationUtils_1 = require("../utils/RelationUtils");
|
|
16
16
|
const TimeSeriesUtils_1 = require("../utils/TimeSeriesUtils");
|
|
17
17
|
const ModelUtils_1 = require("../utils/ModelUtils");
|
|
18
|
+
const HydrateUtils_1 = require("../utils/HydrateUtils");
|
|
18
19
|
class RWSModel {
|
|
19
20
|
constructor(data = null) {
|
|
20
21
|
if (!this.getCollection()) {
|
|
@@ -76,7 +77,6 @@ class RWSModel {
|
|
|
76
77
|
}
|
|
77
78
|
async _asyncFill(data, fullDataMode = false, allowRelations = true) {
|
|
78
79
|
const collections_to_models = {};
|
|
79
|
-
const timeSeriesIds = TimeSeriesUtils_1.TimeSeriesUtils.getTimeSeriesModelFields(this);
|
|
80
80
|
const classFields = FieldsHelper_1.FieldsHelper.getAllClassFields(this.constructor);
|
|
81
81
|
// Get both relation metadata types asynchronously
|
|
82
82
|
const [relOneData, relManyData] = await Promise.all([
|
|
@@ -88,73 +88,10 @@ class RWSModel {
|
|
|
88
88
|
});
|
|
89
89
|
const seriesHydrationfields = [];
|
|
90
90
|
if (allowRelations) {
|
|
91
|
-
|
|
92
|
-
for (const key in relManyData) {
|
|
93
|
-
if (!fullDataMode && this.constructor._CUT_KEYS.includes(key)) {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
const relMeta = relManyData[key];
|
|
97
|
-
const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(this, relMeta.key);
|
|
98
|
-
if (relationEnabled) {
|
|
99
|
-
this[relMeta.key] = await relMeta.inversionModel.findBy({
|
|
100
|
-
conditions: {
|
|
101
|
-
[relMeta.foreignKey]: data.id
|
|
102
|
-
},
|
|
103
|
-
allowRelations: false
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// Handle one-to-one relations
|
|
108
|
-
for (const key in relOneData) {
|
|
109
|
-
if (!fullDataMode && this.constructor._CUT_KEYS.includes(key)) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
const relMeta = relOneData[key];
|
|
113
|
-
const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(this, relMeta.key);
|
|
114
|
-
if (!data[relMeta.hydrationField] && relMeta.required) {
|
|
115
|
-
throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`);
|
|
116
|
-
}
|
|
117
|
-
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
118
|
-
this[relMeta.key] = await relMeta.model.find(data[relMeta.hydrationField], { allowRelations: false });
|
|
119
|
-
}
|
|
120
|
-
else if (relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]) {
|
|
121
|
-
const newRelModel = await relMeta.model.create(data[relMeta.key]);
|
|
122
|
-
this[relMeta.key] = await newRelModel.save();
|
|
123
|
-
}
|
|
124
|
-
const cutKeys = this.constructor._CUT_KEYS;
|
|
125
|
-
const trackedField = Object.keys((await ModelUtils_1.ModelUtils.getModelAnnotations(this.constructor))).includes(relMeta.hydrationField);
|
|
126
|
-
if (!cutKeys.includes(relMeta.hydrationField) && !trackedField) {
|
|
127
|
-
cutKeys.push(relMeta.hydrationField);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
91
|
+
await HydrateUtils_1.HydrateUtils.hydrateRelations(this, relManyData, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
130
92
|
}
|
|
131
93
|
// Process regular fields and time series
|
|
132
|
-
|
|
133
|
-
if (data.hasOwnProperty(key)) {
|
|
134
|
-
if (!fullDataMode && this.constructor._CUT_KEYS.includes(key)) {
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
if (Object.keys(relOneData).includes(key)) {
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
if (seriesHydrationfields.includes(key)) {
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
const timeSeriesMetaData = timeSeriesIds[key];
|
|
144
|
-
if (timeSeriesMetaData) {
|
|
145
|
-
this[key] = data[key];
|
|
146
|
-
const seriesModel = collections_to_models[timeSeriesMetaData.collection];
|
|
147
|
-
const dataModels = await seriesModel.findBy({
|
|
148
|
-
id: { in: data[key] }
|
|
149
|
-
});
|
|
150
|
-
seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
|
|
151
|
-
this[timeSeriesMetaData.hydrationField] = dataModels;
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
this[key] = data[key];
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
94
|
+
await HydrateUtils_1.HydrateUtils.hydrateDataFields(this, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
158
95
|
return this;
|
|
159
96
|
}
|
|
160
97
|
getModelScalarFields(model) {
|
|
@@ -334,7 +271,8 @@ class RWSModel {
|
|
|
334
271
|
const collection = Reflect.get(this, '_collection');
|
|
335
272
|
this.checkForInclusionWithThrow(this.name);
|
|
336
273
|
try {
|
|
337
|
-
const
|
|
274
|
+
const paginateParams = (findParams === null || findParams === void 0 ? void 0 : findParams.pagination) ? findParams === null || findParams === void 0 ? void 0 : findParams.pagination : undefined;
|
|
275
|
+
const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
338
276
|
if (dbData.length) {
|
|
339
277
|
const instanced = [];
|
|
340
278
|
for (const data of dbData) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { RWSModel } from "../core/RWSModel";
|
|
2
|
+
import { RelManyMetaType, RelOneMetaType } from "../types/RelationTypes";
|
|
3
|
+
import { IRWSModel } from "../../types/IRWSModel";
|
|
4
|
+
export declare class HydrateUtils {
|
|
5
|
+
static hydrateDataFields(model: RWSModel<any>, collections_to_models: {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
static hydrateRelations(model: RWSModel<any>, relManyData: RelManyMetaType<IRWSModel>, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HydrateUtils = void 0;
|
|
4
|
+
const TimeSeriesUtils_1 = require("./TimeSeriesUtils");
|
|
5
|
+
const RelationUtils_1 = require("./RelationUtils");
|
|
6
|
+
const ModelUtils_1 = require("./ModelUtils");
|
|
7
|
+
class HydrateUtils {
|
|
8
|
+
static async hydrateDataFields(model, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data) {
|
|
9
|
+
const timeSeriesIds = TimeSeriesUtils_1.TimeSeriesUtils.getTimeSeriesModelFields(model);
|
|
10
|
+
for (const key in data) {
|
|
11
|
+
if (data.hasOwnProperty(key)) {
|
|
12
|
+
if (!fullDataMode && (model).constructor._CUT_KEYS.includes(key)) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (Object.keys(relOneData).includes(key)) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (seriesHydrationfields.includes(key)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const timeSeriesMetaData = timeSeriesIds[key];
|
|
22
|
+
if (timeSeriesMetaData) {
|
|
23
|
+
model[key] = data[key];
|
|
24
|
+
const seriesModel = collections_to_models[timeSeriesMetaData.collection];
|
|
25
|
+
const dataModels = await seriesModel.findBy({
|
|
26
|
+
id: { in: data[key] }
|
|
27
|
+
});
|
|
28
|
+
seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
|
|
29
|
+
model[timeSeriesMetaData.hydrationField] = dataModels;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
model[key] = data[key];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
static async hydrateRelations(model, relManyData, relOneData, seriesHydrationfields, fullDataMode, data) {
|
|
38
|
+
// Handle many-to-many relations
|
|
39
|
+
for (const key in relManyData) {
|
|
40
|
+
if (!fullDataMode && model.constructor._CUT_KEYS.includes(key)) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const relMeta = relManyData[key];
|
|
44
|
+
// console.log({relMeta});
|
|
45
|
+
const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
46
|
+
if (relationEnabled) {
|
|
47
|
+
model[relMeta.key] = await relMeta.inversionModel.findBy({
|
|
48
|
+
conditions: {
|
|
49
|
+
[relMeta.foreignKey]: data.id
|
|
50
|
+
},
|
|
51
|
+
allowRelations: false
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Handle one-to-one relations
|
|
56
|
+
for (const key in relOneData) {
|
|
57
|
+
if (!fullDataMode && model.constructor._CUT_KEYS.includes(key)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const relMeta = relOneData[key];
|
|
61
|
+
const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
62
|
+
if (!data[relMeta.hydrationField] && relMeta.required) {
|
|
63
|
+
throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`);
|
|
64
|
+
}
|
|
65
|
+
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
66
|
+
model[relMeta.key] = await relMeta.model.findOneBy({ conditions: { [relMeta.foreignKey]: data[relMeta.hydrationField] } }, { allowRelations: false });
|
|
67
|
+
}
|
|
68
|
+
else if (relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]) {
|
|
69
|
+
const newRelModel = await relMeta.model.create(data[relMeta.key]);
|
|
70
|
+
model[relMeta.key] = await newRelModel.save();
|
|
71
|
+
}
|
|
72
|
+
const cutKeys = model.constructor._CUT_KEYS;
|
|
73
|
+
const trackedField = Object.keys((await ModelUtils_1.ModelUtils.getModelAnnotations(model.constructor))).includes(relMeta.hydrationField);
|
|
74
|
+
if (!cutKeys.includes(relMeta.hydrationField) && !trackedField) {
|
|
75
|
+
cutKeys.push(relMeta.hydrationField);
|
|
76
|
+
}
|
|
77
|
+
// seriesHydrationfields.push(relMeta.hydrationField);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.HydrateUtils = HydrateUtils;
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import { RWSModel, OpModelType } from '../models/_model';
|
|
3
|
+
import { ModelUtils } from '../models/utils/ModelUtils';
|
|
3
4
|
|
|
4
5
|
export interface InverseRelationOpts {
|
|
5
6
|
key: string,
|
|
@@ -10,17 +11,57 @@ export interface InverseRelationOpts {
|
|
|
10
11
|
mappingName?: string
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
function guessForeignKey(inversionModel: OpModelType<RWSModel<any>>, bindingModel: OpModelType<RWSModel<any>>, decoratorsData: any)
|
|
15
|
+
{
|
|
16
|
+
let key: string | null = null;
|
|
17
|
+
let defaultKey = `${bindingModel._collection}_id`;
|
|
18
|
+
|
|
19
|
+
const relDecorators: Record<string, {
|
|
20
|
+
annotationType: string;
|
|
21
|
+
metadata: any;
|
|
22
|
+
}> = {};
|
|
23
|
+
|
|
24
|
+
const trackDecorators: Record<string, {
|
|
25
|
+
annotationType: string;
|
|
26
|
+
metadata: any;
|
|
27
|
+
}> = {};
|
|
28
|
+
|
|
29
|
+
if(Object.keys(trackDecorators).includes(key)){
|
|
30
|
+
return key;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for(const decKey of Object.keys(decoratorsData)){
|
|
34
|
+
const dec = decoratorsData[decKey];
|
|
35
|
+
if(dec.annotationType === 'Relation'){
|
|
36
|
+
relDecorators[decKey] = dec;
|
|
37
|
+
}
|
|
38
|
+
if(dec.annotationType === 'TrackType'){
|
|
39
|
+
trackDecorators[decKey] = dec;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for(const relKey of Object.keys(relDecorators)){
|
|
44
|
+
const prodMeta = relDecorators[relKey]?.metadata;
|
|
45
|
+
if(prodMeta && prodMeta.relatedTo._collection === bindingModel._collection){
|
|
46
|
+
return prodMeta.relationField;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return key;
|
|
51
|
+
}
|
|
52
|
+
|
|
13
53
|
function InverseRelation(inversionModel: () => OpModelType<RWSModel<any>>, sourceModel: () => OpModelType<RWSModel<any>>, relationOptions: Partial<InverseRelationOpts> = null) {
|
|
14
54
|
return function (target: any, key: string) {
|
|
15
|
-
const metadataPromise = Promise.resolve().then(() => {
|
|
55
|
+
const metadataPromise = Promise.resolve().then(async () => {
|
|
16
56
|
const model = inversionModel();
|
|
17
57
|
const source = sourceModel();
|
|
58
|
+
const decoratorsData = await ModelUtils.getModelAnnotations(model);
|
|
18
59
|
|
|
19
60
|
const metaOpts: InverseRelationOpts = {
|
|
20
61
|
...relationOptions,
|
|
21
62
|
key,
|
|
22
63
|
inversionModel: model,
|
|
23
|
-
foreignKey: relationOptions && relationOptions.foreignKey ? relationOptions.foreignKey :
|
|
64
|
+
foreignKey: relationOptions && relationOptions.foreignKey ? relationOptions.foreignKey : guessForeignKey(model, source, decoratorsData),
|
|
24
65
|
// Generate a unique relation name if one is not provided
|
|
25
66
|
relationName: relationOptions && relationOptions.relationName ?
|
|
26
67
|
relationOptions.relationName.toLowerCase() :
|
package/src/helper/DbHelper.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IDbConfigHandler, IDbConfigParams, IdGeneratorOptions } from '../types/DbConfigHandler';
|
|
2
2
|
import { OpModelType } from '../models/_model';
|
|
3
3
|
import { DBService } from '../services/DBService';
|
|
4
|
+
import { rwsShell } from '@rws-framework/console';
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
7
|
DbUtils,
|
|
@@ -41,6 +42,14 @@ export class DbHelper {
|
|
|
41
42
|
static async pushDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
|
|
42
43
|
return SchemaGenerator.pushDBModels(configService, dbService, leaveFile);
|
|
43
44
|
}
|
|
45
|
+
|
|
46
|
+
static async migrateDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
|
|
47
|
+
process.env = { ...process.env, [this.dbUrlVarName]: configService.get('db_url') };
|
|
48
|
+
|
|
49
|
+
const [_, schemaPath] = DbUtils.getSchemaDir();
|
|
50
|
+
|
|
51
|
+
await rwsShell.runCommand(`${DbUtils.detectInstaller()} prisma migrate dev --create-only --schema=${schemaPath}`, process.cwd());
|
|
52
|
+
}
|
|
44
53
|
|
|
45
54
|
/**
|
|
46
55
|
* Generate model sections for the schema
|
|
@@ -62,7 +62,7 @@ datasource db {
|
|
|
62
62
|
if(
|
|
63
63
|
!model._NO_ID
|
|
64
64
|
){
|
|
65
|
-
section += `\t${DbUtils.generateId(dbType, modelMetadatas
|
|
65
|
+
section += `\t${DbUtils.generateId(dbType, modelMetadatas)}\n`;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
for (const key in modelMetadatas) {
|
|
@@ -108,7 +108,11 @@ datasource db {
|
|
|
108
108
|
const relationFieldName = modelMetadata.relationField ? modelMetadata.relationField : key.toLowerCase() + '_' + modelMetadata.relationField.toLowerCase();
|
|
109
109
|
|
|
110
110
|
const relatedToField = modelMetadata.relatedToField || 'id';
|
|
111
|
-
const bindingFieldExists = !!modelMetadatas[relationFieldName];
|
|
111
|
+
const bindingFieldExists = !!modelMetadatas[relationFieldName];
|
|
112
|
+
|
|
113
|
+
if(modelMetadata.required === false){
|
|
114
|
+
requiredString = '?';
|
|
115
|
+
}
|
|
112
116
|
|
|
113
117
|
if (isMany) {
|
|
114
118
|
// Add an inverse field to the related model if it doesn't exist
|
package/src/helper/db/utils.ts
CHANGED
|
@@ -40,7 +40,7 @@ export class DbUtils {
|
|
|
40
40
|
static generateId(
|
|
41
41
|
dbType: IDbConfigParams['db_type'],
|
|
42
42
|
modelMeta: Record<string, { annotationType: string, metadata: IIdMetaOpts }>,
|
|
43
|
-
|
|
43
|
+
optional = false
|
|
44
44
|
): string {
|
|
45
45
|
let useUuid = false;
|
|
46
46
|
let field = 'id';
|
|
@@ -53,10 +53,7 @@ export class DbUtils {
|
|
|
53
53
|
if(key !== 'id'){
|
|
54
54
|
if(annotationType == 'IdType'){
|
|
55
55
|
const dbSpecificTags = TypeConverter.processTypeOptions({ tags: [], dbOptions: modelMetadata.dbOptions }, dbType);
|
|
56
|
-
tags.push(...dbSpecificTags);
|
|
57
|
-
if(debug){
|
|
58
|
-
console.log({modelMetadata: modelMetadata.dbOptions});
|
|
59
|
-
}
|
|
56
|
+
tags.push(...dbSpecificTags);
|
|
60
57
|
|
|
61
58
|
field = key;
|
|
62
59
|
|
|
@@ -76,29 +73,35 @@ export class DbUtils {
|
|
|
76
73
|
}
|
|
77
74
|
|
|
78
75
|
let idString: string;
|
|
76
|
+
|
|
77
|
+
let reqStr = '';
|
|
78
|
+
|
|
79
|
+
if(optional){
|
|
80
|
+
reqStr = '?';
|
|
81
|
+
}
|
|
79
82
|
|
|
80
83
|
switch (dbType) {
|
|
81
84
|
case 'mongodb':
|
|
82
|
-
idString = `${field} String @id @default(auto()) @map("_id") @db.ObjectId`;
|
|
85
|
+
idString = `${field} String${reqStr} @id @default(auto()) @map("_id") @db.ObjectId`;
|
|
83
86
|
break;
|
|
84
87
|
|
|
85
88
|
case 'mysql':
|
|
86
89
|
idString = useUuid
|
|
87
|
-
? `${field} String @id @default(uuid())`
|
|
88
|
-
: `${field} Int @id @default(autoincrement())`;
|
|
90
|
+
? `${field} String${reqStr} @id @default(uuid())`
|
|
91
|
+
: `${field} Int${reqStr} @id @default(autoincrement())`;
|
|
89
92
|
break;
|
|
90
93
|
|
|
91
94
|
case 'postgresql':
|
|
92
95
|
case 'postgres':
|
|
93
96
|
idString = useUuid
|
|
94
|
-
? `${field} String @id @default(uuid())`
|
|
95
|
-
: `${field} Int @id @default(autoincrement())`;
|
|
97
|
+
? `${field} String${reqStr} @id @default(uuid())`
|
|
98
|
+
: `${field} Int${reqStr} @id @default(autoincrement())`;
|
|
96
99
|
break;
|
|
97
100
|
|
|
98
101
|
case 'sqlite':
|
|
99
|
-
idString = `${field} Int @id @default(autoincrement())`;
|
|
102
|
+
idString = `${field} Int${reqStr} @id @default(autoincrement())`;
|
|
100
103
|
break;
|
|
101
|
-
}
|
|
104
|
+
}
|
|
102
105
|
|
|
103
106
|
if(tags.length){
|
|
104
107
|
idString += ' '+tags.join(' ');
|
|
@@ -108,9 +111,6 @@ export class DbUtils {
|
|
|
108
111
|
throw new Error(`DB type "${dbType}" is not supported!`);
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
if(debug){
|
|
112
|
-
console.log({idString, useUuid});
|
|
113
|
-
}
|
|
114
114
|
|
|
115
115
|
return idString;
|
|
116
116
|
}
|
|
@@ -11,6 +11,9 @@ import { ModelUtils } from '../utils/ModelUtils';
|
|
|
11
11
|
// import timeSeriesModel from './TimeSeriesModel';
|
|
12
12
|
import { DBService } from '../../services/DBService';
|
|
13
13
|
import { ISuperTagData } from '../../decorators/RWSCollection';
|
|
14
|
+
import { RelManyMetaType, RelOneMetaType } from '../types/RelationTypes';
|
|
15
|
+
import { IRWSModel } from '../../types/IRWSModel';
|
|
16
|
+
import { HydrateUtils } from '../utils/HydrateUtils';
|
|
14
17
|
|
|
15
18
|
class RWSModel<T> implements IModel {
|
|
16
19
|
static services: IRWSModelServices = {};
|
|
@@ -97,9 +100,7 @@ class RWSModel<T> implements IModel {
|
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
public async _asyncFill(data: any, fullDataMode = false, allowRelations = true): Promise<T> {
|
|
100
|
-
const collections_to_models: {[key: string]: any} = {};
|
|
101
|
-
const timeSeriesIds = TimeSeriesUtils.getTimeSeriesModelFields(this);
|
|
102
|
-
|
|
103
|
+
const collections_to_models: {[key: string]: any} = {};
|
|
103
104
|
const classFields = FieldsHelper.getAllClassFields(this.constructor);
|
|
104
105
|
|
|
105
106
|
// Get both relation metadata types asynchronously
|
|
@@ -116,93 +117,16 @@ class RWSModel<T> implements IModel {
|
|
|
116
117
|
|
|
117
118
|
|
|
118
119
|
if (allowRelations) {
|
|
119
|
-
|
|
120
|
-
for (const key in relManyData) {
|
|
121
|
-
if(!fullDataMode && (this as any).constructor._CUT_KEYS.includes(key)){
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const relMeta = relManyData[key];
|
|
126
|
-
|
|
127
|
-
const relationEnabled = !RelationUtils.checkRelDisabled(this, relMeta.key);
|
|
128
|
-
if (relationEnabled) {
|
|
129
|
-
this[relMeta.key] = await relMeta.inversionModel.findBy({
|
|
130
|
-
conditions: {
|
|
131
|
-
[relMeta.foreignKey]: data.id
|
|
132
|
-
},
|
|
133
|
-
allowRelations: false
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Handle one-to-one relations
|
|
139
|
-
for (const key in relOneData) {
|
|
140
|
-
if(!fullDataMode && (this as any).constructor._CUT_KEYS.includes(key)){
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const relMeta = relOneData[key];
|
|
145
|
-
const relationEnabled = !RelationUtils.checkRelDisabled(this, relMeta.key);
|
|
146
|
-
|
|
147
|
-
if(!data[relMeta.hydrationField] && relMeta.required){
|
|
148
|
-
throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
152
|
-
this[relMeta.key] = await relMeta.model.find(data[relMeta.hydrationField], { allowRelations: false });
|
|
153
|
-
}
|
|
154
|
-
else if(relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]){
|
|
155
|
-
const newRelModel: RWSModel<any> = await relMeta.model.create(data[relMeta.key]);
|
|
156
|
-
this[relMeta.key] = await newRelModel.save();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const cutKeys = ((this.constructor as any)._CUT_KEYS as string[]);
|
|
160
|
-
|
|
161
|
-
const trackedField = Object.keys((await ModelUtils.getModelAnnotations(this.constructor as any))).includes(relMeta.hydrationField);
|
|
162
|
-
|
|
163
|
-
if(!cutKeys.includes(relMeta.hydrationField) && !trackedField){
|
|
164
|
-
cutKeys.push(relMeta.hydrationField)
|
|
165
|
-
}
|
|
166
|
-
}
|
|
120
|
+
await HydrateUtils.hydrateRelations(this, relManyData, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
167
121
|
}
|
|
168
122
|
|
|
169
123
|
// Process regular fields and time series
|
|
170
|
-
|
|
171
|
-
if (data.hasOwnProperty(key)) {
|
|
172
|
-
if(!fullDataMode && (this as any).constructor._CUT_KEYS.includes(key)){
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (Object.keys(relOneData).includes(key)) {
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (seriesHydrationfields.includes(key)) {
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const timeSeriesMetaData = timeSeriesIds[key];
|
|
186
|
-
|
|
187
|
-
if (timeSeriesMetaData) {
|
|
188
|
-
this[key] = data[key];
|
|
189
|
-
const seriesModel = collections_to_models[timeSeriesMetaData.collection];
|
|
190
|
-
|
|
191
|
-
const dataModels = await seriesModel.findBy({
|
|
192
|
-
id: { in: data[key] }
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
|
|
196
|
-
|
|
197
|
-
this[timeSeriesMetaData.hydrationField] = dataModels;
|
|
198
|
-
} else {
|
|
199
|
-
this[key] = data[key];
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
124
|
+
await HydrateUtils.hydrateDataFields(this, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
203
125
|
|
|
204
126
|
return this as any as T;
|
|
205
|
-
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
206
130
|
|
|
207
131
|
private getModelScalarFields(model: RWSModel<T>): string[] {
|
|
208
132
|
return ModelUtils.getModelScalarFields(model);
|
|
@@ -449,7 +373,8 @@ class RWSModel<T> implements IModel {
|
|
|
449
373
|
const collection = Reflect.get(this, '_collection');
|
|
450
374
|
this.checkForInclusionWithThrow(this.name);
|
|
451
375
|
try {
|
|
452
|
-
const
|
|
376
|
+
const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
|
|
377
|
+
const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
453
378
|
|
|
454
379
|
if (dbData.length) {
|
|
455
380
|
const instanced: T[] = [];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { RWSModel } from "../core/RWSModel";
|
|
2
|
+
import { RelManyMetaType, RelOneMetaType } from "../types/RelationTypes";
|
|
3
|
+
import { IRWSModel } from "../../types/IRWSModel";
|
|
4
|
+
import { TimeSeriesUtils } from "./TimeSeriesUtils";
|
|
5
|
+
import { RelationUtils } from "./RelationUtils";
|
|
6
|
+
import { OpModelType } from "..";
|
|
7
|
+
import { ModelUtils } from "./ModelUtils";
|
|
8
|
+
|
|
9
|
+
export class HydrateUtils {
|
|
10
|
+
static async hydrateDataFields(model: RWSModel<any>, collections_to_models: {[key: string]: any}, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {[key: string] : any}){
|
|
11
|
+
const timeSeriesIds = TimeSeriesUtils.getTimeSeriesModelFields(model);
|
|
12
|
+
for (const key in data) {
|
|
13
|
+
if (data.hasOwnProperty(key)) {
|
|
14
|
+
if(!fullDataMode && ((model).constructor as OpModelType<any>)._CUT_KEYS.includes(key)){
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (Object.keys(relOneData).includes(key)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (seriesHydrationfields.includes(key)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const timeSeriesMetaData = timeSeriesIds[key];
|
|
28
|
+
|
|
29
|
+
if (timeSeriesMetaData) {
|
|
30
|
+
model[key] = data[key];
|
|
31
|
+
const seriesModel = collections_to_models[timeSeriesMetaData.collection];
|
|
32
|
+
|
|
33
|
+
const dataModels = await seriesModel.findBy({
|
|
34
|
+
id: { in: data[key] }
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
|
|
38
|
+
|
|
39
|
+
model[timeSeriesMetaData.hydrationField] = dataModels;
|
|
40
|
+
} else {
|
|
41
|
+
model[key] = data[key];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static async hydrateRelations(model: RWSModel<any>, relManyData: RelManyMetaType<IRWSModel>, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {[key: string] : any})
|
|
48
|
+
{
|
|
49
|
+
// Handle many-to-many relations
|
|
50
|
+
for (const key in relManyData) {
|
|
51
|
+
if(!fullDataMode && (model as any).constructor._CUT_KEYS.includes(key)){
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const relMeta = relManyData[key];
|
|
56
|
+
|
|
57
|
+
// console.log({relMeta});
|
|
58
|
+
|
|
59
|
+
const relationEnabled = !RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
60
|
+
if (relationEnabled) {
|
|
61
|
+
model[relMeta.key] = await relMeta.inversionModel.findBy({
|
|
62
|
+
conditions: {
|
|
63
|
+
[relMeta.foreignKey]: data.id
|
|
64
|
+
},
|
|
65
|
+
allowRelations: false
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Handle one-to-one relations
|
|
71
|
+
for (const key in relOneData) {
|
|
72
|
+
if(!fullDataMode && ((model as any).constructor as OpModelType<any>)._CUT_KEYS.includes(key)){
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const relMeta = relOneData[key];
|
|
77
|
+
const relationEnabled = !RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
78
|
+
|
|
79
|
+
if(!data[relMeta.hydrationField] && relMeta.required){
|
|
80
|
+
throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
84
|
+
model[relMeta.key] = await relMeta.model.findOneBy({conditions: {[relMeta.foreignKey] : data[relMeta.hydrationField]}}, { allowRelations: false });
|
|
85
|
+
}
|
|
86
|
+
else if(relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]){
|
|
87
|
+
const newRelModel: RWSModel<any> = await relMeta.model.create(data[relMeta.key]);
|
|
88
|
+
model[relMeta.key] = await newRelModel.save();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const cutKeys = ((model.constructor as OpModelType<any>)._CUT_KEYS as string[]);
|
|
92
|
+
|
|
93
|
+
const trackedField = Object.keys((await ModelUtils.getModelAnnotations(model.constructor as OpModelType<any>))).includes(relMeta.hydrationField);
|
|
94
|
+
|
|
95
|
+
if(!cutKeys.includes(relMeta.hydrationField) && !trackedField){
|
|
96
|
+
cutKeys.push(relMeta.hydrationField)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// seriesHydrationfields.push(relMeta.hydrationField);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|