@reldens/storage 0.79.0 → 0.81.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.
@@ -5,8 +5,10 @@
5
5
  */
6
6
 
7
7
  const { BaseDriver } = require('../base-driver');
8
+ const { PrismaTypeCaster } = require('./prisma-type-caster');
9
+ const { PrismaMetadataLoader } = require('./prisma-metadata-loader');
10
+ const { PrismaRelationResolver } = require('./prisma-relation-resolver');
8
11
  const { Logger, sc } = require('@reldens/utils');
9
- const { Prisma } = require('@prisma/client');
10
12
 
11
13
  class PrismaDriver extends BaseDriver
12
14
  {
@@ -24,302 +26,59 @@ class PrismaDriver extends BaseDriver
24
26
  }
25
27
  this.prisma = props.prisma;
26
28
  this.model = props.model;
27
- this.requiredFields = [];
28
- this.optionalFields = [];
29
- this.fieldTypes = {};
30
- this.fieldDefaults = {};
31
- this.idFieldType = 'String';
32
- this.referenceFields = {};
33
- this.relationMetadata = {};
34
- this.foreignKeyMappings = {};
35
- this.jsonFields = new Set();
29
+ this.initHelpers();
36
30
  this.initModelMetadata();
37
31
  }
38
32
 
39
- initModelMetadata()
40
- {
41
- let dmmf = this.getDmmf();
42
- if(!dmmf){
43
- Logger.warning('Could not access Prisma DMMF metadata');
44
- return;
45
- }
46
- let modelName = this.tableName().toLowerCase();
47
- let modelInfo = dmmf.models?.[modelName] || dmmf.models?.find(m => m.name.toLowerCase() === modelName);
48
- if(!modelInfo){
49
- Logger.warning('Could not find model info for: '+modelName);
50
- return;
51
- }
52
- for(let field of modelInfo.fields){
53
- this.processFieldMetadata(field);
54
- }
55
- if(this.rawModel && this.rawModel.relationTypes){
56
- for(let relationName of Object.keys(this.rawModel.relationTypes)){
57
- if(sc.hasOwn(this.relationMetadata, relationName)){
58
- this.relationMetadata[relationName].type = this.rawModel.relationTypes[relationName];
59
- }
60
- }
61
- }
62
- }
63
-
64
- getDmmf()
65
- {
66
- try {
67
- if(this.prisma._dmmf){
68
- return this.prisma._dmmf.datamodel;
69
- }
70
- if(this.prisma._getDmmf && sc.isFunction(this.prisma._getDmmf)){
71
- return this.prisma._getDmmf().datamodel;
72
- }
73
- if(this.prisma._runtimeDataModel){
74
- return this.prisma._runtimeDataModel;
75
- }
76
- if(Prisma.dmmf && Prisma.dmmf.datamodel){
77
- return Prisma.dmmf.datamodel;
78
- }
79
- return null;
80
- } catch(error) {
81
- Logger.warning('Failed to access DMMF: '+error.message);
82
- return null;
83
- }
84
- }
85
-
86
- processFieldMetadata(field)
87
- {
88
- this.fieldTypes[field.name] = field.type;
89
- if('Json' === field.type){
90
- this.jsonFields.add(field.name);
91
- }
92
- if(field.isId){
93
- this.idFieldType = field.type;
94
- }
95
- if(field.hasDefaultValue){
96
- this.fieldDefaults[field.name] = field.default;
97
- }
98
- if(field.isRequired && !field.hasDefaultValue && !field.isId && 'object' !== field.kind){
99
- this.requiredFields.push(field.name);
100
- }
101
- if(field.isOptional || field.hasDefaultValue){
102
- this.optionalFields.push(field.name);
103
- }
104
- if(field.kind === 'scalar' && field.isList === false){
105
- let isNumericType = this.isNumericFieldType(field.type);
106
- let isReferenceField = field.relationFromFields && 0 < field.relationFromFields.length;
107
- if(isNumericType || isReferenceField){
108
- this.referenceFields[field.name] = field.type;
109
- }
110
- }
111
- if('object' === field.kind){
112
- let relationType = field.isList ? 'many' : 'one';
113
- this.relationMetadata[field.name] = {
114
- type: relationType,
115
- model: field.type,
116
- isList: field.isList,
117
- isOptional: field.isOptional
118
- };
119
- }
120
- if('object' === field.kind && sc.hasOwn(field, 'relationFromFields') && sc.isArray(field.relationFromFields)){
121
- for(let foreignKeyField of field.relationFromFields){
122
- this.foreignKeyMappings[foreignKeyField] = field.name;
123
- }
124
- }
125
- }
126
-
127
- getAllRelations()
128
- {
129
- return Object.keys(this.relationMetadata || {});
130
- }
131
-
132
- isNumericFieldType(fieldType)
133
- {
134
- return ('Int' === fieldType || 'BigInt' === fieldType || 'Float' === fieldType || 'Decimal' === fieldType);
33
+ initHelpers()
34
+ {
35
+ this.metadataLoader = new PrismaMetadataLoader({
36
+ prisma: this.prisma,
37
+ rawModel: this.rawModel
38
+ });
39
+ this.typeCaster = new PrismaTypeCaster({
40
+ idFieldType: 'String',
41
+ jsonFields: new Set(),
42
+ fieldTypes: {},
43
+ fieldDefaults: {},
44
+ requiredFields: [],
45
+ optionalFields: [],
46
+ rawModel: this.rawModel
47
+ });
48
+ this.relationResolver = new PrismaRelationResolver({
49
+ relationMetadata: {},
50
+ relationAliases: {},
51
+ metadataLoader: this.metadataLoader
52
+ });
135
53
  }
136
54
 
137
- isBooleanFieldType(fieldType)
138
- {
139
- return 'Boolean' === fieldType;
140
- }
141
-
142
- isDateTimeFieldType(fieldType)
143
- {
144
- return 'DateTime' === fieldType || 'Date' === fieldType;
145
- }
146
-
147
- isJsonFieldType(fieldType)
148
- {
149
- return 'Json' === fieldType;
150
- }
151
-
152
- isJsonFieldByName(fieldName)
153
- {
154
- if(this.jsonFields.has(fieldName)){
155
- return true;
156
- }
157
- if(!this.rawModel || !this.rawModel.properties){
158
- return false;
159
- }
160
- return 'json' === sc.get(this.rawModel.properties[fieldName], 'dbType', '');
161
- }
162
-
163
- isStringFieldType(fieldType)
164
- {
165
- return 'String' === fieldType;
166
- }
167
-
168
- castValue(value, fieldType, fieldName = null)
169
- {
170
- if('id' === fieldName){
171
- return this.castToIdType(value);
172
- }
173
- if(this.isNullOrEmpty(value)){
174
- if(sc.hasOwn(this.fieldDefaults, fieldName)){
175
- return undefined;
176
- }
177
- if(-1 !== this.optionalFields.indexOf(fieldName)){
178
- return null;
179
- }
180
- if(-1 !== this.requiredFields.indexOf(fieldName)){
181
- Logger.warning('Required field '+fieldName+' cannot be null or empty');
182
- return undefined;
183
- }
184
- return null;
185
- }
186
- if(this.isJsonFieldByName(fieldName)){
187
- return this.castToJsonType(value);
188
- }
189
- if(this.isNumericFieldType(fieldType)){
190
- return this.castToNumericType(value, fieldType);
191
- }
192
- if(this.isBooleanFieldType(fieldType)){
193
- return this.castToBooleanType(value);
194
- }
195
- if(this.isDateTimeFieldType(fieldType)){
196
- return this.castToDateType(value);
197
- }
198
- if(this.isStringFieldType(fieldType)){
199
- return this.castToStringType(value);
200
- }
201
- return value;
202
- }
203
-
204
- isNullOrEmpty(value)
205
- {
206
- return null === value || undefined === value || '' === value;
207
- }
208
-
209
- castToIdType(value)
210
- {
211
- if(this.isNullOrEmpty(value)){
212
- return value;
213
- }
214
- if(this.isNumericFieldType(this.idFieldType)){
215
- let numeric = Number(value);
216
- if(!isNaN(numeric)){
217
- return ('Int' === this.idFieldType || 'BigInt' === this.idFieldType) ? Math.floor(numeric) : numeric;
218
- }
219
- }
220
- return String(value);
221
- }
222
-
223
- castToNumericType(value, fieldType)
224
- {
225
- if(this.isNullOrEmpty(value)){
226
- return null;
227
- }
228
- let numericValue = Number(value);
229
- if(isNaN(numericValue)){
230
- Logger.warning('Cannot convert value to numeric: '+value);
231
- return null;
232
- }
233
- if('Int' === fieldType || 'BigInt' === fieldType){
234
- return Math.floor(numericValue);
235
- }
236
- return numericValue;
237
- }
238
-
239
- castToBooleanType(value)
240
- {
241
- if(this.isNullOrEmpty(value)){
242
- return null;
243
- }
244
- if('boolean' === typeof value){
245
- return value;
246
- }
247
- if('number' === typeof value){
248
- return 0 !== value;
249
- }
250
- if('string' === typeof value){
251
- let lowerValue = value.toLowerCase();
252
- if('true' === lowerValue || '1' === lowerValue || 'yes' === lowerValue){
253
- return true;
254
- }
255
- if('false' === lowerValue || '0' === lowerValue || 'no' === lowerValue){
256
- return false;
257
- }
258
- }
259
- return Boolean(value);
260
- }
261
-
262
- castToDateType(dateValue)
263
- {
264
- if(dateValue instanceof Date){
265
- return dateValue;
266
- }
267
- if(this.isNullOrEmpty(dateValue)){
268
- return null;
269
- }
270
- let dateString = String(dateValue);
271
- if(dateString.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/)){
272
- return new Date(dateString.replace(' ', 'T') + 'Z');
273
- }
274
- if(dateString.match(/^\d{4}-\d{2}-\d{2}$/)){
275
- return new Date(dateString + 'T00:00:00Z');
276
- }
277
- try {
278
- let parsedDate = new Date(dateString);
279
- if(isNaN(parsedDate.getTime())){
280
- Logger.warning('Invalid date value: '+dateString);
281
- return null;
282
- }
283
- return parsedDate;
284
- } catch(error) {
285
- Logger.warning('Failed to convert date value: '+dateString);
286
- return null;
287
- }
288
- }
289
-
290
- castToJsonType(value)
291
- {
292
- if(this.isNullOrEmpty(value)){
293
- return Prisma.DbNull;
294
- }
295
- if('object' === typeof value){
296
- return value;
297
- }
298
- if('string' === typeof value){
299
- if(value.startsWith('%') && value.endsWith('%')){
300
- return value;
301
- }
302
- try {
303
- return JSON.parse(value);
304
- } catch(error) {
305
- return value;
306
- }
307
- }
308
- return value;
309
- }
310
-
311
- castToStringType(value)
55
+ initModelMetadata()
312
56
  {
313
- if(null === value || undefined === value){
314
- return null;
315
- }
316
- if('string' === typeof value){
317
- if('null' === value){
318
- return null;
319
- }
320
- return value;
57
+ let metadata = this.metadataLoader.loadModelMetadata(this.tableName());
58
+ if(!metadata){
59
+ return;
321
60
  }
322
- return String(value);
61
+ this.requiredFields = metadata.requiredFields;
62
+ this.optionalFields = metadata.optionalFields;
63
+ this.fieldTypes = metadata.fieldTypes;
64
+ this.fieldDefaults = metadata.fieldDefaults;
65
+ this.idFieldType = metadata.idFieldType;
66
+ this.referenceFields = metadata.referenceFields;
67
+ this.relationMetadata = metadata.relationMetadata;
68
+ this.foreignKeyMappings = metadata.foreignKeyMappings;
69
+ this.jsonFields = metadata.jsonFields;
70
+ this.typeCaster.updateMetadata({
71
+ idFieldType: this.idFieldType,
72
+ jsonFields: this.jsonFields,
73
+ fieldTypes: this.fieldTypes,
74
+ fieldDefaults: this.fieldDefaults,
75
+ requiredFields: this.requiredFields,
76
+ optionalFields: this.optionalFields
77
+ });
78
+ this.relationResolver.updateMetadata({
79
+ relationMetadata: this.relationMetadata
80
+ });
81
+ this.relationAliases = this.relationResolver.buildRelationAliases(this.tableName());
323
82
  }
324
83
 
325
84
  databaseName()
@@ -347,6 +106,11 @@ class PrismaDriver extends BaseDriver
347
106
  return this.rawModel[propertyName] || null;
348
107
  }
349
108
 
109
+ getAllRelations()
110
+ {
111
+ return this.relationResolver.getAllRelations();
112
+ }
113
+
350
114
  prepareData(params)
351
115
  {
352
116
  let data = {};
@@ -356,7 +120,7 @@ class PrismaDriver extends BaseDriver
356
120
  data[key] = params[key];
357
121
  continue;
358
122
  }
359
- let castedValue = this.castValue(params[key], fieldType, key);
123
+ let castedValue = this.typeCaster.castValue(params[key], fieldType, key);
360
124
  if(undefined !== castedValue){
361
125
  data[key] = castedValue;
362
126
  }
@@ -372,9 +136,9 @@ class PrismaDriver extends BaseDriver
372
136
  if(sc.hasOwn(this.foreignKeyMappings, key)){
373
137
  let relationName = this.foreignKeyMappings[key];
374
138
  let value = params[key];
375
- if(!this.isNullOrEmpty(value)){
139
+ if(!this.typeCaster.isNullOrEmpty(value)){
376
140
  relations[relationName] = {
377
- connect: {id: this.castToIdType(value)}
141
+ connect: {id: this.typeCaster.castToIdType(value)}
378
142
  };
379
143
  continue;
380
144
  }
@@ -387,14 +151,14 @@ class PrismaDriver extends BaseDriver
387
151
  }
388
152
  let fieldType = this.fieldTypes[key];
389
153
  if(!fieldType){
390
- if(!this.isNullOrEmpty(params[key])){
154
+ if(!this.typeCaster.isNullOrEmpty(params[key])){
391
155
  data[key] = params[key];
392
156
  }
393
157
  continue;
394
158
  }
395
- let castedValue = this.castValue(params[key], fieldType, key);
159
+ let castedValue = this.typeCaster.castValue(params[key], fieldType, key);
396
160
  if(undefined !== castedValue){
397
- if(this.isJsonFieldType(fieldType) && null === castedValue){
161
+ if(this.typeCaster.isJsonFieldType(fieldType) && null === castedValue){
398
162
  continue;
399
163
  }
400
164
  data[key] = castedValue;
@@ -447,60 +211,69 @@ class PrismaDriver extends BaseDriver
447
211
  {
448
212
  if(sc.isArray(value)){
449
213
  if('id' === key){
450
- return value.map(id => this.castToIdType(id));
214
+ return value.map(id => this.typeCaster.castToIdType(id)).filter(id => null !== id);
451
215
  }
452
216
  let fieldType = this.fieldTypes[key];
453
217
  if(fieldType){
454
- return value.map(val => this.castValue(val, fieldType, key)).filter(val => undefined !== val);
218
+ return value.map(val => this.typeCaster.castValue(val, fieldType, key)).filter(val => undefined !== val);
455
219
  }
456
220
  return value;
457
221
  }
458
222
  if('id' === key){
459
- return this.castToIdType(value);
223
+ return this.typeCaster.castToIdType(value);
460
224
  }
461
225
  let fieldType = this.fieldTypes[key];
462
226
  if(fieldType){
463
- let castedValue = this.castValue(value, fieldType, key);
227
+ let castedValue = this.typeCaster.castValue(value, fieldType, key);
464
228
  return undefined !== castedValue ? castedValue : value;
465
229
  }
466
230
  return value;
467
231
  }
468
232
 
469
- transformRelationResults(result, includeConfig)
233
+ applyOperator(value, operator, fieldName = null)
470
234
  {
471
- if(!result || !includeConfig){
472
- return result;
473
- }
474
- if(sc.isArray(result)){
475
- return result.map(item => this.transformSingleResult(item, includeConfig));
235
+ let upperOperator = operator ? operator.toUpperCase() : '';
236
+ if('LIKE' === upperOperator){
237
+ return this.handleLikeOperator(value, fieldName);
476
238
  }
477
- return this.transformSingleResult(result, includeConfig);
239
+ let operatorsMap = {
240
+ '=': value,
241
+ '!=': {not: value},
242
+ '>': {gt: value},
243
+ '>=': {gte: value},
244
+ '<': {lt: value},
245
+ '<=': {lte: value},
246
+ 'IN': {in: value},
247
+ 'NOT IN': {notIn: value}
248
+ };
249
+ return operatorsMap[upperOperator] || value;
478
250
  }
479
251
 
480
- transformSingleResult(item, includeConfig)
252
+ handleLikeOperator(value, fieldName)
481
253
  {
482
- if(!item || !sc.isObject(item)){
483
- return item;
254
+ let cleanValue = String(value).replace(/%/g, '');
255
+ if(this.typeCaster.isJsonFieldByName(fieldName) || this.isJsonField(fieldName)){
256
+ return this.handleJsonTextSearch(cleanValue);
484
257
  }
485
- let transformed = {...item};
486
- for(let relationName of Object.keys(includeConfig)){
487
- if(!sc.hasOwn(transformed, relationName)){
488
- continue;
489
- }
490
- let relationMeta = this.relationMetadata[relationName];
491
- if(!relationMeta){
492
- continue;
493
- }
494
- let relationValue = transformed[relationName];
495
- if('one' === relationMeta.type && sc.isArray(relationValue)){
496
- transformed[relationName] = 0 < relationValue.length ? relationValue[0] : null;
497
- continue;
498
- }
499
- if('many' === relationMeta.type && !sc.isArray(relationValue)){
500
- transformed[relationName] = relationValue ? [relationValue] : [];
258
+ if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
259
+ let numericValue = Number(cleanValue);
260
+ if(!isNaN(numericValue)){
261
+ return numericValue;
501
262
  }
502
263
  }
503
- return transformed;
264
+ return {contains: cleanValue};
265
+ }
266
+
267
+ handleJsonTextSearch(searchValue)
268
+ {
269
+ return {
270
+ string_contains: searchValue
271
+ };
272
+ }
273
+
274
+ isJsonField(fieldName)
275
+ {
276
+ return this.jsonFields && this.jsonFields.has(fieldName);
504
277
  }
505
278
 
506
279
  async create(params)
@@ -526,26 +299,37 @@ class PrismaDriver extends BaseDriver
526
299
  this.ensureRequiredFields(preparedData);
527
300
  let createData = {data: preparedData};
528
301
  if(0 < relations.length){
529
- let includeConfig = this.buildIncludeObject(relations);
530
- createData.include = includeConfig;
302
+ let includeData = this.relationResolver.buildIncludeObjectWithMapping(relations);
303
+ createData.include = includeData.include;
531
304
  for(let relation of relations){
532
- if(!sc.hasOwn(params, relation)){
305
+ let normalizedRelation = this.relationResolver.normalizeRelationName(relation);
306
+ if(!sc.hasOwn(params, relation) && !sc.hasOwn(params, normalizedRelation)){
533
307
  continue;
534
308
  }
535
- let relationData = params[relation];
309
+ let relationData = sc.get(params, relation, sc.get(params, normalizedRelation, null));
536
310
  if(sc.isArray(relationData)){
537
- createData.data[relation] = {
538
- connect: relationData.map(item => ({id: this.castToIdType(item.id)}))
311
+ createData.data[normalizedRelation] = {
312
+ connect: relationData.map(item => ({id: this.typeCaster.castToIdType(item.id)}))
539
313
  };
540
314
  continue;
541
315
  }
542
- createData.data[relation] = {
543
- connect: {id: this.castToIdType(relationData.id)}
316
+ createData.data[normalizedRelation] = {
317
+ connect: {id: this.typeCaster.castToIdType(relationData.id)}
544
318
  };
545
319
  }
320
+ try {
321
+ return this.relationResolver.transformRelationResults(
322
+ await this.model.create(createData),
323
+ includeData.include,
324
+ includeData.mapping
325
+ );
326
+ } catch(error) {
327
+ Logger.error('Create with relations error: '+error.message);
328
+ return false;
329
+ }
546
330
  }
547
331
  try {
548
- return this.transformRelationResults(await this.model.create(createData), createData.include);
332
+ return await this.model.create(createData);
549
333
  } catch(error) {
550
334
  Logger.error('Create with relations error: '+error.message);
551
335
  return false;
@@ -584,7 +368,7 @@ class PrismaDriver extends BaseDriver
584
368
 
585
369
  async updateById(id, params)
586
370
  {
587
- let castedId = this.castToIdType(id);
371
+ let castedId = this.typeCaster.castToIdType(id);
588
372
  let found = await this.loadById(castedId);
589
373
  if(!found){
590
374
  return false;
@@ -606,7 +390,7 @@ class PrismaDriver extends BaseDriver
606
390
  let preparedData = this.prepareDataWithRelations(params);
607
391
  let existing = false;
608
392
  if(params.id){
609
- let castedId = this.castToIdType(params.id);
393
+ let castedId = this.typeCaster.castToIdType(params.id);
610
394
  existing = await this.loadById(castedId);
611
395
  if(existing){
612
396
  let patch = Object.assign({}, preparedData);
@@ -627,7 +411,7 @@ class PrismaDriver extends BaseDriver
627
411
  if(existing){
628
412
  try {
629
413
  return await this.model.update({
630
- where: {id: this.castToIdType(existing.id)},
414
+ where: {id: this.typeCaster.castToIdType(existing.id)},
631
415
  data: preparedData
632
416
  });
633
417
  } catch(error) {
@@ -654,7 +438,7 @@ class PrismaDriver extends BaseDriver
654
438
 
655
439
  async deleteById(id)
656
440
  {
657
- let castedId = this.castToIdType(id);
441
+ let castedId = this.typeCaster.castToIdType(id);
658
442
  let found = await this.loadById(castedId);
659
443
  if(!found){
660
444
  return false;
@@ -692,7 +476,7 @@ class PrismaDriver extends BaseDriver
692
476
  where: processedFilters
693
477
  };
694
478
  if(0 < relations.length){
695
- query.include = this.buildIncludeObject(relations);
479
+ query.include = this.relationResolver.buildIncludeObjectWithMapping(relations).include;
696
480
  }
697
481
  try {
698
482
  return await this.model.count(query);
@@ -714,22 +498,13 @@ class PrismaDriver extends BaseDriver
714
498
 
715
499
  async loadAllWithRelations(relations)
716
500
  {
717
- if(!sc.isArray(relations) || 0 === relations.length){
718
- relations = this.getAllRelations();
719
- }
720
- let query = this.buildQueryOptions();
721
- let includeConfig = {};
722
- if(0 < relations.length){
723
- includeConfig = this.buildIncludeObject(relations);
724
- query.include = includeConfig;
725
- }
726
- try {
727
- let results = await this.model.findMany(query);
728
- return this.transformRelationResults(results, includeConfig);
729
- } catch(error) {
730
- Logger.error('Load all with relations error: '+error.message);
731
- return [];
732
- }
501
+ return this.executeQueryWithRelations(
502
+ (q) => this.model.findMany(q),
503
+ this.buildQueryOptions(),
504
+ relations,
505
+ 'Load all with relations error: ',
506
+ []
507
+ );
733
508
  }
734
509
 
735
510
  async load(filters)
@@ -747,24 +522,15 @@ class PrismaDriver extends BaseDriver
747
522
 
748
523
  async loadWithRelations(filters, relations)
749
524
  {
750
- if(!sc.isArray(relations) || 0 === relations.length){
751
- relations = this.getAllRelations();
752
- }
753
- let processedFilters = this.processFilters(filters);
754
525
  let query = this.buildQueryOptions();
755
- query.where = processedFilters;
756
- let includeConfig = {};
757
- if(0 < relations.length){
758
- includeConfig = this.buildIncludeObject(relations);
759
- query.include = includeConfig;
760
- }
761
- try {
762
- let results = await this.model.findMany(query);
763
- return this.transformRelationResults(results, includeConfig);
764
- } catch(error) {
765
- Logger.error('Load with relations error: '+error.message);
766
- return [];
767
- }
526
+ query.where = this.processFilters(filters);
527
+ return this.executeQueryWithRelations(
528
+ (q) => this.model.findMany(q),
529
+ query,
530
+ relations,
531
+ 'Load with relations error: ',
532
+ []
533
+ );
768
534
  }
769
535
 
770
536
  async loadBy(field, fieldValue, operator = null)
@@ -782,29 +548,20 @@ class PrismaDriver extends BaseDriver
782
548
 
783
549
  async loadByWithRelations(field, fieldValue, relations, operator = null)
784
550
  {
785
- if(!sc.isArray(relations) || 0 === relations.length){
786
- relations = this.getAllRelations();
787
- }
788
- let filter = this.createSingleFilter(field, fieldValue, operator);
789
551
  let query = this.buildQueryOptions();
790
- query.where = filter;
791
- let includeConfig = {};
792
- if(0 < relations.length){
793
- includeConfig = this.buildIncludeObject(relations);
794
- query.include = includeConfig;
795
- }
796
- try {
797
- let results = await this.model.findMany(query);
798
- return this.transformRelationResults(results, includeConfig);
799
- } catch(error) {
800
- Logger.error('Load by with relations error: '+error.message);
801
- return [];
802
- }
552
+ query.where = this.createSingleFilter(field, fieldValue, operator);
553
+ return this.executeQueryWithRelations(
554
+ (q) => this.model.findMany(q),
555
+ query,
556
+ relations,
557
+ 'Load by with relations error: ',
558
+ []
559
+ );
803
560
  }
804
561
 
805
562
  async loadById(id)
806
563
  {
807
- let castedId = this.castToIdType(id);
564
+ let castedId = this.typeCaster.castToIdType(id);
808
565
  try {
809
566
  return await this.model.findUnique({
810
567
  where: {id: castedId}
@@ -817,30 +574,21 @@ class PrismaDriver extends BaseDriver
817
574
 
818
575
  async loadByIdWithRelations(id, relations)
819
576
  {
820
- if(!sc.isArray(relations) || 0 === relations.length){
821
- relations = this.getAllRelations();
822
- }
823
- let castedId = this.castToIdType(id);
824
- let query = {
825
- where: {id: castedId}
826
- };
827
- let includeConfig = {};
828
- if(0 < relations.length){
829
- includeConfig = this.buildIncludeObject(relations);
830
- query.include = includeConfig;
831
- }
832
- try {
833
- let result = await this.model.findUnique(query);
834
- return this.transformRelationResults(result, includeConfig);
835
- } catch(error) {
836
- Logger.error('Load by ID with relations error: '+error.message);
837
- return null;
838
- }
577
+ return this.executeQueryWithRelations(
578
+ (q) => this.model.findUnique(q),
579
+ {where: {id: this.typeCaster.castToIdType(id)}},
580
+ relations,
581
+ 'Load by ID with relations error: ',
582
+ null
583
+ );
839
584
  }
840
585
 
841
586
  async loadByIds(ids)
842
587
  {
843
- let castedIds = ids.map(id => this.castToIdType(id));
588
+ let castedIds = ids.map(id => this.typeCaster.castToIdType(id)).filter(id => null !== id);
589
+ if(0 === castedIds.length){
590
+ return [];
591
+ }
844
592
  try {
845
593
  return await this.model.findMany({
846
594
  where: {
@@ -868,24 +616,15 @@ class PrismaDriver extends BaseDriver
868
616
 
869
617
  async loadOneWithRelations(filters, relations)
870
618
  {
871
- if(!sc.isArray(relations) || 0 === relations.length){
872
- relations = this.getAllRelations();
873
- }
874
- let processedFilters = this.processFilters(filters);
875
619
  let query = this.buildQueryOptions(false);
876
- query.where = processedFilters;
877
- let includeConfig = {};
878
- if(0 < relations.length){
879
- includeConfig = this.buildIncludeObject(relations);
880
- query.include = includeConfig;
881
- }
882
- try {
883
- let result = await this.model.findFirst(query);
884
- return this.transformRelationResults(result, includeConfig);
885
- } catch(error) {
886
- Logger.error('Load one with relations error: '+error.message);
887
- return null;
888
- }
620
+ query.where = this.processFilters(filters);
621
+ return this.executeQueryWithRelations(
622
+ (q) => this.model.findFirst(q),
623
+ query,
624
+ relations,
625
+ 'Load one with relations error: ',
626
+ null
627
+ );
889
628
  }
890
629
 
891
630
  async loadOneBy(field, fieldValue, operator = null)
@@ -903,24 +642,15 @@ class PrismaDriver extends BaseDriver
903
642
 
904
643
  async loadOneByWithRelations(field, fieldValue, relations, operator = null)
905
644
  {
906
- if(!sc.isArray(relations) || 0 === relations.length){
907
- relations = this.getAllRelations();
908
- }
909
- let filter = this.createSingleFilter(field, fieldValue, operator);
910
645
  let query = this.buildQueryOptions(false);
911
- query.where = filter;
912
- let includeConfig = {};
913
- if(0 < relations.length){
914
- includeConfig = this.buildIncludeObject(relations);
915
- query.include = includeConfig;
916
- }
917
- try {
918
- let result = await this.model.findFirst(query);
919
- return this.transformRelationResults(result, includeConfig);
920
- } catch(error) {
921
- Logger.error('Load one by with relations error: '+error.message);
922
- return null;
923
- }
646
+ query.where = this.createSingleFilter(field, fieldValue, operator);
647
+ return this.executeQueryWithRelations(
648
+ (q) => this.model.findFirst(q),
649
+ query,
650
+ relations,
651
+ 'Load one by with relations error: ',
652
+ null
653
+ );
924
654
  }
925
655
 
926
656
  buildQueryOptions(useLimit = true)
@@ -958,54 +688,21 @@ class PrismaDriver extends BaseDriver
958
688
  return this.processFilters(filter);
959
689
  }
960
690
 
961
- applyOperator(value, operator, fieldName = null)
691
+ async executeQueryWithRelations(modelMethod, query, relations, errorMessage, defaultReturn)
962
692
  {
963
- let upperOperator = operator ? operator.toUpperCase() : '';
964
- if('LIKE' === upperOperator){
965
- return this.handleLikeOperator(value, fieldName);
966
- }
967
- let operatorsMap = {
968
- '=': value,
969
- '!=': {not: value},
970
- '>': {gt: value},
971
- '>=': {gte: value},
972
- '<': {lt: value},
973
- '<=': {lte: value},
974
- 'IN': {in: value},
975
- 'NOT IN': {notIn: value}
976
- };
977
- return operatorsMap[upperOperator] || value;
978
- }
979
-
980
- handleLikeOperator(value, fieldName)
981
- {
982
- let cleanValue = String(value).replace(/%/g, '');
983
- if(this.isJsonFieldByName(fieldName) || this.isJsonField(fieldName)){
984
- return this.handleJsonTextSearch(cleanValue);
693
+ if(!sc.isArray(relations) || 0 === relations.length){
694
+ relations = this.getAllRelations();
985
695
  }
986
- if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
987
- let numericValue = Number(cleanValue);
988
- if(!isNaN(numericValue)){
989
- return numericValue;
990
- }
696
+ let includeData = this.relationResolver.buildIncludeObjectWithMapping(relations);
697
+ if(0 < Object.keys(includeData.include).length){
698
+ query.include = includeData.include;
991
699
  }
992
- return {contains: cleanValue};
993
- }
994
-
995
- handleJsonTextSearch(searchValue)
996
- {
997
- return {
998
- string_contains: searchValue
999
- };
1000
- }
1001
-
1002
- buildIncludeObject(relations)
1003
- {
1004
- let include = {};
1005
- for(let relation of relations){
1006
- include[relation] = true;
700
+ try {
701
+ return this.relationResolver.transformRelationResults(await modelMethod(query), includeData.include, includeData.mapping);
702
+ } catch(error) {
703
+ Logger.error(errorMessage+error.message);
704
+ return defaultReturn;
1007
705
  }
1008
- return include;
1009
706
  }
1010
707
 
1011
708
  }