@rws-framework/db 2.3.2 → 2.4.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/.bin/add-v.sh +9 -9
- package/.bin/emerge.sh +10 -10
- package/.eslintrc.json +53 -53
- package/README.md +404 -367
- package/dist/decorators/InverseRelation.d.ts +12 -12
- package/dist/decorators/InverseRelation.js +24 -24
- package/dist/decorators/InverseTimeSeries.d.ts +8 -8
- package/dist/decorators/InverseTimeSeries.js +13 -13
- package/dist/decorators/RWSCollection.d.ts +12 -12
- package/dist/decorators/RWSCollection.js +16 -16
- package/dist/decorators/Relation.d.ts +19 -19
- package/dist/decorators/Relation.js +26 -26
- package/dist/decorators/TrackType.d.ts +20 -20
- package/dist/decorators/TrackType.js +41 -41
- package/dist/decorators/index.d.ts +5 -5
- package/dist/decorators/index.js +14 -14
- package/dist/helper/DbHelper.d.ts +8 -8
- package/dist/helper/DbHelper.js +141 -141
- package/dist/helper/FieldsHelper.d.ts +4 -4
- package/dist/helper/FieldsHelper.js +35 -35
- package/dist/index.d.ts +12 -12
- package/dist/index.js +19 -19
- package/dist/models/TimeSeriesModel.d.ts +7 -7
- package/dist/models/TimeSeriesModel.js +33 -33
- package/dist/models/_model.d.ts +6 -6
- package/dist/models/_model.js +9 -9
- package/dist/models/core/RWSModel.d.ts +66 -66
- package/dist/models/core/RWSModel.js +400 -400
- package/dist/models/core/TimeSeriesModel.d.ts +1 -1
- package/dist/models/core/TimeSeriesModel.js +14 -14
- package/dist/models/index.d.ts +7 -7
- package/dist/models/index.js +8 -8
- package/dist/models/interfaces/IModel.d.ts +11 -11
- package/dist/models/interfaces/IModel.js +2 -2
- package/dist/models/interfaces/IRWSModelServices.d.ts +6 -6
- package/dist/models/interfaces/IRWSModelServices.js +2 -2
- package/dist/models/interfaces/OpModelType.d.ts +31 -31
- package/dist/models/interfaces/OpModelType.js +2 -2
- package/dist/models/types/RelationTypes.d.ts +24 -24
- package/dist/models/types/RelationTypes.js +2 -2
- package/dist/models/utils/ModelUtils.d.ts +10 -10
- package/dist/models/utils/ModelUtils.js +56 -56
- package/dist/models/utils/PaginationUtils.d.ts +5 -5
- package/dist/models/utils/PaginationUtils.js +32 -32
- package/dist/models/utils/RelationUtils.d.ts +14 -14
- package/dist/models/utils/RelationUtils.js +65 -65
- package/dist/models/utils/TimeSeriesUtils.d.ts +11 -11
- package/dist/models/utils/TimeSeriesUtils.js +35 -35
- package/dist/services/DBService.d.ts +37 -37
- package/dist/services/DBService.js +198 -198
- package/dist/types/DbConfigHandler.d.ts +9 -9
- package/dist/types/DbConfigHandler.js +2 -2
- package/dist/types/FindParams.d.ts +14 -14
- package/dist/types/FindParams.js +2 -2
- package/dist/types/IRWSModel.d.ts +3 -3
- package/dist/types/IRWSModel.js +2 -2
- package/dist/types/ITimeSeries.d.ts +6 -6
- package/dist/types/ITimeSeries.js +2 -2
- package/exec/console.js +110 -110
- package/exec/db.rws.webpack.config.js +168 -168
- package/exec/src/cli.ts +74 -73
- package/exec/tsconfig.json +32 -32
- package/exec/webpackFilters.js +17 -17
- package/package.json +36 -36
- package/src/decorators/InverseRelation.ts +36 -36
- package/src/decorators/InverseTimeSeries.ts +21 -21
- package/src/decorators/RWSCollection.ts +27 -27
- package/src/decorators/Relation.ts +47 -47
- package/src/decorators/TrackType.ts +69 -69
- package/src/decorators/index.ts +7 -7
- package/src/empty.js +0 -0
- package/src/helper/DbHelper.ts +177 -177
- package/src/helper/FieldsHelper.ts +34 -34
- package/src/index.ts +36 -36
- package/src/models/_model.ts +29 -29
- package/src/models/core/RWSModel.ts +520 -520
- package/src/models/core/TimeSeriesModel.ts +19 -19
- package/src/models/index.ts +20 -20
- package/src/models/interfaces/IModel.ts +12 -12
- package/src/models/interfaces/IRWSModelServices.ts +7 -7
- package/src/models/interfaces/OpModelType.ts +49 -49
- package/src/models/types/RelationTypes.ts +25 -25
- package/src/models/utils/ModelUtils.ts +65 -65
- package/src/models/utils/PaginationUtils.ts +42 -42
- package/src/models/utils/RelationUtils.ts +76 -76
- package/src/models/utils/TimeSeriesUtils.ts +38 -38
- package/src/services/DBService.ts +277 -277
- package/src/types/DbConfigHandler.ts +12 -11
- package/src/types/FindParams.ts +13 -13
- package/src/types/IRWSModel.ts +2 -2
- package/src/types/ITimeSeries.ts +5 -5
- package/tsconfig.json +22 -22
package/README.md
CHANGED
|
@@ -1,368 +1,405 @@
|
|
|
1
|
-
# Models
|
|
2
|
-
|
|
3
|
-
RWS models are converted to Prisma schemas and are wrapping around generated PrismaClient providing complete typing and better Relation handling + TimeSeries in future minor versions.
|
|
4
|
-
|
|
5
|
-
## Models index file
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import ApiKey from "./ApiKey";
|
|
9
|
-
import User from "./User";
|
|
10
|
-
|
|
11
|
-
export const models = [ User, ApiKey];
|
|
12
|
-
```
|
|
13
|
-
## Example user model
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { TrackType, InverseRelation, RWSCollection, RWSModel } from '@rws-framework/db';
|
|
17
|
-
|
|
18
|
-
import IUser from './interfaces/IUser';
|
|
19
|
-
import 'reflect-metadata';
|
|
20
|
-
|
|
21
|
-
import ApiKey from './ApiKey';
|
|
22
|
-
import IApiKey from './interfaces/IApiKey';
|
|
23
|
-
|
|
24
|
-
@RWSCollection('users', {
|
|
25
|
-
relations: {
|
|
26
|
-
transcriptions: true,
|
|
27
|
-
apiKeys: true
|
|
28
|
-
},
|
|
29
|
-
ignored_keys: ['passwd']
|
|
30
|
-
})
|
|
31
|
-
class User extends RWSModel<User> implements IUser {
|
|
32
|
-
@TrackType(String)
|
|
33
|
-
username: string;
|
|
34
|
-
|
|
35
|
-
@TrackType(String) // Can also handle Object and Number
|
|
36
|
-
passwd: string;
|
|
37
|
-
|
|
38
|
-
@TrackType(Boolean)
|
|
39
|
-
active: boolean;
|
|
40
|
-
|
|
41
|
-
@TrackType(Date, { required: true })
|
|
42
|
-
created_at: Date;
|
|
43
|
-
|
|
44
|
-
@TrackType(Date)
|
|
45
|
-
updated_at: Date;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Every relation and inverse relation decorator
|
|
49
|
-
* uses arrow function model passing
|
|
50
|
-
**/
|
|
51
|
-
@InverseRelation(() => ApiKey, () => User)
|
|
52
|
-
apiKeys: IApiKey[];
|
|
53
|
-
|
|
54
|
-
constructor(data?: IUser) {
|
|
55
|
-
super(data);
|
|
56
|
-
|
|
57
|
-
if(!this.created_at){
|
|
58
|
-
this.created_at = new Date();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
//Must export default for automated DI / build work.
|
|
64
|
-
export default User;
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Relations
|
|
68
|
-
|
|
69
|
-
***Basic many to one relation***
|
|
70
|
-
```typescript
|
|
71
|
-
import { RWSModel, TrackType, Relation } from '@rws-framework/db';
|
|
72
|
-
|
|
73
|
-
import 'reflect-metadata';
|
|
74
|
-
import User from './User';
|
|
75
|
-
import IApiKey from './interfaces/IApiKey';
|
|
76
|
-
|
|
77
|
-
class ApiKey extends RWSModel<ApiKey> implements IApiKey {
|
|
78
|
-
static _RELATIONS = {
|
|
79
|
-
user: true,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
@Relation(() => User, true) // second attribute is required = false
|
|
83
|
-
user: User;
|
|
84
|
-
|
|
85
|
-
@TrackType(Object)
|
|
86
|
-
keyval: string;
|
|
87
|
-
|
|
88
|
-
@TrackType(Date, { required: true })
|
|
89
|
-
created_at: Date;
|
|
90
|
-
|
|
91
|
-
@TrackType(Date)
|
|
92
|
-
updated_at: Date;
|
|
93
|
-
|
|
94
|
-
static _collection = 'api_keys';
|
|
95
|
-
|
|
96
|
-
constructor(data?: IApiKey) {
|
|
97
|
-
super(data);
|
|
98
|
-
|
|
99
|
-
if(!this.created_at){
|
|
100
|
-
this.created_at = new Date();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
this.updated_at = new Date();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export default ApiKey;
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
***Relation decorator*** (many-to-one)
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
import 'reflect-metadata';
|
|
114
|
-
|
|
115
|
-
import { RWSModel, OpModelType } from '@rws-framework/db';
|
|
116
|
-
|
|
117
|
-
interface IRelationOpts {
|
|
118
|
-
required?: boolean
|
|
119
|
-
key?: string
|
|
120
|
-
relationField?: string
|
|
121
|
-
relatedToField?: string
|
|
122
|
-
relatedTo: OpModelType<Model<any>>
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function Relation(theModel: () => OpModelType<RWSModel<any>>, required: boolean = false, relationField: string = null, relatedToField: string = 'id') {
|
|
126
|
-
return function(target: any, key: string) {
|
|
127
|
-
// Store the promise in metadata immediately
|
|
128
|
-
const metadataPromise = Promise.resolve().then(() => {
|
|
129
|
-
const relatedTo = theModel();
|
|
130
|
-
const metaOpts: IRelationOpts = {required, relatedTo, relatedToField};
|
|
131
|
-
if(!relationField){
|
|
132
|
-
metaOpts.relationField = relatedTo._collection + '_id';
|
|
133
|
-
} else{
|
|
134
|
-
metaOpts.relationField = relationField;
|
|
135
|
-
}
|
|
136
|
-
metaOpts.key = key;
|
|
137
|
-
return metaOpts;
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Store both the promise and the key information
|
|
141
|
-
Reflect.defineMetadata(`Relation:${key}`, {
|
|
142
|
-
promise: metadataPromise,
|
|
143
|
-
key
|
|
144
|
-
}, target);
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
export default Relation;
|
|
150
|
-
export {IRelationOpts};
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
***Inverse relation decorator*** (one-to-many)
|
|
154
|
-
```typescript
|
|
155
|
-
import 'reflect-metadata';
|
|
156
|
-
import { RWSModel, OpModelType } from '@rws-framework/db';
|
|
157
|
-
|
|
158
|
-
interface InverseRelationOpts{
|
|
159
|
-
key: string,
|
|
160
|
-
inversionModel: OpModelType<RWSModel<any>>,
|
|
161
|
-
foreignKey: string
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function InverseRelation(inversionModel: () => OpModelType<RWSModel<any>>, sourceModel: () => OpModelType<RWSModel<any>>, foreignKey: string = null) {
|
|
165
|
-
return function(target: any, key: string) {
|
|
166
|
-
// Store the promise in metadata immediately
|
|
167
|
-
const metadataPromise = Promise.resolve().then(() => {
|
|
168
|
-
const model = inversionModel();
|
|
169
|
-
const source = sourceModel();
|
|
170
|
-
|
|
171
|
-
const metaOpts: InverseRelationOpts = {
|
|
172
|
-
key,
|
|
173
|
-
inversionModel: model,
|
|
174
|
-
foreignKey: foreignKey ? foreignKey : `${source._collection}_id`
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
return metaOpts;
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// Store both the promise and the key information
|
|
181
|
-
Reflect.defineMetadata(`InverseRelation:${key}`, {
|
|
182
|
-
promise: metadataPromise,
|
|
183
|
-
key
|
|
184
|
-
}, target);
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export default InverseRelation;
|
|
189
|
-
export {InverseRelationOpts};
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
## RWS Model to prisma conversion
|
|
194
|
-
|
|
195
|
-
### Init helper class
|
|
196
|
-
|
|
197
|
-
**This needs to be run either from the package or CLI - it changes models to prisma schema and registers it.**
|
|
198
|
-
|
|
199
|
-
*IDbConfigHandler* - An interface for config bag for DBService
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
import { OpModelType } from "../models/_model";
|
|
203
|
-
|
|
204
|
-
export interface IDbConfigParams {
|
|
205
|
-
mongo_url?: string;
|
|
206
|
-
mongo_db?: string;
|
|
207
|
-
db_models?: OpModelType<any>[]
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export interface IDbConfigHandler {
|
|
211
|
-
get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K];
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
**Helper prisma install example**
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
class Config implements IDbConfigHandler {
|
|
219
|
-
private data: IDbConfigParams = {
|
|
220
|
-
db_models: [],
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
private
|
|
227
|
-
private
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
this._instance
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
this.data.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
getModelsDir(): string
|
|
256
|
-
{
|
|
257
|
-
return this.modelsDir
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
getCliExecRoot(): string
|
|
261
|
-
{
|
|
262
|
-
return this.cliExecRoot
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K] {
|
|
266
|
-
return this.data[key];
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
async function main(): Promise<void>
|
|
271
|
-
{
|
|
272
|
-
console.log('INSTALL PRISMA');
|
|
273
|
-
const cfg = await Config.getInstance();
|
|
274
|
-
DbHelper.installPrisma(cfg, new DBService(cfg), false);
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Init CLI
|
|
279
|
-
Basic CLI command that executes **generateModelSections()** from conversion script is:
|
|
280
|
-
|
|
281
|
-
**rws-db [DB_URL] [DB_NAME] [MODELS_DIRECTORY]**
|
|
282
|
-
|
|
283
|
-
The exec file.
|
|
284
|
-
```
|
|
285
|
-
/exec/src/console.js
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
yarn
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
1
|
+
# Models
|
|
2
|
+
|
|
3
|
+
RWS models are converted to Prisma schemas and are wrapping around generated PrismaClient providing complete typing and better Relation handling + TimeSeries in future minor versions.
|
|
4
|
+
|
|
5
|
+
## Models index file
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import ApiKey from "./ApiKey";
|
|
9
|
+
import User from "./User";
|
|
10
|
+
|
|
11
|
+
export const models = [ User, ApiKey];
|
|
12
|
+
```
|
|
13
|
+
## Example user model
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { TrackType, InverseRelation, RWSCollection, RWSModel } from '@rws-framework/db';
|
|
17
|
+
|
|
18
|
+
import IUser from './interfaces/IUser';
|
|
19
|
+
import 'reflect-metadata';
|
|
20
|
+
|
|
21
|
+
import ApiKey from './ApiKey';
|
|
22
|
+
import IApiKey from './interfaces/IApiKey';
|
|
23
|
+
|
|
24
|
+
@RWSCollection('users', {
|
|
25
|
+
relations: {
|
|
26
|
+
transcriptions: true,
|
|
27
|
+
apiKeys: true
|
|
28
|
+
},
|
|
29
|
+
ignored_keys: ['passwd']
|
|
30
|
+
})
|
|
31
|
+
class User extends RWSModel<User> implements IUser {
|
|
32
|
+
@TrackType(String)
|
|
33
|
+
username: string;
|
|
34
|
+
|
|
35
|
+
@TrackType(String) // Can also handle Object and Number
|
|
36
|
+
passwd: string;
|
|
37
|
+
|
|
38
|
+
@TrackType(Boolean)
|
|
39
|
+
active: boolean;
|
|
40
|
+
|
|
41
|
+
@TrackType(Date, { required: true })
|
|
42
|
+
created_at: Date;
|
|
43
|
+
|
|
44
|
+
@TrackType(Date)
|
|
45
|
+
updated_at: Date;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Every relation and inverse relation decorator
|
|
49
|
+
* uses arrow function model passing
|
|
50
|
+
**/
|
|
51
|
+
@InverseRelation(() => ApiKey, () => User)
|
|
52
|
+
apiKeys: IApiKey[];
|
|
53
|
+
|
|
54
|
+
constructor(data?: IUser) {
|
|
55
|
+
super(data);
|
|
56
|
+
|
|
57
|
+
if(!this.created_at){
|
|
58
|
+
this.created_at = new Date();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//Must export default for automated DI / build work.
|
|
64
|
+
export default User;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Relations
|
|
68
|
+
|
|
69
|
+
***Basic many to one relation***
|
|
70
|
+
```typescript
|
|
71
|
+
import { RWSModel, TrackType, Relation } from '@rws-framework/db';
|
|
72
|
+
|
|
73
|
+
import 'reflect-metadata';
|
|
74
|
+
import User from './User';
|
|
75
|
+
import IApiKey from './interfaces/IApiKey';
|
|
76
|
+
|
|
77
|
+
class ApiKey extends RWSModel<ApiKey> implements IApiKey {
|
|
78
|
+
static _RELATIONS = {
|
|
79
|
+
user: true,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
@Relation(() => User, true) // second attribute is required = false
|
|
83
|
+
user: User;
|
|
84
|
+
|
|
85
|
+
@TrackType(Object)
|
|
86
|
+
keyval: string;
|
|
87
|
+
|
|
88
|
+
@TrackType(Date, { required: true })
|
|
89
|
+
created_at: Date;
|
|
90
|
+
|
|
91
|
+
@TrackType(Date)
|
|
92
|
+
updated_at: Date;
|
|
93
|
+
|
|
94
|
+
static _collection = 'api_keys';
|
|
95
|
+
|
|
96
|
+
constructor(data?: IApiKey) {
|
|
97
|
+
super(data);
|
|
98
|
+
|
|
99
|
+
if(!this.created_at){
|
|
100
|
+
this.created_at = new Date();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.updated_at = new Date();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default ApiKey;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
***Relation decorator*** (many-to-one)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import 'reflect-metadata';
|
|
114
|
+
|
|
115
|
+
import { RWSModel, OpModelType } from '@rws-framework/db';
|
|
116
|
+
|
|
117
|
+
interface IRelationOpts {
|
|
118
|
+
required?: boolean
|
|
119
|
+
key?: string
|
|
120
|
+
relationField?: string
|
|
121
|
+
relatedToField?: string
|
|
122
|
+
relatedTo: OpModelType<Model<any>>
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function Relation(theModel: () => OpModelType<RWSModel<any>>, required: boolean = false, relationField: string = null, relatedToField: string = 'id') {
|
|
126
|
+
return function(target: any, key: string) {
|
|
127
|
+
// Store the promise in metadata immediately
|
|
128
|
+
const metadataPromise = Promise.resolve().then(() => {
|
|
129
|
+
const relatedTo = theModel();
|
|
130
|
+
const metaOpts: IRelationOpts = {required, relatedTo, relatedToField};
|
|
131
|
+
if(!relationField){
|
|
132
|
+
metaOpts.relationField = relatedTo._collection + '_id';
|
|
133
|
+
} else{
|
|
134
|
+
metaOpts.relationField = relationField;
|
|
135
|
+
}
|
|
136
|
+
metaOpts.key = key;
|
|
137
|
+
return metaOpts;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Store both the promise and the key information
|
|
141
|
+
Reflect.defineMetadata(`Relation:${key}`, {
|
|
142
|
+
promise: metadataPromise,
|
|
143
|
+
key
|
|
144
|
+
}, target);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
export default Relation;
|
|
150
|
+
export {IRelationOpts};
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
***Inverse relation decorator*** (one-to-many)
|
|
154
|
+
```typescript
|
|
155
|
+
import 'reflect-metadata';
|
|
156
|
+
import { RWSModel, OpModelType } from '@rws-framework/db';
|
|
157
|
+
|
|
158
|
+
interface InverseRelationOpts{
|
|
159
|
+
key: string,
|
|
160
|
+
inversionModel: OpModelType<RWSModel<any>>,
|
|
161
|
+
foreignKey: string
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function InverseRelation(inversionModel: () => OpModelType<RWSModel<any>>, sourceModel: () => OpModelType<RWSModel<any>>, foreignKey: string = null) {
|
|
165
|
+
return function(target: any, key: string) {
|
|
166
|
+
// Store the promise in metadata immediately
|
|
167
|
+
const metadataPromise = Promise.resolve().then(() => {
|
|
168
|
+
const model = inversionModel();
|
|
169
|
+
const source = sourceModel();
|
|
170
|
+
|
|
171
|
+
const metaOpts: InverseRelationOpts = {
|
|
172
|
+
key,
|
|
173
|
+
inversionModel: model,
|
|
174
|
+
foreignKey: foreignKey ? foreignKey : `${source._collection}_id`
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
return metaOpts;
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Store both the promise and the key information
|
|
181
|
+
Reflect.defineMetadata(`InverseRelation:${key}`, {
|
|
182
|
+
promise: metadataPromise,
|
|
183
|
+
key
|
|
184
|
+
}, target);
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export default InverseRelation;
|
|
189
|
+
export {InverseRelationOpts};
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
## RWS Model to prisma conversion
|
|
194
|
+
|
|
195
|
+
### Init helper class
|
|
196
|
+
|
|
197
|
+
**This needs to be run either from the package or CLI - it changes models to prisma schema and registers it.**
|
|
198
|
+
|
|
199
|
+
*IDbConfigHandler* - An interface for config bag for DBService
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { OpModelType } from "../models/_model";
|
|
203
|
+
|
|
204
|
+
export interface IDbConfigParams {
|
|
205
|
+
mongo_url?: string;
|
|
206
|
+
mongo_db?: string;
|
|
207
|
+
db_models?: OpModelType<any>[]
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface IDbConfigHandler {
|
|
211
|
+
get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K];
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Helper prisma install example**
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
class Config implements IDbConfigHandler {
|
|
219
|
+
private data: IDbConfigParams = {
|
|
220
|
+
db_models: [],
|
|
221
|
+
db_name: null,
|
|
222
|
+
db_url: null,
|
|
223
|
+
db_type: null
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
private modelsDir: string;
|
|
227
|
+
private cliExecRoot: string;
|
|
228
|
+
private static _instance: Config = null;
|
|
229
|
+
|
|
230
|
+
private constructor(){}
|
|
231
|
+
|
|
232
|
+
static async getInstance(): Promise<Config>
|
|
233
|
+
{
|
|
234
|
+
if(!this._instance){
|
|
235
|
+
this._instance = new Config();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
await this._instance.fill();
|
|
239
|
+
|
|
240
|
+
return this._instance;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
async fill(): Promise<void>
|
|
245
|
+
{
|
|
246
|
+
this.data.db_url = args[0];
|
|
247
|
+
this.data.db_name = args[1];
|
|
248
|
+
this.data.db_type = args[2];
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
this.modelsDir = args[3];
|
|
252
|
+
this.cliExecRoot = args[4];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
getModelsDir(): string
|
|
256
|
+
{
|
|
257
|
+
return this.modelsDir
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
getCliExecRoot(): string
|
|
261
|
+
{
|
|
262
|
+
return this.cliExecRoot
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K] {
|
|
266
|
+
return this.data[key];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function main(): Promise<void>
|
|
271
|
+
{
|
|
272
|
+
console.log('INSTALL PRISMA');
|
|
273
|
+
const cfg = await Config.getInstance();
|
|
274
|
+
DbHelper.installPrisma(cfg, new DBService(cfg), false);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Init CLI
|
|
279
|
+
Basic CLI command that executes **generateModelSections()** from conversion script is:
|
|
280
|
+
|
|
281
|
+
**rws-db [DB_URL] [DB_NAME] [MODELS_DIRECTORY]**
|
|
282
|
+
|
|
283
|
+
The exec file.
|
|
284
|
+
```
|
|
285
|
+
/exec/src/console.js
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
dbType can be any prisma db driver - mongodb by default
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
#npm
|
|
292
|
+
|
|
293
|
+
npx rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName dbType src/models
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
#yarn
|
|
298
|
+
|
|
299
|
+
yarn rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName dbType src/models
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
#bun
|
|
304
|
+
|
|
305
|
+
bunx rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName dbType src/models
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Code for RWS to prisma conversion from "@rws-framework/server" package:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
static async generateModelSections(model: OpModelType<any>): Promise<string> {
|
|
312
|
+
let section = '';
|
|
313
|
+
const modelMetadatas: Record<string, {annotationType: string, metadata: any}> = await RWSModel.getModelAnnotations(model);
|
|
314
|
+
|
|
315
|
+
const modelName: string = (model as any)._collection;
|
|
316
|
+
|
|
317
|
+
section += `model ${modelName} {\n`;
|
|
318
|
+
section += '\tid String @map("_id") @id @default(auto()) @db.ObjectId\n';
|
|
319
|
+
|
|
320
|
+
for (const key in modelMetadatas) {
|
|
321
|
+
const modelMetadata = modelMetadatas[key].metadata;
|
|
322
|
+
let requiredString = modelMetadata.required ? '' : '?';
|
|
323
|
+
const annotationType: string = modelMetadatas[key].annotationType;
|
|
324
|
+
|
|
325
|
+
if(key === 'id'){
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
if(annotationType === 'Relation'){
|
|
331
|
+
const relationMeta = modelMetadata as IRelationOpts
|
|
332
|
+
|
|
333
|
+
const relatedModel = relationMeta.relatedTo as OpModelType<any>;
|
|
334
|
+
const isMany = relationMeta.many;
|
|
335
|
+
const cascadeOpts = [];
|
|
336
|
+
|
|
337
|
+
if (relationMeta.cascade?.onDelete) {
|
|
338
|
+
cascadeOpts.push(`onDelete: ${relationMeta.cascade.onDelete}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (relationMeta.cascade?.onUpdate) {
|
|
342
|
+
cascadeOpts.push(`onUpdate: ${relationMeta.cascade.onUpdate}`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (isMany) {
|
|
346
|
+
// Handle many-to-many or one-to-many relation
|
|
347
|
+
section += `\t${key} ${relatedModel._collection}[] @relation("${modelName}_${relatedModel._collection}")\n`;
|
|
348
|
+
} else {
|
|
349
|
+
// Handle one-to-one or many-to-one relation
|
|
350
|
+
section += `\t${key} ${relatedModel._collection}${requiredString} @relation("${modelName}_${relatedModel._collection}", fields: [${modelMetadata.relationField}], references: [${modelMetadata.relatedToField || 'id'}], ${cascadeOpts.join(', ')})\n`;
|
|
351
|
+
section += `\t${modelMetadata.relationField} String${requiredString} @db.ObjectId\n`;
|
|
352
|
+
}
|
|
353
|
+
} else if (annotationType === 'InverseRelation'){
|
|
354
|
+
const relationMeta = modelMetadata as InverseRelationOpts;
|
|
355
|
+
|
|
356
|
+
// Handle inverse relation (one-to-many or one-to-one)
|
|
357
|
+
section += `\t${key} ${relationMeta.inversionModel._collection}[] @relation("${ relationMeta.relationName ? relationMeta.relationName : `${relationMeta.inversionModel._collection}_${modelName}`}")\n`;
|
|
358
|
+
} else if (annotationType === 'InverseTimeSeries'){
|
|
359
|
+
section += `\t${key} String[] @db.ObjectId\n`;
|
|
360
|
+
} else if (annotationType === 'TrackType'){
|
|
361
|
+
const tags: string[] = modelMetadata.tags.map((item: string) => '@' + item);
|
|
362
|
+
|
|
363
|
+
if(modelMetadata.isArray || modelMetadata.type.name === 'Array'){
|
|
364
|
+
requiredString = '';
|
|
365
|
+
}
|
|
366
|
+
section += `\t${key} ${DbHelper.toConfigCase(modelMetadata)}${requiredString} ${tags.join(' ')}\n`;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
section += '}\n';
|
|
371
|
+
return section;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
static toConfigCase(modelType: IMetaOpts): string {
|
|
375
|
+
const type = modelType.type;
|
|
376
|
+
let input = type.name;
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
if(input == 'Number'){
|
|
380
|
+
input = 'Int';
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if(input == 'Object'){
|
|
384
|
+
input = 'Json';
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if(input == 'Date'){
|
|
388
|
+
input = 'DateTime';
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if(input == 'Array'){
|
|
392
|
+
input = 'Json[]';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const firstChar = input.charAt(0).toUpperCase();
|
|
396
|
+
const restOfString = input.slice(1);
|
|
397
|
+
let resultField = firstChar + restOfString;
|
|
398
|
+
|
|
399
|
+
if(modelType.isArray){
|
|
400
|
+
resultField += '[]';
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return resultField;
|
|
404
|
+
}
|
|
368
405
|
```
|