@rws-framework/db 3.5.1 → 3.6.1
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/models/core/RWSModel.d.ts +10 -6
- package/dist/models/core/RWSModel.js +23 -9
- package/dist/models/interfaces/IModel.d.ts +13 -3
- package/dist/models/interfaces/OpModelType.d.ts +12 -1
- package/dist/models/utils/FindUtils.js +6 -4
- package/dist/models/utils/HydrateUtils.d.ts +1 -1
- package/dist/models/utils/HydrateUtils.js +5 -3
- package/dist/types/FindParams.d.ts +1 -0
- package/package.json +1 -1
- package/src/models/core/RWSModel.ts +33 -13
- package/src/models/interfaces/IModel.ts +17 -4
- package/src/models/interfaces/OpModelType.ts +33 -10
- package/src/models/utils/FindUtils.ts +6 -4
- package/src/models/utils/HydrateUtils.ts +115 -114
- package/src/types/FindParams.ts +1 -0
|
@@ -15,7 +15,10 @@ declare class RWSModel<T> implements IModel {
|
|
|
15
15
|
static _BANNED_KEYS: string[];
|
|
16
16
|
static allModels: OpModelType<any>[];
|
|
17
17
|
static _CUT_KEYS: string[];
|
|
18
|
+
private postLoadExecuted;
|
|
18
19
|
constructor(data?: any);
|
|
20
|
+
isPostLoadExecuted(): boolean;
|
|
21
|
+
setPostLoadExecuted(): void;
|
|
19
22
|
checkForInclusionWithThrow(): void;
|
|
20
23
|
static checkForInclusionWithThrow(this: OpModelType<any>, checkModelType: string): void;
|
|
21
24
|
checkForInclusion(): boolean;
|
|
@@ -27,7 +30,7 @@ declare class RWSModel<T> implements IModel {
|
|
|
27
30
|
id: string | number;
|
|
28
31
|
};
|
|
29
32
|
};
|
|
30
|
-
_asyncFill(data: any, fullDataMode?: boolean, allowRelations?: boolean): Promise<T>;
|
|
33
|
+
_asyncFill(data: any, fullDataMode?: boolean, allowRelations?: boolean, postLoadExecute?: boolean): Promise<T>;
|
|
31
34
|
private getModelScalarFields;
|
|
32
35
|
private getRelationOneMeta;
|
|
33
36
|
static getRelationOneMeta(model: any, classFields: string[]): Promise<import("..").RelOneMetaType<import("../..").IRWSModel>>;
|
|
@@ -42,10 +45,11 @@ declare class RWSModel<T> implements IModel {
|
|
|
42
45
|
annotationType: string;
|
|
43
46
|
metadata: any;
|
|
44
47
|
}>>;
|
|
45
|
-
preUpdate(): void
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
preUpdate(): Promise<void>;
|
|
49
|
+
postLoad(): Promise<void>;
|
|
50
|
+
postUpdate(): Promise<void>;
|
|
51
|
+
preCreate(): Promise<void>;
|
|
52
|
+
postCreate(): Promise<void>;
|
|
49
53
|
static isSubclass<T extends RWSModel<T>, C extends new () => T>(constructor: C, baseClass: new () => T): boolean;
|
|
50
54
|
hasTimeSeries(): boolean;
|
|
51
55
|
static checkTimeSeries(constructor: any): boolean;
|
|
@@ -68,6 +72,6 @@ declare class RWSModel<T> implements IModel {
|
|
|
68
72
|
[k: string]: any;
|
|
69
73
|
}): Promise<number>;
|
|
70
74
|
static getDb(): DBService;
|
|
71
|
-
reload(): Promise<T | null>;
|
|
75
|
+
reload(): Promise<RWSModel<T> | null>;
|
|
72
76
|
}
|
|
73
77
|
export { RWSModel };
|
|
@@ -27,6 +27,7 @@ class RWSModel {
|
|
|
27
27
|
static _BANNED_KEYS = ['_collection'];
|
|
28
28
|
static allModels = [];
|
|
29
29
|
static _CUT_KEYS = [];
|
|
30
|
+
postLoadExecuted = false;
|
|
30
31
|
constructor(data = null) {
|
|
31
32
|
if (!this.getCollection()) {
|
|
32
33
|
throw new Error('Model must have a collection defined');
|
|
@@ -43,6 +44,12 @@ class RWSModel {
|
|
|
43
44
|
throw new Error('Time Series not supported in synchronous constructor. Use `await Model.create(data)` static method to instantiate this model.');
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
isPostLoadExecuted() {
|
|
48
|
+
return this.postLoadExecuted;
|
|
49
|
+
}
|
|
50
|
+
setPostLoadExecuted() {
|
|
51
|
+
this.postLoadExecuted = true;
|
|
52
|
+
}
|
|
46
53
|
checkForInclusionWithThrow() {
|
|
47
54
|
const constructor = this.constructor;
|
|
48
55
|
if (!constructor.checkForInclusion(constructor.name)) {
|
|
@@ -85,7 +92,7 @@ class RWSModel {
|
|
|
85
92
|
bindRelation(key, relatedModel) {
|
|
86
93
|
return RelationUtils_1.RelationUtils.bindRelation(relatedModel);
|
|
87
94
|
}
|
|
88
|
-
async _asyncFill(data, fullDataMode = false, allowRelations = true) {
|
|
95
|
+
async _asyncFill(data, fullDataMode = false, allowRelations = true, postLoadExecute = true) {
|
|
89
96
|
const collections_to_models = {};
|
|
90
97
|
const classFields = FieldsHelper_1.FieldsHelper.getAllClassFields(this.constructor);
|
|
91
98
|
// Get both relation metadata types asynchronously
|
|
@@ -102,6 +109,10 @@ class RWSModel {
|
|
|
102
109
|
}
|
|
103
110
|
// Process regular fields and time series
|
|
104
111
|
await HydrateUtils_1.HydrateUtils.hydrateDataFields(this, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
112
|
+
if (!this.isPostLoadExecuted() && postLoadExecute) {
|
|
113
|
+
await this.postLoad();
|
|
114
|
+
this.setPostLoadExecuted();
|
|
115
|
+
}
|
|
105
116
|
return this;
|
|
106
117
|
}
|
|
107
118
|
getModelScalarFields(model) {
|
|
@@ -159,34 +170,37 @@ class RWSModel {
|
|
|
159
170
|
let updatedModelData = data;
|
|
160
171
|
const entryExists = await ModelUtils_1.ModelUtils.entryExists(this);
|
|
161
172
|
if (entryExists) {
|
|
162
|
-
this.preUpdate();
|
|
173
|
+
await this.preUpdate();
|
|
163
174
|
const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
|
|
164
175
|
updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
|
|
165
176
|
await this._asyncFill(updatedModelData);
|
|
166
|
-
this.postUpdate();
|
|
177
|
+
await this.postUpdate();
|
|
167
178
|
}
|
|
168
179
|
else {
|
|
169
|
-
this.preCreate();
|
|
180
|
+
await this.preCreate();
|
|
170
181
|
const isTimeSeries = false; //this instanceof timeSeriesModel;
|
|
171
182
|
updatedModelData = await this.dbService.insert(data, this.getCollection(), isTimeSeries);
|
|
172
183
|
await this._asyncFill(updatedModelData);
|
|
173
|
-
this.postCreate();
|
|
184
|
+
await this.postCreate();
|
|
174
185
|
}
|
|
175
186
|
return this;
|
|
176
187
|
}
|
|
177
188
|
static async getModelAnnotations(constructor) {
|
|
178
189
|
return ModelUtils_1.ModelUtils.getModelAnnotations(constructor);
|
|
179
190
|
}
|
|
180
|
-
preUpdate() {
|
|
191
|
+
async preUpdate() {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
async postLoad() {
|
|
181
195
|
return;
|
|
182
196
|
}
|
|
183
|
-
postUpdate() {
|
|
197
|
+
async postUpdate() {
|
|
184
198
|
return;
|
|
185
199
|
}
|
|
186
|
-
preCreate() {
|
|
200
|
+
async preCreate() {
|
|
187
201
|
return;
|
|
188
202
|
}
|
|
189
|
-
postCreate() {
|
|
203
|
+
async postCreate() {
|
|
190
204
|
return;
|
|
191
205
|
}
|
|
192
206
|
static isSubclass(constructor, baseClass) {
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { IDbConfigHandler } from '../../types/DbConfigHandler';
|
|
2
2
|
import { DBService } from '../../services/DBService';
|
|
3
|
+
import { RWSModel } from '..';
|
|
3
4
|
export interface IModel {
|
|
4
5
|
[key: string]: any;
|
|
5
6
|
id: string | number | null;
|
|
6
|
-
save: () => void;
|
|
7
|
-
getDb: () => DBService;
|
|
8
|
-
getCollection: () => string | null;
|
|
9
7
|
configService?: IDbConfigHandler;
|
|
10
8
|
dbService?: DBService;
|
|
9
|
+
save: () => Promise<this>;
|
|
10
|
+
getDb: () => DBService;
|
|
11
|
+
getCollection: () => string | null;
|
|
12
|
+
reload: () => Promise<RWSModel<any>>;
|
|
13
|
+
delete: () => Promise<void>;
|
|
14
|
+
hasTimeSeries: () => boolean;
|
|
15
|
+
_asyncFill: (data: any, fullDataMode?: boolean, allowRelations?: boolean) => Promise<any>;
|
|
16
|
+
preUpdate: () => Promise<void>;
|
|
17
|
+
postUpdate: () => Promise<void>;
|
|
18
|
+
preCreate: () => Promise<void>;
|
|
19
|
+
postCreate: () => Promise<void>;
|
|
20
|
+
postLoad: () => Promise<void>;
|
|
11
21
|
}
|
|
@@ -28,7 +28,18 @@ export interface OpModelType<T> {
|
|
|
28
28
|
create<T extends RWSModel<T>>(this: new () => T, data: any): Promise<T>;
|
|
29
29
|
getRelationOneMeta(model: any, classFields: string[]): Promise<RelOneMetaType<IRWSModel>>;
|
|
30
30
|
getRelationManyMeta(model: any, classFields: string[]): Promise<RelManyMetaType<IRWSModel>>;
|
|
31
|
-
getCollection(): string;
|
|
31
|
+
getCollection(): string | null;
|
|
32
32
|
getDb(): DBService;
|
|
33
33
|
setServices(services: IRWSModelServices): void;
|
|
34
|
+
watchCollection<T extends RWSModel<T>>(this: OpModelType<T>, preRun: () => void): Promise<any>;
|
|
35
|
+
count(where?: {
|
|
36
|
+
[k: string]: any;
|
|
37
|
+
}): Promise<number>;
|
|
38
|
+
isSubclass<T extends RWSModel<T>, C extends new () => T>(constructor: C, baseClass: new () => T): boolean;
|
|
39
|
+
getModelAnnotations<T extends unknown>(constructor: new () => T): Promise<Record<string, {
|
|
40
|
+
annotationType: string;
|
|
41
|
+
metadata: any;
|
|
42
|
+
}>>;
|
|
43
|
+
checkTimeSeries(constructor: any): boolean;
|
|
44
|
+
checkDbVariable(constructor: any, variable: string): Promise<boolean>;
|
|
34
45
|
}
|
|
@@ -13,7 +13,8 @@ class FindUtils {
|
|
|
13
13
|
const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
|
|
14
14
|
if (dbData) {
|
|
15
15
|
const inst = new opModel();
|
|
16
|
-
|
|
16
|
+
const loaded = await inst._asyncFill(dbData, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
17
|
+
return loaded;
|
|
17
18
|
}
|
|
18
19
|
return null;
|
|
19
20
|
}
|
|
@@ -27,7 +28,8 @@ class FindUtils {
|
|
|
27
28
|
const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
|
|
28
29
|
if (dbData) {
|
|
29
30
|
const inst = new opModel();
|
|
30
|
-
|
|
31
|
+
const loaded = await inst._asyncFill(dbData, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
32
|
+
return loaded;
|
|
31
33
|
}
|
|
32
34
|
return null;
|
|
33
35
|
}
|
|
@@ -46,7 +48,7 @@ class FindUtils {
|
|
|
46
48
|
const instanced = [];
|
|
47
49
|
for (const data of dbData) {
|
|
48
50
|
const inst = new opModel();
|
|
49
|
-
instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
|
|
51
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations, findParams?.cancelPostLoad ? false : true)));
|
|
50
52
|
}
|
|
51
53
|
return instanced;
|
|
52
54
|
}
|
|
@@ -71,7 +73,7 @@ class FindUtils {
|
|
|
71
73
|
const instanced = [];
|
|
72
74
|
for (const data of dbData) {
|
|
73
75
|
const inst = new opModel();
|
|
74
|
-
instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
|
|
76
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations, findParams?.cancelPostLoad ? false : true)));
|
|
75
77
|
}
|
|
76
78
|
return instanced;
|
|
77
79
|
}
|
|
@@ -9,5 +9,5 @@ export declare class HydrateUtils {
|
|
|
9
9
|
}): Promise<void>;
|
|
10
10
|
static hydrateRelations(model: RWSModel<any>, relManyData: RelManyMetaType<IRWSModel>, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {
|
|
11
11
|
[key: string]: any;
|
|
12
|
-
}): Promise<void>;
|
|
12
|
+
}, postLoadExecute?: boolean): Promise<void>;
|
|
13
13
|
}
|
|
@@ -38,7 +38,7 @@ class HydrateUtils {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
static async hydrateRelations(model, relManyData, relOneData, seriesHydrationfields, fullDataMode, data) {
|
|
41
|
+
static async hydrateRelations(model, relManyData, relOneData, seriesHydrationfields, fullDataMode, data, postLoadExecute = false) {
|
|
42
42
|
// Handle many-to-many relations
|
|
43
43
|
for (const key in relManyData) {
|
|
44
44
|
if (!fullDataMode && model.constructor._CUT_KEYS.includes(key)) {
|
|
@@ -53,7 +53,8 @@ class HydrateUtils {
|
|
|
53
53
|
conditions: {
|
|
54
54
|
[relMeta.foreignKey]: data[pk]
|
|
55
55
|
},
|
|
56
|
-
allowRelations: false
|
|
56
|
+
allowRelations: false,
|
|
57
|
+
cancelPostLoad: !postLoadExecute
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
else {
|
|
@@ -61,7 +62,8 @@ class HydrateUtils {
|
|
|
61
62
|
conditions: {
|
|
62
63
|
[relMeta.foreignKey]: data[pk]
|
|
63
64
|
},
|
|
64
|
-
allowRelations: false
|
|
65
|
+
allowRelations: false,
|
|
66
|
+
cancelPostLoad: !postLoadExecute
|
|
65
67
|
});
|
|
66
68
|
}
|
|
67
69
|
}
|
package/package.json
CHANGED
|
@@ -28,6 +28,8 @@ class RWSModel<T> implements IModel {
|
|
|
28
28
|
static allModels: OpModelType<any>[] = [];
|
|
29
29
|
static _CUT_KEYS: string[] = [];
|
|
30
30
|
|
|
31
|
+
private postLoadExecuted: boolean = false;
|
|
32
|
+
|
|
31
33
|
constructor(data: any = null) {
|
|
32
34
|
if(!this.getCollection()){
|
|
33
35
|
throw new Error('Model must have a collection defined');
|
|
@@ -45,7 +47,16 @@ class RWSModel<T> implements IModel {
|
|
|
45
47
|
}else{
|
|
46
48
|
throw new Error('Time Series not supported in synchronous constructor. Use `await Model.create(data)` static method to instantiate this model.');
|
|
47
49
|
}
|
|
48
|
-
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
isPostLoadExecuted(): boolean
|
|
53
|
+
{
|
|
54
|
+
return this.postLoadExecuted;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setPostLoadExecuted(){
|
|
58
|
+
this.postLoadExecuted = true;
|
|
59
|
+
}
|
|
49
60
|
|
|
50
61
|
checkForInclusionWithThrow(): void {
|
|
51
62
|
const constructor = this.constructor as OpModelType<any>;
|
|
@@ -98,7 +109,7 @@ class RWSModel<T> implements IModel {
|
|
|
98
109
|
return RelationUtils.bindRelation(relatedModel);
|
|
99
110
|
}
|
|
100
111
|
|
|
101
|
-
public async _asyncFill(data: any, fullDataMode = false, allowRelations = true): Promise<T> {
|
|
112
|
+
public async _asyncFill(data: any, fullDataMode = false, allowRelations = true, postLoadExecute = true): Promise<T> {
|
|
102
113
|
const collections_to_models: {[key: string]: any} = {};
|
|
103
114
|
const classFields = FieldsHelper.getAllClassFields(this.constructor);
|
|
104
115
|
|
|
@@ -120,8 +131,13 @@ class RWSModel<T> implements IModel {
|
|
|
120
131
|
}
|
|
121
132
|
|
|
122
133
|
// Process regular fields and time series
|
|
123
|
-
|
|
134
|
+
await HydrateUtils.hydrateDataFields(this, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
124
135
|
|
|
136
|
+
if(!this.isPostLoadExecuted() && postLoadExecute){
|
|
137
|
+
await this.postLoad();
|
|
138
|
+
this.setPostLoadExecuted();
|
|
139
|
+
}
|
|
140
|
+
|
|
125
141
|
return this as any as T;
|
|
126
142
|
}
|
|
127
143
|
|
|
@@ -205,16 +221,16 @@ class RWSModel<T> implements IModel {
|
|
|
205
221
|
const entryExists = await ModelUtils.entryExists(this);
|
|
206
222
|
|
|
207
223
|
if (entryExists) {
|
|
208
|
-
this.preUpdate();
|
|
224
|
+
await this.preUpdate();
|
|
209
225
|
|
|
210
226
|
const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<any>);
|
|
211
227
|
|
|
212
228
|
updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
|
|
213
229
|
|
|
214
230
|
await this._asyncFill(updatedModelData);
|
|
215
|
-
this.postUpdate();
|
|
231
|
+
await this.postUpdate();
|
|
216
232
|
} else {
|
|
217
|
-
this.preCreate();
|
|
233
|
+
await this.preCreate();
|
|
218
234
|
|
|
219
235
|
const isTimeSeries = false;//this instanceof timeSeriesModel;
|
|
220
236
|
|
|
@@ -222,7 +238,7 @@ class RWSModel<T> implements IModel {
|
|
|
222
238
|
|
|
223
239
|
await this._asyncFill(updatedModelData);
|
|
224
240
|
|
|
225
|
-
this.postCreate();
|
|
241
|
+
await this.postCreate();
|
|
226
242
|
}
|
|
227
243
|
|
|
228
244
|
return this;
|
|
@@ -232,19 +248,23 @@ class RWSModel<T> implements IModel {
|
|
|
232
248
|
return ModelUtils.getModelAnnotations(constructor);
|
|
233
249
|
}
|
|
234
250
|
|
|
235
|
-
public preUpdate(): void {
|
|
251
|
+
public async preUpdate(): Promise<void> {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
public async postLoad(): Promise<void> {
|
|
236
256
|
return;
|
|
237
257
|
}
|
|
238
258
|
|
|
239
|
-
public postUpdate(): void {
|
|
259
|
+
public async postUpdate(): Promise<void> {
|
|
240
260
|
return;
|
|
241
261
|
}
|
|
242
262
|
|
|
243
|
-
public preCreate(): void {
|
|
263
|
+
public async preCreate(): Promise<void> {
|
|
244
264
|
return;
|
|
245
265
|
}
|
|
246
266
|
|
|
247
|
-
public postCreate(): void {
|
|
267
|
+
public async postCreate(): Promise<void> {
|
|
248
268
|
return;
|
|
249
269
|
}
|
|
250
270
|
|
|
@@ -370,9 +390,9 @@ class RWSModel<T> implements IModel {
|
|
|
370
390
|
return this.services.dbService;
|
|
371
391
|
}
|
|
372
392
|
|
|
373
|
-
public async reload(): Promise<T | null>
|
|
393
|
+
public async reload(): Promise<RWSModel<T> | null>
|
|
374
394
|
{
|
|
375
|
-
const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<
|
|
395
|
+
const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<T>);
|
|
376
396
|
const where: any = {};
|
|
377
397
|
|
|
378
398
|
if(Array.isArray(pk)){
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import { IDbConfigHandler } from '../../types/DbConfigHandler';
|
|
2
2
|
import { DBService } from '../../services/DBService';
|
|
3
|
+
import { RWSModel } from '..';
|
|
3
4
|
|
|
4
5
|
export interface IModel {
|
|
5
6
|
[key: string]: any;
|
|
6
|
-
id: string |number | null;
|
|
7
|
-
save: () => void;
|
|
8
|
-
getDb: () => DBService;
|
|
9
|
-
getCollection: () => string | null;
|
|
7
|
+
id: string | number | null;
|
|
10
8
|
configService?: IDbConfigHandler;
|
|
11
9
|
dbService?: DBService;
|
|
10
|
+
// Core methods
|
|
11
|
+
save: () => Promise<this>;
|
|
12
|
+
getDb: () => DBService;
|
|
13
|
+
getCollection: () => string | null;
|
|
14
|
+
reload: () => Promise<RWSModel<any>>;
|
|
15
|
+
delete: () => Promise<void>;
|
|
16
|
+
hasTimeSeries: () => boolean;
|
|
17
|
+
|
|
18
|
+
_asyncFill: (data: any, fullDataMode?: boolean, allowRelations?: boolean) => Promise<any>;
|
|
19
|
+
// Lifecycle hooks
|
|
20
|
+
preUpdate: () => Promise<void>;
|
|
21
|
+
postUpdate: () => Promise<void>;
|
|
22
|
+
preCreate: () => Promise<void>;
|
|
23
|
+
postCreate: () => Promise<void>;
|
|
24
|
+
postLoad: () => Promise<void>;
|
|
12
25
|
}
|
|
@@ -3,21 +3,21 @@ import { FindByType, IPaginationParams } from '../../types/FindParams';
|
|
|
3
3
|
import { IRWSModelServices } from './IRWSModelServices';
|
|
4
4
|
import { RelOneMetaType, RelManyMetaType } from '../types/RelationTypes';
|
|
5
5
|
import { DBService } from '../../services/DBService';
|
|
6
|
-
|
|
7
|
-
// Reference to the RWSModel class to avoid circular dependency
|
|
8
6
|
import type { RWSModel } from '../core/RWSModel';
|
|
9
7
|
import { ISuperTagData } from '../../decorators/RWSCollection';
|
|
10
8
|
|
|
11
9
|
export interface OpModelType<T> {
|
|
12
10
|
new(data?: any | null): T;
|
|
11
|
+
// Static properties
|
|
13
12
|
services: IRWSModelServices;
|
|
14
13
|
name: string;
|
|
15
14
|
_collection: string;
|
|
16
15
|
_NO_ID: boolean;
|
|
17
16
|
_SUPER_TAGS: ISuperTagData[];
|
|
18
|
-
_RELATIONS: {[key: string]: boolean};
|
|
17
|
+
_RELATIONS: { [key: string]: boolean };
|
|
19
18
|
_CUT_KEYS: string[];
|
|
20
19
|
allModels: OpModelType<any>[];
|
|
20
|
+
// Static methods
|
|
21
21
|
loadModels: () => OpModelType<any>[];
|
|
22
22
|
checkForInclusionWithThrow: (className: string) => void;
|
|
23
23
|
checkForInclusion: (className: string) => boolean;
|
|
@@ -27,15 +27,15 @@ export interface OpModelType<T> {
|
|
|
27
27
|
): Promise<T | null>;
|
|
28
28
|
find<T extends RWSModel<T>>(
|
|
29
29
|
this: OpModelType<T>,
|
|
30
|
-
id: string | number,
|
|
30
|
+
id: string | number,
|
|
31
31
|
findParams?: Omit<FindByType, 'conditions'>
|
|
32
32
|
): Promise<T | null>;
|
|
33
33
|
findBy<T extends RWSModel<T>>(
|
|
34
|
-
this: OpModelType<T>,
|
|
34
|
+
this: OpModelType<T>,
|
|
35
35
|
findParams?: FindByType
|
|
36
36
|
): Promise<T[]>;
|
|
37
37
|
paginate<T extends RWSModel<T>>(
|
|
38
|
-
this: OpModelType<T>,
|
|
38
|
+
this: OpModelType<T>,
|
|
39
39
|
paginateParams?: IPaginationParams,
|
|
40
40
|
findParams?: FindByType
|
|
41
41
|
): Promise<T[]>;
|
|
@@ -43,10 +43,33 @@ export interface OpModelType<T> {
|
|
|
43
43
|
this: OpModelType<T>,
|
|
44
44
|
conditions: any
|
|
45
45
|
): Promise<void>;
|
|
46
|
-
create<T extends RWSModel<T>>(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
create<T extends RWSModel<T>>(
|
|
47
|
+
this: new () => T,
|
|
48
|
+
data: any
|
|
49
|
+
): Promise<T>;
|
|
50
|
+
getRelationOneMeta(
|
|
51
|
+
model: any,
|
|
52
|
+
classFields: string[]
|
|
53
|
+
): Promise<RelOneMetaType<IRWSModel>>;
|
|
54
|
+
getRelationManyMeta(
|
|
55
|
+
model: any,
|
|
56
|
+
classFields: string[]
|
|
57
|
+
): Promise<RelManyMetaType<IRWSModel>>;
|
|
58
|
+
getCollection(): string | null;
|
|
50
59
|
getDb(): DBService;
|
|
51
60
|
setServices(services: IRWSModelServices): void;
|
|
61
|
+
watchCollection<T extends RWSModel<T>>(
|
|
62
|
+
this: OpModelType<T>,
|
|
63
|
+
preRun: () => void
|
|
64
|
+
): Promise<any>;
|
|
65
|
+
count(where?: { [k: string]: any }): Promise<number>;
|
|
66
|
+
isSubclass<T extends RWSModel<T>, C extends new () => T>(
|
|
67
|
+
constructor: C,
|
|
68
|
+
baseClass: new () => T
|
|
69
|
+
): boolean;
|
|
70
|
+
getModelAnnotations<T extends unknown>(
|
|
71
|
+
constructor: new () => T
|
|
72
|
+
): Promise<Record<string, { annotationType: string; metadata: any }>>;
|
|
73
|
+
checkTimeSeries(constructor: any): boolean;
|
|
74
|
+
checkDbVariable(constructor: any, variable: string): Promise<boolean>;
|
|
52
75
|
}
|
|
@@ -27,7 +27,8 @@ export class FindUtils {
|
|
|
27
27
|
|
|
28
28
|
if (dbData) {
|
|
29
29
|
const inst: T = new (opModel as { new(): T })();
|
|
30
|
-
|
|
30
|
+
const loaded = await inst._asyncFill(dbData, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
31
|
+
return loaded as T;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
return null;
|
|
@@ -50,7 +51,8 @@ export class FindUtils {
|
|
|
50
51
|
|
|
51
52
|
if (dbData) {
|
|
52
53
|
const inst: T = new (opModel as { new(): T })();
|
|
53
|
-
|
|
54
|
+
const loaded = await inst._asyncFill(dbData, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
55
|
+
return loaded as T;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
return null;
|
|
@@ -78,7 +80,7 @@ export class FindUtils {
|
|
|
78
80
|
for (const data of dbData) {
|
|
79
81
|
const inst: T = new (opModel as { new(): T })();
|
|
80
82
|
|
|
81
|
-
instanced.push((await inst._asyncFill(data, fullData, allowRelations)) as T);
|
|
83
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations, findParams?.cancelPostLoad ? false : true)) as T);
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
return instanced;
|
|
@@ -112,7 +114,7 @@ export class FindUtils {
|
|
|
112
114
|
|
|
113
115
|
for (const data of dbData) {
|
|
114
116
|
const inst: T = new (opModel as { new(): T })();
|
|
115
|
-
instanced.push((await inst._asyncFill(data, fullData, allowRelations)) as T);
|
|
117
|
+
instanced.push((await inst._asyncFill(data, fullData, allowRelations, findParams?.cancelPostLoad ? false : true)) as T);
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
return instanced;
|
|
@@ -8,119 +8,120 @@ import { ModelUtils } from "./ModelUtils";
|
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
|
|
10
10
|
export class HydrateUtils {
|
|
11
|
-
static async hydrateDataFields(model: RWSModel<any>, collections_to_models: {[key: string]: any}, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {[key: string]
|
|
11
|
+
static async hydrateDataFields(model: RWSModel<any>, collections_to_models: { [key: string]: any }, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: { [key: string]: any }) {
|
|
12
12
|
const timeSeriesIds = TimeSeriesUtils.getTimeSeriesModelFields(model);
|
|
13
|
-
for (const key in data) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
13
|
+
for (const key in data) {
|
|
14
|
+
if (data.hasOwnProperty(key)) {
|
|
15
|
+
if (!fullDataMode && ((model).constructor as OpModelType<any>)._CUT_KEYS.includes(key)) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (Object.keys(relOneData).includes(key)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (seriesHydrationfields.includes(key)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const timeSeriesMetaData = timeSeriesIds[key];
|
|
29
|
+
|
|
30
|
+
if (timeSeriesMetaData) {
|
|
31
|
+
model[key] = data[key];
|
|
32
|
+
const seriesModel = collections_to_models[timeSeriesMetaData.collection];
|
|
33
|
+
|
|
34
|
+
const dataModels = await seriesModel.findBy({
|
|
35
|
+
id: { in: data[key] }
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
|
|
39
|
+
|
|
40
|
+
model[timeSeriesMetaData.hydrationField] = dataModels;
|
|
41
|
+
} else {
|
|
42
|
+
model[key] = data[key];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static async hydrateRelations(model: RWSModel<any>, relManyData: RelManyMetaType<IRWSModel>, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: { [key: string]: any }, postLoadExecute = false) {
|
|
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
|
+
const relationEnabled = !RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if (relationEnabled) {
|
|
62
|
+
const pk = ModelUtils.findPrimaryKeyFields(model.constructor as OpModelType<any>) as string;
|
|
63
|
+
|
|
64
|
+
if (relMeta.singular) {
|
|
65
|
+
model[relMeta.key] = await relMeta.inversionModel.findOneBy({
|
|
66
|
+
conditions: {
|
|
67
|
+
[relMeta.foreignKey]: data[pk]
|
|
68
|
+
},
|
|
69
|
+
allowRelations: false,
|
|
70
|
+
cancelPostLoad: !postLoadExecute
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
model[relMeta.key] = await relMeta.inversionModel.findBy({
|
|
74
|
+
conditions: {
|
|
75
|
+
[relMeta.foreignKey]: data[pk]
|
|
76
|
+
},
|
|
77
|
+
allowRelations: false,
|
|
78
|
+
cancelPostLoad: !postLoadExecute
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Handle one-to-one relations
|
|
85
|
+
for (const key in relOneData) {
|
|
86
|
+
if (!fullDataMode && ((model as any).constructor as OpModelType<any>)._CUT_KEYS.includes(key)) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const relMeta = relOneData[key];
|
|
91
|
+
const relationEnabled = !RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
92
|
+
|
|
93
|
+
if (!data[relMeta.hydrationField] && relMeta.required) {
|
|
94
|
+
throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (relationEnabled && data[relMeta.hydrationField]) {
|
|
98
|
+
const pk = ModelUtils.findPrimaryKeyFields(relMeta.model);
|
|
99
|
+
|
|
100
|
+
const where: any = {};
|
|
101
|
+
|
|
102
|
+
if (Array.isArray(pk)) {
|
|
103
|
+
console.log(chalk.yellowBright(`Hydration field "${relMeta.hydrationField}" on model "${model.constructor.name}" leads to compound key. Ignoring.`));
|
|
104
|
+
continue;
|
|
105
|
+
} else {
|
|
106
|
+
where[pk as string] = data[relMeta.hydrationField]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
model[relMeta.key] = await relMeta.model.findOneBy({ conditions: where }, { allowRelations: false });
|
|
110
|
+
}
|
|
111
|
+
else if (relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]) {
|
|
112
|
+
const newRelModel: RWSModel<any> = await relMeta.model.create(data[relMeta.key]);
|
|
113
|
+
model[relMeta.key] = await newRelModel.save();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const cutKeys = ((model.constructor as OpModelType<any>)._CUT_KEYS as string[]);
|
|
117
|
+
|
|
118
|
+
const trackedField = Object.keys((await ModelUtils.getModelAnnotations(model.constructor as OpModelType<any>))).includes(relMeta.hydrationField);
|
|
119
|
+
|
|
120
|
+
if (!cutKeys.includes(relMeta.hydrationField) && !trackedField) {
|
|
121
|
+
cutKeys.push(relMeta.hydrationField)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// seriesHydrationfields.push(relMeta.hydrationField);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
126
127
|
}
|