@rws-framework/db 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +74 -136
  2. package/dist/decorators/IdType.d.ts +0 -0
  3. package/dist/decorators/IdType.js +0 -0
  4. package/dist/decorators/InverseRelation.js +30 -2
  5. package/dist/decorators/TypeFunctions.d.ts +0 -0
  6. package/dist/decorators/TypeFunctions.js +0 -0
  7. package/dist/helper/DbHelper.d.ts +1 -0
  8. package/dist/helper/DbHelper.js +6 -0
  9. package/dist/helper/db/index.d.ts +0 -0
  10. package/dist/helper/db/index.js +0 -0
  11. package/dist/helper/db/relation-manager.d.ts +0 -0
  12. package/dist/helper/db/relation-manager.js +0 -0
  13. package/dist/helper/db/schema-generator.d.ts +0 -0
  14. package/dist/helper/db/schema-generator.js +16 -1
  15. package/dist/helper/db/type-converter.d.ts +0 -0
  16. package/dist/helper/db/type-converter.js +0 -0
  17. package/dist/helper/db/utils.d.ts +1 -1
  18. package/dist/helper/db/utils.js +11 -13
  19. package/dist/models/core/RWSModel.d.ts +5 -3
  20. package/dist/models/core/RWSModel.js +5 -66
  21. package/dist/models/interfaces/IDbOpts.d.ts +0 -0
  22. package/dist/models/interfaces/IDbOpts.js +0 -0
  23. package/dist/models/interfaces/IIdOpts.d.ts +0 -0
  24. package/dist/models/interfaces/IIdOpts.js +0 -0
  25. package/dist/models/interfaces/IIdTypeOpts.d.ts +0 -0
  26. package/dist/models/interfaces/IIdTypeOpts.js +0 -0
  27. package/dist/models/interfaces/ITrackerOpts.d.ts +0 -0
  28. package/dist/models/interfaces/ITrackerOpts.js +0 -0
  29. package/dist/models/interfaces/OpModelType.d.ts +1 -1
  30. package/dist/models/utils/HydrateUtils.d.ts +13 -0
  31. package/dist/models/utils/HydrateUtils.js +81 -0
  32. package/package.json +1 -1
  33. package/src/decorators/InverseRelation.ts +43 -2
  34. package/src/helper/DbHelper.ts +9 -0
  35. package/src/helper/db/index.ts +0 -0
  36. package/src/helper/db/relation-manager.ts +0 -0
  37. package/src/helper/db/schema-generator.ts +23 -3
  38. package/src/helper/db/type-converter.ts +0 -0
  39. package/src/helper/db/utils.ts +15 -15
  40. package/src/models/core/RWSModel.ts +15 -84
  41. package/src/models/interfaces/IDbOpts.ts +0 -0
  42. package/src/models/interfaces/IIdTypeOpts.ts +0 -0
  43. package/src/models/interfaces/ITrackerOpts.ts +0 -0
  44. package/src/models/interfaces/OpModelType.ts +1 -1
  45. package/src/models/utils/HydrateUtils.ts +102 -0
@@ -21,7 +21,7 @@ export interface OpModelType<T> {
21
21
  checkForInclusionWithThrow: (className: string) => void;
22
22
  checkForInclusion: (className: string) => boolean;
23
23
  findOneBy<T extends RWSModel<T>>(this: OpModelType<T>, findParams?: FindByType): Promise<T | null>;
24
- find<T extends RWSModel<T>>(this: OpModelType<T>, id: string, findParams?: Omit<FindByType, 'conditions'>): Promise<T | null>;
24
+ find<T extends RWSModel<T>>(this: OpModelType<T>, id: string | number, findParams?: Omit<FindByType, 'conditions'>): Promise<T | null>;
25
25
  findBy<T extends RWSModel<T>>(this: OpModelType<T>, findParams?: FindByType): Promise<T[]>;
26
26
  paginate<T extends RWSModel<T>>(this: OpModelType<T>, paginateParams?: IPaginationParams, findParams?: FindByType): Promise<T[]>;
27
27
  delete<T extends RWSModel<T>>(this: OpModelType<T>, conditions: any): Promise<void>;
@@ -0,0 +1,13 @@
1
+ import { RWSModel } from "../core/RWSModel";
2
+ import { RelManyMetaType, RelOneMetaType } from "../types/RelationTypes";
3
+ import { IRWSModel } from "../../types/IRWSModel";
4
+ export declare class HydrateUtils {
5
+ static hydrateDataFields(model: RWSModel<any>, collections_to_models: {
6
+ [key: string]: any;
7
+ }, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {
8
+ [key: string]: any;
9
+ }): Promise<void>;
10
+ static hydrateRelations(model: RWSModel<any>, relManyData: RelManyMetaType<IRWSModel>, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {
11
+ [key: string]: any;
12
+ }): Promise<void>;
13
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HydrateUtils = void 0;
4
+ const TimeSeriesUtils_1 = require("./TimeSeriesUtils");
5
+ const RelationUtils_1 = require("./RelationUtils");
6
+ const ModelUtils_1 = require("./ModelUtils");
7
+ class HydrateUtils {
8
+ static async hydrateDataFields(model, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data) {
9
+ const timeSeriesIds = TimeSeriesUtils_1.TimeSeriesUtils.getTimeSeriesModelFields(model);
10
+ for (const key in data) {
11
+ if (data.hasOwnProperty(key)) {
12
+ if (!fullDataMode && (model).constructor._CUT_KEYS.includes(key)) {
13
+ continue;
14
+ }
15
+ if (Object.keys(relOneData).includes(key)) {
16
+ continue;
17
+ }
18
+ if (seriesHydrationfields.includes(key)) {
19
+ continue;
20
+ }
21
+ const timeSeriesMetaData = timeSeriesIds[key];
22
+ if (timeSeriesMetaData) {
23
+ model[key] = data[key];
24
+ const seriesModel = collections_to_models[timeSeriesMetaData.collection];
25
+ const dataModels = await seriesModel.findBy({
26
+ id: { in: data[key] }
27
+ });
28
+ seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
29
+ model[timeSeriesMetaData.hydrationField] = dataModels;
30
+ }
31
+ else {
32
+ model[key] = data[key];
33
+ }
34
+ }
35
+ }
36
+ }
37
+ static async hydrateRelations(model, relManyData, relOneData, seriesHydrationfields, fullDataMode, data) {
38
+ // Handle many-to-many relations
39
+ for (const key in relManyData) {
40
+ if (!fullDataMode && model.constructor._CUT_KEYS.includes(key)) {
41
+ continue;
42
+ }
43
+ const relMeta = relManyData[key];
44
+ // console.log({relMeta});
45
+ const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(model, relMeta.key);
46
+ if (relationEnabled) {
47
+ model[relMeta.key] = await relMeta.inversionModel.findBy({
48
+ conditions: {
49
+ [relMeta.foreignKey]: data.id
50
+ },
51
+ allowRelations: false
52
+ });
53
+ }
54
+ }
55
+ // Handle one-to-one relations
56
+ for (const key in relOneData) {
57
+ if (!fullDataMode && model.constructor._CUT_KEYS.includes(key)) {
58
+ continue;
59
+ }
60
+ const relMeta = relOneData[key];
61
+ const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(model, relMeta.key);
62
+ if (!data[relMeta.hydrationField] && relMeta.required) {
63
+ throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`);
64
+ }
65
+ if (relationEnabled && data[relMeta.hydrationField]) {
66
+ model[relMeta.key] = await relMeta.model.findOneBy({ conditions: { [relMeta.foreignKey]: data[relMeta.hydrationField] } }, { allowRelations: false });
67
+ }
68
+ else if (relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]) {
69
+ const newRelModel = await relMeta.model.create(data[relMeta.key]);
70
+ model[relMeta.key] = await newRelModel.save();
71
+ }
72
+ const cutKeys = model.constructor._CUT_KEYS;
73
+ const trackedField = Object.keys((await ModelUtils_1.ModelUtils.getModelAnnotations(model.constructor))).includes(relMeta.hydrationField);
74
+ if (!cutKeys.includes(relMeta.hydrationField) && !trackedField) {
75
+ cutKeys.push(relMeta.hydrationField);
76
+ }
77
+ // seriesHydrationfields.push(relMeta.hydrationField);
78
+ }
79
+ }
80
+ }
81
+ exports.HydrateUtils = HydrateUtils;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rws-framework/db",
3
3
  "private": false,
4
- "version": "3.0.0",
4
+ "version": "3.1.0",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -1,5 +1,6 @@
1
1
  import 'reflect-metadata';
2
2
  import { RWSModel, OpModelType } from '../models/_model';
3
+ import { ModelUtils } from '../models/utils/ModelUtils';
3
4
 
4
5
  export interface InverseRelationOpts {
5
6
  key: string,
@@ -10,17 +11,57 @@ export interface InverseRelationOpts {
10
11
  mappingName?: string
11
12
  }
12
13
 
14
+ function guessForeignKey(inversionModel: OpModelType<RWSModel<any>>, bindingModel: OpModelType<RWSModel<any>>, decoratorsData: any)
15
+ {
16
+ let key: string | null = null;
17
+ let defaultKey = `${bindingModel._collection}_id`;
18
+
19
+ const relDecorators: Record<string, {
20
+ annotationType: string;
21
+ metadata: any;
22
+ }> = {};
23
+
24
+ const trackDecorators: Record<string, {
25
+ annotationType: string;
26
+ metadata: any;
27
+ }> = {};
28
+
29
+ if(Object.keys(trackDecorators).includes(key)){
30
+ return key;
31
+ }
32
+
33
+ for(const decKey of Object.keys(decoratorsData)){
34
+ const dec = decoratorsData[decKey];
35
+ if(dec.annotationType === 'Relation'){
36
+ relDecorators[decKey] = dec;
37
+ }
38
+ if(dec.annotationType === 'TrackType'){
39
+ trackDecorators[decKey] = dec;
40
+ }
41
+ }
42
+
43
+ for(const relKey of Object.keys(relDecorators)){
44
+ const prodMeta = relDecorators[relKey]?.metadata;
45
+ if(prodMeta && prodMeta.relatedTo._collection === bindingModel._collection){
46
+ return prodMeta.relationField;
47
+ }
48
+ }
49
+
50
+ return key;
51
+ }
52
+
13
53
  function InverseRelation(inversionModel: () => OpModelType<RWSModel<any>>, sourceModel: () => OpModelType<RWSModel<any>>, relationOptions: Partial<InverseRelationOpts> = null) {
14
54
  return function (target: any, key: string) {
15
- const metadataPromise = Promise.resolve().then(() => {
55
+ const metadataPromise = Promise.resolve().then(async () => {
16
56
  const model = inversionModel();
17
57
  const source = sourceModel();
58
+ const decoratorsData = await ModelUtils.getModelAnnotations(model);
18
59
 
19
60
  const metaOpts: InverseRelationOpts = {
20
61
  ...relationOptions,
21
62
  key,
22
63
  inversionModel: model,
23
- foreignKey: relationOptions && relationOptions.foreignKey ? relationOptions.foreignKey : `${source._collection}_id`,
64
+ foreignKey: relationOptions && relationOptions.foreignKey ? relationOptions.foreignKey : guessForeignKey(model, source, decoratorsData),
24
65
  // Generate a unique relation name if one is not provided
25
66
  relationName: relationOptions && relationOptions.relationName ?
26
67
  relationOptions.relationName.toLowerCase() :
@@ -1,6 +1,7 @@
1
1
  import { IDbConfigHandler, IDbConfigParams, IdGeneratorOptions } from '../types/DbConfigHandler';
2
2
  import { OpModelType } from '../models/_model';
3
3
  import { DBService } from '../services/DBService';
4
+ import { rwsShell } from '@rws-framework/console';
4
5
 
5
6
  import {
6
7
  DbUtils,
@@ -41,6 +42,14 @@ export class DbHelper {
41
42
  static async pushDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
42
43
  return SchemaGenerator.pushDBModels(configService, dbService, leaveFile);
43
44
  }
45
+
46
+ static async migrateDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
47
+ process.env = { ...process.env, [this.dbUrlVarName]: configService.get('db_url') };
48
+
49
+ const [_, schemaPath] = DbUtils.getSchemaDir();
50
+
51
+ await rwsShell.runCommand(`${DbUtils.detectInstaller()} prisma migrate dev --create-only --schema=${schemaPath}`, process.cwd());
52
+ }
44
53
 
45
54
  /**
46
55
  * Generate model sections for the schema
File without changes
File without changes
@@ -62,7 +62,7 @@ datasource db {
62
62
  if(
63
63
  !model._NO_ID
64
64
  ){
65
- section += `\t${DbUtils.generateId(dbType, modelMetadatas, false)}\n`;
65
+ section += `\t${DbUtils.generateId(dbType, modelMetadatas)}\n`;
66
66
  }
67
67
 
68
68
  for (const key in modelMetadatas) {
@@ -108,7 +108,11 @@ datasource db {
108
108
  const relationFieldName = modelMetadata.relationField ? modelMetadata.relationField : key.toLowerCase() + '_' + modelMetadata.relationField.toLowerCase();
109
109
 
110
110
  const relatedToField = modelMetadata.relatedToField || 'id';
111
- const bindingFieldExists = !!modelMetadatas[relationFieldName];
111
+ const bindingFieldExists = !!modelMetadatas[relationFieldName];
112
+
113
+ if(modelMetadata.required === false){
114
+ requiredString = '?';
115
+ }
112
116
 
113
117
  if (isMany) {
114
118
  // Add an inverse field to the related model if it doesn't exist
@@ -178,21 +182,37 @@ datasource db {
178
182
  }
179
183
  } else if (annotationType === 'TrackType') {
180
184
  const trackMeta = modelMetadata as ITrackerMetaOpts;
181
- const tags: string[] = trackMeta.tags.map((item: string) => '@' + item);
185
+ const tags: string[] = trackMeta.tags.map((item: string) => '@' + item);
186
+
187
+ if(key === 'id' && model._NO_ID && !model._SUPER_TAGS.some(tag => tag.tagType === 'id' && tag.fields.includes('id'))){
188
+ continue;
189
+ }
182
190
 
183
191
  if(trackMeta.unique){
184
192
  const fieldDetail: string | null = typeof trackMeta.unique === 'string' ? trackMeta.unique : null;
185
193
  tags.push(`@unique(${fieldDetail ? `map: "${fieldDetail}"` : ''})`);
186
194
  }
187
195
 
196
+ if(!trackMeta.required){
197
+ requiredString = '?';
198
+ }
199
+
188
200
  if (trackMeta.isArray || trackMeta.type.name === 'Array') {
189
201
  requiredString = '';
190
202
  }
191
203
 
204
+ if(model._SUPER_TAGS.some(tag => tag.tagType === 'id' && tag.fields.includes(key))){
205
+ requiredString = '';
206
+ }
207
+
192
208
  // Process any database-specific options from the metadata
193
209
  const dbSpecificTags = TypeConverter.processTypeOptions(trackMeta as { tags: string[], dbOptions: IDbOpts['dbOptions'] }, dbType);
194
210
  tags.push(...dbSpecificTags);
195
211
 
212
+ if(modelName === 'category_translation' && key === 'meta_keywords'){
213
+ console.log({requiredString, trackMeta});
214
+ }
215
+
196
216
  section += `\t${key} ${TypeConverter.toConfigCase(trackMeta, dbType, key === 'id')}${requiredString} ${tags.join(' ')}\n`;
197
217
  }
198
218
  }
File without changes
@@ -40,7 +40,7 @@ export class DbUtils {
40
40
  static generateId(
41
41
  dbType: IDbConfigParams['db_type'],
42
42
  modelMeta: Record<string, { annotationType: string, metadata: IIdMetaOpts }>,
43
- debug = false
43
+ optional = false
44
44
  ): string {
45
45
  let useUuid = false;
46
46
  let field = 'id';
@@ -53,10 +53,7 @@ export class DbUtils {
53
53
  if(key !== 'id'){
54
54
  if(annotationType == 'IdType'){
55
55
  const dbSpecificTags = TypeConverter.processTypeOptions({ tags: [], dbOptions: modelMetadata.dbOptions }, dbType);
56
- tags.push(...dbSpecificTags);
57
- if(debug){
58
- console.log({modelMetadata: modelMetadata.dbOptions});
59
- }
56
+ tags.push(...dbSpecificTags);
60
57
 
61
58
  field = key;
62
59
 
@@ -76,29 +73,35 @@ export class DbUtils {
76
73
  }
77
74
 
78
75
  let idString: string;
76
+
77
+ let reqStr = '';
78
+
79
+ if(optional){
80
+ reqStr = '?';
81
+ }
79
82
 
80
83
  switch (dbType) {
81
84
  case 'mongodb':
82
- idString = `${field} String @id @default(auto()) @map("_id") @db.ObjectId`;
85
+ idString = `${field} String${reqStr} @id @default(auto()) @map("_id") @db.ObjectId`;
83
86
  break;
84
87
 
85
88
  case 'mysql':
86
89
  idString = useUuid
87
- ? `${field} String @id @default(uuid())`
88
- : `${field} Int @id @default(autoincrement())`;
90
+ ? `${field} String${reqStr} @id @default(uuid())`
91
+ : `${field} Int${reqStr} @id @default(autoincrement())`;
89
92
  break;
90
93
 
91
94
  case 'postgresql':
92
95
  case 'postgres':
93
96
  idString = useUuid
94
- ? `${field} String @id @default(uuid())`
95
- : `${field} Int @id @default(autoincrement())`;
97
+ ? `${field} String${reqStr} @id @default(uuid())`
98
+ : `${field} Int${reqStr} @id @default(autoincrement())`;
96
99
  break;
97
100
 
98
101
  case 'sqlite':
99
- idString = `${field} Int @id @default(autoincrement())`;
102
+ idString = `${field} Int${reqStr} @id @default(autoincrement())`;
100
103
  break;
101
- }
104
+ }
102
105
 
103
106
  if(tags.length){
104
107
  idString += ' '+tags.join(' ');
@@ -108,9 +111,6 @@ export class DbUtils {
108
111
  throw new Error(`DB type "${dbType}" is not supported!`);
109
112
  }
110
113
 
111
- if(debug){
112
- console.log({idString, useUuid});
113
- }
114
114
 
115
115
  return idString;
116
116
  }
@@ -11,6 +11,9 @@ 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
+ import { HydrateUtils } from '../utils/HydrateUtils';
14
17
 
15
18
  class RWSModel<T> implements IModel {
16
19
  static services: IRWSModelServices = {};
@@ -97,9 +100,7 @@ class RWSModel<T> implements IModel {
97
100
  }
98
101
 
99
102
  public async _asyncFill(data: any, fullDataMode = false, allowRelations = true): Promise<T> {
100
- const collections_to_models: {[key: string]: any} = {};
101
- const timeSeriesIds = TimeSeriesUtils.getTimeSeriesModelFields(this);
102
-
103
+ const collections_to_models: {[key: string]: any} = {};
103
104
  const classFields = FieldsHelper.getAllClassFields(this.constructor);
104
105
 
105
106
  // Get both relation metadata types asynchronously
@@ -113,92 +114,19 @@ class RWSModel<T> implements IModel {
113
114
  });
114
115
 
115
116
  const seriesHydrationfields: string[] = [];
116
-
117
- if (allowRelations) {
118
- // Handle many-to-many relations
119
- for (const key in relManyData) {
120
- if(!fullDataMode && (this as any).constructor._CUT_KEYS.includes(key)){
121
- continue;
122
- }
123
117
 
124
- const relMeta = relManyData[key];
125
-
126
- const relationEnabled = !RelationUtils.checkRelDisabled(this, relMeta.key);
127
- if (relationEnabled) {
128
- this[relMeta.key] = await relMeta.inversionModel.findBy({
129
- conditions: {
130
- [relMeta.foreignKey]: data.id
131
- },
132
- allowRelations: false
133
- });
134
- }
135
- }
136
-
137
- // Handle one-to-one relations
138
- for (const key in relOneData) {
139
- if(!fullDataMode && (this as any).constructor._CUT_KEYS.includes(key)){
140
- continue;
141
- }
142
118
 
143
- const relMeta = relOneData[key];
144
- const relationEnabled = !RelationUtils.checkRelDisabled(this, relMeta.key);
145
-
146
- if(!data[relMeta.hydrationField] && relMeta.required){
147
- throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`)
148
- }
149
-
150
- if (relationEnabled && data[relMeta.hydrationField]) {
151
- this[relMeta.key] = await relMeta.model.find(data[relMeta.hydrationField], { allowRelations: false });
152
- }
153
- else if(relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]){
154
- const newRelModel: RWSModel<any> = await relMeta.model.create(data[relMeta.key]);
155
- this[relMeta.key] = await newRelModel.save();
156
- }
157
-
158
- const cutKeys = ((this.constructor as any)._CUT_KEYS as string[]);
159
-
160
- if(!cutKeys.includes(relMeta.hydrationField)){
161
- cutKeys.push(relMeta.hydrationField)
162
- }
163
- }
119
+ if (allowRelations) {
120
+ await HydrateUtils.hydrateRelations(this, relManyData, relOneData, seriesHydrationfields, fullDataMode, data);
164
121
  }
165
122
 
166
123
  // Process regular fields and time series
167
- for (const key in data) {
168
- if (data.hasOwnProperty(key)) {
169
- if(!fullDataMode && (this as any).constructor._CUT_KEYS.includes(key)){
170
- continue;
171
- }
172
-
173
- if (Object.keys(relOneData).includes(key)) {
174
- continue;
175
- }
176
-
177
- if (seriesHydrationfields.includes(key)) {
178
- continue;
179
- }
180
-
181
- const timeSeriesMetaData = timeSeriesIds[key];
182
-
183
- if (timeSeriesMetaData) {
184
- this[key] = data[key];
185
- const seriesModel = collections_to_models[timeSeriesMetaData.collection];
186
-
187
- const dataModels = await seriesModel.findBy({
188
- id: { in: data[key] }
189
- });
190
-
191
- seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
192
-
193
- this[timeSeriesMetaData.hydrationField] = dataModels;
194
- } else {
195
- this[key] = data[key];
196
- }
197
- }
198
- }
124
+ await HydrateUtils.hydrateDataFields(this, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data);
199
125
 
200
126
  return this as any as T;
201
- }
127
+ }
128
+
129
+
202
130
 
203
131
  private getModelScalarFields(model: RWSModel<T>): string[] {
204
132
  return ModelUtils.getModelScalarFields(model);
@@ -411,7 +339,7 @@ class RWSModel<T> implements IModel {
411
339
 
412
340
  public static async find<T extends RWSModel<T>>(
413
341
  this: OpModelType<T>,
414
- id: string,
342
+ id: string | number,
415
343
  findParams: Omit<FindByType, 'conditions'> = null
416
344
  ): Promise<T | null> {
417
345
  const ordering = findParams?.ordering ?? null;
@@ -445,12 +373,15 @@ class RWSModel<T> implements IModel {
445
373
  const collection = Reflect.get(this, '_collection');
446
374
  this.checkForInclusionWithThrow(this.name);
447
375
  try {
448
- const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering);
376
+ const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
377
+ const dbData = await this.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
378
+
449
379
  if (dbData.length) {
450
380
  const instanced: T[] = [];
451
381
 
452
382
  for (const data of dbData) {
453
383
  const inst: T = new (this as { new(): T })();
384
+
454
385
  instanced.push((await inst._asyncFill(data, fullData,allowRelations)) as T);
455
386
  }
456
387
 
File without changes
File without changes
File without changes
@@ -27,7 +27,7 @@ export interface OpModelType<T> {
27
27
  ): Promise<T | null>;
28
28
  find<T extends RWSModel<T>>(
29
29
  this: OpModelType<T>,
30
- id: string,
30
+ id: string | number,
31
31
  findParams?: Omit<FindByType, 'conditions'>
32
32
  ): Promise<T | null>;
33
33
  findBy<T extends RWSModel<T>>(
@@ -0,0 +1,102 @@
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
+
9
+ export class HydrateUtils {
10
+ static async hydrateDataFields(model: RWSModel<any>, collections_to_models: {[key: string]: any}, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {[key: string] : any}){
11
+ const timeSeriesIds = TimeSeriesUtils.getTimeSeriesModelFields(model);
12
+ for (const key in data) {
13
+ if (data.hasOwnProperty(key)) {
14
+ if(!fullDataMode && ((model).constructor as OpModelType<any>)._CUT_KEYS.includes(key)){
15
+ continue;
16
+ }
17
+
18
+ if (Object.keys(relOneData).includes(key)) {
19
+ continue;
20
+ }
21
+
22
+ if (seriesHydrationfields.includes(key)) {
23
+ continue;
24
+ }
25
+
26
+
27
+ const timeSeriesMetaData = timeSeriesIds[key];
28
+
29
+ if (timeSeriesMetaData) {
30
+ model[key] = data[key];
31
+ const seriesModel = collections_to_models[timeSeriesMetaData.collection];
32
+
33
+ const dataModels = await seriesModel.findBy({
34
+ id: { in: data[key] }
35
+ });
36
+
37
+ seriesHydrationfields.push(timeSeriesMetaData.hydrationField);
38
+
39
+ model[timeSeriesMetaData.hydrationField] = dataModels;
40
+ } else {
41
+ model[key] = data[key];
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ static async hydrateRelations(model: RWSModel<any>, relManyData: RelManyMetaType<IRWSModel>, relOneData: RelOneMetaType<IRWSModel>, seriesHydrationfields: string[], fullDataMode: boolean, data: {[key: string] : any})
48
+ {
49
+ // Handle many-to-many relations
50
+ for (const key in relManyData) {
51
+ if(!fullDataMode && (model as any).constructor._CUT_KEYS.includes(key)){
52
+ continue;
53
+ }
54
+
55
+ const relMeta = relManyData[key];
56
+
57
+ // console.log({relMeta});
58
+
59
+ const relationEnabled = !RelationUtils.checkRelDisabled(model, relMeta.key);
60
+ if (relationEnabled) {
61
+ model[relMeta.key] = await relMeta.inversionModel.findBy({
62
+ conditions: {
63
+ [relMeta.foreignKey]: data.id
64
+ },
65
+ allowRelations: false
66
+ });
67
+ }
68
+ }
69
+
70
+ // Handle one-to-one relations
71
+ for (const key in relOneData) {
72
+ if(!fullDataMode && ((model as any).constructor as OpModelType<any>)._CUT_KEYS.includes(key)){
73
+ continue;
74
+ }
75
+
76
+ const relMeta = relOneData[key];
77
+ const relationEnabled = !RelationUtils.checkRelDisabled(model, relMeta.key);
78
+
79
+ if(!data[relMeta.hydrationField] && relMeta.required){
80
+ throw new Error(`Relation field "${relMeta.hydrationField}" is required in model ${this.constructor.name}.`)
81
+ }
82
+
83
+ if (relationEnabled && data[relMeta.hydrationField]) {
84
+ model[relMeta.key] = await relMeta.model.findOneBy({conditions: {[relMeta.foreignKey] : data[relMeta.hydrationField]}}, { allowRelations: false });
85
+ }
86
+ else if(relationEnabled && !data[relMeta.hydrationField] && data[relMeta.key]){
87
+ const newRelModel: RWSModel<any> = await relMeta.model.create(data[relMeta.key]);
88
+ model[relMeta.key] = await newRelModel.save();
89
+ }
90
+
91
+ const cutKeys = ((model.constructor as OpModelType<any>)._CUT_KEYS as string[]);
92
+
93
+ const trackedField = Object.keys((await ModelUtils.getModelAnnotations(model.constructor as OpModelType<any>))).includes(relMeta.hydrationField);
94
+
95
+ if(!cutKeys.includes(relMeta.hydrationField) && !trackedField){
96
+ cutKeys.push(relMeta.hydrationField)
97
+ }
98
+
99
+ // seriesHydrationfields.push(relMeta.hydrationField);
100
+ }
101
+ }
102
+ }