@rws-framework/db 3.3.2 → 3.3.4
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/RWSCollection.d.ts +4 -1
- package/dist/decorators/Relation.js +3 -0
- package/dist/helper/db/schema-generator.d.ts +1 -0
- package/dist/helper/db/schema-generator.js +27 -10
- package/dist/models/core/RWSModel.d.ts +3 -4
- package/dist/models/core/RWSModel.js +22 -74
- package/dist/models/utils/FindUtils.d.ts +9 -0
- package/dist/models/utils/FindUtils.js +86 -0
- package/dist/models/utils/HydrateUtils.js +16 -2
- package/dist/models/utils/ModelUtils.d.ts +3 -0
- package/dist/models/utils/ModelUtils.js +52 -0
- package/dist/services/DBService.d.ts +2 -2
- package/dist/services/DBService.js +21 -8
- package/package.json +1 -1
- package/src/decorators/RWSCollection.ts +2 -1
- package/src/decorators/Relation.ts +3 -0
- package/src/helper/db/schema-generator.ts +43 -13
- package/src/models/core/RWSModel.ts +30 -98
- package/src/models/utils/FindUtils.ts +128 -0
- package/src/models/utils/HydrateUtils.ts +19 -5
- package/src/models/utils/ModelUtils.ts +70 -0
- package/src/services/DBService.ts +24 -9
|
@@ -20,6 +20,7 @@ export declare class SchemaGenerator {
|
|
|
20
20
|
* @returns The model section
|
|
21
21
|
*/
|
|
22
22
|
static generateModelSections(model: OpModelType<any>, configService: IDbConfigHandler): Promise<string>;
|
|
23
|
+
private static getSuperFieldFromModel;
|
|
23
24
|
/**
|
|
24
25
|
* Install Prisma with the generated schema
|
|
25
26
|
* @param configService The configuration service
|
|
@@ -108,13 +108,8 @@ datasource db {
|
|
|
108
108
|
if (!relatedFieldMeta.metadata.required) {
|
|
109
109
|
requiredString = '';
|
|
110
110
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
* @todo: Detect type
|
|
114
|
-
*/
|
|
115
|
-
if (relatedToField === 'id' && dbType !== 'mongodb') {
|
|
116
|
-
relatedFieldType = 'Int';
|
|
117
|
-
}
|
|
111
|
+
const defaultIdType = utils_1.DbUtils.getDefaultPrismaType(dbType, relatedFieldMeta.annotationType !== 'TrackType' && relatedFieldMeta.metadata.type.name === 'String' && relatedToField === 'id' && dbType !== 'mongodb');
|
|
112
|
+
let relatedFieldType = type_converter_1.TypeConverter.toConfigCase(relatedFieldMeta.metadata, dbType, true, relatedFieldMeta.annotationType !== 'TrackType' && relatedToField === 'id' && relatedFieldMeta.metadata.type !== defaultIdType);
|
|
118
113
|
if (relationMeta.required === false) {
|
|
119
114
|
requiredString = '?';
|
|
120
115
|
}
|
|
@@ -218,10 +213,24 @@ datasource db {
|
|
|
218
213
|
section += '\n';
|
|
219
214
|
}
|
|
220
215
|
for (const superTag of model._SUPER_TAGS) {
|
|
221
|
-
|
|
216
|
+
let mapStr = '';
|
|
217
|
+
if (superTag.map) {
|
|
218
|
+
const superFieldMapMeta = modelMetadatas[superTag.map];
|
|
219
|
+
let mapField = superTag.map;
|
|
220
|
+
if (superFieldMapMeta) {
|
|
221
|
+
mapField = this.getSuperFieldFromModel(mapField, superFieldMapMeta);
|
|
222
|
+
}
|
|
223
|
+
mapStr = `, map: "${mapField}"`;
|
|
224
|
+
}
|
|
222
225
|
const superFields = [];
|
|
223
|
-
for (
|
|
224
|
-
const
|
|
226
|
+
for (let superField of superTag.fields) {
|
|
227
|
+
const superFieldElemMeta = modelMetadatas[superField];
|
|
228
|
+
if (!superFieldElemMeta) {
|
|
229
|
+
console.log(chalk_1.default.yellowBright(`Ignoring "${superField}" field in "${superTag.tagType}" supertag in model "${modelName}"`));
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const fieldMetadata = superFieldElemMeta.metadata;
|
|
233
|
+
superField = this.getSuperFieldFromModel(superField, superFieldElemMeta);
|
|
225
234
|
let pushed = false;
|
|
226
235
|
if (fieldMetadata.dbOptions && fieldMetadata.dbOptions.mysql && fieldMetadata.dbOptions.mysql.useType) {
|
|
227
236
|
switch (fieldMetadata.dbOptions.mysql.useType) {
|
|
@@ -240,6 +249,14 @@ datasource db {
|
|
|
240
249
|
section += '}\n';
|
|
241
250
|
return section;
|
|
242
251
|
}
|
|
252
|
+
static getSuperFieldFromModel(superFieldElemName, superFieldElemMeta) {
|
|
253
|
+
const fieldDecorator = superFieldElemMeta.annotationType;
|
|
254
|
+
if (fieldDecorator === 'Relation') {
|
|
255
|
+
const fieldMetadata = superFieldElemMeta.metadata;
|
|
256
|
+
superFieldElemName = fieldMetadata.relationField;
|
|
257
|
+
}
|
|
258
|
+
return superFieldElemName;
|
|
259
|
+
}
|
|
243
260
|
/**
|
|
244
261
|
* Install Prisma with the generated schema
|
|
245
262
|
* @param configService The configuration service
|
|
@@ -4,8 +4,6 @@ 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';
|
|
9
7
|
declare class RWSModel<T> implements IModel {
|
|
10
8
|
static services: IRWSModelServices;
|
|
11
9
|
[key: string]: any;
|
|
@@ -32,9 +30,9 @@ declare class RWSModel<T> implements IModel {
|
|
|
32
30
|
_asyncFill(data: any, fullDataMode?: boolean, allowRelations?: boolean): Promise<T>;
|
|
33
31
|
private getModelScalarFields;
|
|
34
32
|
private getRelationOneMeta;
|
|
35
|
-
static getRelationOneMeta(model: any, classFields: string[]): Promise<RelOneMetaType<IRWSModel>>;
|
|
33
|
+
static getRelationOneMeta(model: any, classFields: string[]): Promise<import("..").RelOneMetaType<import("../..").IRWSModel>>;
|
|
36
34
|
private getRelationManyMeta;
|
|
37
|
-
static getRelationManyMeta(model: any, classFields: string[]): Promise<RelManyMetaType<IRWSModel>>;
|
|
35
|
+
static getRelationManyMeta(model: any, classFields: string[]): Promise<import("..").RelManyMetaType<import("../..").IRWSModel>>;
|
|
38
36
|
static paginate<T extends RWSModel<T>>(this: OpModelType<T>, paginateParams: IPaginationParams, findParams?: FindByType): Promise<T[]>;
|
|
39
37
|
toMongo(): Promise<any>;
|
|
40
38
|
getCollection(): string | null;
|
|
@@ -67,5 +65,6 @@ declare class RWSModel<T> implements IModel {
|
|
|
67
65
|
static setServices(services: IRWSModelServices): void;
|
|
68
66
|
getDb(): DBService;
|
|
69
67
|
static getDb(): DBService;
|
|
68
|
+
reload(): Promise<T | null>;
|
|
70
69
|
}
|
|
71
70
|
export { RWSModel };
|
|
@@ -16,6 +16,7 @@ const RelationUtils_1 = require("../utils/RelationUtils");
|
|
|
16
16
|
const TimeSeriesUtils_1 = require("../utils/TimeSeriesUtils");
|
|
17
17
|
const ModelUtils_1 = require("../utils/ModelUtils");
|
|
18
18
|
const HydrateUtils_1 = require("../utils/HydrateUtils");
|
|
19
|
+
const FindUtils_1 = require("../utils/FindUtils");
|
|
19
20
|
class RWSModel {
|
|
20
21
|
static services = {};
|
|
21
22
|
id;
|
|
@@ -119,29 +120,7 @@ class RWSModel {
|
|
|
119
120
|
return RelationUtils_1.RelationUtils.getRelationManyMeta(model, classFields);
|
|
120
121
|
}
|
|
121
122
|
static async paginate(paginateParams, findParams) {
|
|
122
|
-
|
|
123
|
-
const ordering = findParams?.ordering ?? null;
|
|
124
|
-
const fields = findParams?.fields ?? null;
|
|
125
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
126
|
-
const fullData = findParams?.fullData ?? false;
|
|
127
|
-
const collection = Reflect.get(this, '_collection');
|
|
128
|
-
this.checkForInclusionWithThrow(this.name);
|
|
129
|
-
try {
|
|
130
|
-
const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
131
|
-
if (dbData.length) {
|
|
132
|
-
const instanced = [];
|
|
133
|
-
for (const data of dbData) {
|
|
134
|
-
const inst = new this();
|
|
135
|
-
instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
|
|
136
|
-
}
|
|
137
|
-
return instanced;
|
|
138
|
-
}
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
catch (rwsError) {
|
|
142
|
-
console.error(rwsError);
|
|
143
|
-
throw rwsError;
|
|
144
|
-
}
|
|
123
|
+
return await FindUtils_1.FindUtils.paginate(this, paginateParams, findParams);
|
|
145
124
|
}
|
|
146
125
|
async toMongo() {
|
|
147
126
|
const data = {};
|
|
@@ -178,9 +157,11 @@ class RWSModel {
|
|
|
178
157
|
async save() {
|
|
179
158
|
const data = await this.toMongo();
|
|
180
159
|
let updatedModelData = data;
|
|
181
|
-
|
|
160
|
+
const entryExists = await ModelUtils_1.ModelUtils.entryExists(this);
|
|
161
|
+
if (entryExists) {
|
|
182
162
|
this.preUpdate();
|
|
183
|
-
|
|
163
|
+
const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
|
|
164
|
+
updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
|
|
184
165
|
await this._asyncFill(updatedModelData);
|
|
185
166
|
this.postUpdate();
|
|
186
167
|
}
|
|
@@ -239,59 +220,13 @@ class RWSModel {
|
|
|
239
220
|
return await this.services.dbService.watchCollection(collection, preRun);
|
|
240
221
|
}
|
|
241
222
|
static async findOneBy(findParams) {
|
|
242
|
-
|
|
243
|
-
const ordering = findParams?.ordering ?? null;
|
|
244
|
-
const fields = findParams?.fields ?? null;
|
|
245
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
246
|
-
const fullData = findParams?.fullData ?? false;
|
|
247
|
-
this.checkForInclusionWithThrow('');
|
|
248
|
-
const collection = Reflect.get(this, '_collection');
|
|
249
|
-
const dbData = await this.services.dbService.findOneBy(collection, conditions, fields, ordering, allowRelations);
|
|
250
|
-
if (dbData) {
|
|
251
|
-
const inst = new this();
|
|
252
|
-
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
253
|
-
}
|
|
254
|
-
return null;
|
|
223
|
+
return await FindUtils_1.FindUtils.findOneBy(this, findParams);
|
|
255
224
|
}
|
|
256
225
|
static async find(id, findParams = null) {
|
|
257
|
-
|
|
258
|
-
const fields = findParams?.fields ?? null;
|
|
259
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
260
|
-
const fullData = findParams?.fullData ?? false;
|
|
261
|
-
const collection = Reflect.get(this, '_collection');
|
|
262
|
-
this.checkForInclusionWithThrow(this.name);
|
|
263
|
-
const dbData = await this.services.dbService.findOneBy(collection, { id }, fields, ordering, allowRelations);
|
|
264
|
-
if (dbData) {
|
|
265
|
-
const inst = new this();
|
|
266
|
-
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
267
|
-
}
|
|
268
|
-
return null;
|
|
226
|
+
return await FindUtils_1.FindUtils.find(this, id, findParams);
|
|
269
227
|
}
|
|
270
228
|
static async findBy(findParams) {
|
|
271
|
-
|
|
272
|
-
const ordering = findParams?.ordering ?? null;
|
|
273
|
-
const fields = findParams?.fields ?? null;
|
|
274
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
275
|
-
const fullData = findParams?.fullData ?? false;
|
|
276
|
-
const collection = Reflect.get(this, '_collection');
|
|
277
|
-
this.checkForInclusionWithThrow(this.name);
|
|
278
|
-
try {
|
|
279
|
-
const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
|
|
280
|
-
const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
281
|
-
if (dbData.length) {
|
|
282
|
-
const instanced = [];
|
|
283
|
-
for (const data of dbData) {
|
|
284
|
-
const inst = new this();
|
|
285
|
-
instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
|
|
286
|
-
}
|
|
287
|
-
return instanced;
|
|
288
|
-
}
|
|
289
|
-
return [];
|
|
290
|
-
}
|
|
291
|
-
catch (rwsError) {
|
|
292
|
-
console.error(rwsError);
|
|
293
|
-
throw rwsError;
|
|
294
|
-
}
|
|
229
|
+
return await FindUtils_1.FindUtils.findBy(this, findParams);
|
|
295
230
|
}
|
|
296
231
|
static async delete(conditions) {
|
|
297
232
|
const collection = Reflect.get(this, '_collection');
|
|
@@ -330,6 +265,19 @@ class RWSModel {
|
|
|
330
265
|
static getDb() {
|
|
331
266
|
return this.services.dbService;
|
|
332
267
|
}
|
|
268
|
+
async reload() {
|
|
269
|
+
const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
|
|
270
|
+
const where = {};
|
|
271
|
+
if (Array.isArray(pk)) {
|
|
272
|
+
for (const pkElem of pk) {
|
|
273
|
+
where[pkElem] = this[pkElem];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
where[pk] = this[pk];
|
|
278
|
+
}
|
|
279
|
+
return await FindUtils_1.FindUtils.findOneBy(this.constructor, { conditions: where });
|
|
280
|
+
}
|
|
333
281
|
}
|
|
334
282
|
exports.RWSModel = RWSModel;
|
|
335
283
|
__decorate([
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RWSModel } from "../core/RWSModel";
|
|
2
|
+
import { OpModelType } from "..";
|
|
3
|
+
import { FindByType, IPaginationParams } from "../../types/FindParams";
|
|
4
|
+
export declare class FindUtils {
|
|
5
|
+
static findOneBy<T extends RWSModel<T>>(opModel: OpModelType<T>, findParams?: FindByType): Promise<T | null>;
|
|
6
|
+
static find<T extends RWSModel<T>>(opModel: OpModelType<T>, id: string | number, findParams?: Omit<FindByType, 'conditions'>): Promise<T | null>;
|
|
7
|
+
static findBy<T extends RWSModel<T>>(opModel: OpModelType<T>, findParams?: FindByType): Promise<T[]>;
|
|
8
|
+
static paginate<T extends RWSModel<T>>(opModel: OpModelType<T>, paginateParams: IPaginationParams, findParams?: FindByType): Promise<T[]>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FindUtils = void 0;
|
|
4
|
+
class FindUtils {
|
|
5
|
+
static async findOneBy(opModel, findParams) {
|
|
6
|
+
const conditions = findParams?.conditions ?? {};
|
|
7
|
+
const ordering = findParams?.ordering ?? null;
|
|
8
|
+
const fields = findParams?.fields ?? null;
|
|
9
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
10
|
+
const fullData = findParams?.fullData ?? false;
|
|
11
|
+
opModel.checkForInclusionWithThrow('');
|
|
12
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
13
|
+
const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
|
|
14
|
+
if (dbData) {
|
|
15
|
+
const inst = new opModel();
|
|
16
|
+
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
static async find(opModel, id, findParams = null) {
|
|
21
|
+
const ordering = findParams?.ordering ?? null;
|
|
22
|
+
const fields = findParams?.fields ?? null;
|
|
23
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
24
|
+
const fullData = findParams?.fullData ?? false;
|
|
25
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
26
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
27
|
+
const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
|
|
28
|
+
if (dbData) {
|
|
29
|
+
const inst = new opModel();
|
|
30
|
+
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
static async findBy(opModel, findParams) {
|
|
35
|
+
const conditions = findParams?.conditions ?? {};
|
|
36
|
+
const ordering = findParams?.ordering ?? null;
|
|
37
|
+
const fields = findParams?.fields ?? null;
|
|
38
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
39
|
+
const fullData = findParams?.fullData ?? false;
|
|
40
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
41
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
42
|
+
try {
|
|
43
|
+
const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
|
|
44
|
+
const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
45
|
+
if (dbData.length) {
|
|
46
|
+
const instanced = [];
|
|
47
|
+
for (const data of dbData) {
|
|
48
|
+
const inst = new opModel();
|
|
49
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
|
|
50
|
+
}
|
|
51
|
+
return instanced;
|
|
52
|
+
}
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
catch (rwsError) {
|
|
56
|
+
console.error(rwsError);
|
|
57
|
+
throw rwsError;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
static async paginate(opModel, paginateParams, findParams) {
|
|
61
|
+
const conditions = findParams?.conditions ?? {};
|
|
62
|
+
const ordering = findParams?.ordering ?? null;
|
|
63
|
+
const fields = findParams?.fields ?? null;
|
|
64
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
65
|
+
const fullData = findParams?.fullData ?? false;
|
|
66
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
67
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
68
|
+
try {
|
|
69
|
+
const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
70
|
+
if (dbData.length) {
|
|
71
|
+
const instanced = [];
|
|
72
|
+
for (const data of dbData) {
|
|
73
|
+
const inst = new opModel();
|
|
74
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
|
|
75
|
+
}
|
|
76
|
+
return instanced;
|
|
77
|
+
}
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
catch (rwsError) {
|
|
81
|
+
console.error(rwsError);
|
|
82
|
+
throw rwsError;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.FindUtils = FindUtils;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.HydrateUtils = void 0;
|
|
4
7
|
const TimeSeriesUtils_1 = require("./TimeSeriesUtils");
|
|
5
8
|
const RelationUtils_1 = require("./RelationUtils");
|
|
6
9
|
const ModelUtils_1 = require("./ModelUtils");
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
7
11
|
class HydrateUtils {
|
|
8
12
|
static async hydrateDataFields(model, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data) {
|
|
9
13
|
const timeSeriesIds = TimeSeriesUtils_1.TimeSeriesUtils.getTimeSeriesModelFields(model);
|
|
@@ -43,9 +47,10 @@ class HydrateUtils {
|
|
|
43
47
|
const relMeta = relManyData[key];
|
|
44
48
|
const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
45
49
|
if (relationEnabled) {
|
|
50
|
+
const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(model.constructor);
|
|
46
51
|
model[relMeta.key] = await relMeta.inversionModel.findBy({
|
|
47
52
|
conditions: {
|
|
48
|
-
[relMeta.foreignKey]: data
|
|
53
|
+
[relMeta.foreignKey]: data[pk]
|
|
49
54
|
},
|
|
50
55
|
allowRelations: false
|
|
51
56
|
});
|
|
@@ -62,7 +67,16 @@ class HydrateUtils {
|
|
|
62
67
|
throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`);
|
|
63
68
|
}
|
|
64
69
|
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
65
|
-
|
|
70
|
+
const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(relMeta.model);
|
|
71
|
+
const where = {};
|
|
72
|
+
if (Array.isArray(pk)) {
|
|
73
|
+
console.log(chalk_1.default.yellowBright(`Hydration field "${relMeta.hydrationField}" on model "${model.constructor.name}" leads to compound key. Ignoring.`));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
where[pk] = data[relMeta.hydrationField];
|
|
78
|
+
}
|
|
79
|
+
model[relMeta.key] = await relMeta.model.findOneBy({ conditions: where }, { allowRelations: false });
|
|
66
80
|
}
|
|
67
81
|
else if (relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]) {
|
|
68
82
|
const newRelModel = await relMeta.model.create(data[relMeta.key]);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RWSModel } from "../core/RWSModel";
|
|
2
|
+
import { OpModelType } from "..";
|
|
2
3
|
export declare class ModelUtils {
|
|
3
4
|
static getModelAnnotations<T extends unknown>(constructor: new () => T): Promise<Record<string, {
|
|
4
5
|
annotationType: string;
|
|
@@ -7,4 +8,6 @@ export declare class ModelUtils {
|
|
|
7
8
|
static checkDbVariable(constructor: any, variable: string): Promise<boolean>;
|
|
8
9
|
static isSubclass<T, C extends new () => T>(constructor: C, baseClass: new () => T): boolean;
|
|
9
10
|
static getModelScalarFields(model: RWSModel<any>): string[];
|
|
11
|
+
static findPrimaryKeyFields(opModel: OpModelType<any>): string | string[];
|
|
12
|
+
static entryExists(model: RWSModel<any>): Promise<boolean>;
|
|
10
13
|
}
|
|
@@ -59,5 +59,57 @@ class ModelUtils {
|
|
|
59
59
|
.filter((item) => item.indexOf('TrackType') === 0)
|
|
60
60
|
.map((item) => item.split(':').at(-1));
|
|
61
61
|
}
|
|
62
|
+
static findPrimaryKeyFields(opModel) {
|
|
63
|
+
if (opModel._NO_ID) {
|
|
64
|
+
const foundSuperId = opModel._SUPER_TAGS.find(tag => tag.tagType === 'id');
|
|
65
|
+
if (foundSuperId) {
|
|
66
|
+
return foundSuperId.fields;
|
|
67
|
+
}
|
|
68
|
+
const foundSuperUnique = opModel._SUPER_TAGS.find(tag => tag.tagType === 'unique');
|
|
69
|
+
if (foundSuperUnique) {
|
|
70
|
+
return foundSuperUnique.fields;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return 'id';
|
|
74
|
+
}
|
|
75
|
+
static async entryExists(model) {
|
|
76
|
+
let entryHasData = true;
|
|
77
|
+
let compoundId = false;
|
|
78
|
+
const foundPrimaryKey = this.findPrimaryKeyFields(model.constructor);
|
|
79
|
+
if (Array.isArray(foundPrimaryKey)) {
|
|
80
|
+
compoundId = true;
|
|
81
|
+
for (const idKey of foundPrimaryKey) {
|
|
82
|
+
if (!Object.hasOwn(model, idKey)) {
|
|
83
|
+
entryHasData = false;
|
|
84
|
+
}
|
|
85
|
+
if (Object.hasOwn(model, idKey) && !model[idKey]) {
|
|
86
|
+
entryHasData = false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
if (Object.hasOwn(model, foundPrimaryKey) && !model[foundPrimaryKey]) {
|
|
92
|
+
entryHasData = false;
|
|
93
|
+
}
|
|
94
|
+
if (!Object.hasOwn(model, foundPrimaryKey)) {
|
|
95
|
+
entryHasData = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!entryHasData) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const constructor = model.constructor;
|
|
102
|
+
const conditions = {};
|
|
103
|
+
if (compoundId) {
|
|
104
|
+
for (const key of foundPrimaryKey) {
|
|
105
|
+
conditions[key] = model[key];
|
|
106
|
+
}
|
|
107
|
+
return (await constructor.findOneBy({ conditions }) !== null);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
conditions[foundPrimaryKey] = model[foundPrimaryKey];
|
|
111
|
+
}
|
|
112
|
+
return (await constructor.findOneBy({ conditions })) !== null;
|
|
113
|
+
}
|
|
62
114
|
}
|
|
63
115
|
exports.ModelUtils = ModelUtils;
|
|
@@ -21,10 +21,10 @@ declare class DBService {
|
|
|
21
21
|
cloneDatabase(source: string, target: string): Promise<void>;
|
|
22
22
|
watchCollection(collectionName: string, preRun: () => void): Promise<any>;
|
|
23
23
|
insert(data: any, collection: string, isTimeSeries?: boolean): Promise<any>;
|
|
24
|
-
update(data: any, collection: string): Promise<IModel>;
|
|
24
|
+
update(data: any, collection: string, pk: string | string[]): Promise<IModel>;
|
|
25
25
|
findOneBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
|
|
26
26
|
[fieldName: string]: string;
|
|
27
|
-
}
|
|
27
|
+
}): Promise<IModel | null>;
|
|
28
28
|
delete(collection: string, conditions: any): Promise<void>;
|
|
29
29
|
findBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
|
|
30
30
|
[fieldName: string]: string;
|
|
@@ -101,19 +101,32 @@ class DBService {
|
|
|
101
101
|
result = await prismaCollection.create({ data });
|
|
102
102
|
return await this.findOneBy(collection, { id: result.id });
|
|
103
103
|
}
|
|
104
|
-
async update(data, collection) {
|
|
105
|
-
const model_id = data.id;
|
|
106
|
-
delete data['id'];
|
|
104
|
+
async update(data, collection, pk) {
|
|
107
105
|
const prismaCollection = this.getCollectionHandler(collection);
|
|
106
|
+
const where = {};
|
|
107
|
+
if (Array.isArray(pk)) {
|
|
108
|
+
for (const pkElem of pk) {
|
|
109
|
+
where[pkElem] = data[pkElem];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
where[pk] = data[pk];
|
|
114
|
+
}
|
|
115
|
+
if (!Array.isArray(pk)) {
|
|
116
|
+
delete data[pk];
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
for (const cKey in pk) {
|
|
120
|
+
delete data[cKey];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
108
123
|
await prismaCollection.update({
|
|
109
|
-
where
|
|
110
|
-
id: model_id,
|
|
111
|
-
},
|
|
124
|
+
where,
|
|
112
125
|
data: data,
|
|
113
126
|
});
|
|
114
|
-
return await this.findOneBy(collection,
|
|
127
|
+
return await this.findOneBy(collection, where);
|
|
115
128
|
}
|
|
116
|
-
async findOneBy(collection, conditions, fields = null, ordering = null
|
|
129
|
+
async findOneBy(collection, conditions, fields = null, ordering = null) {
|
|
117
130
|
const params = { where: conditions };
|
|
118
131
|
if (fields) {
|
|
119
132
|
params.select = {};
|
package/package.json
CHANGED
|
@@ -144,15 +144,9 @@ datasource db {
|
|
|
144
144
|
requiredString = '';
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
* @todo: Detect type
|
|
151
|
-
*/
|
|
152
|
-
if(relatedToField === 'id' && dbType !== 'mongodb'){
|
|
153
|
-
relatedFieldType = 'Int';
|
|
154
|
-
}
|
|
155
|
-
|
|
147
|
+
const defaultIdType = DbUtils.getDefaultPrismaType(dbType, relatedFieldMeta.annotationType !== 'TrackType' && relatedFieldMeta.metadata.type.name === 'String' && relatedToField === 'id' && dbType !== 'mongodb');
|
|
148
|
+
let relatedFieldType = TypeConverter.toConfigCase(relatedFieldMeta.metadata, dbType, true, relatedFieldMeta.annotationType !== 'TrackType' && relatedToField === 'id' && relatedFieldMeta.metadata.type !== defaultIdType);
|
|
149
|
+
|
|
156
150
|
if(relationMeta.required === false){
|
|
157
151
|
requiredString = '?';
|
|
158
152
|
}
|
|
@@ -271,13 +265,33 @@ datasource db {
|
|
|
271
265
|
|
|
272
266
|
for(const superTag of model._SUPER_TAGS){
|
|
273
267
|
|
|
274
|
-
|
|
268
|
+
let mapStr = '';
|
|
269
|
+
|
|
270
|
+
if(superTag.map){
|
|
271
|
+
const superFieldMapMeta = modelMetadatas[superTag.map];
|
|
272
|
+
|
|
273
|
+
let mapField: string = superTag.map;
|
|
274
|
+
|
|
275
|
+
if(superFieldMapMeta){
|
|
276
|
+
mapField = this.getSuperFieldFromModel(mapField, superFieldMapMeta);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
mapStr = `, map: "${mapField}"`;
|
|
280
|
+
}
|
|
275
281
|
|
|
276
282
|
const superFields = [];
|
|
277
283
|
|
|
278
|
-
for(
|
|
279
|
-
const
|
|
280
|
-
|
|
284
|
+
for(let superField of superTag.fields){
|
|
285
|
+
const superFieldElemMeta = modelMetadatas[superField];
|
|
286
|
+
|
|
287
|
+
if(!superFieldElemMeta){
|
|
288
|
+
console.log(chalk.yellowBright(`Ignoring "${superField}" field in "${superTag.tagType}" supertag in model "${modelName}"`));
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const fieldMetadata = superFieldElemMeta.metadata;
|
|
293
|
+
|
|
294
|
+
superField = this.getSuperFieldFromModel(superField, superFieldElemMeta);
|
|
281
295
|
|
|
282
296
|
let pushed = false;
|
|
283
297
|
|
|
@@ -302,6 +316,22 @@ datasource db {
|
|
|
302
316
|
return section;
|
|
303
317
|
}
|
|
304
318
|
|
|
319
|
+
private static getSuperFieldFromModel(superFieldElemName: string, superFieldElemMeta: {
|
|
320
|
+
annotationType: string;
|
|
321
|
+
metadata: any;
|
|
322
|
+
}): string
|
|
323
|
+
{
|
|
324
|
+
|
|
325
|
+
const fieldDecorator = superFieldElemMeta.annotationType;
|
|
326
|
+
|
|
327
|
+
if(fieldDecorator === 'Relation'){
|
|
328
|
+
const fieldMetadata = superFieldElemMeta.metadata as IRelationOpts;
|
|
329
|
+
superFieldElemName = fieldMetadata.relationField;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return superFieldElemName;
|
|
333
|
+
}
|
|
334
|
+
|
|
305
335
|
/**
|
|
306
336
|
* Install Prisma with the generated schema
|
|
307
337
|
* @param configService The configuration service
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IModel } from '../interfaces/IModel';
|
|
2
2
|
import { IRWSModelServices } from '../interfaces/IRWSModelServices';
|
|
3
3
|
import { OpModelType } from '../interfaces/OpModelType';
|
|
4
|
-
import { TrackType
|
|
4
|
+
import { TrackType } from '../../decorators';
|
|
5
5
|
import { FieldsHelper } from '../../helper/FieldsHelper';
|
|
6
6
|
import { FindByType, IPaginationParams } from '../../types/FindParams';
|
|
7
7
|
import { RelationUtils } from '../utils/RelationUtils';
|
|
@@ -11,9 +11,8 @@ 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
14
|
import { HydrateUtils } from '../utils/HydrateUtils';
|
|
15
|
+
import { FindUtils } from '../utils/FindUtils';
|
|
17
16
|
|
|
18
17
|
class RWSModel<T> implements IModel {
|
|
19
18
|
static services: IRWSModelServices = {};
|
|
@@ -153,33 +152,7 @@ class RWSModel<T> implements IModel {
|
|
|
153
152
|
paginateParams: IPaginationParams,
|
|
154
153
|
findParams?: FindByType
|
|
155
154
|
): Promise<T[]> {
|
|
156
|
-
|
|
157
|
-
const ordering = findParams?.ordering ?? null;
|
|
158
|
-
const fields = findParams?.fields ?? null;
|
|
159
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
160
|
-
const fullData = findParams?.fullData ?? false;
|
|
161
|
-
|
|
162
|
-
const collection = Reflect.get(this, '_collection');
|
|
163
|
-
this.checkForInclusionWithThrow(this.name);
|
|
164
|
-
try {
|
|
165
|
-
const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
166
|
-
if (dbData.length) {
|
|
167
|
-
const instanced: T[] = [];
|
|
168
|
-
|
|
169
|
-
for (const data of dbData) {
|
|
170
|
-
const inst: T = new (this as { new(): T })();
|
|
171
|
-
instanced.push((await inst._asyncFill(data, fullData,allowRelations)) as T);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return instanced;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return [];
|
|
178
|
-
} catch (rwsError: Error | any) {
|
|
179
|
-
console.error(rwsError);
|
|
180
|
-
|
|
181
|
-
throw rwsError;
|
|
182
|
-
}
|
|
155
|
+
return await FindUtils.paginate(this, paginateParams, findParams);
|
|
183
156
|
}
|
|
184
157
|
|
|
185
158
|
public async toMongo(): Promise<any> {
|
|
@@ -227,11 +200,16 @@ class RWSModel<T> implements IModel {
|
|
|
227
200
|
|
|
228
201
|
async save(): Promise<this> {
|
|
229
202
|
const data = await this.toMongo();
|
|
230
|
-
let updatedModelData = data;
|
|
231
|
-
|
|
203
|
+
let updatedModelData = data;
|
|
204
|
+
|
|
205
|
+
const entryExists = await ModelUtils.entryExists(this);
|
|
206
|
+
|
|
207
|
+
if (entryExists) {
|
|
232
208
|
this.preUpdate();
|
|
233
209
|
|
|
234
|
-
|
|
210
|
+
const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<any>);
|
|
211
|
+
|
|
212
|
+
updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
|
|
235
213
|
|
|
236
214
|
await this._asyncFill(updatedModelData);
|
|
237
215
|
this.postUpdate();
|
|
@@ -316,25 +294,7 @@ class RWSModel<T> implements IModel {
|
|
|
316
294
|
this: OpModelType<T>,
|
|
317
295
|
findParams?: FindByType
|
|
318
296
|
): Promise<T | null> {
|
|
319
|
-
|
|
320
|
-
const ordering = findParams?.ordering ?? null;
|
|
321
|
-
const fields = findParams?.fields ?? null;
|
|
322
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
323
|
-
const fullData = findParams?.fullData ?? false;
|
|
324
|
-
|
|
325
|
-
this.checkForInclusionWithThrow('');
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const collection = Reflect.get(this, '_collection');
|
|
329
|
-
const dbData = await this.services.dbService.findOneBy(collection, conditions, fields, ordering, allowRelations);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (dbData) {
|
|
333
|
-
const inst: T = new (this as { new(): T })();
|
|
334
|
-
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return null;
|
|
297
|
+
return await FindUtils.findOneBy(this, findParams);
|
|
338
298
|
}
|
|
339
299
|
|
|
340
300
|
public static async find<T extends RWSModel<T>>(
|
|
@@ -342,58 +302,14 @@ class RWSModel<T> implements IModel {
|
|
|
342
302
|
id: string | number,
|
|
343
303
|
findParams: Omit<FindByType, 'conditions'> = null
|
|
344
304
|
): Promise<T | null> {
|
|
345
|
-
|
|
346
|
-
const fields = findParams?.fields ?? null;
|
|
347
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
348
|
-
const fullData = findParams?.fullData ?? false;
|
|
349
|
-
|
|
350
|
-
const collection = Reflect.get(this, '_collection');
|
|
351
|
-
this.checkForInclusionWithThrow(this.name);
|
|
352
|
-
|
|
353
|
-
const dbData = await this.services.dbService.findOneBy(collection, { id }, fields, ordering, allowRelations);
|
|
354
|
-
|
|
355
|
-
if (dbData) {
|
|
356
|
-
const inst: T = new (this as { new(): T })();
|
|
357
|
-
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return null;
|
|
305
|
+
return await FindUtils.find(this, id, findParams)
|
|
361
306
|
}
|
|
362
307
|
|
|
363
308
|
public static async findBy<T extends RWSModel<T>>(
|
|
364
309
|
this: OpModelType<T>,
|
|
365
310
|
findParams?: FindByType
|
|
366
311
|
): Promise<T[]> {
|
|
367
|
-
|
|
368
|
-
const ordering = findParams?.ordering ?? null;
|
|
369
|
-
const fields = findParams?.fields ?? null;
|
|
370
|
-
const allowRelations = findParams?.allowRelations ?? true;
|
|
371
|
-
const fullData = findParams?.fullData ?? false;
|
|
372
|
-
|
|
373
|
-
const collection = Reflect.get(this, '_collection');
|
|
374
|
-
this.checkForInclusionWithThrow(this.name);
|
|
375
|
-
try {
|
|
376
|
-
const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
|
|
377
|
-
const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
378
|
-
|
|
379
|
-
if (dbData.length) {
|
|
380
|
-
const instanced: T[] = [];
|
|
381
|
-
|
|
382
|
-
for (const data of dbData) {
|
|
383
|
-
const inst: T = new (this as { new(): T })();
|
|
384
|
-
|
|
385
|
-
instanced.push((await inst._asyncFill(data, fullData,allowRelations)) as T);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return instanced;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
return [];
|
|
392
|
-
} catch (rwsError: Error | any) {
|
|
393
|
-
console.error(rwsError);
|
|
394
|
-
|
|
395
|
-
throw rwsError;
|
|
396
|
-
}
|
|
312
|
+
return await FindUtils.findBy(this, findParams);
|
|
397
313
|
}
|
|
398
314
|
|
|
399
315
|
public static async delete<T extends RWSModel<T>>(
|
|
@@ -449,6 +365,22 @@ class RWSModel<T> implements IModel {
|
|
|
449
365
|
{
|
|
450
366
|
return this.services.dbService;
|
|
451
367
|
}
|
|
368
|
+
|
|
369
|
+
public async reload(): Promise<T | null>
|
|
370
|
+
{
|
|
371
|
+
const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<any>);
|
|
372
|
+
const where: any = {};
|
|
373
|
+
|
|
374
|
+
if(Array.isArray(pk)){
|
|
375
|
+
for(const pkElem of pk){
|
|
376
|
+
where[pkElem] = this[pkElem];
|
|
377
|
+
}
|
|
378
|
+
}else{
|
|
379
|
+
where[pk as string] = this[pk as string]
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return await FindUtils.findOneBy(this.constructor as OpModelType<any>, { conditions: where });
|
|
383
|
+
}
|
|
452
384
|
}
|
|
453
385
|
|
|
454
386
|
export { RWSModel };
|
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
import { FindByType, IPaginationParams } from "../../types/FindParams";
|
|
9
|
+
|
|
10
|
+
export class FindUtils {
|
|
11
|
+
public static async findOneBy<T extends RWSModel<T>>(
|
|
12
|
+
opModel: OpModelType<T>,
|
|
13
|
+
findParams?: FindByType
|
|
14
|
+
): Promise<T | null> {
|
|
15
|
+
const conditions = findParams?.conditions ?? {};
|
|
16
|
+
const ordering = findParams?.ordering ?? null;
|
|
17
|
+
const fields = findParams?.fields ?? null;
|
|
18
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
19
|
+
const fullData = findParams?.fullData ?? false;
|
|
20
|
+
|
|
21
|
+
opModel.checkForInclusionWithThrow('');
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
25
|
+
const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if (dbData) {
|
|
29
|
+
const inst: T = new (opModel as { new(): T })();
|
|
30
|
+
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static async find<T extends RWSModel<T>>(
|
|
37
|
+
opModel: OpModelType<T>,
|
|
38
|
+
id: string | number,
|
|
39
|
+
findParams: Omit<FindByType, 'conditions'> = null
|
|
40
|
+
): Promise<T | null> {
|
|
41
|
+
const ordering = findParams?.ordering ?? null;
|
|
42
|
+
const fields = findParams?.fields ?? null;
|
|
43
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
44
|
+
const fullData = findParams?.fullData ?? false;
|
|
45
|
+
|
|
46
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
47
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
48
|
+
|
|
49
|
+
const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
|
|
50
|
+
|
|
51
|
+
if (dbData) {
|
|
52
|
+
const inst: T = new (opModel as { new(): T })();
|
|
53
|
+
return await inst._asyncFill(dbData, fullData, allowRelations);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public static async findBy<T extends RWSModel<T>>(
|
|
60
|
+
opModel: OpModelType<T>,
|
|
61
|
+
findParams?: FindByType
|
|
62
|
+
): Promise<T[]> {
|
|
63
|
+
const conditions = findParams?.conditions ?? {};
|
|
64
|
+
const ordering = findParams?.ordering ?? null;
|
|
65
|
+
const fields = findParams?.fields ?? null;
|
|
66
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
67
|
+
const fullData = findParams?.fullData ?? false;
|
|
68
|
+
|
|
69
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
70
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
71
|
+
try {
|
|
72
|
+
const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
|
|
73
|
+
const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
74
|
+
|
|
75
|
+
if (dbData.length) {
|
|
76
|
+
const instanced: T[] = [];
|
|
77
|
+
|
|
78
|
+
for (const data of dbData) {
|
|
79
|
+
const inst: T = new (opModel as { new(): T })();
|
|
80
|
+
|
|
81
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations)) as T);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return instanced;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return [];
|
|
88
|
+
} catch (rwsError: Error | any) {
|
|
89
|
+
console.error(rwsError);
|
|
90
|
+
|
|
91
|
+
throw rwsError;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public static async paginate<T extends RWSModel<T>>(
|
|
96
|
+
opModel: OpModelType<T>,
|
|
97
|
+
paginateParams: IPaginationParams,
|
|
98
|
+
findParams?: FindByType
|
|
99
|
+
): Promise<T[]> {
|
|
100
|
+
const conditions = findParams?.conditions ?? {};
|
|
101
|
+
const ordering = findParams?.ordering ?? null;
|
|
102
|
+
const fields = findParams?.fields ?? null;
|
|
103
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
104
|
+
const fullData = findParams?.fullData ?? false;
|
|
105
|
+
|
|
106
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
107
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
108
|
+
try {
|
|
109
|
+
const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
110
|
+
if (dbData.length) {
|
|
111
|
+
const instanced: T[] = [];
|
|
112
|
+
|
|
113
|
+
for (const data of dbData) {
|
|
114
|
+
const inst: T = new (opModel as { new(): T })();
|
|
115
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations)) as T);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return instanced;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return [];
|
|
122
|
+
} catch (rwsError: Error | any) {
|
|
123
|
+
console.error(rwsError);
|
|
124
|
+
|
|
125
|
+
throw rwsError;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -5,6 +5,7 @@ import { TimeSeriesUtils } from "./TimeSeriesUtils";
|
|
|
5
5
|
import { RelationUtils } from "./RelationUtils";
|
|
6
6
|
import { OpModelType } from "..";
|
|
7
7
|
import { ModelUtils } from "./ModelUtils";
|
|
8
|
+
import chalk from 'chalk';
|
|
8
9
|
|
|
9
10
|
export class HydrateUtils {
|
|
10
11
|
static async hydrateDataFields(model: RWSModel<any>, collections_to_models: {[key: string]: any}, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {[key: string] : any}){
|
|
@@ -58,13 +59,15 @@ export class HydrateUtils {
|
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
|
|
61
|
-
if (relationEnabled) {
|
|
62
|
+
if (relationEnabled) {
|
|
63
|
+
const pk = ModelUtils.findPrimaryKeyFields(model.constructor as OpModelType<any>) as string;
|
|
64
|
+
|
|
62
65
|
model[relMeta.key] = await relMeta.inversionModel.findBy({
|
|
63
66
|
conditions: {
|
|
64
|
-
[relMeta.foreignKey]: data
|
|
67
|
+
[relMeta.foreignKey]: data[pk]
|
|
65
68
|
},
|
|
66
69
|
allowRelations: false
|
|
67
|
-
});
|
|
70
|
+
});
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -81,8 +84,19 @@ export class HydrateUtils {
|
|
|
81
84
|
throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`)
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
85
|
-
|
|
87
|
+
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
88
|
+
const pk = ModelUtils.findPrimaryKeyFields(relMeta.model);
|
|
89
|
+
|
|
90
|
+
const where: any = {};
|
|
91
|
+
|
|
92
|
+
if(Array.isArray(pk)){
|
|
93
|
+
console.log(chalk.yellowBright(`Hydration field "${relMeta.hydrationField}" on model "${model.constructor.name}" leads to compound key. Ignoring.`));
|
|
94
|
+
continue;
|
|
95
|
+
}else{
|
|
96
|
+
where[pk as string] = data[relMeta.hydrationField]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
model[relMeta.key] = await relMeta.model.findOneBy({conditions: where}, { allowRelations: false });
|
|
86
100
|
}
|
|
87
101
|
else if(relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]){
|
|
88
102
|
const newRelModel: RWSModel<any> = await relMeta.model.create(data[relMeta.key]);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { RWSModel } from "../core/RWSModel";
|
|
2
2
|
import { FieldsHelper } from '../../helper/FieldsHelper';
|
|
3
|
+
import { OpModelType } from "..";
|
|
4
|
+
import { ISuperTagData } from "../../decorators/RWSCollection";
|
|
5
|
+
import { FindByType } from "../../types/FindParams";
|
|
3
6
|
|
|
4
7
|
export class ModelUtils {
|
|
5
8
|
static async getModelAnnotations<T extends unknown>(constructor: new () => T): Promise<Record<string, {annotationType: string, metadata: any}>> {
|
|
@@ -71,4 +74,71 @@ export class ModelUtils {
|
|
|
71
74
|
.filter((item: string) => item.indexOf('TrackType') === 0)
|
|
72
75
|
.map((item: string) => item.split(':').at(-1));
|
|
73
76
|
}
|
|
77
|
+
|
|
78
|
+
static findPrimaryKeyFields(opModel: OpModelType<any>): string | string[]
|
|
79
|
+
{
|
|
80
|
+
if(opModel._NO_ID){
|
|
81
|
+
const foundSuperId: ISuperTagData = opModel._SUPER_TAGS.find(tag => tag.tagType === 'id');
|
|
82
|
+
|
|
83
|
+
if(foundSuperId){
|
|
84
|
+
return foundSuperId.fields;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const foundSuperUnique: ISuperTagData = opModel._SUPER_TAGS.find(tag => tag.tagType === 'unique');
|
|
88
|
+
|
|
89
|
+
if(foundSuperUnique){
|
|
90
|
+
return foundSuperUnique.fields;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return 'id';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static async entryExists(model: RWSModel<any>): Promise<boolean>
|
|
98
|
+
{
|
|
99
|
+
let entryHasData = true;
|
|
100
|
+
let compoundId = false;
|
|
101
|
+
|
|
102
|
+
const foundPrimaryKey = this.findPrimaryKeyFields(model.constructor as OpModelType<any>);
|
|
103
|
+
|
|
104
|
+
if(Array.isArray(foundPrimaryKey)){
|
|
105
|
+
compoundId = true;
|
|
106
|
+
for(const idKey of foundPrimaryKey){
|
|
107
|
+
if(!Object.hasOwn(model, idKey)){
|
|
108
|
+
entryHasData = false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if(Object.hasOwn(model, idKey) && !model[idKey]){
|
|
112
|
+
entryHasData = false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}else{
|
|
116
|
+
if(Object.hasOwn(model, foundPrimaryKey) && !model[foundPrimaryKey]){
|
|
117
|
+
entryHasData = false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if(!Object.hasOwn(model, foundPrimaryKey)){
|
|
121
|
+
entryHasData = false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if(!entryHasData){
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const constructor = model.constructor as OpModelType<any>;
|
|
130
|
+
const conditions: FindByType['conditions'] = {};
|
|
131
|
+
|
|
132
|
+
if(compoundId){
|
|
133
|
+
for(const key of foundPrimaryKey){
|
|
134
|
+
conditions[key] = model[key];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return (await constructor.findOneBy({ conditions }) !== null);
|
|
138
|
+
}else{
|
|
139
|
+
conditions[foundPrimaryKey as string] = model[foundPrimaryKey as string];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return (await constructor.findOneBy({ conditions })) !== null;
|
|
143
|
+
}
|
|
74
144
|
}
|
|
@@ -137,26 +137,41 @@ class DBService {
|
|
|
137
137
|
return await this.findOneBy(collection, { id: result.id });
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
async update(data: any, collection: string): Promise<IModel>
|
|
141
|
-
{
|
|
142
|
-
const model_id: string = data.id;
|
|
143
|
-
delete data['id'];
|
|
140
|
+
async update(data: any, collection: string, pk: string | string[]): Promise<IModel>
|
|
141
|
+
{
|
|
144
142
|
|
|
145
143
|
const prismaCollection = this.getCollectionHandler(collection);
|
|
146
144
|
|
|
145
|
+
|
|
146
|
+
const where: any = {};
|
|
147
|
+
|
|
148
|
+
if(Array.isArray(pk)){
|
|
149
|
+
for(const pkElem of pk){
|
|
150
|
+
where[pkElem] = data[pkElem];
|
|
151
|
+
}
|
|
152
|
+
}else{
|
|
153
|
+
where[pk as string] = data[pk as string]
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if(!Array.isArray(pk)){
|
|
157
|
+
delete data[pk];
|
|
158
|
+
}else{
|
|
159
|
+
for(const cKey in pk){
|
|
160
|
+
delete data[cKey];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
147
164
|
await prismaCollection.update({
|
|
148
|
-
where
|
|
149
|
-
id: model_id,
|
|
150
|
-
},
|
|
165
|
+
where,
|
|
151
166
|
data: data,
|
|
152
167
|
});
|
|
153
168
|
|
|
154
169
|
|
|
155
|
-
return await this.findOneBy(collection,
|
|
170
|
+
return await this.findOneBy(collection, where);
|
|
156
171
|
}
|
|
157
172
|
|
|
158
173
|
|
|
159
|
-
async findOneBy(collection: string, conditions: any, fields: string[] | null = null, ordering: { [fieldName: string]: string } = null
|
|
174
|
+
async findOneBy(collection: string, conditions: any, fields: string[] | null = null, ordering: { [fieldName: string]: string } = null): Promise<IModel|null>
|
|
160
175
|
{
|
|
161
176
|
const params: any = { where: conditions };
|
|
162
177
|
|