@reldens/storage 0.88.0 → 0.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/.claude/driver-methods-complete-analysis.md +1978 -0
  2. package/.claude/test-architecture.md +973 -0
  3. package/CLAUDE.md +121 -1
  4. package/bin/reldens-storage.js +1 -1
  5. package/lib/base-driver.js +8 -0
  6. package/lib/entities-generator.js +1 -3
  7. package/lib/entity-templates/mikro-orm-model.template +2 -1
  8. package/lib/generators/models-generation.js +126 -5
  9. package/lib/mikro-orm/mikro-orm-data-server.js +24 -10
  10. package/lib/mikro-orm/mikro-orm-driver.js +184 -116
  11. package/lib/objection-js/objection-js-driver.js +111 -19
  12. package/lib/prisma/prisma-data-server.js +3 -2
  13. package/lib/prisma/prisma-driver.js +12 -10
  14. package/lib/prisma/prisma-filter-processor.js +193 -146
  15. package/lib/prisma/prisma-metadata-loader.js +0 -4
  16. package/lib/prisma/prisma-relation-resolver.js +292 -267
  17. package/lib/prisma/prisma-type-caster.js +280 -260
  18. package/package.json +15 -6
  19. package/tests/.env.test.example +7 -0
  20. package/tests/fixtures/categories-fixtures.js +164 -0
  21. package/tests/fixtures/expected-entities-mikro-orm/entities/test-categories-entity.js +70 -0
  22. package/tests/fixtures/expected-entities-mikro-orm/entities/test-products-entity.js +95 -0
  23. package/tests/fixtures/expected-entities-mikro-orm/entities/test-reviews-entity.js +84 -0
  24. package/tests/fixtures/expected-entities-mikro-orm/entities-config.js +17 -0
  25. package/tests/fixtures/expected-entities-mikro-orm/entities-translations.js +13 -0
  26. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/registered-models-mikro-orm.js +23 -0
  27. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-categories-model.js +57 -0
  28. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-products-model.js +79 -0
  29. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-reviews-model.js +70 -0
  30. package/tests/fixtures/expected-entities-objection-js/entities/test-categories-entity.js +70 -0
  31. package/tests/fixtures/expected-entities-objection-js/entities/test-products-entity.js +95 -0
  32. package/tests/fixtures/expected-entities-objection-js/entities/test-reviews-entity.js +84 -0
  33. package/tests/fixtures/expected-entities-objection-js/entities-config.js +17 -0
  34. package/tests/fixtures/expected-entities-objection-js/entities-translations.js +13 -0
  35. package/tests/fixtures/expected-entities-objection-js/models/objection-js/registered-models-objection-js.js +23 -0
  36. package/tests/fixtures/expected-entities-objection-js/models/objection-js/test-categories-model.js +33 -0
  37. package/tests/fixtures/expected-entities-objection-js/models/objection-js/test-products-model.js +42 -0
  38. package/tests/fixtures/expected-entities-objection-js/models/objection-js/test-reviews-model.js +33 -0
  39. package/tests/fixtures/expected-entities-prisma/entities/test-categories-entity.js +70 -0
  40. package/tests/fixtures/expected-entities-prisma/entities/test-products-entity.js +95 -0
  41. package/tests/fixtures/expected-entities-prisma/entities/test-reviews-entity.js +84 -0
  42. package/tests/fixtures/expected-entities-prisma/entities-config.js +17 -0
  43. package/tests/fixtures/expected-entities-prisma/entities-translations.js +13 -0
  44. package/tests/fixtures/expected-entities-prisma/models/prisma/registered-models-prisma.js +23 -0
  45. package/tests/fixtures/expected-entities-prisma/models/prisma/test-categories-model.js +43 -0
  46. package/tests/fixtures/expected-entities-prisma/models/prisma/test-products-model.js +50 -0
  47. package/tests/fixtures/expected-entities-prisma/models/prisma/test-reviews-model.js +46 -0
  48. package/tests/fixtures/products-fixtures.js +119 -0
  49. package/tests/fixtures/reviews-fixtures.js +42 -0
  50. package/tests/fixtures/sql/test-schema.sql +59 -0
  51. package/tests/integration/test-drivers.js +257 -0
  52. package/tests/integration/test-nested-filters.js +408 -0
  53. package/tests/integration/test-relations.js +349 -0
  54. package/tests/run-tests.js +213 -0
  55. package/tests/unit/test-drivers.js +89 -0
  56. package/tests/unit/test-entities-generator.js +533 -0
  57. package/tests/unit/test-entity-manager.js +128 -0
  58. package/tests/unit/test-type-mapper.js +232 -0
  59. package/tests/utils/custom-reporter.js +73 -0
  60. package/tests/utils/driver-registry.js +144 -0
  61. package/tests/utils/prisma-subprocess-worker.js +150 -0
  62. package/tests/utils/test-helpers.js +726 -0
  63. package/tests/utils/test-runner.js +63 -0
@@ -67,14 +67,15 @@ class ObjectionJsDriver extends BaseDriver
67
67
  async upsert(params, filters)
68
68
  {
69
69
  if(params.id){
70
- let patch = Object.assign({}, params);
71
- delete patch.id;
72
- return this.queryBuilder().patchAndFetchById(params.id, patch).onConflict().merge();
70
+ let existent = await this.loadById(params.id);
71
+ if(existent){
72
+ return this.updateById(params.id, params);
73
+ }
73
74
  }
74
75
  if(filters){
75
76
  let existent = await this.loadOne(filters);
76
77
  if(existent){
77
- return this.queryBuilder().patchAndFetchById(existent.id, params).onConflict().merge();
78
+ return this.updateById(existent.id, params);
78
79
  }
79
80
  }
80
81
  return this.create(params);
@@ -103,7 +104,7 @@ class ObjectionJsDriver extends BaseDriver
103
104
  {
104
105
  let queryBuilder = this.queryBuilder(true, true, true);
105
106
  this.appendFilters(queryBuilder, filters);
106
- let count = await this.appendRelationsToQuery(queryBuilder, relations).count().first();
107
+ let count = await this.appendRelationsToQuery(queryBuilder, relations, null, this.containsRelationFilters(filters)).count().first();
107
108
  return count ? count['count(*)'] : 0;
108
109
  }
109
110
 
@@ -128,7 +129,7 @@ class ObjectionJsDriver extends BaseDriver
128
129
  {
129
130
  let queryBuilder = this.queryBuilder(true, true, true);
130
131
  this.appendFilters(queryBuilder, filters);
131
- return this.appendRelationsToQuery(queryBuilder, relations);
132
+ return this.appendRelationsToQuery(queryBuilder, relations, null, this.containsRelationFilters(filters));
132
133
  }
133
134
 
134
135
  loadBy(field, fieldValue, operator = null)
@@ -171,7 +172,12 @@ class ObjectionJsDriver extends BaseDriver
171
172
  {
172
173
  let queryBuilder = this.queryBuilder(false, true, true);
173
174
  this.appendFilters(queryBuilder, filters);
174
- return this.appendRelationsToQuery(queryBuilder, relations).limit(1).first();
175
+ return this.appendRelationsToQuery(
176
+ queryBuilder,
177
+ relations,
178
+ null,
179
+ this.containsRelationFilters(filters)
180
+ ).limit(1).first();
175
181
  }
176
182
 
177
183
  loadOneBy(field, fieldValue, operator = null)
@@ -200,7 +206,7 @@ class ObjectionJsDriver extends BaseDriver
200
206
  if(useOffset && 0 !== this.offset){
201
207
  queryBuilder.offset(this.offset)
202
208
  }
203
- if(useSort && false !== this.sortBy && false !== this.sortDirection){
209
+ if(useSort && this.sortBy && this.sortDirection){
204
210
  queryBuilder.orderBy(this.sortBy, this.sortDirection)
205
211
  }
206
212
  return queryBuilder;
@@ -231,6 +237,45 @@ class ObjectionJsDriver extends BaseDriver
231
237
  queryBuilder.where(field, 'like', '%' + cleanValue + '%');
232
238
  }
233
239
 
240
+ isRelationField(fieldName)
241
+ {
242
+ let relationMappings = sc.get(this.rawModel, 'relationMappings', false);
243
+ if(!relationMappings){
244
+ return false;
245
+ }
246
+ if('function' === typeof relationMappings){
247
+ relationMappings = relationMappings();
248
+ }
249
+ return sc.hasOwn(relationMappings, fieldName);
250
+ }
251
+
252
+ flattenRelationFilters(relationName, nestedFilters)
253
+ {
254
+ let flattened = {};
255
+ for(let key of Object.keys(nestedFilters)){
256
+ let value = nestedFilters[key];
257
+ if('OR' === key && sc.isArray(value)){
258
+ flattened.OR = this.flattenOrConditions(relationName, value);
259
+ continue;
260
+ }
261
+ flattened[relationName+'.'+key] = value;
262
+ }
263
+ return flattened;
264
+ }
265
+
266
+ flattenOrConditions(relationName, conditions)
267
+ {
268
+ let flattenedConditions = [];
269
+ for(let condition of conditions){
270
+ let flatCondition = {};
271
+ for(let condKey of Object.keys(condition)){
272
+ flatCondition[relationName+'.'+condKey] = condition[condKey];
273
+ }
274
+ flattenedConditions.push(flatCondition);
275
+ }
276
+ return flattenedConditions;
277
+ }
278
+
234
279
  appendFilters(queryBuilder, filters = {})
235
280
  {
236
281
  let filtersKeys = Object.keys(filters);
@@ -239,17 +284,25 @@ class ObjectionJsDriver extends BaseDriver
239
284
  }
240
285
  for(let i of filtersKeys){
241
286
  let filter = filters[i];
287
+ if('AND' === i && sc.isArray(filter)){
288
+ for(let condition of filter){
289
+ queryBuilder.where((nestedQb) => {
290
+ this.appendFilters(nestedQb, condition);
291
+ });
292
+ }
293
+ continue;
294
+ }
242
295
  if('OR' === i && sc.isArray(filter)){
243
- queryBuilder.where(function(){
296
+ queryBuilder.where((outerQb) => {
244
297
  for(let condition of filter){
245
- this.orWhere(function(){
246
- this.appendFilters(this, condition);
247
- }.bind(this));
298
+ outerQb.orWhere((innerQb) => {
299
+ this.appendFilters(innerQb, condition);
300
+ });
248
301
  }
249
- }.bind(this));
302
+ });
250
303
  continue;
251
304
  }
252
- let filterOperator = sc.get(filter, 'operator');
305
+ let filterOperator = sc.get(filter, 'operator', '').toUpperCase();
253
306
  if(filterOperator){
254
307
  if('OR' === filterOperator){
255
308
  queryBuilder.orWhere(i, filter.value);
@@ -267,7 +320,13 @@ class ObjectionJsDriver extends BaseDriver
267
320
  this.handleLikeFilter(queryBuilder, i, filter.value);
268
321
  continue;
269
322
  }
270
- queryBuilder.where(i, filter.operator, filter.value);
323
+ let sqlOperator = this.operatorsMap[filterOperator] || filter.operator;
324
+ queryBuilder.where(i, sqlOperator, filter.value);
325
+ continue;
326
+ }
327
+ if(this.isRelationField(i) && sc.isObject(filter) && !sc.isArray(filter)){
328
+ let flattenedFilters = this.flattenRelationFilters(i, filter);
329
+ this.appendFilters(queryBuilder, flattenedFilters);
271
330
  continue;
272
331
  }
273
332
  queryBuilder.where(i, filter);
@@ -275,18 +334,51 @@ class ObjectionJsDriver extends BaseDriver
275
334
  return queryBuilder;
276
335
  }
277
336
 
278
- appendRelationsToQuery(queryBuilder, relations, relationsModifiers)
337
+ containsRelationFilters(filters)
338
+ {
339
+ if(!sc.isObject(filters)){
340
+ return false;
341
+ }
342
+ for(let key of Object.keys(filters)){
343
+ if('AND' === key || 'OR' === key){
344
+ if(sc.isArray(filters[key])){
345
+ for(let condition of filters[key]){
346
+ if(this.containsRelationFilters(condition)){
347
+ return true;
348
+ }
349
+ }
350
+ }
351
+ continue;
352
+ }
353
+ if(this.isRelationField(key)){
354
+ return true;
355
+ }
356
+ }
357
+ return false;
358
+ }
359
+
360
+ appendRelationsToQuery(queryBuilder, relations, relationsModifiers, useJoin = false)
279
361
  {
280
362
  if(!sc.isArray(relations) || 0 === relations.length){
281
363
  relations = Object.keys(this.rawModel.relationMappings || {});
282
364
  }
283
- if(0 < relations.length){
284
- queryBuilder.withGraphFetched('['+relations.join(',')+']');
285
- }
365
+ this.applyGraphMethod(relations, useJoin, queryBuilder);
286
366
  this.appendRelationsModifiers(queryBuilder, relations, relationsModifiers);
287
367
  return queryBuilder;
288
368
  }
289
369
 
370
+ applyGraphMethod(relations, useJoin, queryBuilder)
371
+ {
372
+ if(0 === relations.length){
373
+ return;
374
+ }
375
+ if(useJoin){
376
+ queryBuilder.withGraphJoined('[' + relations.join(',') + ']');
377
+ return;
378
+ }
379
+ queryBuilder.withGraphFetched('[' + relations.join(',') + ']');
380
+ }
381
+
290
382
  appendRelationsModifiers(queryBuilder, relations, relationsModifiers)
291
383
  {
292
384
  if(!sc.isArray(relationsModifiers)){
@@ -7,7 +7,7 @@
7
7
  const { BaseDataServer } = require('../base-data-server');
8
8
  const { PrismaDriver } = require('./prisma-driver');
9
9
  const { MySQLTablesProvider } = require('../mysql-tables-provider');
10
- const { PrismaClient } = require('@prisma/client');
10
+ const { PrismaClient, Prisma } = require('@prisma/client');
11
11
  const { FileHandler } = require('@reldens/server-utils');
12
12
  const { Logger, sc } = require('@reldens/utils');
13
13
 
@@ -91,7 +91,8 @@ class PrismaDataServer extends BaseDataServer
91
91
  prisma: this.prisma,
92
92
  model: prismaModel,
93
93
  server: this,
94
- allRelationMappings: this.allRelationMappings
94
+ allRelationMappings: this.allRelationMappings,
95
+ prismaDbNull: Prisma.DbNull
95
96
  });
96
97
  }
97
98
  this.entityManager.setEntities(this.entities);
@@ -29,6 +29,7 @@ class PrismaDriver extends BaseDriver
29
29
  this.prisma = props.prisma;
30
30
  this.model = props.model;
31
31
  this.allRelationMappings = sc.get(props, 'allRelationMappings', {});
32
+ this.prismaDbNull = sc.get(props, 'prismaDbNull', null);
32
33
  this.initHelpers();
33
34
  this.initModelMetadata();
34
35
  }
@@ -46,7 +47,8 @@ class PrismaDriver extends BaseDriver
46
47
  fieldDefaults: {},
47
48
  requiredFields: [],
48
49
  optionalFields: [],
49
- rawModel: this.rawModel
50
+ rawModel: this.rawModel,
51
+ prismaDbNull: this.prismaDbNull
50
52
  });
51
53
  this.relationResolver = new PrismaRelationResolver({
52
54
  relationMetadata: {},
@@ -60,7 +62,9 @@ class PrismaDriver extends BaseDriver
60
62
  typeCaster: this.typeCaster,
61
63
  fieldTypes: {},
62
64
  referenceFields: {},
63
- jsonFields: new Set()
65
+ jsonFields: new Set(),
66
+ operatorsMap: this.operatorsMap,
67
+ relationResolver: this.relationResolver
64
68
  });
65
69
  this.queryBuilder = new PrismaQueryBuilder();
66
70
  }
@@ -237,6 +241,11 @@ class PrismaDriver extends BaseDriver
237
241
  relations = this.getAllRelations();
238
242
  }
239
243
  let preparedData = this.prepareData(params);
244
+ for(let relation of relations){
245
+ if(sc.hasOwn(preparedData, relation)){
246
+ delete preparedData[relation];
247
+ }
248
+ }
240
249
  this.ensureRequiredFields(preparedData);
241
250
  let createData = {data: preparedData};
242
251
  if(0 < relations.length){
@@ -367,16 +376,9 @@ class PrismaDriver extends BaseDriver
367
376
 
368
377
  async countWithRelations(filters, relations)
369
378
  {
370
- if(!sc.isArray(relations) || 0 === relations.length){
371
- relations = this.getAllRelations();
372
- }
373
379
  let processedFilters = this.filterProcessor.processFilters(filters);
374
- let query = {where: processedFilters};
375
- if(0 < relations.length){
376
- query.include = this.relationResolver.buildIncludeObjectWithMapping(relations).include;
377
- }
378
380
  return this.executeWithNormalization(
379
- () => this.model.count(query),
381
+ () => this.model.count({where: processedFilters}),
380
382
  'Count with relations error: ',
381
383
  0
382
384
  );
@@ -1,146 +1,193 @@
1
- /**
2
- *
3
- * Reldens - PrismaFilterProcessor
4
- *
5
- */
6
-
7
- const { sc } = require('@reldens/utils');
8
-
9
- class PrismaFilterProcessor
10
- {
11
-
12
- constructor(props)
13
- {
14
- this.typeCaster = sc.get(props, 'typeCaster', null);
15
- this.fieldTypes = sc.get(props, 'fieldTypes', {});
16
- this.referenceFields = sc.get(props, 'referenceFields', {});
17
- this.jsonFields = sc.get(props, 'jsonFields', new Set());
18
- }
19
-
20
- updateMetadata(metadata)
21
- {
22
- this.fieldTypes = sc.get(metadata, 'fieldTypes', this.fieldTypes);
23
- this.referenceFields = sc.get(metadata, 'referenceFields', this.referenceFields);
24
- this.jsonFields = sc.get(metadata, 'jsonFields', this.jsonFields);
25
- }
26
-
27
- processFilters(filters)
28
- {
29
- if(!sc.isObject(filters)){
30
- return filters;
31
- }
32
- let processedFilters = {};
33
- for(let key of Object.keys(filters)){
34
- let value = filters[key];
35
- if('OR' === key && sc.isArray(value)){
36
- processedFilters.OR = value.map(condition => this.processFilters(condition));
37
- continue;
38
- }
39
- if(sc.hasOwn(value, 'operator') && sc.hasOwn(value, 'value')){
40
- let operatorValue = this.processFilterValue(value.value, key);
41
- processedFilters[key] = this.applyOperator(operatorValue, value.operator, key);
42
- continue;
43
- }
44
- if(sc.isObject(value) && !sc.isArray(value)){
45
- processedFilters[key] = this.processFilters(value);
46
- continue;
47
- }
48
- processedFilters[key] = this.processFilterValue(value, key);
49
- }
50
- return processedFilters;
51
- }
52
-
53
- processFilterValue(value, key)
54
- {
55
- if(sc.isArray(value)){
56
- if('id' === key){
57
- return value.map(id => this.typeCaster.castToIdType(id)).filter(id => null !== id);
58
- }
59
- let fieldType = this.fieldTypes[key];
60
- if(fieldType){
61
- return value.map(val => this.typeCaster.castValue(val, fieldType, key))
62
- .filter(val => this.typeCaster.isValidCastedValue(val));
63
- }
64
- return value;
65
- }
66
- if('id' === key){
67
- return this.typeCaster.castToIdType(value);
68
- }
69
- let fieldType = this.fieldTypes[key];
70
- if(!fieldType){
71
- return value;
72
- }
73
- let castedValue = this.typeCaster.castValue(value, fieldType, key);
74
- if(this.typeCaster.isValidCastedValue(castedValue)){
75
- return castedValue;
76
- }
77
- return value;
78
- }
79
-
80
- applyOperator(value, operator, fieldName = null)
81
- {
82
- let upperOperator = operator ? operator.toUpperCase() : '';
83
- if('LIKE' === upperOperator){
84
- return this.handleLikeOperator(value, fieldName);
85
- }
86
- let operatorsMap = {
87
- '=': value,
88
- '!=': {not: value},
89
- '>': {gt: value},
90
- '>=': {gte: value},
91
- '<': {lt: value},
92
- '<=': {lte: value},
93
- 'IN': {in: value},
94
- 'NOT IN': {notIn: value}
95
- };
96
- return operatorsMap[upperOperator] || value;
97
- }
98
-
99
- handleLikeOperator(value, fieldName)
100
- {
101
- let cleanValue = String(value).replace(/%/g, '');
102
- if(this.isJsonField(fieldName)){
103
- return this.handleJsonTextSearch(cleanValue);
104
- }
105
- if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
106
- let numericValue = Number(cleanValue);
107
- if(!isNaN(numericValue)){
108
- return numericValue;
109
- }
110
- }
111
- return {contains: cleanValue};
112
- }
113
-
114
- handleJsonTextSearch(searchValue)
115
- {
116
- return {
117
- string_contains: searchValue
118
- };
119
- }
120
-
121
- isJsonField(fieldName)
122
- {
123
- if(!this.jsonFields){
124
- return false;
125
- }
126
- if(this.jsonFields.has(fieldName)){
127
- return true;
128
- }
129
- return this.typeCaster && this.typeCaster.isJsonFieldByName(fieldName);
130
- }
131
-
132
- createSingleFilter(field, fieldValue, operator = null)
133
- {
134
- let filter = {};
135
- let processedValue = this.processFilterValue(fieldValue, field);
136
- if(null === operator){
137
- filter[field] = processedValue;
138
- return filter;
139
- }
140
- filter[field] = {operator, value: processedValue};
141
- return this.processFilters(filter);
142
- }
143
-
144
- }
145
-
146
- module.exports.PrismaFilterProcessor = PrismaFilterProcessor;
1
+ /**
2
+ *
3
+ * Reldens - PrismaFilterProcessor
4
+ *
5
+ */
6
+
7
+ const { sc } = require('@reldens/utils');
8
+
9
+ class PrismaFilterProcessor
10
+ {
11
+
12
+ constructor(props)
13
+ {
14
+ this.typeCaster = sc.get(props, 'typeCaster', null);
15
+ this.fieldTypes = sc.get(props, 'fieldTypes', {});
16
+ this.referenceFields = sc.get(props, 'referenceFields', {});
17
+ this.jsonFields = sc.get(props, 'jsonFields', new Set());
18
+ this.operatorsMap = sc.get(props, 'operatorsMap', {});
19
+ this.relationResolver = sc.get(props, 'relationResolver', null);
20
+ }
21
+
22
+ updateMetadata(metadata)
23
+ {
24
+ this.fieldTypes = sc.get(metadata, 'fieldTypes', this.fieldTypes);
25
+ this.referenceFields = sc.get(metadata, 'referenceFields', this.referenceFields);
26
+ this.jsonFields = sc.get(metadata, 'jsonFields', this.jsonFields);
27
+ this.relationResolver = sc.get(metadata, 'relationResolver', this.relationResolver);
28
+ }
29
+
30
+ processFilters(filters)
31
+ {
32
+ if(!sc.isObject(filters)){
33
+ return filters;
34
+ }
35
+ let processedFilters = {};
36
+ for(let key of Object.keys(filters)){
37
+ let value = filters[key];
38
+ if('AND' === key && sc.isArray(value)){
39
+ processedFilters.AND = value.map(condition => this.processFilters(condition));
40
+ continue;
41
+ }
42
+ if('OR' === key && sc.isArray(value)){
43
+ processedFilters.OR = value.map(condition => this.processFilters(condition));
44
+ continue;
45
+ }
46
+ let translatedKey = this.translateRelationKey(key);
47
+ if(sc.hasOwn(value, 'operator') && sc.hasOwn(value, 'value')){
48
+ let operatorValue = this.processFilterValue(value.value, translatedKey);
49
+ processedFilters[translatedKey] = this.applyOperator(operatorValue, value.operator, translatedKey);
50
+ continue;
51
+ }
52
+ if(sc.isObject(value) && !sc.isArray(value)){
53
+ if(this.isRelationKey(key)){
54
+ processedFilters[translatedKey] = {
55
+ some: this.processFilters(value)
56
+ };
57
+ continue;
58
+ }
59
+ processedFilters[translatedKey] = this.processFilters(value);
60
+ continue;
61
+ }
62
+ processedFilters[translatedKey] = this.processFilterValue(value, translatedKey);
63
+ }
64
+ return processedFilters;
65
+ }
66
+
67
+ processFilterValue(value, key)
68
+ {
69
+ if(sc.isArray(value)){
70
+ if('id' === key){
71
+ return value.map(id => this.typeCaster.castToIdType(id)).filter(id => null !== id);
72
+ }
73
+ let fieldType = this.fieldTypes[key];
74
+ if(fieldType){
75
+ return value.map(val => this.typeCaster.castValue(val, fieldType, key))
76
+ .filter(val => this.typeCaster.isValidCastedValue(val));
77
+ }
78
+ return value;
79
+ }
80
+ if('id' === key){
81
+ return this.typeCaster.castToIdType(value);
82
+ }
83
+ let fieldType = this.fieldTypes[key];
84
+ if(!fieldType){
85
+ return value;
86
+ }
87
+ let castedValue = this.typeCaster.castValue(value, fieldType, key);
88
+ if(this.typeCaster.isValidCastedValue(castedValue)){
89
+ return castedValue;
90
+ }
91
+ return value;
92
+ }
93
+
94
+ applyOperator(value, operator, fieldName = null)
95
+ {
96
+ let upperOperator = operator ? operator.toUpperCase() : '';
97
+ if('LIKE' === upperOperator){
98
+ return this.handleLikeOperator(value, fieldName);
99
+ }
100
+ if('IN' === upperOperator){
101
+ return {in: value};
102
+ }
103
+ if('NOT IN' === upperOperator){
104
+ return {notIn: value};
105
+ }
106
+ if('NOT' === upperOperator){
107
+ return {not: value};
108
+ }
109
+ let sqlOperator = this.operatorsMap[upperOperator] || upperOperator;
110
+ let prismaSyntaxMap = {
111
+ '=': value,
112
+ '!=': {not: value},
113
+ '>': {gt: value},
114
+ '>=': {gte: value},
115
+ '<': {lt: value},
116
+ '<=': {lte: value}
117
+ };
118
+ return prismaSyntaxMap[sqlOperator] || value;
119
+ }
120
+
121
+ handleLikeOperator(value, fieldName)
122
+ {
123
+ let cleanValue = String(value).replace(/%/g, '');
124
+ if(this.isJsonField(fieldName)){
125
+ return this.handleJsonTextSearch(cleanValue);
126
+ }
127
+ if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
128
+ let numericValue = Number(cleanValue);
129
+ if(!isNaN(numericValue)){
130
+ return numericValue;
131
+ }
132
+ }
133
+ return {contains: cleanValue};
134
+ }
135
+
136
+ handleJsonTextSearch(searchValue)
137
+ {
138
+ return {
139
+ string_contains: searchValue
140
+ };
141
+ }
142
+
143
+ isJsonField(fieldName)
144
+ {
145
+ if(!this.jsonFields){
146
+ return false;
147
+ }
148
+ if(this.jsonFields.has(fieldName)){
149
+ return true;
150
+ }
151
+ return this.typeCaster && this.typeCaster.isJsonFieldByName(fieldName);
152
+ }
153
+
154
+ createSingleFilter(field, fieldValue, operator = null)
155
+ {
156
+ let filter = {};
157
+ let processedValue = this.processFilterValue(fieldValue, field);
158
+ if(null === operator){
159
+ filter[field] = processedValue;
160
+ return filter;
161
+ }
162
+ filter[field] = {operator, value: processedValue};
163
+ return this.processFilters(filter);
164
+ }
165
+
166
+ translateRelationKey(key)
167
+ {
168
+ if(!this.relationResolver){
169
+ return key;
170
+ }
171
+ let prismaName = this.relationResolver.mapToPrismaName(key, null);
172
+ if(prismaName){
173
+ return prismaName;
174
+ }
175
+ return key;
176
+ }
177
+
178
+ isRelationKey(key)
179
+ {
180
+ if(!this.relationResolver){
181
+ return false;
182
+ }
183
+ let prismaName = this.relationResolver.mapToPrismaName(key, null);
184
+ if(prismaName && prismaName !== key){
185
+ return true;
186
+ }
187
+ let relationMetadata = sc.get(this.relationResolver, 'relationMetadata', {});
188
+ return sc.hasOwn(relationMetadata, key);
189
+ }
190
+
191
+ }
192
+
193
+ module.exports.PrismaFilterProcessor = PrismaFilterProcessor;
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  const { Logger, sc } = require('@reldens/utils');
8
- const { Prisma } = require('@prisma/client');
9
8
 
10
9
  class PrismaMetadataLoader
11
10
  {
@@ -28,9 +27,6 @@ class PrismaMetadataLoader
28
27
  if(this.prisma._runtimeDataModel){
29
28
  return this.prisma._runtimeDataModel;
30
29
  }
31
- if(Prisma.dmmf && Prisma.dmmf.datamodel){
32
- return Prisma.dmmf.datamodel;
33
- }
34
30
  return null;
35
31
  } catch(error) {
36
32
  Logger.warning('Failed to access DMMF: '+error.message);