@reldens/storage 0.58.0 → 0.60.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,127 +22,279 @@ 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.prisma._runtimeDataModel || Prisma.dmmf?.datamodel;
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
+ processFieldMetadata(field)
75
65
  {
76
- 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
- }
66
+ this.fieldTypes[field.name] = field.type;
67
+ if('Json' === field.type){
68
+ this.jsonFields.add(field.name);
69
+ }
70
+ if(field.isId){
71
+ this.idFieldType = field.type;
72
+ }
73
+ if(field.hasDefaultValue){
74
+ this.fieldDefaults[field.name] = field.default;
75
+ }
76
+ if(field.isRequired && !field.hasDefaultValue && !field.isId && 'object' !== field.kind){
77
+ this.requiredFields.push(field.name);
78
+ }
79
+ if(field.isOptional || field.hasDefaultValue){
80
+ this.optionalFields.push(field.name);
81
+ }
82
+ if(field.kind === 'scalar' && field.isList === false){
83
+ let isNumericType = this.isNumericFieldType(field.type);
84
+ let isReferenceField = field.relationFromFields && 0 < field.relationFromFields.length;
85
+ if(isNumericType || isReferenceField){
86
+ this.referenceFields[field.name] = field.type;
99
87
  }
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
- }
88
+ }
89
+ if('object' === field.kind){
90
+ let relationType = field.isList ? 'many' : 'one';
91
+ this.relationMetadata[field.name] = {
92
+ type: relationType,
93
+ model: field.type,
94
+ isList: field.isList,
95
+ isOptional: field.isOptional
96
+ };
97
+ }
98
+ if('object' === field.kind && sc.hasOwn(field, 'relationFromFields') && sc.isArray(field.relationFromFields)){
99
+ for(let foreignKeyField of field.relationFromFields){
100
+ this.foreignKeyMappings[foreignKeyField] = field.name;
106
101
  }
107
- } catch(error) {
108
- Logger.warning('Could not initialize relation metadata: '+error.message);
109
102
  }
110
103
  }
111
104
 
112
- castIdValue(id)
105
+ isNumericFieldType(fieldType)
106
+ {
107
+ return ('Int' === fieldType || 'BigInt' === fieldType || 'Float' === fieldType || 'Decimal' === fieldType);
108
+ }
109
+
110
+ isBooleanFieldType(fieldType)
111
+ {
112
+ return 'Boolean' === fieldType;
113
+ }
114
+
115
+ isDateTimeFieldType(fieldType)
116
+ {
117
+ return 'DateTime' === fieldType || 'Date' === fieldType;
118
+ }
119
+
120
+ isJsonFieldType(fieldType)
121
+ {
122
+ return 'Json' === fieldType;
123
+ }
124
+
125
+ isJsonFieldByName(fieldName)
126
+ {
127
+ if(this.jsonFields.has(fieldName)){
128
+ return true;
129
+ }
130
+ if(!this.rawModel || !this.rawModel.properties){
131
+ return false;
132
+ }
133
+ return 'json' === sc.get(this.rawModel.properties[fieldName], 'dbType', '');
134
+ }
135
+
136
+ isStringFieldType(fieldType)
137
+ {
138
+ return 'String' === fieldType;
139
+ }
140
+
141
+ castValue(value, fieldType, fieldName = null)
142
+ {
143
+ if('id' === fieldName){
144
+ return this.castToIdType(value);
145
+ }
146
+ if(this.isNullOrEmpty(value)){
147
+ if(sc.hasOwn(this.fieldDefaults, fieldName)){
148
+ return undefined;
149
+ }
150
+ if(-1 !== this.optionalFields.indexOf(fieldName)){
151
+ return null;
152
+ }
153
+ if(-1 !== this.requiredFields.indexOf(fieldName)){
154
+ Logger.warning('Required field '+fieldName+' cannot be null or empty');
155
+ return undefined;
156
+ }
157
+ return null;
158
+ }
159
+ if(this.isJsonFieldByName(fieldName)){
160
+ return this.castToJsonType(value);
161
+ }
162
+ if(this.isNumericFieldType(fieldType)){
163
+ return this.castToNumericType(value, fieldType);
164
+ }
165
+ if(this.isBooleanFieldType(fieldType)){
166
+ return this.castToBooleanType(value);
167
+ }
168
+ if(this.isDateTimeFieldType(fieldType)){
169
+ return this.castToDateType(value);
170
+ }
171
+ if(this.isStringFieldType(fieldType)){
172
+ return this.castToStringType(value);
173
+ }
174
+ return value;
175
+ }
176
+
177
+ isNullOrEmpty(value)
113
178
  {
114
- if(null === id || undefined === id){
115
- return id;
179
+ return null === value || undefined === value || '' === value;
180
+ }
181
+
182
+ castToIdType(value)
183
+ {
184
+ if(this.isNullOrEmpty(value)){
185
+ return value;
116
186
  }
117
- if('Int' === this.idFieldType || 'BigInt' === this.idFieldType){
118
- let numericId = Number(id);
119
- if(!isNaN(numericId)){
120
- return numericId;
187
+ if(this.isNumericFieldType(this.idFieldType)){
188
+ let numeric = Number(value);
189
+ if(!isNaN(numeric)){
190
+ return ('Int' === this.idFieldType || 'BigInt' === this.idFieldType) ? Math.floor(numeric) : numeric;
121
191
  }
122
192
  }
123
- return String(id);
193
+ return String(value);
124
194
  }
125
195
 
126
- castNumericValue(value, fieldType)
196
+ castToNumericType(value, fieldType)
127
197
  {
128
- if(null === value || undefined === value || '' === value){
198
+ if(this.isNullOrEmpty(value)){
199
+ return null;
200
+ }
201
+ let numericValue = Number(value);
202
+ if(isNaN(numericValue)){
203
+ Logger.warning('Cannot convert value to numeric: '+value);
129
204
  return null;
130
205
  }
131
206
  if('Int' === fieldType || 'BigInt' === fieldType){
132
- let numericValue = Number(value);
133
- if(!isNaN(numericValue)){
134
- return Math.floor(numericValue);
207
+ return Math.floor(numericValue);
208
+ }
209
+ return numericValue;
210
+ }
211
+
212
+ castToBooleanType(value)
213
+ {
214
+ if(this.isNullOrEmpty(value)){
215
+ return null;
216
+ }
217
+ if('boolean' === typeof value){
218
+ return value;
219
+ }
220
+ if('number' === typeof value){
221
+ return 0 !== value;
222
+ }
223
+ if('string' === typeof value){
224
+ let lowerValue = value.toLowerCase();
225
+ if('true' === lowerValue || '1' === lowerValue || 'yes' === lowerValue){
226
+ return true;
227
+ }
228
+ if('false' === lowerValue || '0' === lowerValue || 'no' === lowerValue){
229
+ return false;
135
230
  }
136
231
  }
137
- if('Float' === fieldType || 'Decimal' === fieldType){
138
- let numericValue = Number(value);
139
- if(!isNaN(numericValue)){
140
- return numericValue;
232
+ return Boolean(value);
233
+ }
234
+
235
+ castToDateType(dateValue)
236
+ {
237
+ if(dateValue instanceof Date){
238
+ return dateValue;
239
+ }
240
+ if(this.isNullOrEmpty(dateValue)){
241
+ return null;
242
+ }
243
+ let dateString = String(dateValue);
244
+ if(dateString.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/)){
245
+ return new Date(dateString.replace(' ', 'T') + 'Z');
246
+ }
247
+ if(dateString.match(/^\d{4}-\d{2}-\d{2}$/)){
248
+ return new Date(dateString + 'T00:00:00Z');
249
+ }
250
+ try {
251
+ let parsedDate = new Date(dateString);
252
+ if(isNaN(parsedDate.getTime())){
253
+ Logger.warning('Invalid date value: '+dateString);
254
+ return null;
255
+ }
256
+ return parsedDate;
257
+ } catch(error) {
258
+ Logger.warning('Failed to convert date value: '+dateString);
259
+ return null;
260
+ }
261
+ }
262
+
263
+ castToJsonType(value)
264
+ {
265
+ if(this.isNullOrEmpty(value)){
266
+ return Prisma.DbNull;
267
+ }
268
+ if('object' === typeof value){
269
+ return value;
270
+ }
271
+ if('string' === typeof value){
272
+ if(value.startsWith('%') && value.endsWith('%')){
273
+ return value;
274
+ }
275
+ try {
276
+ return JSON.parse(value);
277
+ } catch(error) {
278
+ return value;
141
279
  }
142
280
  }
143
281
  return value;
144
282
  }
145
283
 
284
+ castToStringType(value)
285
+ {
286
+ if(null === value || undefined === value){
287
+ return null;
288
+ }
289
+ if('string' === typeof value){
290
+ if('null' === value){
291
+ return null;
292
+ }
293
+ return value;
294
+ }
295
+ return String(value);
296
+ }
297
+
146
298
  databaseName()
147
299
  {
148
300
  return this.config.database || '';
@@ -170,49 +322,56 @@ class PrismaDriver extends BaseDriver
170
322
 
171
323
  prepareData(params)
172
324
  {
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]);
177
- }
178
- if(this.isDateTimeField(key)){
179
- data[key] = this.convertToDate(data[key], key);
325
+ let data = {};
326
+ for(let key of Object.keys(params)){
327
+ let fieldType = this.fieldTypes[key];
328
+ if(!fieldType){
329
+ data[key] = params[key];
180
330
  continue;
181
331
  }
182
- if(sc.hasOwn(this.referenceFields, key)){
183
- data[key] = this.castNumericValue(data[key], this.referenceFields[key]);
332
+ let castedValue = this.castValue(params[key], fieldType, key);
333
+ if(undefined !== castedValue){
334
+ data[key] = castedValue;
184
335
  }
185
336
  }
186
337
  return data;
187
338
  }
188
339
 
189
- isDateTimeField(fieldName)
340
+ prepareDataWithRelations(params)
190
341
  {
191
- let fieldType = this.fieldTypes[fieldName];
192
- return fieldType === 'DateTime' || fieldType === 'Date';
193
- }
194
-
195
- convertToDate(dateValue, fieldName)
196
- {
197
- if(dateValue instanceof Date){
198
- return dateValue;
199
- }
200
- if(!dateValue || '' === dateValue){
201
- return null;
202
- }
203
- let dateString = String(dateValue);
204
- if(dateString.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/)){
205
- return new Date(dateString.replace(' ', 'T') + 'Z');
206
- }
207
- if(dateString.match(/^\d{4}-\d{2}-\d{2}$/)){
208
- return new Date(dateString + 'T00:00:00Z');
209
- }
210
- try {
211
- return new Date(dateString);
212
- } catch(error) {
213
- Logger.warning('Failed to convert date value: '+dateString);
214
- return dateValue;
342
+ let data = {};
343
+ let relations = {};
344
+ for(let key of Object.keys(params)){
345
+ if(sc.hasOwn(this.foreignKeyMappings, key)){
346
+ let relationName = this.foreignKeyMappings[key];
347
+ let value = params[key];
348
+ if(!this.isNullOrEmpty(value)){
349
+ relations[relationName] = {
350
+ connect: {id: this.castToIdType(value)}
351
+ };
352
+ continue;
353
+ }
354
+ relations[relationName] = {
355
+ disconnect: true
356
+ };
357
+ continue;
358
+ }
359
+ let fieldType = this.fieldTypes[key];
360
+ if(!fieldType){
361
+ if(!this.isNullOrEmpty(params[key])){
362
+ data[key] = params[key];
363
+ }
364
+ continue;
365
+ }
366
+ let castedValue = this.castValue(params[key], fieldType, key);
367
+ if(undefined !== castedValue){
368
+ if(this.isJsonFieldType(fieldType) && null === castedValue){
369
+ continue;
370
+ }
371
+ data[key] = castedValue;
372
+ }
215
373
  }
374
+ return {...data, ...relations};
216
375
  }
217
376
 
218
377
  ensureRequiredFields(data)
@@ -237,20 +396,12 @@ class PrismaDriver extends BaseDriver
237
396
  let processedFilters = {};
238
397
  for(let key of Object.keys(filters)){
239
398
  let value = filters[key];
399
+ if('OR' === key && sc.isArray(value)){
400
+ processedFilters.OR = value.map(condition => this.processFilters(condition));
401
+ continue;
402
+ }
240
403
  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
- }
404
+ let operatorValue = this.processFilterValue(value.value, key);
254
405
  processedFilters[key] = this.applyOperator(operatorValue, value.operator, key);
255
406
  continue;
256
407
  }
@@ -258,25 +409,32 @@ class PrismaDriver extends BaseDriver
258
409
  processedFilters[key] = this.processFilters(value);
259
410
  continue;
260
411
  }
261
- if('id' === key && sc.isArray(value)){
262
- processedFilters[key] = value.map(id => this.castIdValue(id));
263
- continue;
264
- }
412
+ processedFilters[key] = this.processFilterValue(value, key);
413
+ }
414
+ return processedFilters;
415
+ }
416
+
417
+ processFilterValue(value, key)
418
+ {
419
+ if(sc.isArray(value)){
265
420
  if('id' === key){
266
- processedFilters[key] = this.castIdValue(value);
267
- continue;
421
+ return value.map(id => this.castToIdType(id));
268
422
  }
269
- if(sc.hasOwn(this.referenceFields, key) && sc.isArray(value)){
270
- processedFilters[key] = value.map(val => this.castNumericValue(val, this.referenceFields[key]));
271
- continue;
272
- }
273
- if(sc.hasOwn(this.referenceFields, key)){
274
- processedFilters[key] = this.castNumericValue(value, this.referenceFields[key]);
275
- continue;
423
+ let fieldType = this.fieldTypes[key];
424
+ if(fieldType){
425
+ return value.map(val => this.castValue(val, fieldType, key)).filter(val => undefined !== val);
276
426
  }
277
- processedFilters[key] = value;
427
+ return value;
278
428
  }
279
- return processedFilters;
429
+ if('id' === key){
430
+ return this.castToIdType(value);
431
+ }
432
+ let fieldType = this.fieldTypes[key];
433
+ if(fieldType){
434
+ let castedValue = this.castValue(value, fieldType, key);
435
+ return undefined !== castedValue ? castedValue : value;
436
+ }
437
+ return value;
280
438
  }
281
439
 
282
440
  transformRelationResults(result, includeConfig)
@@ -318,9 +476,9 @@ class PrismaDriver extends BaseDriver
318
476
 
319
477
  async create(params)
320
478
  {
479
+ let preparedData = this.prepareDataWithRelations(params);
480
+ this.ensureRequiredFields(preparedData);
321
481
  try {
322
- let preparedData = this.prepareData(params);
323
- this.ensureRequiredFields(preparedData);
324
482
  return await this.model.create({
325
483
  data: preparedData
326
484
  });
@@ -332,27 +490,27 @@ class PrismaDriver extends BaseDriver
332
490
 
333
491
  async createWithRelations(params, relations)
334
492
  {
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
- }
493
+ let preparedData = this.prepareData(params);
494
+ this.ensureRequiredFields(preparedData);
495
+ let createData = {data: preparedData};
496
+ if(sc.isArray(relations) && 0 < relations.length){
497
+ for(let relation of relations){
498
+ if(!sc.hasOwn(params, relation)){
499
+ continue;
500
+ }
501
+ let relationData = params[relation];
502
+ if(sc.isArray(relationData)){
351
503
  createData.data[relation] = {
352
- connect: {id: this.castIdValue(relationData.id)}
504
+ connect: relationData.map(item => ({id: this.castToIdType(item.id)}))
353
505
  };
506
+ continue;
354
507
  }
508
+ createData.data[relation] = {
509
+ connect: {id: this.castToIdType(relationData.id)}
510
+ };
355
511
  }
512
+ }
513
+ try {
356
514
  return await this.model.create(createData);
357
515
  } catch(error) {
358
516
  Logger.error('Create with relations error: '+error.message);
@@ -362,9 +520,9 @@ class PrismaDriver extends BaseDriver
362
520
 
363
521
  async update(filters, updatePatch)
364
522
  {
523
+ let preparedData = this.prepareDataWithRelations(updatePatch);
524
+ let processedFilters = this.processFilters(filters);
365
525
  try {
366
- let preparedData = this.prepareData(updatePatch);
367
- let processedFilters = this.processFilters(filters);
368
526
  return await this.model.updateMany({
369
527
  where: processedFilters,
370
528
  data: preparedData
@@ -378,8 +536,8 @@ class PrismaDriver extends BaseDriver
378
536
  async updateBy(field, fieldValue, updatePatch, operator = null)
379
537
  {
380
538
  let filter = this.createSingleFilter(field, fieldValue, operator);
539
+ let preparedData = this.prepareDataWithRelations(updatePatch);
381
540
  try {
382
- let preparedData = this.prepareData(updatePatch);
383
541
  return await this.model.updateMany({
384
542
  where: filter,
385
543
  data: preparedData
@@ -392,13 +550,13 @@ class PrismaDriver extends BaseDriver
392
550
 
393
551
  async updateById(id, params)
394
552
  {
553
+ let castedId = this.castToIdType(id);
554
+ let found = await this.loadById(castedId);
555
+ if(!found){
556
+ return false;
557
+ }
558
+ let preparedData = this.prepareDataWithRelations(params);
395
559
  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
560
  return await this.model.update({
403
561
  where: {id: castedId},
404
562
  data: preparedData
@@ -411,41 +569,46 @@ class PrismaDriver extends BaseDriver
411
569
 
412
570
  async upsert(params, filters)
413
571
  {
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;
572
+ let preparedData = this.prepareDataWithRelations(params);
573
+ let existing = false;
574
+ if(params.id){
575
+ let castedId = this.castToIdType(params.id);
576
+ existing = await this.loadById(castedId);
577
+ if(existing){
578
+ let patch = Object.assign({}, preparedData);
579
+ delete patch.id;
580
+ try {
423
581
  return await this.model.update({
424
582
  where: {id: castedId},
425
583
  data: patch
426
584
  });
585
+ } catch(error) {
586
+ Logger.error('Upsert update error: '+error.message);
587
+ return false;
427
588
  }
428
589
  }
429
- if(filters){
430
- let existing = await this.loadOne(filters);
431
- if(existing){
590
+ }
591
+ if(filters){
592
+ let existing = await this.loadOne(filters);
593
+ if(existing){
594
+ try {
432
595
  return await this.model.update({
433
- where: {id: this.castIdValue(existing.id)},
596
+ where: {id: this.castToIdType(existing.id)},
434
597
  data: preparedData
435
598
  });
599
+ } catch(error) {
600
+ Logger.error('Upsert update by filter error: '+error.message);
601
+ return false;
436
602
  }
437
603
  }
438
- return await this.create(preparedData);
439
- } catch(error) {
440
- Logger.error('Upsert error: '+error.message);
441
- return false;
442
604
  }
605
+ return await this.create(preparedData);
443
606
  }
444
607
 
445
608
  async delete(filters = {})
446
609
  {
610
+ let processedFilters = this.processFilters(filters);
447
611
  try {
448
- let processedFilters = this.processFilters(filters);
449
612
  return await this.model.deleteMany({
450
613
  where: processedFilters
451
614
  });
@@ -457,12 +620,12 @@ class PrismaDriver extends BaseDriver
457
620
 
458
621
  async deleteById(id)
459
622
  {
623
+ let castedId = this.castToIdType(id);
624
+ let found = await this.loadById(castedId);
625
+ if(!found){
626
+ return false;
627
+ }
460
628
  try {
461
- let castedId = this.castIdValue(id);
462
- let found = await this.loadById(castedId);
463
- if(!found){
464
- return false;
465
- }
466
629
  return await this.model.delete({
467
630
  where: {id: castedId}
468
631
  });
@@ -474,8 +637,8 @@ class PrismaDriver extends BaseDriver
474
637
 
475
638
  async count(filters)
476
639
  {
640
+ let processedFilters = this.processFilters(filters);
477
641
  try {
478
- let processedFilters = this.processFilters(filters);
479
642
  return await this.model.count({
480
643
  where: processedFilters
481
644
  });
@@ -487,14 +650,14 @@ class PrismaDriver extends BaseDriver
487
650
 
488
651
  async countWithRelations(filters, relations)
489
652
  {
653
+ let processedFilters = this.processFilters(filters);
654
+ let query = {
655
+ where: processedFilters
656
+ };
657
+ if(sc.isArray(relations) && 0 < relations.length){
658
+ query.include = this.buildIncludeObject(relations);
659
+ }
490
660
  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
661
  return await this.model.count(query);
499
662
  } catch(error) {
500
663
  Logger.error('Count with relations error: '+error.message);
@@ -514,13 +677,13 @@ class PrismaDriver extends BaseDriver
514
677
 
515
678
  async loadAllWithRelations(relations)
516
679
  {
680
+ let query = this.buildQueryOptions();
681
+ let includeConfig = {};
682
+ if(sc.isArray(relations) && 0 < relations.length){
683
+ includeConfig = this.buildIncludeObject(relations);
684
+ query.include = includeConfig;
685
+ }
517
686
  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
687
  let results = await this.model.findMany(query);
525
688
  return this.transformRelationResults(results, includeConfig);
526
689
  } catch(error) {
@@ -531,10 +694,10 @@ class PrismaDriver extends BaseDriver
531
694
 
532
695
  async load(filters)
533
696
  {
697
+ let processedFilters = this.processFilters(filters);
698
+ let query = this.buildQueryOptions();
699
+ query.where = processedFilters;
534
700
  try {
535
- let processedFilters = this.processFilters(filters);
536
- let query = this.buildQueryOptions();
537
- query.where = processedFilters;
538
701
  return await this.model.findMany(query);
539
702
  } catch(error) {
540
703
  Logger.error('Load error: '+error.message);
@@ -544,15 +707,15 @@ class PrismaDriver extends BaseDriver
544
707
 
545
708
  async loadWithRelations(filters, relations)
546
709
  {
710
+ let processedFilters = this.processFilters(filters);
711
+ let query = this.buildQueryOptions();
712
+ query.where = processedFilters;
713
+ let includeConfig = {};
714
+ if(sc.isArray(relations) && 0 < relations.length){
715
+ includeConfig = this.buildIncludeObject(relations);
716
+ query.include = includeConfig;
717
+ }
547
718
  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
719
  let results = await this.model.findMany(query);
557
720
  return this.transformRelationResults(results, includeConfig);
558
721
  } catch(error) {
@@ -563,10 +726,10 @@ class PrismaDriver extends BaseDriver
563
726
 
564
727
  async loadBy(field, fieldValue, operator = null)
565
728
  {
729
+ let filter = this.createSingleFilter(field, fieldValue, operator);
730
+ let query = this.buildQueryOptions();
731
+ query.where = filter;
566
732
  try {
567
- let filter = this.createSingleFilter(field, fieldValue, operator);
568
- let query = this.buildQueryOptions();
569
- query.where = filter;
570
733
  return await this.model.findMany(query);
571
734
  } catch(error) {
572
735
  Logger.error('Load by error: '+error.message);
@@ -576,15 +739,15 @@ class PrismaDriver extends BaseDriver
576
739
 
577
740
  async loadByWithRelations(field, fieldValue, relations, operator = null)
578
741
  {
742
+ let filter = this.createSingleFilter(field, fieldValue, operator);
743
+ let query = this.buildQueryOptions();
744
+ query.where = filter;
745
+ let includeConfig = {};
746
+ if(sc.isArray(relations) && 0 < relations.length){
747
+ includeConfig = this.buildIncludeObject(relations);
748
+ query.include = includeConfig;
749
+ }
579
750
  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
751
  let results = await this.model.findMany(query);
589
752
  return this.transformRelationResults(results, includeConfig);
590
753
  } catch(error) {
@@ -595,8 +758,8 @@ class PrismaDriver extends BaseDriver
595
758
 
596
759
  async loadById(id)
597
760
  {
761
+ let castedId = this.castToIdType(id);
598
762
  try {
599
- let castedId = this.castIdValue(id);
600
763
  return await this.model.findUnique({
601
764
  where: {id: castedId}
602
765
  });
@@ -608,16 +771,16 @@ class PrismaDriver extends BaseDriver
608
771
 
609
772
  async loadByIdWithRelations(id, relations)
610
773
  {
774
+ let castedId = this.castToIdType(id);
775
+ let query = {
776
+ where: {id: castedId}
777
+ };
778
+ let includeConfig = {};
779
+ if(sc.isArray(relations) && 0 < relations.length){
780
+ includeConfig = this.buildIncludeObject(relations);
781
+ query.include = includeConfig;
782
+ }
611
783
  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
784
  let result = await this.model.findUnique(query);
622
785
  return this.transformRelationResults(result, includeConfig);
623
786
  } catch(error) {
@@ -628,8 +791,8 @@ class PrismaDriver extends BaseDriver
628
791
 
629
792
  async loadByIds(ids)
630
793
  {
794
+ let castedIds = ids.map(id => this.castToIdType(id));
631
795
  try {
632
- let castedIds = ids.map(id => this.castIdValue(id));
633
796
  return await this.model.findMany({
634
797
  where: {
635
798
  id: {in: castedIds}
@@ -643,10 +806,10 @@ class PrismaDriver extends BaseDriver
643
806
 
644
807
  async loadOne(filters)
645
808
  {
809
+ let processedFilters = this.processFilters(filters);
810
+ let query = this.buildQueryOptions(false);
811
+ query.where = processedFilters;
646
812
  try {
647
- let processedFilters = this.processFilters(filters);
648
- let query = this.buildQueryOptions(false);
649
- query.where = processedFilters;
650
813
  return await this.model.findFirst(query);
651
814
  } catch(error) {
652
815
  Logger.error('Load one error: '+error.message);
@@ -656,15 +819,15 @@ class PrismaDriver extends BaseDriver
656
819
 
657
820
  async loadOneWithRelations(filters, relations)
658
821
  {
822
+ let processedFilters = this.processFilters(filters);
823
+ let query = this.buildQueryOptions(false);
824
+ query.where = processedFilters;
825
+ let includeConfig = {};
826
+ if(sc.isArray(relations) && 0 < relations.length){
827
+ includeConfig = this.buildIncludeObject(relations);
828
+ query.include = includeConfig;
829
+ }
659
830
  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
831
  let result = await this.model.findFirst(query);
669
832
  return this.transformRelationResults(result, includeConfig);
670
833
  } catch(error) {
@@ -675,10 +838,10 @@ class PrismaDriver extends BaseDriver
675
838
 
676
839
  async loadOneBy(field, fieldValue, operator = null)
677
840
  {
841
+ let filter = this.createSingleFilter(field, fieldValue, operator);
842
+ let query = this.buildQueryOptions(false);
843
+ query.where = filter;
678
844
  try {
679
- let filter = this.createSingleFilter(field, fieldValue, operator);
680
- let query = this.buildQueryOptions(false);
681
- query.where = filter;
682
845
  return await this.model.findFirst(query);
683
846
  } catch(error) {
684
847
  Logger.error('Load one by error: '+error.message);
@@ -688,15 +851,15 @@ class PrismaDriver extends BaseDriver
688
851
 
689
852
  async loadOneByWithRelations(field, fieldValue, relations, operator = null)
690
853
  {
854
+ let filter = this.createSingleFilter(field, fieldValue, operator);
855
+ let query = this.buildQueryOptions(false);
856
+ query.where = filter;
857
+ let includeConfig = {};
858
+ if(sc.isArray(relations) && 0 < relations.length){
859
+ includeConfig = this.buildIncludeObject(relations);
860
+ query.include = includeConfig;
861
+ }
691
862
  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
863
  let result = await this.model.findFirst(query);
701
864
  return this.transformRelationResults(result, includeConfig);
702
865
  } catch(error) {
@@ -731,23 +894,21 @@ class PrismaDriver extends BaseDriver
731
894
  createSingleFilter(field, fieldValue, operator = null)
732
895
  {
733
896
  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
- }
897
+ let processedValue = this.processFilterValue(fieldValue, field);
741
898
  if(null === operator){
742
899
  filter[field] = processedValue;
743
900
  return filter;
744
901
  }
745
- filter[field] = this.applyOperator(processedValue, operator, field);
746
- return filter;
902
+ filter[field] = {operator, value: processedValue};
903
+ return this.processFilters(filter);
747
904
  }
748
905
 
749
906
  applyOperator(value, operator, fieldName = null)
750
907
  {
908
+ let upperOperator = operator ? operator.toUpperCase() : '';
909
+ if('LIKE' === upperOperator){
910
+ return this.handleLikeOperator(value, fieldName);
911
+ }
751
912
  let operatorsMap = {
752
913
  '=': value,
753
914
  '!=': {not: value},
@@ -755,22 +916,32 @@ class PrismaDriver extends BaseDriver
755
916
  '>=': {gte: value},
756
917
  '<': {lt: value},
757
918
  '<=': {lte: value},
758
- 'LIKE': this.handleLikeOperator(value, fieldName),
759
919
  'IN': {in: value},
760
920
  'NOT IN': {notIn: value}
761
921
  };
762
- return operatorsMap[operator] || value;
922
+ return operatorsMap[upperOperator] || value;
763
923
  }
764
924
 
765
925
  handleLikeOperator(value, fieldName)
766
926
  {
767
- if('id' === fieldName || (this.referenceFields && sc.hasOwn(this.referenceFields, fieldName))){
768
- let numericValue = Number(value.replace(/%/g, ''));
927
+ let cleanValue = String(value).replace(/%/g, '');
928
+ if(this.isJsonFieldByName(fieldName) || this.isJsonField(fieldName)){
929
+ return this.handleJsonTextSearch(cleanValue);
930
+ }
931
+ if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
932
+ let numericValue = Number(cleanValue);
769
933
  if(!isNaN(numericValue)){
770
934
  return numericValue;
771
935
  }
772
936
  }
773
- return {contains: value};
937
+ return {contains: cleanValue};
938
+ }
939
+
940
+ handleJsonTextSearch(searchValue)
941
+ {
942
+ return {
943
+ string_contains: searchValue
944
+ };
774
945
  }
775
946
 
776
947
  buildIncludeObject(relations)