@reldens/storage 0.59.0 → 0.61.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.
@@ -22,182 +22,244 @@ class PrismaDriver extends BaseDriver
22
22
  Logger.critical('Missing Prisma model on Prisma driver.');
23
23
  return false;
24
24
  }
25
- if(!props.server){
26
- Logger.critical('Missing Server Driver on Prisma driver.');
27
- return false;
28
- }
29
25
  this.prisma = props.prisma;
30
26
  this.model = props.model;
31
- this.server = props.server;
32
27
  this.requiredFields = [];
28
+ this.optionalFields = [];
33
29
  this.fieldTypes = {};
30
+ this.fieldDefaults = {};
34
31
  this.idFieldType = 'String';
35
32
  this.referenceFields = {};
36
33
  this.relationMetadata = {};
37
- this.initFieldMetadata();
38
- this.initRelationMetadata();
34
+ this.foreignKeyMappings = {};
35
+ this.jsonFields = new Set();
36
+ this.initModelMetadata();
39
37
  }
40
38
 
41
- initFieldMetadata()
39
+ initModelMetadata()
42
40
  {
43
- try {
44
- let dmmf = this.prisma._runtimeDataModel || Prisma.dmmf?.datamodel;
45
- if(!dmmf){
46
- return;
47
- }
48
- let modelName = this.tableName().toLowerCase();
49
- let modelInfo = dmmf.models?.[modelName] || dmmf.models?.find(m => m.name.toLowerCase() === modelName);
50
- if(!modelInfo){
51
- return;
52
- }
53
- for(let field of modelInfo.fields){
54
- if(field.isRequired && !field.hasDefaultValue && !field.isId){
55
- this.requiredFields.push(field.name);
56
- }
57
- this.fieldTypes[field.name] = field.type;
58
- if(field.isId){
59
- this.idFieldType = field.type;
60
- }
61
- if(field.kind === 'scalar' && field.isList === false){
62
- let isNumericType = ('Int' === field.type || 'BigInt' === field.type || 'Float' === field.type || 'Decimal' === field.type);
63
- let isReferenceField = field.relationFromFields && 0 < field.relationFromFields.length;
64
- if(isNumericType || isReferenceField){
65
- this.referenceFields[field.name] = field.type;
66
- }
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];
67
59
  }
68
60
  }
69
- } catch(error) {
70
- Logger.warning('Could not initialize field metadata: '+error.message);
71
61
  }
72
62
  }
73
63
 
74
- initRelationMetadata()
64
+ getDmmf()
75
65
  {
76
66
  try {
77
- let dmmf = this.prisma._runtimeDataModel || Prisma.dmmf?.datamodel;
78
- if(!dmmf){
79
- return;
80
- }
81
- let modelName = this.tableName().toLowerCase();
82
- let modelInfo = dmmf.models?.[modelName] || dmmf.models?.find(m => m.name.toLowerCase() === modelName);
83
- if(!modelInfo){
84
- return;
85
- }
86
- for(let field of modelInfo.fields){
87
- if('object' === field.kind){
88
- let relationType = 'many';
89
- if(!field.isList){
90
- relationType = 'one';
91
- }
92
- this.relationMetadata[field.name] = {
93
- type: relationType,
94
- model: field.type,
95
- isList: field.isList,
96
- isOptional: field.isOptional
97
- };
98
- }
67
+ if(this.prisma._dmmf){
68
+ return this.prisma._dmmf.datamodel;
99
69
  }
100
- if(this.rawModel && this.rawModel.relationTypes){
101
- for(let relationName of Object.keys(this.rawModel.relationTypes)){
102
- if(sc.hasOwn(this.relationMetadata, relationName)){
103
- this.relationMetadata[relationName].type = this.rawModel.relationTypes[relationName];
104
- }
105
- }
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;
106
78
  }
79
+ return null;
107
80
  } catch(error) {
108
- Logger.warning('Could not initialize relation metadata: '+error.message);
81
+ Logger.warning('Failed to access DMMF: '+error.message);
82
+ return null;
109
83
  }
110
84
  }
111
85
 
112
- castIdValue(id)
86
+ processFieldMetadata(field)
113
87
  {
114
- if(null === id || undefined === id){
115
- return id;
88
+ this.fieldTypes[field.name] = field.type;
89
+ if('Json' === field.type){
90
+ this.jsonFields.add(field.name);
116
91
  }
117
- if('Int' === this.idFieldType || 'BigInt' === this.idFieldType){
118
- let numericId = Number(id);
119
- if(!isNaN(numericId)){
120
- return numericId;
121
- }
92
+ if(field.isId){
93
+ this.idFieldType = field.type;
122
94
  }
123
- return String(id);
124
- }
125
-
126
- castNumericValue(value, fieldType)
127
- {
128
- if(null === value || undefined === value || '' === value){
129
- return null;
95
+ if(field.hasDefaultValue){
96
+ this.fieldDefaults[field.name] = field.default;
130
97
  }
131
- if('Int' === fieldType || 'BigInt' === fieldType){
132
- let numericValue = Number(value);
133
- if(!isNaN(numericValue)){
134
- return Math.floor(numericValue);
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;
135
109
  }
136
110
  }
137
- if('Float' === fieldType || 'Decimal' === fieldType){
138
- let numericValue = Number(value);
139
- if(!isNaN(numericValue)){
140
- return numericValue;
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;
141
123
  }
142
124
  }
143
- return value;
144
125
  }
145
126
 
146
- databaseName()
127
+ isNumericFieldType(fieldType)
147
128
  {
148
- return this.config.database || '';
129
+ return ('Int' === fieldType || 'BigInt' === fieldType || 'Float' === fieldType || 'Decimal' === fieldType);
149
130
  }
150
131
 
151
- id()
132
+ isBooleanFieldType(fieldType)
152
133
  {
153
- return this.name || '';
134
+ return 'Boolean' === fieldType;
154
135
  }
155
136
 
156
- name()
137
+ isDateTimeFieldType(fieldType)
157
138
  {
158
- return this.rawName || '';
139
+ return 'DateTime' === fieldType || 'Date' === fieldType;
159
140
  }
160
141
 
161
- tableName()
142
+ isJsonFieldType(fieldType)
162
143
  {
163
- return this.model.name || '';
144
+ return 'Json' === fieldType;
164
145
  }
165
146
 
166
- property(propertyName)
147
+ isJsonFieldByName(fieldName)
167
148
  {
168
- return this.rawModel[propertyName] || null;
149
+ if(this.jsonFields.has(fieldName)){
150
+ return true;
151
+ }
152
+ if(!this.rawModel || !this.rawModel.properties){
153
+ return false;
154
+ }
155
+ return 'json' === sc.get(this.rawModel.properties[fieldName], 'dbType', '');
169
156
  }
170
157
 
171
- prepareData(params)
158
+ isStringFieldType(fieldType)
159
+ {
160
+ return 'String' === fieldType;
161
+ }
162
+
163
+ castValue(value, fieldType, fieldName = null)
172
164
  {
173
- let data = {...params};
174
- for(let key of Object.keys(data)){
175
- if('status' === key && 'number' === typeof data[key]){
176
- data[key] = String(data[key]);
165
+ if('id' === fieldName){
166
+ return this.castToIdType(value);
167
+ }
168
+ if(this.isNullOrEmpty(value)){
169
+ if(sc.hasOwn(this.fieldDefaults, fieldName)){
170
+ return undefined;
177
171
  }
178
- if(this.isDateTimeField(key)){
179
- data[key] = this.convertToDate(data[key], key);
180
- continue;
172
+ if(-1 !== this.optionalFields.indexOf(fieldName)){
173
+ return null;
181
174
  }
182
- if(sc.hasOwn(this.referenceFields, key)){
183
- data[key] = this.castNumericValue(data[key], this.referenceFields[key]);
175
+ if(-1 !== this.requiredFields.indexOf(fieldName)){
176
+ Logger.warning('Required field '+fieldName+' cannot be null or empty');
177
+ return undefined;
184
178
  }
179
+ return null;
185
180
  }
186
- return data;
181
+ if(this.isJsonFieldByName(fieldName)){
182
+ return this.castToJsonType(value);
183
+ }
184
+ if(this.isNumericFieldType(fieldType)){
185
+ return this.castToNumericType(value, fieldType);
186
+ }
187
+ if(this.isBooleanFieldType(fieldType)){
188
+ return this.castToBooleanType(value);
189
+ }
190
+ if(this.isDateTimeFieldType(fieldType)){
191
+ return this.castToDateType(value);
192
+ }
193
+ if(this.isStringFieldType(fieldType)){
194
+ return this.castToStringType(value);
195
+ }
196
+ return value;
197
+ }
198
+
199
+ isNullOrEmpty(value)
200
+ {
201
+ return null === value || undefined === value || '' === value;
202
+ }
203
+
204
+ castToIdType(value)
205
+ {
206
+ if(this.isNullOrEmpty(value)){
207
+ return value;
208
+ }
209
+ if(this.isNumericFieldType(this.idFieldType)){
210
+ let numeric = Number(value);
211
+ if(!isNaN(numeric)){
212
+ return ('Int' === this.idFieldType || 'BigInt' === this.idFieldType) ? Math.floor(numeric) : numeric;
213
+ }
214
+ }
215
+ return String(value);
187
216
  }
188
217
 
189
- isDateTimeField(fieldName)
218
+ castToNumericType(value, fieldType)
190
219
  {
191
- let fieldType = this.fieldTypes[fieldName];
192
- return fieldType === 'DateTime' || fieldType === 'Date';
220
+ if(this.isNullOrEmpty(value)){
221
+ return null;
222
+ }
223
+ let numericValue = Number(value);
224
+ if(isNaN(numericValue)){
225
+ Logger.warning('Cannot convert value to numeric: '+value);
226
+ return null;
227
+ }
228
+ if('Int' === fieldType || 'BigInt' === fieldType){
229
+ return Math.floor(numericValue);
230
+ }
231
+ return numericValue;
232
+ }
233
+
234
+ castToBooleanType(value)
235
+ {
236
+ if(this.isNullOrEmpty(value)){
237
+ return null;
238
+ }
239
+ if('boolean' === typeof value){
240
+ return value;
241
+ }
242
+ if('number' === typeof value){
243
+ return 0 !== value;
244
+ }
245
+ if('string' === typeof value){
246
+ let lowerValue = value.toLowerCase();
247
+ if('true' === lowerValue || '1' === lowerValue || 'yes' === lowerValue){
248
+ return true;
249
+ }
250
+ if('false' === lowerValue || '0' === lowerValue || 'no' === lowerValue){
251
+ return false;
252
+ }
253
+ }
254
+ return Boolean(value);
193
255
  }
194
256
 
195
- convertToDate(dateValue, fieldName)
257
+ castToDateType(dateValue)
196
258
  {
197
259
  if(dateValue instanceof Date){
198
260
  return dateValue;
199
261
  }
200
- if(!dateValue || '' === dateValue){
262
+ if(this.isNullOrEmpty(dateValue)){
201
263
  return null;
202
264
  }
203
265
  let dateString = String(dateValue);
@@ -208,11 +270,132 @@ class PrismaDriver extends BaseDriver
208
270
  return new Date(dateString + 'T00:00:00Z');
209
271
  }
210
272
  try {
211
- return new Date(dateString);
273
+ let parsedDate = new Date(dateString);
274
+ if(isNaN(parsedDate.getTime())){
275
+ Logger.warning('Invalid date value: '+dateString);
276
+ return null;
277
+ }
278
+ return parsedDate;
212
279
  } catch(error) {
213
280
  Logger.warning('Failed to convert date value: '+dateString);
214
- return dateValue;
281
+ return null;
282
+ }
283
+ }
284
+
285
+ castToJsonType(value)
286
+ {
287
+ if(this.isNullOrEmpty(value)){
288
+ return Prisma.DbNull;
289
+ }
290
+ if('object' === typeof value){
291
+ return value;
292
+ }
293
+ if('string' === typeof value){
294
+ if(value.startsWith('%') && value.endsWith('%')){
295
+ return value;
296
+ }
297
+ try {
298
+ return JSON.parse(value);
299
+ } catch(error) {
300
+ return value;
301
+ }
302
+ }
303
+ return value;
304
+ }
305
+
306
+ castToStringType(value)
307
+ {
308
+ if(null === value || undefined === value){
309
+ return null;
310
+ }
311
+ if('string' === typeof value){
312
+ if('null' === value){
313
+ return null;
314
+ }
315
+ return value;
316
+ }
317
+ return String(value);
318
+ }
319
+
320
+ databaseName()
321
+ {
322
+ return this.config.database || '';
323
+ }
324
+
325
+ id()
326
+ {
327
+ return this.name || '';
328
+ }
329
+
330
+ name()
331
+ {
332
+ return this.rawName || '';
333
+ }
334
+
335
+ tableName()
336
+ {
337
+ return this.model.$name || this.model.name || '';
338
+ }
339
+
340
+ property(propertyName)
341
+ {
342
+ return this.rawModel[propertyName] || null;
343
+ }
344
+
345
+ prepareData(params)
346
+ {
347
+ let data = {};
348
+ for(let key of Object.keys(params)){
349
+ let fieldType = this.fieldTypes[key];
350
+ if(!fieldType){
351
+ data[key] = params[key];
352
+ continue;
353
+ }
354
+ let castedValue = this.castValue(params[key], fieldType, key);
355
+ if(undefined !== castedValue){
356
+ data[key] = castedValue;
357
+ }
215
358
  }
359
+ return data;
360
+ }
361
+
362
+ prepareDataWithRelations(params, isCreate = false)
363
+ {
364
+ let data = {};
365
+ let relations = {};
366
+ for(let key of Object.keys(params)){
367
+ if(sc.hasOwn(this.foreignKeyMappings, key)){
368
+ let relationName = this.foreignKeyMappings[key];
369
+ let value = params[key];
370
+ if(!this.isNullOrEmpty(value)){
371
+ relations[relationName] = {
372
+ connect: {id: this.castToIdType(value)}
373
+ };
374
+ continue;
375
+ }
376
+ if(!isCreate){
377
+ relations[relationName] = {
378
+ disconnect: true
379
+ };
380
+ }
381
+ continue;
382
+ }
383
+ let fieldType = this.fieldTypes[key];
384
+ if(!fieldType){
385
+ if(!this.isNullOrEmpty(params[key])){
386
+ data[key] = params[key];
387
+ }
388
+ continue;
389
+ }
390
+ let castedValue = this.castValue(params[key], fieldType, key);
391
+ if(undefined !== castedValue){
392
+ if(this.isJsonFieldType(fieldType) && null === castedValue){
393
+ continue;
394
+ }
395
+ data[key] = castedValue;
396
+ }
397
+ }
398
+ return {...data, ...relations};
216
399
  }
217
400
 
218
401
  ensureRequiredFields(data)
@@ -237,20 +420,12 @@ class PrismaDriver extends BaseDriver
237
420
  let processedFilters = {};
238
421
  for(let key of Object.keys(filters)){
239
422
  let value = filters[key];
423
+ if('OR' === key && sc.isArray(value)){
424
+ processedFilters.OR = value.map(condition => this.processFilters(condition));
425
+ continue;
426
+ }
240
427
  if(sc.hasOwn(value, 'operator') && sc.hasOwn(value, 'value')){
241
- let operatorValue = value.value;
242
- if('id' === key && sc.isArray(operatorValue)){
243
- operatorValue = operatorValue.map(id => this.castIdValue(id));
244
- }
245
- if('id' === key && !sc.isArray(operatorValue)){
246
- operatorValue = this.castIdValue(operatorValue);
247
- }
248
- if(sc.hasOwn(this.referenceFields, key) && sc.isArray(operatorValue)){
249
- operatorValue = operatorValue.map(val => this.castNumericValue(val, this.referenceFields[key]));
250
- }
251
- if(sc.hasOwn(this.referenceFields, key) && !sc.isArray(operatorValue)){
252
- operatorValue = this.castNumericValue(operatorValue, this.referenceFields[key]);
253
- }
428
+ let operatorValue = this.processFilterValue(value.value, key);
254
429
  processedFilters[key] = this.applyOperator(operatorValue, value.operator, key);
255
430
  continue;
256
431
  }
@@ -258,25 +433,32 @@ class PrismaDriver extends BaseDriver
258
433
  processedFilters[key] = this.processFilters(value);
259
434
  continue;
260
435
  }
261
- if('id' === key && sc.isArray(value)){
262
- processedFilters[key] = value.map(id => this.castIdValue(id));
263
- continue;
264
- }
436
+ processedFilters[key] = this.processFilterValue(value, key);
437
+ }
438
+ return processedFilters;
439
+ }
440
+
441
+ processFilterValue(value, key)
442
+ {
443
+ if(sc.isArray(value)){
265
444
  if('id' === key){
266
- processedFilters[key] = this.castIdValue(value);
267
- continue;
445
+ return value.map(id => this.castToIdType(id));
268
446
  }
269
- if(sc.hasOwn(this.referenceFields, key) && sc.isArray(value)){
270
- processedFilters[key] = value.map(val => this.castNumericValue(val, this.referenceFields[key]));
271
- continue;
447
+ let fieldType = this.fieldTypes[key];
448
+ if(fieldType){
449
+ return value.map(val => this.castValue(val, fieldType, key)).filter(val => undefined !== val);
272
450
  }
273
- if(sc.hasOwn(this.referenceFields, key)){
274
- processedFilters[key] = this.castNumericValue(value, this.referenceFields[key]);
275
- continue;
276
- }
277
- processedFilters[key] = value;
451
+ return value;
278
452
  }
279
- return processedFilters;
453
+ if('id' === key){
454
+ return this.castToIdType(value);
455
+ }
456
+ let fieldType = this.fieldTypes[key];
457
+ if(fieldType){
458
+ let castedValue = this.castValue(value, fieldType, key);
459
+ return undefined !== castedValue ? castedValue : value;
460
+ }
461
+ return value;
280
462
  }
281
463
 
282
464
  transformRelationResults(result, includeConfig)
@@ -318,9 +500,9 @@ class PrismaDriver extends BaseDriver
318
500
 
319
501
  async create(params)
320
502
  {
503
+ let preparedData = this.prepareDataWithRelations(params, true);
504
+ this.ensureRequiredFields(preparedData);
321
505
  try {
322
- let preparedData = this.prepareData(params);
323
- this.ensureRequiredFields(preparedData);
324
506
  return await this.model.create({
325
507
  data: preparedData
326
508
  });
@@ -332,27 +514,27 @@ class PrismaDriver extends BaseDriver
332
514
 
333
515
  async createWithRelations(params, relations)
334
516
  {
335
- try {
336
- let preparedData = this.prepareData(params);
337
- this.ensureRequiredFields(preparedData);
338
- let createData = {data: preparedData};
339
- if(sc.isArray(relations) && 0 < relations.length){
340
- for(let relation of relations){
341
- if(!sc.hasOwn(params, relation)){
342
- continue;
343
- }
344
- let relationData = params[relation];
345
- if(sc.isArray(relationData)){
346
- createData.data[relation] = {
347
- connect: relationData.map(item => ({id: this.castIdValue(item.id)}))
348
- };
349
- continue;
350
- }
517
+ let preparedData = this.prepareData(params);
518
+ this.ensureRequiredFields(preparedData);
519
+ let createData = {data: preparedData};
520
+ if(sc.isArray(relations) && 0 < relations.length){
521
+ for(let relation of relations){
522
+ if(!sc.hasOwn(params, relation)){
523
+ continue;
524
+ }
525
+ let relationData = params[relation];
526
+ if(sc.isArray(relationData)){
351
527
  createData.data[relation] = {
352
- connect: {id: this.castIdValue(relationData.id)}
528
+ connect: relationData.map(item => ({id: this.castToIdType(item.id)}))
353
529
  };
530
+ continue;
354
531
  }
532
+ createData.data[relation] = {
533
+ connect: {id: this.castToIdType(relationData.id)}
534
+ };
355
535
  }
536
+ }
537
+ try {
356
538
  return await this.model.create(createData);
357
539
  } catch(error) {
358
540
  Logger.error('Create with relations error: '+error.message);
@@ -362,9 +544,9 @@ class PrismaDriver extends BaseDriver
362
544
 
363
545
  async update(filters, updatePatch)
364
546
  {
547
+ let preparedData = this.prepareDataWithRelations(updatePatch);
548
+ let processedFilters = this.processFilters(filters);
365
549
  try {
366
- let preparedData = this.prepareData(updatePatch);
367
- let processedFilters = this.processFilters(filters);
368
550
  return await this.model.updateMany({
369
551
  where: processedFilters,
370
552
  data: preparedData
@@ -378,8 +560,8 @@ class PrismaDriver extends BaseDriver
378
560
  async updateBy(field, fieldValue, updatePatch, operator = null)
379
561
  {
380
562
  let filter = this.createSingleFilter(field, fieldValue, operator);
563
+ let preparedData = this.prepareDataWithRelations(updatePatch);
381
564
  try {
382
- let preparedData = this.prepareData(updatePatch);
383
565
  return await this.model.updateMany({
384
566
  where: filter,
385
567
  data: preparedData
@@ -392,13 +574,13 @@ class PrismaDriver extends BaseDriver
392
574
 
393
575
  async updateById(id, params)
394
576
  {
577
+ let castedId = this.castToIdType(id);
578
+ let found = await this.loadById(castedId);
579
+ if(!found){
580
+ return false;
581
+ }
582
+ let preparedData = this.prepareDataWithRelations(params);
395
583
  try {
396
- let castedId = this.castIdValue(id);
397
- let found = await this.loadById(castedId);
398
- if(!found){
399
- return false;
400
- }
401
- let preparedData = this.prepareData(params);
402
584
  return await this.model.update({
403
585
  where: {id: castedId},
404
586
  data: preparedData
@@ -411,41 +593,46 @@ class PrismaDriver extends BaseDriver
411
593
 
412
594
  async upsert(params, filters)
413
595
  {
414
- try {
415
- let preparedData = this.prepareData(params);
416
- let existing = false;
417
- if(params.id){
418
- let castedId = this.castIdValue(params.id);
419
- existing = await this.loadById(castedId);
420
- if(existing){
421
- let patch = Object.assign({}, preparedData);
422
- delete patch.id;
596
+ let preparedData = this.prepareDataWithRelations(params);
597
+ let existing = false;
598
+ if(params.id){
599
+ let castedId = this.castToIdType(params.id);
600
+ existing = await this.loadById(castedId);
601
+ if(existing){
602
+ let patch = Object.assign({}, preparedData);
603
+ delete patch.id;
604
+ try {
423
605
  return await this.model.update({
424
606
  where: {id: castedId},
425
607
  data: patch
426
608
  });
609
+ } catch(error) {
610
+ Logger.error('Upsert update error: '+error.message);
611
+ return false;
427
612
  }
428
613
  }
429
- if(filters){
430
- let existing = await this.loadOne(filters);
431
- if(existing){
614
+ }
615
+ if(filters){
616
+ let existing = await this.loadOne(filters);
617
+ if(existing){
618
+ try {
432
619
  return await this.model.update({
433
- where: {id: this.castIdValue(existing.id)},
620
+ where: {id: this.castToIdType(existing.id)},
434
621
  data: preparedData
435
622
  });
623
+ } catch(error) {
624
+ Logger.error('Upsert update by filter error: '+error.message);
625
+ return false;
436
626
  }
437
627
  }
438
- return await this.create(preparedData);
439
- } catch(error) {
440
- Logger.error('Upsert error: '+error.message);
441
- return false;
442
628
  }
629
+ return await this.create(preparedData);
443
630
  }
444
631
 
445
632
  async delete(filters = {})
446
633
  {
634
+ let processedFilters = this.processFilters(filters);
447
635
  try {
448
- let processedFilters = this.processFilters(filters);
449
636
  return await this.model.deleteMany({
450
637
  where: processedFilters
451
638
  });
@@ -457,12 +644,12 @@ class PrismaDriver extends BaseDriver
457
644
 
458
645
  async deleteById(id)
459
646
  {
647
+ let castedId = this.castToIdType(id);
648
+ let found = await this.loadById(castedId);
649
+ if(!found){
650
+ return false;
651
+ }
460
652
  try {
461
- let castedId = this.castIdValue(id);
462
- let found = await this.loadById(castedId);
463
- if(!found){
464
- return false;
465
- }
466
653
  return await this.model.delete({
467
654
  where: {id: castedId}
468
655
  });
@@ -474,8 +661,8 @@ class PrismaDriver extends BaseDriver
474
661
 
475
662
  async count(filters)
476
663
  {
664
+ let processedFilters = this.processFilters(filters);
477
665
  try {
478
- let processedFilters = this.processFilters(filters);
479
666
  return await this.model.count({
480
667
  where: processedFilters
481
668
  });
@@ -487,14 +674,14 @@ class PrismaDriver extends BaseDriver
487
674
 
488
675
  async countWithRelations(filters, relations)
489
676
  {
677
+ let processedFilters = this.processFilters(filters);
678
+ let query = {
679
+ where: processedFilters
680
+ };
681
+ if(sc.isArray(relations) && 0 < relations.length){
682
+ query.include = this.buildIncludeObject(relations);
683
+ }
490
684
  try {
491
- let processedFilters = this.processFilters(filters);
492
- let query = {
493
- where: processedFilters
494
- };
495
- if(sc.isArray(relations) && 0 < relations.length){
496
- query.include = this.buildIncludeObject(relations);
497
- }
498
685
  return await this.model.count(query);
499
686
  } catch(error) {
500
687
  Logger.error('Count with relations error: '+error.message);
@@ -514,13 +701,13 @@ class PrismaDriver extends BaseDriver
514
701
 
515
702
  async loadAllWithRelations(relations)
516
703
  {
704
+ let query = this.buildQueryOptions();
705
+ let includeConfig = {};
706
+ if(sc.isArray(relations) && 0 < relations.length){
707
+ includeConfig = this.buildIncludeObject(relations);
708
+ query.include = includeConfig;
709
+ }
517
710
  try {
518
- let query = this.buildQueryOptions();
519
- let includeConfig = {};
520
- if(sc.isArray(relations) && 0 < relations.length){
521
- includeConfig = this.buildIncludeObject(relations);
522
- query.include = includeConfig;
523
- }
524
711
  let results = await this.model.findMany(query);
525
712
  return this.transformRelationResults(results, includeConfig);
526
713
  } catch(error) {
@@ -531,10 +718,10 @@ class PrismaDriver extends BaseDriver
531
718
 
532
719
  async load(filters)
533
720
  {
721
+ let processedFilters = this.processFilters(filters);
722
+ let query = this.buildQueryOptions();
723
+ query.where = processedFilters;
534
724
  try {
535
- let processedFilters = this.processFilters(filters);
536
- let query = this.buildQueryOptions();
537
- query.where = processedFilters;
538
725
  return await this.model.findMany(query);
539
726
  } catch(error) {
540
727
  Logger.error('Load error: '+error.message);
@@ -544,15 +731,15 @@ class PrismaDriver extends BaseDriver
544
731
 
545
732
  async loadWithRelations(filters, relations)
546
733
  {
734
+ let processedFilters = this.processFilters(filters);
735
+ let query = this.buildQueryOptions();
736
+ query.where = processedFilters;
737
+ let includeConfig = {};
738
+ if(sc.isArray(relations) && 0 < relations.length){
739
+ includeConfig = this.buildIncludeObject(relations);
740
+ query.include = includeConfig;
741
+ }
547
742
  try {
548
- let processedFilters = this.processFilters(filters);
549
- let query = this.buildQueryOptions();
550
- query.where = processedFilters;
551
- let includeConfig = {};
552
- if(sc.isArray(relations) && 0 < relations.length){
553
- includeConfig = this.buildIncludeObject(relations);
554
- query.include = includeConfig;
555
- }
556
743
  let results = await this.model.findMany(query);
557
744
  return this.transformRelationResults(results, includeConfig);
558
745
  } catch(error) {
@@ -563,10 +750,10 @@ class PrismaDriver extends BaseDriver
563
750
 
564
751
  async loadBy(field, fieldValue, operator = null)
565
752
  {
753
+ let filter = this.createSingleFilter(field, fieldValue, operator);
754
+ let query = this.buildQueryOptions();
755
+ query.where = filter;
566
756
  try {
567
- let filter = this.createSingleFilter(field, fieldValue, operator);
568
- let query = this.buildQueryOptions();
569
- query.where = filter;
570
757
  return await this.model.findMany(query);
571
758
  } catch(error) {
572
759
  Logger.error('Load by error: '+error.message);
@@ -576,15 +763,15 @@ class PrismaDriver extends BaseDriver
576
763
 
577
764
  async loadByWithRelations(field, fieldValue, relations, operator = null)
578
765
  {
766
+ let filter = this.createSingleFilter(field, fieldValue, operator);
767
+ let query = this.buildQueryOptions();
768
+ query.where = filter;
769
+ let includeConfig = {};
770
+ if(sc.isArray(relations) && 0 < relations.length){
771
+ includeConfig = this.buildIncludeObject(relations);
772
+ query.include = includeConfig;
773
+ }
579
774
  try {
580
- let filter = this.createSingleFilter(field, fieldValue, operator);
581
- let query = this.buildQueryOptions();
582
- query.where = filter;
583
- let includeConfig = {};
584
- if(sc.isArray(relations) && 0 < relations.length){
585
- includeConfig = this.buildIncludeObject(relations);
586
- query.include = includeConfig;
587
- }
588
775
  let results = await this.model.findMany(query);
589
776
  return this.transformRelationResults(results, includeConfig);
590
777
  } catch(error) {
@@ -595,8 +782,8 @@ class PrismaDriver extends BaseDriver
595
782
 
596
783
  async loadById(id)
597
784
  {
785
+ let castedId = this.castToIdType(id);
598
786
  try {
599
- let castedId = this.castIdValue(id);
600
787
  return await this.model.findUnique({
601
788
  where: {id: castedId}
602
789
  });
@@ -608,16 +795,16 @@ class PrismaDriver extends BaseDriver
608
795
 
609
796
  async loadByIdWithRelations(id, relations)
610
797
  {
798
+ let castedId = this.castToIdType(id);
799
+ let query = {
800
+ where: {id: castedId}
801
+ };
802
+ let includeConfig = {};
803
+ if(sc.isArray(relations) && 0 < relations.length){
804
+ includeConfig = this.buildIncludeObject(relations);
805
+ query.include = includeConfig;
806
+ }
611
807
  try {
612
- let castedId = this.castIdValue(id);
613
- let query = {
614
- where: {id: castedId}
615
- };
616
- let includeConfig = {};
617
- if(sc.isArray(relations) && 0 < relations.length){
618
- includeConfig = this.buildIncludeObject(relations);
619
- query.include = includeConfig;
620
- }
621
808
  let result = await this.model.findUnique(query);
622
809
  return this.transformRelationResults(result, includeConfig);
623
810
  } catch(error) {
@@ -628,8 +815,8 @@ class PrismaDriver extends BaseDriver
628
815
 
629
816
  async loadByIds(ids)
630
817
  {
818
+ let castedIds = ids.map(id => this.castToIdType(id));
631
819
  try {
632
- let castedIds = ids.map(id => this.castIdValue(id));
633
820
  return await this.model.findMany({
634
821
  where: {
635
822
  id: {in: castedIds}
@@ -643,10 +830,10 @@ class PrismaDriver extends BaseDriver
643
830
 
644
831
  async loadOne(filters)
645
832
  {
833
+ let processedFilters = this.processFilters(filters);
834
+ let query = this.buildQueryOptions(false);
835
+ query.where = processedFilters;
646
836
  try {
647
- let processedFilters = this.processFilters(filters);
648
- let query = this.buildQueryOptions(false);
649
- query.where = processedFilters;
650
837
  return await this.model.findFirst(query);
651
838
  } catch(error) {
652
839
  Logger.error('Load one error: '+error.message);
@@ -656,15 +843,15 @@ class PrismaDriver extends BaseDriver
656
843
 
657
844
  async loadOneWithRelations(filters, relations)
658
845
  {
846
+ let processedFilters = this.processFilters(filters);
847
+ let query = this.buildQueryOptions(false);
848
+ query.where = processedFilters;
849
+ let includeConfig = {};
850
+ if(sc.isArray(relations) && 0 < relations.length){
851
+ includeConfig = this.buildIncludeObject(relations);
852
+ query.include = includeConfig;
853
+ }
659
854
  try {
660
- let processedFilters = this.processFilters(filters);
661
- let query = this.buildQueryOptions(false);
662
- query.where = processedFilters;
663
- let includeConfig = {};
664
- if(sc.isArray(relations) && 0 < relations.length){
665
- includeConfig = this.buildIncludeObject(relations);
666
- query.include = includeConfig;
667
- }
668
855
  let result = await this.model.findFirst(query);
669
856
  return this.transformRelationResults(result, includeConfig);
670
857
  } catch(error) {
@@ -675,10 +862,10 @@ class PrismaDriver extends BaseDriver
675
862
 
676
863
  async loadOneBy(field, fieldValue, operator = null)
677
864
  {
865
+ let filter = this.createSingleFilter(field, fieldValue, operator);
866
+ let query = this.buildQueryOptions(false);
867
+ query.where = filter;
678
868
  try {
679
- let filter = this.createSingleFilter(field, fieldValue, operator);
680
- let query = this.buildQueryOptions(false);
681
- query.where = filter;
682
869
  return await this.model.findFirst(query);
683
870
  } catch(error) {
684
871
  Logger.error('Load one by error: '+error.message);
@@ -688,15 +875,15 @@ class PrismaDriver extends BaseDriver
688
875
 
689
876
  async loadOneByWithRelations(field, fieldValue, relations, operator = null)
690
877
  {
878
+ let filter = this.createSingleFilter(field, fieldValue, operator);
879
+ let query = this.buildQueryOptions(false);
880
+ query.where = filter;
881
+ let includeConfig = {};
882
+ if(sc.isArray(relations) && 0 < relations.length){
883
+ includeConfig = this.buildIncludeObject(relations);
884
+ query.include = includeConfig;
885
+ }
691
886
  try {
692
- let filter = this.createSingleFilter(field, fieldValue, operator);
693
- let query = this.buildQueryOptions(false);
694
- query.where = filter;
695
- let includeConfig = {};
696
- if(sc.isArray(relations) && 0 < relations.length){
697
- includeConfig = this.buildIncludeObject(relations);
698
- query.include = includeConfig;
699
- }
700
887
  let result = await this.model.findFirst(query);
701
888
  return this.transformRelationResults(result, includeConfig);
702
889
  } catch(error) {
@@ -731,23 +918,21 @@ class PrismaDriver extends BaseDriver
731
918
  createSingleFilter(field, fieldValue, operator = null)
732
919
  {
733
920
  let filter = {};
734
- let processedValue = fieldValue;
735
- if(sc.hasOwn(this.referenceFields, field)){
736
- processedValue = this.castNumericValue(fieldValue, this.referenceFields[field]);
737
- }
738
- if('id' === field){
739
- processedValue = this.castIdValue(fieldValue);
740
- }
921
+ let processedValue = this.processFilterValue(fieldValue, field);
741
922
  if(null === operator){
742
923
  filter[field] = processedValue;
743
924
  return filter;
744
925
  }
745
- filter[field] = this.applyOperator(processedValue, operator, field);
746
- return filter;
926
+ filter[field] = {operator, value: processedValue};
927
+ return this.processFilters(filter);
747
928
  }
748
929
 
749
930
  applyOperator(value, operator, fieldName = null)
750
931
  {
932
+ let upperOperator = operator ? operator.toUpperCase() : '';
933
+ if('LIKE' === upperOperator){
934
+ return this.handleLikeOperator(value, fieldName);
935
+ }
751
936
  let operatorsMap = {
752
937
  '=': value,
753
938
  '!=': {not: value},
@@ -755,22 +940,32 @@ class PrismaDriver extends BaseDriver
755
940
  '>=': {gte: value},
756
941
  '<': {lt: value},
757
942
  '<=': {lte: value},
758
- 'LIKE': this.handleLikeOperator(value, fieldName),
759
943
  'IN': {in: value},
760
944
  'NOT IN': {notIn: value}
761
945
  };
762
- return operatorsMap[operator] || value;
946
+ return operatorsMap[upperOperator] || value;
763
947
  }
764
948
 
765
949
  handleLikeOperator(value, fieldName)
766
950
  {
767
- if('id' === fieldName || (this.referenceFields && sc.hasOwn(this.referenceFields, fieldName))){
768
- let numericValue = Number(value.replace(/%/g, ''));
951
+ let cleanValue = String(value).replace(/%/g, '');
952
+ if(this.isJsonFieldByName(fieldName) || this.isJsonField(fieldName)){
953
+ return this.handleJsonTextSearch(cleanValue);
954
+ }
955
+ if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
956
+ let numericValue = Number(cleanValue);
769
957
  if(!isNaN(numericValue)){
770
958
  return numericValue;
771
959
  }
772
960
  }
773
- return {contains: value};
961
+ return {contains: cleanValue};
962
+ }
963
+
964
+ handleJsonTextSearch(searchValue)
965
+ {
966
+ return {
967
+ string_contains: searchValue
968
+ };
774
969
  }
775
970
 
776
971
  buildIncludeObject(relations)