@rws-framework/db 3.3.7 → 3.4.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 (35) hide show
  1. package/.bin/add-v.sh +88 -6
  2. package/.bin/emerge.sh +10 -10
  3. package/.eslintrc.json +53 -53
  4. package/dist/helper/DbHelper.d.ts +1 -1
  5. package/dist/helper/DbHelper.js +2 -2
  6. package/dist/helper/db/schema-generator.d.ts +2 -1
  7. package/dist/helper/db/schema-generator.js +29 -11
  8. package/dist/models/TimeSeriesModel.d.ts +7 -7
  9. package/dist/models/TimeSeriesModel.js +33 -33
  10. package/dist/models/interfaces/ITrackerOpts.d.ts +2 -0
  11. package/dist/models/types/RelationTypes.d.ts +1 -0
  12. package/dist/models/utils/HydrateUtils.js +16 -6
  13. package/dist/models/utils/RelationUtils.js +2 -1
  14. package/dist/types/DbConfigHandler.d.ts +2 -0
  15. package/exec/db.rws.webpack.config.js +168 -168
  16. package/exec/tsconfig.json +32 -32
  17. package/exec/webpackFilters.js +17 -17
  18. package/package.json +2 -3
  19. package/src/decorators/InverseRelation.ts +1 -1
  20. package/src/decorators/InverseTimeSeries.ts +21 -21
  21. package/src/helper/DbHelper.ts +2 -2
  22. package/src/helper/FieldsHelper.ts +34 -34
  23. package/src/helper/db/schema-generator.ts +36 -12
  24. package/src/models/core/TimeSeriesModel.ts +19 -19
  25. package/src/models/interfaces/IModel.ts +12 -12
  26. package/src/models/interfaces/IRWSModelServices.ts +7 -7
  27. package/src/models/interfaces/ITrackerOpts.ts +3 -1
  28. package/src/models/types/RelationTypes.ts +2 -1
  29. package/src/models/utils/HydrateUtils.ts +16 -7
  30. package/src/models/utils/PaginationUtils.ts +42 -42
  31. package/src/models/utils/RelationUtils.ts +2 -1
  32. package/src/models/utils/TimeSeriesUtils.ts +38 -38
  33. package/src/types/DbConfigHandler.ts +3 -1
  34. package/src/types/FindParams.ts +13 -13
  35. package/src/types/ITimeSeries.ts +5 -5
@@ -30,19 +30,26 @@ export class SchemaGenerator {
30
30
  * @param dbUrl The database URL
31
31
  * @returns The base schema
32
32
  */
33
- static generateBaseSchema(dbType: string, dbUrl: string): string {
33
+ static generateBaseSchema(dbType: string, dbUrl: string, output?: string, binaryTargets?: string[]): string {
34
34
  process.env = { ...process.env, [this.dbUrlVarName]: dbUrl };
35
35
 
36
36
  return `generator client {
37
37
  provider = "prisma-client-js"
38
+ ${output ? `output = "${this.ospath(output)}"` : ''}
39
+ ${binaryTargets ? `binaryTargets = ${JSON.stringify(binaryTargets)}` : ''}
38
40
  }
39
41
 
40
42
  datasource db {
41
43
  provider = "${dbType}"
42
- url = env("${this.dbUrlVarName}")
44
+ url = env("${this.dbUrlVarName}")
43
45
  }`;
44
46
  }
45
47
 
48
+ private static ospath(outPath: string): string
49
+ {
50
+ return outPath.split('')[1] === ':' ? outPath.replace(/\\/g,'\\\\') : outPath
51
+ }
52
+
46
53
  /**
47
54
  * Generate model sections for the schema
48
55
  * @param model The model to generate a section for
@@ -125,12 +132,20 @@ datasource db {
125
132
 
126
133
  const relatedToField = modelMetadata.relatedToField || 'id';
127
134
  const bindingFieldExists = !!modelMetadatas[relationFieldName];
128
-
135
+ const relatedFieldMeta = relatedModelMetadatas[relatedToField];
136
+
137
+ const foundInverseRelation = Object.values(relatedModelMetadatas).find(item => item.metadata.foreignKey === relationFieldName && item.metadata.inversionModel._collection === modelName);
138
+
129
139
  if(modelMetadata.required === false){
130
140
  requiredString = '?';
131
141
  }
132
142
 
133
- const cascadeStr = cascadeOpts.length ? `, ${cascadeOpts.join(', ')}` : '' ;
143
+ let cascadeStr = cascadeOpts.length ? `, ${cascadeOpts.join(', ')}` : '' ;
144
+
145
+ if(foundInverseRelation && foundInverseRelation.metadata.singular){
146
+ cascadeStr = '';
147
+ requiredString = '?';
148
+ }
134
149
 
135
150
  if (isMany) {
136
151
  // Add an inverse field to the related model if it doesn't exist
@@ -138,7 +153,6 @@ datasource db {
138
153
  } else {
139
154
  section += `\t${key} ${relatedModel._collection}${requiredString} @relation(${relationName ? `"${relationName}", ` : ''}fields: [${relationFieldName}], references: [${relatedToField}]${mapName ? `, map: "${mapName}"` : ''}${cascadeStr})\n`;
140
155
  if(!bindingFieldExists){
141
- const relatedFieldMeta = relatedModelMetadatas[relatedToField];
142
156
 
143
157
  if(!relatedFieldMeta.metadata.required){
144
158
  requiredString = '';
@@ -150,21 +164,28 @@ datasource db {
150
164
  if(relationMeta.required === false){
151
165
  requiredString = '?';
152
166
  }
167
+
168
+ let appendix = '';
169
+
170
+ if(foundInverseRelation && foundInverseRelation.metadata.singular){
171
+ appendix = ' @unique';
172
+ requiredString = '?';
173
+ }
153
174
 
154
175
  // Add relation field with appropriate type based on database
155
176
  if (dbType === 'mongodb') {
156
- section += `\t${relationFieldName} String${requiredString} @db.ObjectId\n`;
177
+ section += `\t${relationFieldName} String${requiredString} @db.ObjectId${appendix}\n`;
157
178
  } else if (dbType === 'mysql') {
158
179
  // For MySQL, determine the type based on the related model's ID type
159
- section += `\t${relationFieldName} ${relatedFieldType}${requiredString}\n`;
180
+ section += `\t${relationFieldName} ${relatedFieldType}${requiredString}${appendix}\n`;
160
181
  } else if (dbType === 'postgresql' || dbType === 'postgres') {
161
182
  if (relatedFieldType === 'String') {
162
- section += `\t${relationFieldName} ${relatedFieldType}${requiredString} @db.Uuid\n`;
183
+ section += `\t${relationFieldName} ${relatedFieldType}${requiredString} @db.Uuid${appendix}\n`;
163
184
  } else {
164
- section += `\t${relationFieldName} ${relatedFieldType}${requiredString}\n`;
185
+ section += `\t${relationFieldName} ${relatedFieldType}${requiredString}${appendix}\n`;
165
186
  }
166
187
  } else {
167
- section += `\t${relationFieldName} String${requiredString}\n`;
188
+ section += `\t${relationFieldName} String${requiredString}${appendix}\n`;
168
189
  }
169
190
  }
170
191
  }
@@ -182,6 +203,7 @@ datasource db {
182
203
  const relationIndex = RelationManager.getRelationCounter(relationKey, true);
183
204
 
184
205
  const relationName = RelationManager.getShortenedRelationName(relatedModelName, modelName, relationIndex);
206
+ const singular: boolean = relationMeta.singular;
185
207
 
186
208
  let relationTag = '';
187
209
 
@@ -189,7 +211,7 @@ datasource db {
189
211
  relationTag = ` @relation("${relationMeta.relationName}")`;
190
212
  }
191
213
 
192
- section += `\t${key} ${relationMeta.inversionModel._collection}[]${relationTag}\n`;
214
+ section += `\t${key} ${relationMeta.inversionModel._collection}${singular ? '?' : '[]'}${relationTag}\n`;
193
215
 
194
216
  RelationManager.completeRelation(relationKey, relationIndex, true);
195
217
  } else if (annotationType === 'InverseTimeSeries') {
@@ -341,8 +363,10 @@ datasource db {
341
363
  static async installPrisma(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
342
364
  const dbUrl = configService.get('db_url');
343
365
  const dbType = configService.get('db_type') || 'mongodb';
366
+ const dbPrismaOutput = configService.get('db_prisma_output');
367
+ const dbPrismaBinaryTargets = configService.get('db_prisma_binary_targets');
344
368
 
345
- let template: string = this.generateBaseSchema(dbType, dbUrl);
369
+ let template: string = this.generateBaseSchema(dbType, dbUrl, dbPrismaOutput, dbPrismaBinaryTargets);
346
370
 
347
371
  const dbModels: OpModelType<unknown>[] | null = configService.get('db_models');
348
372
 
@@ -1,19 +1,19 @@
1
- import { RWSModel } from './RWSModel';
2
- import { TrackType } from '../../decorators';
3
-
4
- // export default class TimeSeriesModel<T> extends RWSModel<T> {
5
- // @TrackType(Number) value: number;
6
-
7
- // @TrackType(Date) timestamp: Date;
8
-
9
- // @TrackType(Object)
10
- // params: any;
11
-
12
- // constructor(data?: any) {
13
- // super(data);
14
-
15
- // if(!this.timestamp) {
16
- // this.timestamp = new Date();
17
- // }
18
- // }
19
- // }
1
+ import { RWSModel } from './RWSModel';
2
+ import { TrackType } from '../../decorators';
3
+
4
+ // export default class TimeSeriesModel<T> extends RWSModel<T> {
5
+ // @TrackType(Number) value: number;
6
+
7
+ // @TrackType(Date) timestamp: Date;
8
+
9
+ // @TrackType(Object)
10
+ // params: any;
11
+
12
+ // constructor(data?: any) {
13
+ // super(data);
14
+
15
+ // if(!this.timestamp) {
16
+ // this.timestamp = new Date();
17
+ // }
18
+ // }
19
+ // }
@@ -1,12 +1,12 @@
1
- import { IDbConfigHandler } from '../../types/DbConfigHandler';
2
- import { DBService } from '../../services/DBService';
3
-
4
- export interface IModel {
5
- [key: string]: any;
6
- id: string |number | null;
7
- save: () => void;
8
- getDb: () => DBService;
9
- getCollection: () => string | null;
10
- configService?: IDbConfigHandler;
11
- dbService?: DBService;
12
- }
1
+ import { IDbConfigHandler } from '../../types/DbConfigHandler';
2
+ import { DBService } from '../../services/DBService';
3
+
4
+ export interface IModel {
5
+ [key: string]: any;
6
+ id: string |number | null;
7
+ save: () => void;
8
+ getDb: () => DBService;
9
+ getCollection: () => string | null;
10
+ configService?: IDbConfigHandler;
11
+ dbService?: DBService;
12
+ }
@@ -1,7 +1,7 @@
1
- import { IDbConfigHandler } from '../../types/DbConfigHandler';
2
- import { DBService } from '../../services/DBService';
3
-
4
- export interface IRWSModelServices {
5
- configService?: IDbConfigHandler;
6
- dbService?: DBService;
7
- }
1
+ import { IDbConfigHandler } from '../../types/DbConfigHandler';
2
+ import { DBService } from '../../services/DBService';
3
+
4
+ export interface IRWSModelServices {
5
+ configService?: IDbConfigHandler;
6
+ dbService?: DBService;
7
+ }
@@ -9,6 +9,8 @@ export interface ITrackerOpts extends IDbOpts {
9
9
  relatedToField?: string,
10
10
  relatedTo?: OpModelType<any>,
11
11
  inversionModel?: OpModelType<any>,
12
- relationName?: string
12
+ relationName?: string;
13
+ foreignKey?: string
13
14
  noAuto?: boolean;
15
+ singular?: boolean;
14
16
  }
@@ -20,6 +20,7 @@ export type RelManyMetaType<T extends IRWSModel> = {
20
20
  [key: string]: {
21
21
  key: string,
22
22
  inversionModel: OpModelType<T>,
23
- foreignKey: string
23
+ foreignKey: string,
24
+ singular: boolean
24
25
  }
25
26
  };
@@ -61,13 +61,22 @@ export class HydrateUtils {
61
61
 
62
62
  if (relationEnabled) {
63
63
  const pk = ModelUtils.findPrimaryKeyFields(model.constructor as OpModelType<any>) as string;
64
-
65
- model[relMeta.key] = await relMeta.inversionModel.findBy({
66
- conditions: {
67
- [relMeta.foreignKey]: data[pk]
68
- },
69
- allowRelations: false
70
- });
64
+
65
+ if(relMeta.singular){
66
+ model[relMeta.key] = await relMeta.inversionModel.findOneBy({
67
+ conditions: {
68
+ [relMeta.foreignKey]: data[pk]
69
+ },
70
+ allowRelations: false
71
+ });
72
+ } else {
73
+ model[relMeta.key] = await relMeta.inversionModel.findBy({
74
+ conditions: {
75
+ [relMeta.foreignKey]: data[pk]
76
+ },
77
+ allowRelations: false
78
+ });
79
+ }
71
80
  }
72
81
  }
73
82
 
@@ -1,42 +1,42 @@
1
- import { RelOneMetaType, RelManyMetaType } from '../types/RelationTypes';
2
- import { IRWSModel } from '../../types/IRWSModel';
3
- import { OpModelType, RWSModel } from '../_model';
4
- import { FindByType, IPaginationParams } from '../../types/FindParams';
5
-
6
- export class PaginationUtils {
7
-
8
- public static async paginate<T extends RWSModel<T>>(
9
- this: OpModelType<T>,
10
- paginationParams: IPaginationParams = { page: 0, per_page: 50 },
11
- findParams: FindByType = {},
12
- ): Promise<T[]> {
13
- const conditions = findParams?.conditions ?? {};
14
- const ordering = findParams?.ordering ?? null;
15
- const fields = findParams?.fields ?? null;
16
- const allowRelations = findParams?.allowRelations ?? true;
17
- const fullData = findParams?.fullData ?? false;
18
-
19
- const collection = Reflect.get(this, '_collection');
20
- this.checkForInclusionWithThrow(this.name);
21
- try {
22
- const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginationParams);
23
- if (dbData.length) {
24
- const instanced: T[] = [];
25
-
26
- for (const data of dbData) {
27
- const inst: T = new (this as { new(): T })();
28
- instanced.push((await inst._asyncFill(data, fullData,allowRelations)) as T);
29
- }
30
-
31
- return instanced;
32
- }
33
-
34
- return [];
35
- } catch (rwsError: Error | any) {
36
- console.error(rwsError);
37
-
38
- throw rwsError;
39
- }
40
- }
41
-
42
- }
1
+ import { RelOneMetaType, RelManyMetaType } from '../types/RelationTypes';
2
+ import { IRWSModel } from '../../types/IRWSModel';
3
+ import { OpModelType, RWSModel } from '../_model';
4
+ import { FindByType, IPaginationParams } from '../../types/FindParams';
5
+
6
+ export class PaginationUtils {
7
+
8
+ public static async paginate<T extends RWSModel<T>>(
9
+ this: OpModelType<T>,
10
+ paginationParams: IPaginationParams = { page: 0, per_page: 50 },
11
+ findParams: FindByType = {},
12
+ ): Promise<T[]> {
13
+ const conditions = findParams?.conditions ?? {};
14
+ const ordering = findParams?.ordering ?? null;
15
+ const fields = findParams?.fields ?? null;
16
+ const allowRelations = findParams?.allowRelations ?? true;
17
+ const fullData = findParams?.fullData ?? false;
18
+
19
+ const collection = Reflect.get(this, '_collection');
20
+ this.checkForInclusionWithThrow(this.name);
21
+ try {
22
+ const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginationParams);
23
+ if (dbData.length) {
24
+ const instanced: T[] = [];
25
+
26
+ for (const data of dbData) {
27
+ const inst: T = new (this as { new(): T })();
28
+ instanced.push((await inst._asyncFill(data, fullData,allowRelations)) as T);
29
+ }
30
+
31
+ return instanced;
32
+ }
33
+
34
+ return [];
35
+ } catch (rwsError: Error | any) {
36
+ console.error(rwsError);
37
+
38
+ throw rwsError;
39
+ }
40
+ }
41
+
42
+ }
@@ -47,7 +47,8 @@ export class RelationUtils {
47
47
  relIds[key] = {
48
48
  key: resolvedMetadata.key,
49
49
  inversionModel: resolvedMetadata.inversionModel,
50
- foreignKey: resolvedMetadata.foreignKey
50
+ foreignKey: resolvedMetadata.foreignKey,
51
+ singular: resolvedMetadata?.singular || false
51
52
  };
52
53
  }
53
54
  }
@@ -1,38 +1,38 @@
1
- import { RWSModel } from "../_model";
2
-
3
- export class TimeSeriesUtils {
4
- static getTimeSeriesModelFields(model: RWSModel<any>): {[key: string]: {collection: string, hydrationField: string, ids: string[]}} {
5
- const timeSeriesIds: {[key: string]: {collection: string, hydrationField: string, ids: string[]}} = {};
6
-
7
- for (const key in model) {
8
- if (model.hasOwnProperty(key)) {
9
- const meta = Reflect.getMetadata(`InverseTimeSeries:${key}`, model);
10
- if(meta){
11
- if(!timeSeriesIds[key]){
12
- timeSeriesIds[key] = {
13
- collection: meta.timeSeriesModel,
14
- hydrationField: meta.hydrationField,
15
- ids: model[key]
16
- };
17
- }
18
- }
19
- }
20
- }
21
-
22
- return timeSeriesIds;
23
- }
24
-
25
- static checkTimeSeries(constructor: any): boolean {
26
- const data = constructor.prototype as any;
27
-
28
- for (const key in data) {
29
- if (data.hasOwnProperty(key)) {
30
- if(Reflect.getMetadata(`InverseTimeSeries:${key}`, constructor.prototype)){
31
- return true;
32
- }
33
- }
34
- }
35
-
36
- return false;
37
- }
38
- }
1
+ import { RWSModel } from "../_model";
2
+
3
+ export class TimeSeriesUtils {
4
+ static getTimeSeriesModelFields(model: RWSModel<any>): {[key: string]: {collection: string, hydrationField: string, ids: string[]}} {
5
+ const timeSeriesIds: {[key: string]: {collection: string, hydrationField: string, ids: string[]}} = {};
6
+
7
+ for (const key in model) {
8
+ if (model.hasOwnProperty(key)) {
9
+ const meta = Reflect.getMetadata(`InverseTimeSeries:${key}`, model);
10
+ if(meta){
11
+ if(!timeSeriesIds[key]){
12
+ timeSeriesIds[key] = {
13
+ collection: meta.timeSeriesModel,
14
+ hydrationField: meta.hydrationField,
15
+ ids: model[key]
16
+ };
17
+ }
18
+ }
19
+ }
20
+ }
21
+
22
+ return timeSeriesIds;
23
+ }
24
+
25
+ static checkTimeSeries(constructor: any): boolean {
26
+ const data = constructor.prototype as any;
27
+
28
+ for (const key in data) {
29
+ if (data.hasOwnProperty(key)) {
30
+ if(Reflect.getMetadata(`InverseTimeSeries:${key}`, constructor.prototype)){
31
+ return true;
32
+ }
33
+ }
34
+ }
35
+
36
+ return false;
37
+ }
38
+ }
@@ -4,7 +4,9 @@ export interface IDbConfigParams {
4
4
  db_url?: string;
5
5
  db_name?: string;
6
6
  db_type?: 'mongodb' | 'mysql' | 'sqlite' | 'postgresql' | 'postgres';
7
- db_models?: OpModelType<any>[]
7
+ db_models?: OpModelType<any>[],
8
+ db_prisma_output?: string,
9
+ db_prisma_binary_targets?: string[]
8
10
  }
9
11
 
10
12
  export interface IdGeneratorOptions {
@@ -1,13 +1,13 @@
1
- export type FindByType = {
2
- conditions?: any
3
- ordering?: { [fieldName: string]: string }
4
- fields?: string[]
5
- allowRelations?: boolean
6
- fullData?: boolean
7
- pagination?: IPaginationParams
8
- }
9
-
10
- export interface IPaginationParams {
11
- page: number,
12
- per_page?: number
13
- }
1
+ export type FindByType = {
2
+ conditions?: any
3
+ ordering?: { [fieldName: string]: string }
4
+ fields?: string[]
5
+ allowRelations?: boolean
6
+ fullData?: boolean
7
+ pagination?: IPaginationParams
8
+ }
9
+
10
+ export interface IPaginationParams {
11
+ page: number,
12
+ per_page?: number
13
+ }
@@ -1,6 +1,6 @@
1
- export interface ITimeSeries {
2
- value: number,
3
- timestamp?: Date;
4
- params?: any;
5
- time_tracker_id?: string
1
+ export interface ITimeSeries {
2
+ value: number,
3
+ timestamp?: Date;
4
+ params?: any;
5
+ time_tracker_id?: string
6
6
  }