@rws-framework/db 3.3.3 → 3.3.5

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.
@@ -2,7 +2,10 @@ import { OpModelType } from "../models/_model";
2
2
  export interface ISuperTagData {
3
3
  tagType: string;
4
4
  fields: string[];
5
- map: string;
5
+ fieldParams?: {
6
+ [key: string]: any;
7
+ };
8
+ map?: string;
6
9
  }
7
10
  export interface IRWSCollectionOpts {
8
11
  relations?: {
@@ -20,6 +20,9 @@ function Relation(theModel, relationOptions = _DEFAULTS) {
20
20
  null
21
21
  };
22
22
  if (relationOptions.required) {
23
+ if (!metaOpts.cascade) {
24
+ metaOpts.cascade = {};
25
+ }
23
26
  metaOpts.cascade.onDelete = 'Restrict';
24
27
  }
25
28
  return metaOpts;
@@ -20,6 +20,7 @@ export declare class SchemaGenerator {
20
20
  * @returns The model section
21
21
  */
22
22
  static generateModelSections(model: OpModelType<any>, configService: IDbConfigHandler): Promise<string>;
23
+ private static getSuperFieldFromModel;
23
24
  /**
24
25
  * Install Prisma with the generated schema
25
26
  * @param configService The configuration service
@@ -108,13 +108,8 @@ datasource db {
108
108
  if (!relatedFieldMeta.metadata.required) {
109
109
  requiredString = '';
110
110
  }
111
- let relatedFieldType = type_converter_1.TypeConverter.toConfigCase(relatedFieldMeta.metadata, dbType, true);
112
- /**
113
- * @todo: Detect type
114
- */
115
- if (relatedToField === 'id' && dbType !== 'mongodb') {
116
- relatedFieldType = 'Int';
117
- }
111
+ const defaultIdType = utils_1.DbUtils.getDefaultPrismaType(dbType, relatedFieldMeta.annotationType !== 'TrackType' && relatedFieldMeta.metadata.type.name === 'String' && relatedToField === 'id' && dbType !== 'mongodb');
112
+ let relatedFieldType = type_converter_1.TypeConverter.toConfigCase(relatedFieldMeta.metadata, dbType, true, relatedFieldMeta.annotationType !== 'TrackType' && relatedToField === 'id' && relatedFieldMeta.metadata.type !== defaultIdType);
118
113
  if (relationMeta.required === false) {
119
114
  requiredString = '?';
120
115
  }
@@ -218,10 +213,24 @@ datasource db {
218
213
  section += '\n';
219
214
  }
220
215
  for (const superTag of model._SUPER_TAGS) {
221
- const mapStr = superTag.map ? `, map: "${superTag.map}"` : '';
216
+ let mapStr = '';
217
+ if (superTag.map) {
218
+ const superFieldMapMeta = modelMetadatas[superTag.map];
219
+ let mapField = superTag.map;
220
+ if (superFieldMapMeta) {
221
+ mapField = this.getSuperFieldFromModel(mapField, superFieldMapMeta);
222
+ }
223
+ mapStr = `, map: "${mapField}"`;
224
+ }
222
225
  const superFields = [];
223
- for (const superField of superTag.fields) {
224
- const fieldMetadata = modelMetadatas[superField]['metadata'];
226
+ for (let superField of superTag.fields) {
227
+ const superFieldElemMeta = modelMetadatas[superField];
228
+ if (!superFieldElemMeta) {
229
+ console.log(chalk_1.default.yellowBright(`Ignoring "${superField}" field in "${superTag.tagType}" supertag in model "${modelName}"`));
230
+ continue;
231
+ }
232
+ const fieldMetadata = superFieldElemMeta.metadata;
233
+ superField = this.getSuperFieldFromModel(superField, superFieldElemMeta);
225
234
  let pushed = false;
226
235
  if (fieldMetadata.dbOptions && fieldMetadata.dbOptions.mysql && fieldMetadata.dbOptions.mysql.useType) {
227
236
  switch (fieldMetadata.dbOptions.mysql.useType) {
@@ -240,6 +249,14 @@ datasource db {
240
249
  section += '}\n';
241
250
  return section;
242
251
  }
252
+ static getSuperFieldFromModel(superFieldElemName, superFieldElemMeta) {
253
+ const fieldDecorator = superFieldElemMeta.annotationType;
254
+ if (fieldDecorator === 'Relation') {
255
+ const fieldMetadata = superFieldElemMeta.metadata;
256
+ superFieldElemName = fieldMetadata.relationField;
257
+ }
258
+ return superFieldElemName;
259
+ }
243
260
  /**
244
261
  * Install Prisma with the generated schema
245
262
  * @param configService The configuration service
@@ -65,5 +65,6 @@ declare class RWSModel<T> implements IModel {
65
65
  static setServices(services: IRWSModelServices): void;
66
66
  getDb(): DBService;
67
67
  static getDb(): DBService;
68
+ reload(): Promise<T | null>;
68
69
  }
69
70
  export { RWSModel };
@@ -160,8 +160,8 @@ class RWSModel {
160
160
  const entryExists = await ModelUtils_1.ModelUtils.entryExists(this);
161
161
  if (entryExists) {
162
162
  this.preUpdate();
163
- const compoundId = ModelUtils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
164
- updatedModelData = await this.dbService.update(data, this.getCollection(), Array.isArray(compoundId) ? compoundId : null);
163
+ const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
164
+ updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
165
165
  await this._asyncFill(updatedModelData);
166
166
  this.postUpdate();
167
167
  }
@@ -265,6 +265,19 @@ class RWSModel {
265
265
  static getDb() {
266
266
  return this.services.dbService;
267
267
  }
268
+ async reload() {
269
+ const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
270
+ const where = {};
271
+ if (Array.isArray(pk)) {
272
+ for (const pkElem of pk) {
273
+ where[pkElem] = this[pkElem];
274
+ }
275
+ }
276
+ else {
277
+ where[pk] = this[pk];
278
+ }
279
+ return await FindUtils_1.FindUtils.findOneBy(this.constructor, { conditions: where });
280
+ }
268
281
  }
269
282
  exports.RWSModel = RWSModel;
270
283
  __decorate([
@@ -10,7 +10,7 @@ class FindUtils {
10
10
  const fullData = findParams?.fullData ?? false;
11
11
  opModel.checkForInclusionWithThrow('');
12
12
  const collection = Reflect.get(opModel, '_collection');
13
- const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering, allowRelations);
13
+ const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
14
14
  if (dbData) {
15
15
  const inst = new opModel();
16
16
  return await inst._asyncFill(dbData, fullData, allowRelations);
@@ -24,7 +24,7 @@ class FindUtils {
24
24
  const fullData = findParams?.fullData ?? false;
25
25
  const collection = Reflect.get(opModel, '_collection');
26
26
  opModel.checkForInclusionWithThrow(opModel.name);
27
- const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering, allowRelations);
27
+ const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
28
28
  if (dbData) {
29
29
  const inst = new opModel();
30
30
  return await inst._asyncFill(dbData, fullData, allowRelations);
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.HydrateUtils = void 0;
4
7
  const TimeSeriesUtils_1 = require("./TimeSeriesUtils");
5
8
  const RelationUtils_1 = require("./RelationUtils");
6
9
  const ModelUtils_1 = require("./ModelUtils");
10
+ const chalk_1 = __importDefault(require("chalk"));
7
11
  class HydrateUtils {
8
12
  static async hydrateDataFields(model, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data) {
9
13
  const timeSeriesIds = TimeSeriesUtils_1.TimeSeriesUtils.getTimeSeriesModelFields(model);
@@ -43,9 +47,10 @@ class HydrateUtils {
43
47
  const relMeta = relManyData[key];
44
48
  const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(model, relMeta.key);
45
49
  if (relationEnabled) {
50
+ const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(model.constructor);
46
51
  model[relMeta.key] = await relMeta.inversionModel.findBy({
47
52
  conditions: {
48
- [relMeta.foreignKey]: data.id
53
+ [relMeta.foreignKey]: data[pk]
49
54
  },
50
55
  allowRelations: false
51
56
  });
@@ -62,7 +67,16 @@ class HydrateUtils {
62
67
  throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`);
63
68
  }
64
69
  if (relationEnabled && data[relMeta.hydrationField]) {
65
- model[relMeta.key] = await relMeta.model.findOneBy({ conditions: { [relMeta.foreignKey]: data[relMeta.hydrationField] } }, { allowRelations: false });
70
+ const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(relMeta.model);
71
+ const where = {};
72
+ if (Array.isArray(pk)) {
73
+ console.log(chalk_1.default.yellowBright(`Hydration field "${relMeta.hydrationField}" on model "${model.constructor.name}" leads to compound key. Ignoring.`));
74
+ continue;
75
+ }
76
+ else {
77
+ where[pk] = data[relMeta.hydrationField];
78
+ }
79
+ model[relMeta.key] = await relMeta.model.findOneBy({ conditions: where }, { allowRelations: false });
66
80
  }
67
81
  else if (relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]) {
68
82
  const newRelModel = await relMeta.model.create(data[relMeta.key]);
@@ -21,12 +21,10 @@ declare class DBService {
21
21
  cloneDatabase(source: string, target: string): Promise<void>;
22
22
  watchCollection(collectionName: string, preRun: () => void): Promise<any>;
23
23
  insert(data: any, collection: string, isTimeSeries?: boolean): Promise<any>;
24
- update(data: any, collection: string, compoundId?: {
25
- [key: string]: any;
26
- }): Promise<IModel>;
24
+ update(data: any, collection: string, pk: string | string[]): Promise<IModel>;
27
25
  findOneBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
28
26
  [fieldName: string]: string;
29
- }, allowRelations?: boolean): Promise<IModel | null>;
27
+ }): Promise<IModel | null>;
30
28
  delete(collection: string, conditions: any): Promise<void>;
31
29
  findBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
32
30
  [fieldName: string]: string;
@@ -101,16 +101,22 @@ class DBService {
101
101
  result = await prismaCollection.create({ data });
102
102
  return await this.findOneBy(collection, { id: result.id });
103
103
  }
104
- async update(data, collection, compoundId = null) {
104
+ async update(data, collection, pk) {
105
105
  const prismaCollection = this.getCollectionHandler(collection);
106
- const where = compoundId ? compoundId : {
107
- id: data.id,
108
- };
109
- if (!compoundId) {
110
- delete data['id'];
106
+ const where = {};
107
+ if (Array.isArray(pk)) {
108
+ for (const pkElem of pk) {
109
+ where[pkElem] = data[pkElem];
110
+ }
111
+ }
112
+ else {
113
+ where[pk] = data[pk];
114
+ }
115
+ if (!Array.isArray(pk)) {
116
+ delete data[pk];
111
117
  }
112
118
  else {
113
- for (const cKey in compoundId) {
119
+ for (const cKey in pk) {
114
120
  delete data[cKey];
115
121
  }
116
122
  }
@@ -120,7 +126,7 @@ class DBService {
120
126
  });
121
127
  return await this.findOneBy(collection, where);
122
128
  }
123
- async findOneBy(collection, conditions, fields = null, ordering = null, allowRelations = true) {
129
+ async findOneBy(collection, conditions, fields = null, ordering = null) {
124
130
  const params = { where: conditions };
125
131
  if (fields) {
126
132
  params.select = {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rws-framework/db",
3
3
  "private": false,
4
- "version": "3.3.3",
4
+ "version": "3.3.5",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -5,7 +5,8 @@ import { OpModelType } from "../models/_model";
5
5
  export interface ISuperTagData {
6
6
  tagType: string,
7
7
  fields: string[],
8
- map: string
8
+ fieldParams?: {[key: string]: any};
9
+ map?: string;
9
10
  }
10
11
 
11
12
  export interface IRWSCollectionOpts {
@@ -44,6 +44,9 @@ function Relation(theModel: () => OpModelType<RWSModel<any>>, relationOptions: P
44
44
  };
45
45
 
46
46
  if(relationOptions.required){
47
+ if(!metaOpts.cascade){
48
+ metaOpts.cascade = {};
49
+ }
47
50
  metaOpts.cascade.onDelete = 'Restrict';
48
51
  }
49
52
 
@@ -144,15 +144,9 @@ datasource db {
144
144
  requiredString = '';
145
145
  }
146
146
 
147
- let relatedFieldType = TypeConverter.toConfigCase(relatedFieldMeta.metadata, dbType, true);
148
-
149
- /**
150
- * @todo: Detect type
151
- */
152
- if(relatedToField === 'id' && dbType !== 'mongodb'){
153
- relatedFieldType = 'Int';
154
- }
155
-
147
+ const defaultIdType = DbUtils.getDefaultPrismaType(dbType, relatedFieldMeta.annotationType !== 'TrackType' && relatedFieldMeta.metadata.type.name === 'String' && relatedToField === 'id' && dbType !== 'mongodb');
148
+ let relatedFieldType = TypeConverter.toConfigCase(relatedFieldMeta.metadata, dbType, true, relatedFieldMeta.annotationType !== 'TrackType' && relatedToField === 'id' && relatedFieldMeta.metadata.type !== defaultIdType);
149
+
156
150
  if(relationMeta.required === false){
157
151
  requiredString = '?';
158
152
  }
@@ -271,13 +265,33 @@ datasource db {
271
265
 
272
266
  for(const superTag of model._SUPER_TAGS){
273
267
 
274
- const mapStr = superTag.map ? `, map: "${superTag.map}"` : '';
268
+ let mapStr = '';
269
+
270
+ if(superTag.map){
271
+ const superFieldMapMeta = modelMetadatas[superTag.map];
272
+
273
+ let mapField: string = superTag.map;
274
+
275
+ if(superFieldMapMeta){
276
+ mapField = this.getSuperFieldFromModel(mapField, superFieldMapMeta);
277
+ }
278
+
279
+ mapStr = `, map: "${mapField}"`;
280
+ }
275
281
 
276
282
  const superFields = [];
277
283
 
278
- for(const superField of superTag.fields){
279
- const fieldMetadata = modelMetadatas[superField]['metadata'];
280
-
284
+ for(let superField of superTag.fields){
285
+ const superFieldElemMeta = modelMetadatas[superField];
286
+
287
+ if(!superFieldElemMeta){
288
+ console.log(chalk.yellowBright(`Ignoring "${superField}" field in "${superTag.tagType}" supertag in model "${modelName}"`));
289
+ continue;
290
+ }
291
+
292
+ const fieldMetadata = superFieldElemMeta.metadata;
293
+
294
+ superField = this.getSuperFieldFromModel(superField, superFieldElemMeta);
281
295
 
282
296
  let pushed = false;
283
297
 
@@ -302,6 +316,22 @@ datasource db {
302
316
  return section;
303
317
  }
304
318
 
319
+ private static getSuperFieldFromModel(superFieldElemName: string, superFieldElemMeta: {
320
+ annotationType: string;
321
+ metadata: any;
322
+ }): string
323
+ {
324
+
325
+ const fieldDecorator = superFieldElemMeta.annotationType;
326
+
327
+ if(fieldDecorator === 'Relation'){
328
+ const fieldMetadata = superFieldElemMeta.metadata as IRelationOpts;
329
+ superFieldElemName = fieldMetadata.relationField;
330
+ }
331
+
332
+ return superFieldElemName;
333
+ }
334
+
305
335
  /**
306
336
  * Install Prisma with the generated schema
307
337
  * @param configService The configuration service
@@ -1,8 +1,8 @@
1
1
  import { IDbOpts } from '../../models/interfaces/IDbOpts';
2
2
  import { ITrackerMetaOpts } from '../../models/_model';
3
- import { IIdMetaOpts } from 'src/decorators/IdType';
3
+ import { IIdMetaOpts } from '../../decorators/IdType';
4
4
  import { DbUtils } from './utils';
5
- import { IDbConfigParams } from 'src/types/DbConfigHandler';
5
+ import { IDbConfigParams } from '../../types/DbConfigHandler';
6
6
 
7
7
  /**
8
8
  * Handles type conversion for database schema generation
@@ -207,9 +207,9 @@ class RWSModel<T> implements IModel {
207
207
  if (entryExists) {
208
208
  this.preUpdate();
209
209
 
210
- const compoundId = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<any>);
210
+ const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<any>);
211
211
 
212
- updatedModelData = await this.dbService.update(data, this.getCollection(), Array.isArray(compoundId) ? compoundId : null);
212
+ updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
213
213
 
214
214
  await this._asyncFill(updatedModelData);
215
215
  this.postUpdate();
@@ -365,6 +365,22 @@ class RWSModel<T> implements IModel {
365
365
  {
366
366
  return this.services.dbService;
367
367
  }
368
+
369
+ public async reload(): Promise<T | null>
370
+ {
371
+ const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<any>);
372
+ const where: any = {};
373
+
374
+ if(Array.isArray(pk)){
375
+ for(const pkElem of pk){
376
+ where[pkElem] = this[pkElem];
377
+ }
378
+ }else{
379
+ where[pk as string] = this[pk as string]
380
+ }
381
+
382
+ return await FindUtils.findOneBy(this.constructor as OpModelType<any>, { conditions: where });
383
+ }
368
384
  }
369
385
 
370
386
  export { RWSModel };
@@ -22,7 +22,7 @@ export class FindUtils {
22
22
 
23
23
 
24
24
  const collection = Reflect.get(opModel, '_collection');
25
- const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering, allowRelations);
25
+ const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
26
26
 
27
27
 
28
28
  if (dbData) {
@@ -46,7 +46,7 @@ export class FindUtils {
46
46
  const collection = Reflect.get(opModel, '_collection');
47
47
  opModel.checkForInclusionWithThrow(opModel.name);
48
48
 
49
- const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering, allowRelations);
49
+ const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
50
50
 
51
51
  if (dbData) {
52
52
  const inst: T = new (opModel as { new(): T })();
@@ -5,6 +5,7 @@ import { TimeSeriesUtils } from "./TimeSeriesUtils";
5
5
  import { RelationUtils } from "./RelationUtils";
6
6
  import { OpModelType } from "..";
7
7
  import { ModelUtils } from "./ModelUtils";
8
+ import chalk from 'chalk';
8
9
 
9
10
  export class HydrateUtils {
10
11
  static async hydrateDataFields(model: RWSModel<any>, collections_to_models: {[key: string]: any}, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {[key: string] : any}){
@@ -58,13 +59,15 @@ export class HydrateUtils {
58
59
 
59
60
 
60
61
 
61
- if (relationEnabled) {
62
+ if (relationEnabled) {
63
+ const pk = ModelUtils.findPrimaryKeyFields(model.constructor as OpModelType<any>) as string;
64
+
62
65
  model[relMeta.key] = await relMeta.inversionModel.findBy({
63
66
  conditions: {
64
- [relMeta.foreignKey]: data.id
67
+ [relMeta.foreignKey]: data[pk]
65
68
  },
66
69
  allowRelations: false
67
- });
70
+ });
68
71
  }
69
72
  }
70
73
 
@@ -81,8 +84,19 @@ export class HydrateUtils {
81
84
  throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`)
82
85
  }
83
86
 
84
- if (relationEnabled && data[relMeta.hydrationField]) {
85
- model[relMeta.key] = await relMeta.model.findOneBy({conditions: {[relMeta.foreignKey] : data[relMeta.hydrationField]}}, { allowRelations: false });
87
+ if (relationEnabled && data[relMeta.hydrationField]) {
88
+ const pk = ModelUtils.findPrimaryKeyFields(relMeta.model);
89
+
90
+ const where: any = {};
91
+
92
+ if(Array.isArray(pk)){
93
+ console.log(chalk.yellowBright(`Hydration field "${relMeta.hydrationField}" on model "${model.constructor.name}" leads to compound key. Ignoring.`));
94
+ continue;
95
+ }else{
96
+ where[pk as string] = data[relMeta.hydrationField]
97
+ }
98
+
99
+ model[relMeta.key] = await relMeta.model.findOneBy({conditions: where}, { allowRelations: false });
86
100
  }
87
101
  else if(relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]){
88
102
  const newRelModel: RWSModel<any> = await relMeta.model.create(data[relMeta.key]);
@@ -137,19 +137,26 @@ class DBService {
137
137
  return await this.findOneBy(collection, { id: result.id });
138
138
  }
139
139
 
140
- async update(data: any, collection: string, compoundId: {[key: string]: any} = null): Promise<IModel>
140
+ async update(data: any, collection: string, pk: string | string[]): Promise<IModel>
141
141
  {
142
142
 
143
143
  const prismaCollection = this.getCollectionHandler(collection);
144
144
 
145
- const where = compoundId ? compoundId : {
146
- id: data.id,
147
- };
148
145
 
149
- if(!compoundId){
150
- delete data['id'];
146
+ const where: any = {};
147
+
148
+ if(Array.isArray(pk)){
149
+ for(const pkElem of pk){
150
+ where[pkElem] = data[pkElem];
151
+ }
152
+ }else{
153
+ where[pk as string] = data[pk as string]
154
+ }
155
+
156
+ if(!Array.isArray(pk)){
157
+ delete data[pk];
151
158
  }else{
152
- for(const cKey in compoundId){
159
+ for(const cKey in pk){
153
160
  delete data[cKey];
154
161
  }
155
162
  }
@@ -164,7 +171,7 @@ class DBService {
164
171
  }
165
172
 
166
173
 
167
- async findOneBy(collection: string, conditions: any, fields: string[] | null = null, ordering: { [fieldName: string]: string } = null, allowRelations: boolean = true): Promise<IModel|null>
174
+ async findOneBy(collection: string, conditions: any, fields: string[] | null = null, ordering: { [fieldName: string]: string } = null): Promise<IModel|null>
168
175
  {
169
176
  const params: any = { where: conditions };
170
177