@rws-framework/db 2.4.6 → 3.0.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.
Files changed (123) hide show
  1. package/.bin/add-v.sh +9 -9
  2. package/.bin/emerge.sh +10 -10
  3. package/.eslintrc.json +53 -53
  4. package/README.md +343 -405
  5. package/dist/decorators/IdType.d.ts +8 -0
  6. package/dist/decorators/IdType.js +10 -0
  7. package/dist/decorators/InverseRelation.d.ts +2 -2
  8. package/dist/decorators/InverseRelation.js +5 -1
  9. package/dist/decorators/InverseTimeSeries.d.ts +0 -0
  10. package/dist/decorators/InverseTimeSeries.js +0 -0
  11. package/dist/decorators/RWSCollection.d.ts +7 -0
  12. package/dist/decorators/RWSCollection.js +6 -0
  13. package/dist/decorators/Relation.d.ts +8 -6
  14. package/dist/decorators/Relation.js +8 -1
  15. package/dist/decorators/TrackType.d.ts +2 -14
  16. package/dist/decorators/TrackType.js +7 -0
  17. package/dist/decorators/TypeFunctions.d.ts +44 -0
  18. package/dist/decorators/TypeFunctions.js +174 -0
  19. package/dist/decorators/index.d.ts +4 -2
  20. package/dist/decorators/index.js +3 -1
  21. package/dist/helper/DbHelper.d.ts +76 -5
  22. package/dist/helper/DbHelper.js +93 -154
  23. package/dist/helper/FieldsHelper.d.ts +0 -0
  24. package/dist/helper/FieldsHelper.js +0 -0
  25. package/dist/helper/db/index.d.ts +9 -0
  26. package/dist/helper/db/index.js +18 -0
  27. package/dist/helper/db/relation-manager.d.ts +45 -0
  28. package/dist/helper/db/relation-manager.js +105 -0
  29. package/dist/helper/db/schema-generator.d.ts +37 -0
  30. package/dist/helper/db/schema-generator.js +255 -0
  31. package/dist/helper/db/type-converter.d.ts +22 -0
  32. package/dist/helper/db/type-converter.js +106 -0
  33. package/dist/helper/db/utils.d.ts +24 -0
  34. package/dist/helper/db/utils.js +99 -0
  35. package/dist/index.d.ts +3 -3
  36. package/dist/index.js +2 -1
  37. package/dist/models/TimeSeriesModel.d.ts +7 -7
  38. package/dist/models/TimeSeriesModel.js +33 -33
  39. package/dist/models/_model.d.ts +2 -2
  40. package/dist/models/_model.js +0 -0
  41. package/dist/models/core/RWSModel.d.ts +5 -2
  42. package/dist/models/core/RWSModel.js +8 -5
  43. package/dist/models/core/TimeSeriesModel.d.ts +0 -0
  44. package/dist/models/core/TimeSeriesModel.js +0 -0
  45. package/dist/models/index.d.ts +2 -2
  46. package/dist/models/index.js +0 -0
  47. package/dist/models/interfaces/IDbOpts.d.ts +17 -0
  48. package/dist/models/interfaces/IDbOpts.js +2 -0
  49. package/dist/models/interfaces/IIdOpts.d.ts +0 -0
  50. package/dist/models/interfaces/IIdOpts.js +1 -0
  51. package/dist/models/interfaces/IIdTypeOpts.d.ts +3 -0
  52. package/dist/models/interfaces/IIdTypeOpts.js +2 -0
  53. package/dist/models/interfaces/IModel.d.ts +0 -0
  54. package/dist/models/interfaces/IModel.js +0 -0
  55. package/dist/models/interfaces/IRWSModelServices.d.ts +0 -0
  56. package/dist/models/interfaces/IRWSModelServices.js +0 -0
  57. package/dist/models/interfaces/ITrackerOpts.d.ts +12 -0
  58. package/dist/models/interfaces/ITrackerOpts.js +2 -0
  59. package/dist/models/interfaces/OpModelType.d.ts +4 -1
  60. package/dist/models/interfaces/OpModelType.js +0 -0
  61. package/dist/models/types/RelationTypes.d.ts +0 -0
  62. package/dist/models/types/RelationTypes.js +0 -0
  63. package/dist/models/utils/ModelUtils.d.ts +0 -0
  64. package/dist/models/utils/ModelUtils.js +0 -0
  65. package/dist/models/utils/PaginationUtils.d.ts +0 -0
  66. package/dist/models/utils/PaginationUtils.js +0 -0
  67. package/dist/models/utils/RelationUtils.d.ts +1 -1
  68. package/dist/models/utils/RelationUtils.js +2 -2
  69. package/dist/models/utils/TimeSeriesUtils.d.ts +0 -0
  70. package/dist/models/utils/TimeSeriesUtils.js +0 -0
  71. package/dist/services/DBService.d.ts +0 -0
  72. package/dist/services/DBService.js +0 -0
  73. package/dist/types/DbConfigHandler.d.ts +1 -1
  74. package/dist/types/DbConfigHandler.js +0 -0
  75. package/dist/types/FindParams.d.ts +0 -0
  76. package/dist/types/FindParams.js +0 -0
  77. package/dist/types/IRWSModel.d.ts +1 -1
  78. package/dist/types/IRWSModel.js +0 -0
  79. package/dist/types/ITimeSeries.d.ts +0 -0
  80. package/dist/types/ITimeSeries.js +0 -0
  81. package/exec/console.js +110 -110
  82. package/exec/db.rws.webpack.config.js +168 -168
  83. package/exec/src/cli.ts +73 -75
  84. package/exec/tsconfig.json +32 -32
  85. package/exec/webpackFilters.js +17 -17
  86. package/package.json +36 -36
  87. package/src/decorators/IdType.ts +17 -0
  88. package/src/decorators/InverseRelation.ts +41 -37
  89. package/src/decorators/InverseTimeSeries.ts +21 -21
  90. package/src/decorators/RWSCollection.ts +45 -27
  91. package/src/decorators/Relation.ts +61 -48
  92. package/src/decorators/TrackType.ts +65 -69
  93. package/src/decorators/index.ts +16 -8
  94. package/src/empty.js +0 -0
  95. package/src/helper/DbHelper.ts +133 -223
  96. package/src/helper/FieldsHelper.ts +34 -34
  97. package/src/helper/db/index.ts +10 -0
  98. package/src/helper/db/relation-manager.ts +119 -0
  99. package/src/helper/db/schema-generator.ts +318 -0
  100. package/src/helper/db/type-converter.ts +119 -0
  101. package/src/helper/db/utils.ts +120 -0
  102. package/src/index.ts +47 -38
  103. package/src/models/_model.ts +29 -29
  104. package/src/models/core/RWSModel.ts +529 -520
  105. package/src/models/core/TimeSeriesModel.ts +19 -19
  106. package/src/models/index.ts +20 -20
  107. package/src/models/interfaces/IDbOpts.ts +17 -0
  108. package/src/models/interfaces/IIdTypeOpts.ts +4 -0
  109. package/src/models/interfaces/IModel.ts +12 -12
  110. package/src/models/interfaces/IRWSModelServices.ts +7 -7
  111. package/src/models/interfaces/ITrackerOpts.ts +13 -0
  112. package/src/models/interfaces/OpModelType.ts +52 -49
  113. package/src/models/types/RelationTypes.ts +25 -25
  114. package/src/models/utils/ModelUtils.ts +65 -65
  115. package/src/models/utils/PaginationUtils.ts +42 -42
  116. package/src/models/utils/RelationUtils.ts +76 -76
  117. package/src/models/utils/TimeSeriesUtils.ts +38 -38
  118. package/src/services/DBService.ts +277 -277
  119. package/src/types/DbConfigHandler.ts +17 -17
  120. package/src/types/FindParams.ts +13 -13
  121. package/src/types/IRWSModel.ts +2 -2
  122. package/src/types/ITimeSeries.ts +5 -5
  123. package/tsconfig.json +22 -22
package/README.md CHANGED
@@ -1,405 +1,343 @@
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
- }
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 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
+ ignored_keys: ['passwd']
26
+ })
27
+ class User extends RWSModel<User> implements IUser {
28
+ @TrackType(String)
29
+ username: string;
30
+
31
+ @TrackType(String) // Can also handle Object and Number
32
+ passwd: string;
33
+
34
+ @TrackType(Boolean)
35
+ active: boolean;
36
+
37
+ @TrackType(Date, { required: true })
38
+ created_at: Date;
39
+
40
+ @TrackType(Date)
41
+ updated_at: Date;
42
+
43
+ /**
44
+ * Every relation and inverse relation decorator
45
+ * uses arrow function model passing
46
+ **/
47
+ @InverseRelation(() => ApiKey, () => User)
48
+ apiKeys: IApiKey[];
49
+
50
+ constructor(data?: IUser) {
51
+ super(data);
52
+
53
+ if(!this.created_at){
54
+ this.created_at = new Date();
55
+ }
56
+ }
57
+ }
58
+
59
+ //Must export default for automated DI / build work.
60
+ export default User;
61
+ ```
62
+
63
+ ## Relations
64
+
65
+ ***Basic many to one relation***
66
+ ```typescript
67
+ import { RWSCollection, RWSModel, TrackType, Relation } from '@rws-framework/db';
68
+
69
+ import 'reflect-metadata';
70
+ import User from './User';
71
+ import SomeModel from './SomeModel';
72
+ import IApiKey from './interfaces/IApiKey';
73
+
74
+ @RWSCollection('user_api_keys', {
75
+ relations: {
76
+ dummyIgnoredHydrationRelation: false // ignoring this relation on hydration - will be null
77
+ }
78
+ })
79
+ class ApiKey extends RWSModel<ApiKey> implements IApiKey {
80
+
81
+ @Relation(() => User, { requried: false }) // second attribute is required = false
82
+ user: User;
83
+
84
+ @Relation(() => SomeModel) // relation to be ignored by
85
+ dummyIgnoredHydrationRelation: SomeModel;
86
+
87
+ @TrackType(Object)
88
+ keyval: string;
89
+
90
+ @TrackType(Date, { required: true })
91
+ created_at: Date;
92
+
93
+ @TrackType(Date)
94
+ updated_at: Date;
95
+
96
+ static _collection = 'api_keys';
97
+
98
+ constructor(data?: IApiKey) {
99
+ super(data);
100
+
101
+ if(!this.created_at){
102
+ this.created_at = new Date();
103
+ }
104
+
105
+ this.updated_at = new Date();
106
+ }
107
+ }
108
+
109
+ export default ApiKey;
110
+ ```
111
+
112
+ ***Relation decorator*** (many-to-one)
113
+
114
+ ```typescript
115
+ import 'reflect-metadata';
116
+ import { RWSModel, OpModelType } from '../models/_model';
117
+
118
+ export type CascadingSetup = 'Cascade' | 'Restrict' | 'NoAction' | 'SetNull';
119
+
120
+ export interface IRelationOpts {
121
+ required?: boolean
122
+ key: string
123
+ relationField: string //name of field that will hold the relation key value
124
+ relatedToField?: string //name of related field (id by default)
125
+ mappingName?: string
126
+ relatedTo: OpModelType<RWSModel<any>>
127
+ many?: boolean // is it one-to-many or many-to-one
128
+ embed?: boolean // @deprecated for mongo - new decorator for embeds incoming
129
+ useUuid?: boolean //for sql dbs - if you're using some text based id
130
+ relationName?: string
131
+ cascade?: {
132
+ onDelete?: CascadingSetup,
133
+ onUpdate?: CascadingSetup
134
+ }
135
+ }
136
+
137
+ const _DEFAULTS: Partial<IRelationOpts> = { required: false, many: false, embed: false, cascade: { onDelete: 'SetNull', onUpdate: 'Cascade' }};
138
+
139
+ function Relation(theModel: () => OpModelType<RWSModel<any>>, relationOptions: Partial<IRelationOpts> = _DEFAULTS) {
140
+ return function(target: any, key: string) {
141
+ // Store the promise in metadata immediately
142
+
143
+ const metadataPromise = Promise.resolve().then(() => {
144
+ const relatedTo = theModel();
145
+
146
+ const metaOpts: IRelationOpts = {
147
+ ...relationOptions,
148
+ cascade: relationOptions.cascade || _DEFAULTS.cascade,
149
+ relatedTo,
150
+ relationField: relationOptions.relationField ? relationOptions.relationField : relatedTo._collection + '_id',
151
+ key,
152
+ // Generate a unique relation name if one is not provided
153
+ relationName: relationOptions.relationName ?
154
+ relationOptions.relationName.toLowerCase() :
155
+ `${target.constructor.name.toLowerCase()}_${key}_${relatedTo._collection.toLowerCase()}`
156
+ };
157
+
158
+ if(relationOptions.required){
159
+ metaOpts.cascade.onDelete = 'Restrict';
160
+ }
161
+
162
+ return metaOpts;
163
+ });
164
+
165
+ // Store both the promise and the key information
166
+ Reflect.defineMetadata(`Relation:${key}`, {
167
+ promise: metadataPromise,
168
+ key
169
+ }, target);
170
+ };
171
+ }
172
+
173
+
174
+ export default Relation;
175
+
176
+
177
+ ```
178
+
179
+ ***Inverse relation decorator*** (one-to-many)
180
+ ```typescript
181
+ import 'reflect-metadata';
182
+ import { RWSModel, OpModelType } from '../models/_model';
183
+
184
+ export interface InverseRelationOpts {
185
+ key: string,
186
+ inversionModel: OpModelType<RWSModel<any>>
187
+ foreignKey: string
188
+ singular?: boolean
189
+ relationName?: string
190
+ mappingName?: string
191
+ }
192
+
193
+ function InverseRelation(inversionModel: () => OpModelType<RWSModel<any>>, sourceModel: () => OpModelType<RWSModel<any>>, relationOptions: Partial<InverseRelationOpts> = null) {
194
+ return function (target: any, key: string) {
195
+ const metadataPromise = Promise.resolve().then(() => {
196
+ const model = inversionModel();
197
+ const source = sourceModel();
198
+
199
+ const metaOpts: InverseRelationOpts = {
200
+ ...relationOptions,
201
+ key,
202
+ inversionModel: model,
203
+ foreignKey: relationOptions && relationOptions.foreignKey ? relationOptions.foreignKey : `${source._collection}_id`,
204
+ // Generate a unique relation name if one is not provided
205
+ relationName: relationOptions && relationOptions.relationName ?
206
+ relationOptions.relationName.toLowerCase() :
207
+ `${model._collection}_${key}_${source._collection}`.toLowerCase()
208
+ };
209
+
210
+ return metaOpts;
211
+ });
212
+
213
+ // Store both the promise and the key information
214
+ Reflect.defineMetadata(`InverseRelation:${key}`, {
215
+ promise: metadataPromise,
216
+ key
217
+ }, target);
218
+ };
219
+ }
220
+
221
+ export default InverseRelation;
222
+
223
+ ```
224
+
225
+
226
+ ## RWS Model to prisma conversion
227
+
228
+ ### Init helper class
229
+
230
+ **This needs to be run either from the package or CLI - it changes models to prisma schema and registers it.**
231
+
232
+ *IDbConfigHandler* - An interface for config bag for DBService
233
+
234
+ ```typescript
235
+ import { OpModelType } from "../models/_model";
236
+
237
+ export interface IDbConfigParams {
238
+ mongo_url?: string;
239
+ mongo_db?: string;
240
+ db_models?: OpModelType<any>[]
241
+ }
242
+
243
+ export interface IDbConfigHandler {
244
+ get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K];
245
+ }
246
+ ```
247
+
248
+ **Helper prisma install example**
249
+
250
+ ```typescript
251
+ class Config implements IDbConfigHandler {
252
+ private data: IDbConfigParams = {
253
+ db_models: [],
254
+ db_name: null,
255
+ db_url: null,
256
+ db_type: null
257
+ };
258
+
259
+ private modelsDir: string;
260
+ private cliExecRoot: string;
261
+ private static _instance: Config = null;
262
+
263
+ private constructor(){}
264
+
265
+ static async getInstance(): Promise<Config>
266
+ {
267
+ if(!this._instance){
268
+ this._instance = new Config();
269
+ }
270
+
271
+ await this._instance.fill();
272
+
273
+ return this._instance;
274
+ }
275
+
276
+
277
+ async fill(): Promise<void>
278
+ {
279
+ this.data.db_url = args[0];
280
+ this.data.db_name = args[1];
281
+ this.data.db_type = args[2];
282
+
283
+
284
+ this.modelsDir = args[3];
285
+ this.cliExecRoot = args[4];
286
+ }
287
+
288
+ getModelsDir(): string
289
+ {
290
+ return this.modelsDir
291
+ }
292
+
293
+ getCliExecRoot(): string
294
+ {
295
+ return this.cliExecRoot
296
+ }
297
+
298
+ get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K] {
299
+ return this.data[key];
300
+ }
301
+ }
302
+
303
+ async function main(): Promise<void>
304
+ {
305
+ console.log('INSTALL PRISMA');
306
+ const cfg = await Config.getInstance();
307
+ DbHelper.installPrisma(cfg, new DBService(cfg), false);
308
+ }
309
+ ```
310
+
311
+ ### Init CLI
312
+ Basic CLI command that executes **generateModelSections()** from conversion script is:
313
+
314
+ **rws-db [DB_URL] [DB_NAME] [MODELS_DIRECTORY]**
315
+
316
+ The exec file.
317
+ ```
318
+ /exec/src/console.js
319
+ ```
320
+
321
+ dbType can be any prisma db driver - mongodb by default
322
+
323
+ ```bash
324
+ #npm
325
+
326
+ npx rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName dbType src/models
327
+ ```
328
+
329
+ ```bash
330
+ #yarn
331
+
332
+ yarn rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName dbType src/models
333
+ ```
334
+
335
+ ```bash
336
+ #bun
337
+
338
+ bunx rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName dbType src/models
339
+ ```
340
+
341
+ Code for RWS to prisma conversion from "@rws-framework/server" package:
342
+
343
+ [The repo file](https://github.com/rws-framework/db/blob/master/src/helper/DbHelper.ts)