@rws-framework/db 3.3.2 → 3.3.4

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
@@ -4,8 +4,6 @@ import { OpModelType } from '../interfaces/OpModelType';
4
4
  import { FindByType, IPaginationParams } from '../../types/FindParams';
5
5
  import { DBService } from '../../services/DBService';
6
6
  import { ISuperTagData } from '../../decorators/RWSCollection';
7
- import { RelManyMetaType, RelOneMetaType } from '../types/RelationTypes';
8
- import { IRWSModel } from '../../types/IRWSModel';
9
7
  declare class RWSModel<T> implements IModel {
10
8
  static services: IRWSModelServices;
11
9
  [key: string]: any;
@@ -32,9 +30,9 @@ declare class RWSModel<T> implements IModel {
32
30
  _asyncFill(data: any, fullDataMode?: boolean, allowRelations?: boolean): Promise<T>;
33
31
  private getModelScalarFields;
34
32
  private getRelationOneMeta;
35
- static getRelationOneMeta(model: any, classFields: string[]): Promise<RelOneMetaType<IRWSModel>>;
33
+ static getRelationOneMeta(model: any, classFields: string[]): Promise<import("..").RelOneMetaType<import("../..").IRWSModel>>;
36
34
  private getRelationManyMeta;
37
- static getRelationManyMeta(model: any, classFields: string[]): Promise<RelManyMetaType<IRWSModel>>;
35
+ static getRelationManyMeta(model: any, classFields: string[]): Promise<import("..").RelManyMetaType<import("../..").IRWSModel>>;
38
36
  static paginate<T extends RWSModel<T>>(this: OpModelType<T>, paginateParams: IPaginationParams, findParams?: FindByType): Promise<T[]>;
39
37
  toMongo(): Promise<any>;
40
38
  getCollection(): string | null;
@@ -67,5 +65,6 @@ declare class RWSModel<T> implements IModel {
67
65
  static setServices(services: IRWSModelServices): void;
68
66
  getDb(): DBService;
69
67
  static getDb(): DBService;
68
+ reload(): Promise<T | null>;
70
69
  }
71
70
  export { RWSModel };
@@ -16,6 +16,7 @@ const RelationUtils_1 = require("../utils/RelationUtils");
16
16
  const TimeSeriesUtils_1 = require("../utils/TimeSeriesUtils");
17
17
  const ModelUtils_1 = require("../utils/ModelUtils");
18
18
  const HydrateUtils_1 = require("../utils/HydrateUtils");
19
+ const FindUtils_1 = require("../utils/FindUtils");
19
20
  class RWSModel {
20
21
  static services = {};
21
22
  id;
@@ -119,29 +120,7 @@ class RWSModel {
119
120
  return RelationUtils_1.RelationUtils.getRelationManyMeta(model, classFields);
120
121
  }
121
122
  static async paginate(paginateParams, findParams) {
122
- const conditions = findParams?.conditions ?? {};
123
- const ordering = findParams?.ordering ?? null;
124
- const fields = findParams?.fields ?? null;
125
- const allowRelations = findParams?.allowRelations ?? true;
126
- const fullData = findParams?.fullData ?? false;
127
- const collection = Reflect.get(this, '_collection');
128
- this.checkForInclusionWithThrow(this.name);
129
- try {
130
- const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
131
- if (dbData.length) {
132
- const instanced = [];
133
- for (const data of dbData) {
134
- const inst = new this();
135
- instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
136
- }
137
- return instanced;
138
- }
139
- return [];
140
- }
141
- catch (rwsError) {
142
- console.error(rwsError);
143
- throw rwsError;
144
- }
123
+ return await FindUtils_1.FindUtils.paginate(this, paginateParams, findParams);
145
124
  }
146
125
  async toMongo() {
147
126
  const data = {};
@@ -178,9 +157,11 @@ class RWSModel {
178
157
  async save() {
179
158
  const data = await this.toMongo();
180
159
  let updatedModelData = data;
181
- if (this.id) {
160
+ const entryExists = await ModelUtils_1.ModelUtils.entryExists(this);
161
+ if (entryExists) {
182
162
  this.preUpdate();
183
- updatedModelData = await this.dbService.update(data, this.getCollection());
163
+ const pk = ModelUtils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
164
+ updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
184
165
  await this._asyncFill(updatedModelData);
185
166
  this.postUpdate();
186
167
  }
@@ -239,59 +220,13 @@ class RWSModel {
239
220
  return await this.services.dbService.watchCollection(collection, preRun);
240
221
  }
241
222
  static async findOneBy(findParams) {
242
- const conditions = findParams?.conditions ?? {};
243
- const ordering = findParams?.ordering ?? null;
244
- const fields = findParams?.fields ?? null;
245
- const allowRelations = findParams?.allowRelations ?? true;
246
- const fullData = findParams?.fullData ?? false;
247
- this.checkForInclusionWithThrow('');
248
- const collection = Reflect.get(this, '_collection');
249
- const dbData = await this.services.dbService.findOneBy(collection, conditions, fields, ordering, allowRelations);
250
- if (dbData) {
251
- const inst = new this();
252
- return await inst._asyncFill(dbData, fullData, allowRelations);
253
- }
254
- return null;
223
+ return await FindUtils_1.FindUtils.findOneBy(this, findParams);
255
224
  }
256
225
  static async find(id, findParams = null) {
257
- const ordering = findParams?.ordering ?? null;
258
- const fields = findParams?.fields ?? null;
259
- const allowRelations = findParams?.allowRelations ?? true;
260
- const fullData = findParams?.fullData ?? false;
261
- const collection = Reflect.get(this, '_collection');
262
- this.checkForInclusionWithThrow(this.name);
263
- const dbData = await this.services.dbService.findOneBy(collection, { id }, fields, ordering, allowRelations);
264
- if (dbData) {
265
- const inst = new this();
266
- return await inst._asyncFill(dbData, fullData, allowRelations);
267
- }
268
- return null;
226
+ return await FindUtils_1.FindUtils.find(this, id, findParams);
269
227
  }
270
228
  static async findBy(findParams) {
271
- const conditions = findParams?.conditions ?? {};
272
- const ordering = findParams?.ordering ?? null;
273
- const fields = findParams?.fields ?? null;
274
- const allowRelations = findParams?.allowRelations ?? true;
275
- const fullData = findParams?.fullData ?? false;
276
- const collection = Reflect.get(this, '_collection');
277
- this.checkForInclusionWithThrow(this.name);
278
- try {
279
- const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
280
- const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
281
- if (dbData.length) {
282
- const instanced = [];
283
- for (const data of dbData) {
284
- const inst = new this();
285
- instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
286
- }
287
- return instanced;
288
- }
289
- return [];
290
- }
291
- catch (rwsError) {
292
- console.error(rwsError);
293
- throw rwsError;
294
- }
229
+ return await FindUtils_1.FindUtils.findBy(this, findParams);
295
230
  }
296
231
  static async delete(conditions) {
297
232
  const collection = Reflect.get(this, '_collection');
@@ -330,6 +265,19 @@ class RWSModel {
330
265
  static getDb() {
331
266
  return this.services.dbService;
332
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
+ }
333
281
  }
334
282
  exports.RWSModel = RWSModel;
335
283
  __decorate([
@@ -0,0 +1,9 @@
1
+ import { RWSModel } from "../core/RWSModel";
2
+ import { OpModelType } from "..";
3
+ import { FindByType, IPaginationParams } from "../../types/FindParams";
4
+ export declare class FindUtils {
5
+ static findOneBy<T extends RWSModel<T>>(opModel: OpModelType<T>, findParams?: FindByType): Promise<T | null>;
6
+ static find<T extends RWSModel<T>>(opModel: OpModelType<T>, id: string | number, findParams?: Omit<FindByType, 'conditions'>): Promise<T | null>;
7
+ static findBy<T extends RWSModel<T>>(opModel: OpModelType<T>, findParams?: FindByType): Promise<T[]>;
8
+ static paginate<T extends RWSModel<T>>(opModel: OpModelType<T>, paginateParams: IPaginationParams, findParams?: FindByType): Promise<T[]>;
9
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FindUtils = void 0;
4
+ class FindUtils {
5
+ static async findOneBy(opModel, findParams) {
6
+ const conditions = findParams?.conditions ?? {};
7
+ const ordering = findParams?.ordering ?? null;
8
+ const fields = findParams?.fields ?? null;
9
+ const allowRelations = findParams?.allowRelations ?? true;
10
+ const fullData = findParams?.fullData ?? false;
11
+ opModel.checkForInclusionWithThrow('');
12
+ const collection = Reflect.get(opModel, '_collection');
13
+ const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
14
+ if (dbData) {
15
+ const inst = new opModel();
16
+ return await inst._asyncFill(dbData, fullData, allowRelations);
17
+ }
18
+ return null;
19
+ }
20
+ static async find(opModel, id, findParams = null) {
21
+ const ordering = findParams?.ordering ?? null;
22
+ const fields = findParams?.fields ?? null;
23
+ const allowRelations = findParams?.allowRelations ?? true;
24
+ const fullData = findParams?.fullData ?? false;
25
+ const collection = Reflect.get(opModel, '_collection');
26
+ opModel.checkForInclusionWithThrow(opModel.name);
27
+ const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
28
+ if (dbData) {
29
+ const inst = new opModel();
30
+ return await inst._asyncFill(dbData, fullData, allowRelations);
31
+ }
32
+ return null;
33
+ }
34
+ static async findBy(opModel, findParams) {
35
+ const conditions = findParams?.conditions ?? {};
36
+ const ordering = findParams?.ordering ?? null;
37
+ const fields = findParams?.fields ?? null;
38
+ const allowRelations = findParams?.allowRelations ?? true;
39
+ const fullData = findParams?.fullData ?? false;
40
+ const collection = Reflect.get(opModel, '_collection');
41
+ opModel.checkForInclusionWithThrow(opModel.name);
42
+ try {
43
+ const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
44
+ const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
45
+ if (dbData.length) {
46
+ const instanced = [];
47
+ for (const data of dbData) {
48
+ const inst = new opModel();
49
+ instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
50
+ }
51
+ return instanced;
52
+ }
53
+ return [];
54
+ }
55
+ catch (rwsError) {
56
+ console.error(rwsError);
57
+ throw rwsError;
58
+ }
59
+ }
60
+ static async paginate(opModel, paginateParams, findParams) {
61
+ const conditions = findParams?.conditions ?? {};
62
+ const ordering = findParams?.ordering ?? null;
63
+ const fields = findParams?.fields ?? null;
64
+ const allowRelations = findParams?.allowRelations ?? true;
65
+ const fullData = findParams?.fullData ?? false;
66
+ const collection = Reflect.get(opModel, '_collection');
67
+ opModel.checkForInclusionWithThrow(opModel.name);
68
+ try {
69
+ const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
70
+ if (dbData.length) {
71
+ const instanced = [];
72
+ for (const data of dbData) {
73
+ const inst = new opModel();
74
+ instanced.push((await inst._asyncFill(data, fullData, allowRelations)));
75
+ }
76
+ return instanced;
77
+ }
78
+ return [];
79
+ }
80
+ catch (rwsError) {
81
+ console.error(rwsError);
82
+ throw rwsError;
83
+ }
84
+ }
85
+ }
86
+ exports.FindUtils = FindUtils;
@@ -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]);
@@ -1,4 +1,5 @@
1
1
  import { RWSModel } from "../core/RWSModel";
2
+ import { OpModelType } from "..";
2
3
  export declare class ModelUtils {
3
4
  static getModelAnnotations<T extends unknown>(constructor: new () => T): Promise<Record<string, {
4
5
  annotationType: string;
@@ -7,4 +8,6 @@ export declare class ModelUtils {
7
8
  static checkDbVariable(constructor: any, variable: string): Promise<boolean>;
8
9
  static isSubclass<T, C extends new () => T>(constructor: C, baseClass: new () => T): boolean;
9
10
  static getModelScalarFields(model: RWSModel<any>): string[];
11
+ static findPrimaryKeyFields(opModel: OpModelType<any>): string | string[];
12
+ static entryExists(model: RWSModel<any>): Promise<boolean>;
10
13
  }
@@ -59,5 +59,57 @@ class ModelUtils {
59
59
  .filter((item) => item.indexOf('TrackType') === 0)
60
60
  .map((item) => item.split(':').at(-1));
61
61
  }
62
+ static findPrimaryKeyFields(opModel) {
63
+ if (opModel._NO_ID) {
64
+ const foundSuperId = opModel._SUPER_TAGS.find(tag => tag.tagType === 'id');
65
+ if (foundSuperId) {
66
+ return foundSuperId.fields;
67
+ }
68
+ const foundSuperUnique = opModel._SUPER_TAGS.find(tag => tag.tagType === 'unique');
69
+ if (foundSuperUnique) {
70
+ return foundSuperUnique.fields;
71
+ }
72
+ }
73
+ return 'id';
74
+ }
75
+ static async entryExists(model) {
76
+ let entryHasData = true;
77
+ let compoundId = false;
78
+ const foundPrimaryKey = this.findPrimaryKeyFields(model.constructor);
79
+ if (Array.isArray(foundPrimaryKey)) {
80
+ compoundId = true;
81
+ for (const idKey of foundPrimaryKey) {
82
+ if (!Object.hasOwn(model, idKey)) {
83
+ entryHasData = false;
84
+ }
85
+ if (Object.hasOwn(model, idKey) && !model[idKey]) {
86
+ entryHasData = false;
87
+ }
88
+ }
89
+ }
90
+ else {
91
+ if (Object.hasOwn(model, foundPrimaryKey) && !model[foundPrimaryKey]) {
92
+ entryHasData = false;
93
+ }
94
+ if (!Object.hasOwn(model, foundPrimaryKey)) {
95
+ entryHasData = false;
96
+ }
97
+ }
98
+ if (!entryHasData) {
99
+ return false;
100
+ }
101
+ const constructor = model.constructor;
102
+ const conditions = {};
103
+ if (compoundId) {
104
+ for (const key of foundPrimaryKey) {
105
+ conditions[key] = model[key];
106
+ }
107
+ return (await constructor.findOneBy({ conditions }) !== null);
108
+ }
109
+ else {
110
+ conditions[foundPrimaryKey] = model[foundPrimaryKey];
111
+ }
112
+ return (await constructor.findOneBy({ conditions })) !== null;
113
+ }
62
114
  }
63
115
  exports.ModelUtils = ModelUtils;
@@ -21,10 +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): Promise<IModel>;
24
+ update(data: any, collection: string, pk: string | string[]): Promise<IModel>;
25
25
  findOneBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
26
26
  [fieldName: string]: string;
27
- }, allowRelations?: boolean): Promise<IModel | null>;
27
+ }): Promise<IModel | null>;
28
28
  delete(collection: string, conditions: any): Promise<void>;
29
29
  findBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
30
30
  [fieldName: string]: string;
@@ -101,19 +101,32 @@ 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) {
105
- const model_id = data.id;
106
- delete data['id'];
104
+ async update(data, collection, pk) {
107
105
  const prismaCollection = this.getCollectionHandler(collection);
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];
117
+ }
118
+ else {
119
+ for (const cKey in pk) {
120
+ delete data[cKey];
121
+ }
122
+ }
108
123
  await prismaCollection.update({
109
- where: {
110
- id: model_id,
111
- },
124
+ where,
112
125
  data: data,
113
126
  });
114
- return await this.findOneBy(collection, { id: model_id });
127
+ return await this.findOneBy(collection, where);
115
128
  }
116
- async findOneBy(collection, conditions, fields = null, ordering = null, allowRelations = true) {
129
+ async findOneBy(collection, conditions, fields = null, ordering = null) {
117
130
  const params = { where: conditions };
118
131
  if (fields) {
119
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.2",
4
+ "version": "3.3.4",
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,7 +1,7 @@
1
1
  import { IModel } from '../interfaces/IModel';
2
2
  import { IRWSModelServices } from '../interfaces/IRWSModelServices';
3
3
  import { OpModelType } from '../interfaces/OpModelType';
4
- import { TrackType, ITrackerMetaOpts } from '../../decorators';
4
+ import { TrackType } from '../../decorators';
5
5
  import { FieldsHelper } from '../../helper/FieldsHelper';
6
6
  import { FindByType, IPaginationParams } from '../../types/FindParams';
7
7
  import { RelationUtils } from '../utils/RelationUtils';
@@ -11,9 +11,8 @@ import { ModelUtils } from '../utils/ModelUtils';
11
11
  // import timeSeriesModel from './TimeSeriesModel';
12
12
  import { DBService } from '../../services/DBService';
13
13
  import { ISuperTagData } from '../../decorators/RWSCollection';
14
- import { RelManyMetaType, RelOneMetaType } from '../types/RelationTypes';
15
- import { IRWSModel } from '../../types/IRWSModel';
16
14
  import { HydrateUtils } from '../utils/HydrateUtils';
15
+ import { FindUtils } from '../utils/FindUtils';
17
16
 
18
17
  class RWSModel<T> implements IModel {
19
18
  static services: IRWSModelServices = {};
@@ -153,33 +152,7 @@ class RWSModel<T> implements IModel {
153
152
  paginateParams: IPaginationParams,
154
153
  findParams?: FindByType
155
154
  ): Promise<T[]> {
156
- const conditions = findParams?.conditions ?? {};
157
- const ordering = findParams?.ordering ?? null;
158
- const fields = findParams?.fields ?? null;
159
- const allowRelations = findParams?.allowRelations ?? true;
160
- const fullData = findParams?.fullData ?? false;
161
-
162
- const collection = Reflect.get(this, '_collection');
163
- this.checkForInclusionWithThrow(this.name);
164
- try {
165
- const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
166
- if (dbData.length) {
167
- const instanced: T[] = [];
168
-
169
- for (const data of dbData) {
170
- const inst: T = new (this as { new(): T })();
171
- instanced.push((await inst._asyncFill(data, fullData,allowRelations)) as T);
172
- }
173
-
174
- return instanced;
175
- }
176
-
177
- return [];
178
- } catch (rwsError: Error | any) {
179
- console.error(rwsError);
180
-
181
- throw rwsError;
182
- }
155
+ return await FindUtils.paginate(this, paginateParams, findParams);
183
156
  }
184
157
 
185
158
  public async toMongo(): Promise<any> {
@@ -227,11 +200,16 @@ class RWSModel<T> implements IModel {
227
200
 
228
201
  async save(): Promise<this> {
229
202
  const data = await this.toMongo();
230
- let updatedModelData = data;
231
- if (this.id) {
203
+ let updatedModelData = data;
204
+
205
+ const entryExists = await ModelUtils.entryExists(this);
206
+
207
+ if (entryExists) {
232
208
  this.preUpdate();
233
209
 
234
- updatedModelData = await this.dbService.update(data, this.getCollection());
210
+ const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<any>);
211
+
212
+ updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
235
213
 
236
214
  await this._asyncFill(updatedModelData);
237
215
  this.postUpdate();
@@ -316,25 +294,7 @@ class RWSModel<T> implements IModel {
316
294
  this: OpModelType<T>,
317
295
  findParams?: FindByType
318
296
  ): Promise<T | null> {
319
- const conditions = findParams?.conditions ?? {};
320
- const ordering = findParams?.ordering ?? null;
321
- const fields = findParams?.fields ?? null;
322
- const allowRelations = findParams?.allowRelations ?? true;
323
- const fullData = findParams?.fullData ?? false;
324
-
325
- this.checkForInclusionWithThrow('');
326
-
327
-
328
- const collection = Reflect.get(this, '_collection');
329
- const dbData = await this.services.dbService.findOneBy(collection, conditions, fields, ordering, allowRelations);
330
-
331
-
332
- if (dbData) {
333
- const inst: T = new (this as { new(): T })();
334
- return await inst._asyncFill(dbData, fullData, allowRelations);
335
- }
336
-
337
- return null;
297
+ return await FindUtils.findOneBy(this, findParams);
338
298
  }
339
299
 
340
300
  public static async find<T extends RWSModel<T>>(
@@ -342,58 +302,14 @@ class RWSModel<T> implements IModel {
342
302
  id: string | number,
343
303
  findParams: Omit<FindByType, 'conditions'> = null
344
304
  ): Promise<T | null> {
345
- const ordering = findParams?.ordering ?? null;
346
- const fields = findParams?.fields ?? null;
347
- const allowRelations = findParams?.allowRelations ?? true;
348
- const fullData = findParams?.fullData ?? false;
349
-
350
- const collection = Reflect.get(this, '_collection');
351
- this.checkForInclusionWithThrow(this.name);
352
-
353
- const dbData = await this.services.dbService.findOneBy(collection, { id }, fields, ordering, allowRelations);
354
-
355
- if (dbData) {
356
- const inst: T = new (this as { new(): T })();
357
- return await inst._asyncFill(dbData, fullData, allowRelations);
358
- }
359
-
360
- return null;
305
+ return await FindUtils.find(this, id, findParams)
361
306
  }
362
307
 
363
308
  public static async findBy<T extends RWSModel<T>>(
364
309
  this: OpModelType<T>,
365
310
  findParams?: FindByType
366
311
  ): Promise<T[]> {
367
- const conditions = findParams?.conditions ?? {};
368
- const ordering = findParams?.ordering ?? null;
369
- const fields = findParams?.fields ?? null;
370
- const allowRelations = findParams?.allowRelations ?? true;
371
- const fullData = findParams?.fullData ?? false;
372
-
373
- const collection = Reflect.get(this, '_collection');
374
- this.checkForInclusionWithThrow(this.name);
375
- try {
376
- const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
377
- const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
378
-
379
- if (dbData.length) {
380
- const instanced: T[] = [];
381
-
382
- for (const data of dbData) {
383
- const inst: T = new (this as { new(): T })();
384
-
385
- instanced.push((await inst._asyncFill(data, fullData,allowRelations)) as T);
386
- }
387
-
388
- return instanced;
389
- }
390
-
391
- return [];
392
- } catch (rwsError: Error | any) {
393
- console.error(rwsError);
394
-
395
- throw rwsError;
396
- }
312
+ return await FindUtils.findBy(this, findParams);
397
313
  }
398
314
 
399
315
  public static async delete<T extends RWSModel<T>>(
@@ -449,6 +365,22 @@ class RWSModel<T> implements IModel {
449
365
  {
450
366
  return this.services.dbService;
451
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
+ }
452
384
  }
453
385
 
454
386
  export { RWSModel };
@@ -0,0 +1,128 @@
1
+ import { RWSModel } from "../core/RWSModel";
2
+ import { RelManyMetaType, RelOneMetaType } from "../types/RelationTypes";
3
+ import { IRWSModel } from "../../types/IRWSModel";
4
+ import { TimeSeriesUtils } from "./TimeSeriesUtils";
5
+ import { RelationUtils } from "./RelationUtils";
6
+ import { OpModelType } from "..";
7
+ import { ModelUtils } from "./ModelUtils";
8
+ import { FindByType, IPaginationParams } from "../../types/FindParams";
9
+
10
+ export class FindUtils {
11
+ public static async findOneBy<T extends RWSModel<T>>(
12
+ opModel: OpModelType<T>,
13
+ findParams?: FindByType
14
+ ): Promise<T | null> {
15
+ const conditions = findParams?.conditions ?? {};
16
+ const ordering = findParams?.ordering ?? null;
17
+ const fields = findParams?.fields ?? null;
18
+ const allowRelations = findParams?.allowRelations ?? true;
19
+ const fullData = findParams?.fullData ?? false;
20
+
21
+ opModel.checkForInclusionWithThrow('');
22
+
23
+
24
+ const collection = Reflect.get(opModel, '_collection');
25
+ const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
26
+
27
+
28
+ if (dbData) {
29
+ const inst: T = new (opModel as { new(): T })();
30
+ return await inst._asyncFill(dbData, fullData, allowRelations);
31
+ }
32
+
33
+ return null;
34
+ }
35
+
36
+ public static async find<T extends RWSModel<T>>(
37
+ opModel: OpModelType<T>,
38
+ id: string | number,
39
+ findParams: Omit<FindByType, 'conditions'> = null
40
+ ): Promise<T | null> {
41
+ const ordering = findParams?.ordering ?? null;
42
+ const fields = findParams?.fields ?? null;
43
+ const allowRelations = findParams?.allowRelations ?? true;
44
+ const fullData = findParams?.fullData ?? false;
45
+
46
+ const collection = Reflect.get(opModel, '_collection');
47
+ opModel.checkForInclusionWithThrow(opModel.name);
48
+
49
+ const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
50
+
51
+ if (dbData) {
52
+ const inst: T = new (opModel as { new(): T })();
53
+ return await inst._asyncFill(dbData, fullData, allowRelations);
54
+ }
55
+
56
+ return null;
57
+ }
58
+
59
+ public static async findBy<T extends RWSModel<T>>(
60
+ opModel: OpModelType<T>,
61
+ findParams?: FindByType
62
+ ): Promise<T[]> {
63
+ const conditions = findParams?.conditions ?? {};
64
+ const ordering = findParams?.ordering ?? null;
65
+ const fields = findParams?.fields ?? null;
66
+ const allowRelations = findParams?.allowRelations ?? true;
67
+ const fullData = findParams?.fullData ?? false;
68
+
69
+ const collection = Reflect.get(opModel, '_collection');
70
+ opModel.checkForInclusionWithThrow(opModel.name);
71
+ try {
72
+ const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
73
+ const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
74
+
75
+ if (dbData.length) {
76
+ const instanced: T[] = [];
77
+
78
+ for (const data of dbData) {
79
+ const inst: T = new (opModel as { new(): T })();
80
+
81
+ instanced.push((await inst._asyncFill(data, fullData, allowRelations)) as T);
82
+ }
83
+
84
+ return instanced;
85
+ }
86
+
87
+ return [];
88
+ } catch (rwsError: Error | any) {
89
+ console.error(rwsError);
90
+
91
+ throw rwsError;
92
+ }
93
+ }
94
+
95
+ public static async paginate<T extends RWSModel<T>>(
96
+ opModel: OpModelType<T>,
97
+ paginateParams: IPaginationParams,
98
+ findParams?: FindByType
99
+ ): Promise<T[]> {
100
+ const conditions = findParams?.conditions ?? {};
101
+ const ordering = findParams?.ordering ?? null;
102
+ const fields = findParams?.fields ?? null;
103
+ const allowRelations = findParams?.allowRelations ?? true;
104
+ const fullData = findParams?.fullData ?? false;
105
+
106
+ const collection = Reflect.get(opModel, '_collection');
107
+ opModel.checkForInclusionWithThrow(opModel.name);
108
+ try {
109
+ const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
110
+ if (dbData.length) {
111
+ const instanced: T[] = [];
112
+
113
+ for (const data of dbData) {
114
+ const inst: T = new (opModel as { new(): T })();
115
+ instanced.push((await inst._asyncFill(data, fullData, allowRelations)) as T);
116
+ }
117
+
118
+ return instanced;
119
+ }
120
+
121
+ return [];
122
+ } catch (rwsError: Error | any) {
123
+ console.error(rwsError);
124
+
125
+ throw rwsError;
126
+ }
127
+ }
128
+ }
@@ -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]);
@@ -1,5 +1,8 @@
1
1
  import { RWSModel } from "../core/RWSModel";
2
2
  import { FieldsHelper } from '../../helper/FieldsHelper';
3
+ import { OpModelType } from "..";
4
+ import { ISuperTagData } from "../../decorators/RWSCollection";
5
+ import { FindByType } from "../../types/FindParams";
3
6
 
4
7
  export class ModelUtils {
5
8
  static async getModelAnnotations<T extends unknown>(constructor: new () => T): Promise<Record<string, {annotationType: string, metadata: any}>> {
@@ -71,4 +74,71 @@ export class ModelUtils {
71
74
  .filter((item: string) => item.indexOf('TrackType') === 0)
72
75
  .map((item: string) => item.split(':').at(-1));
73
76
  }
77
+
78
+ static findPrimaryKeyFields(opModel: OpModelType<any>): string | string[]
79
+ {
80
+ if(opModel._NO_ID){
81
+ const foundSuperId: ISuperTagData = opModel._SUPER_TAGS.find(tag => tag.tagType === 'id');
82
+
83
+ if(foundSuperId){
84
+ return foundSuperId.fields;
85
+ }
86
+
87
+ const foundSuperUnique: ISuperTagData = opModel._SUPER_TAGS.find(tag => tag.tagType === 'unique');
88
+
89
+ if(foundSuperUnique){
90
+ return foundSuperUnique.fields;
91
+ }
92
+ }
93
+
94
+ return 'id';
95
+ }
96
+
97
+ static async entryExists(model: RWSModel<any>): Promise<boolean>
98
+ {
99
+ let entryHasData = true;
100
+ let compoundId = false;
101
+
102
+ const foundPrimaryKey = this.findPrimaryKeyFields(model.constructor as OpModelType<any>);
103
+
104
+ if(Array.isArray(foundPrimaryKey)){
105
+ compoundId = true;
106
+ for(const idKey of foundPrimaryKey){
107
+ if(!Object.hasOwn(model, idKey)){
108
+ entryHasData = false;
109
+ }
110
+
111
+ if(Object.hasOwn(model, idKey) && !model[idKey]){
112
+ entryHasData = false;
113
+ }
114
+ }
115
+ }else{
116
+ if(Object.hasOwn(model, foundPrimaryKey) && !model[foundPrimaryKey]){
117
+ entryHasData = false;
118
+ }
119
+
120
+ if(!Object.hasOwn(model, foundPrimaryKey)){
121
+ entryHasData = false;
122
+ }
123
+ }
124
+
125
+ if(!entryHasData){
126
+ return false;
127
+ }
128
+
129
+ const constructor = model.constructor as OpModelType<any>;
130
+ const conditions: FindByType['conditions'] = {};
131
+
132
+ if(compoundId){
133
+ for(const key of foundPrimaryKey){
134
+ conditions[key] = model[key];
135
+ }
136
+
137
+ return (await constructor.findOneBy({ conditions }) !== null);
138
+ }else{
139
+ conditions[foundPrimaryKey as string] = model[foundPrimaryKey as string];
140
+ }
141
+
142
+ return (await constructor.findOneBy({ conditions })) !== null;
143
+ }
74
144
  }
@@ -137,26 +137,41 @@ class DBService {
137
137
  return await this.findOneBy(collection, { id: result.id });
138
138
  }
139
139
 
140
- async update(data: any, collection: string): Promise<IModel>
141
- {
142
- const model_id: string = data.id;
143
- delete data['id'];
140
+ async update(data: any, collection: string, pk: string | string[]): Promise<IModel>
141
+ {
144
142
 
145
143
  const prismaCollection = this.getCollectionHandler(collection);
146
144
 
145
+
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];
158
+ }else{
159
+ for(const cKey in pk){
160
+ delete data[cKey];
161
+ }
162
+ }
163
+
147
164
  await prismaCollection.update({
148
- where: {
149
- id: model_id,
150
- },
165
+ where,
151
166
  data: data,
152
167
  });
153
168
 
154
169
 
155
- return await this.findOneBy(collection, { id: model_id });
170
+ return await this.findOneBy(collection, where);
156
171
  }
157
172
 
158
173
 
159
- 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>
160
175
  {
161
176
  const params: any = { where: conditions };
162
177