@reldens/storage 0.80.0 → 0.82.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.
- package/CLAUDE.md +125 -3
- package/bin/reldens-storage.js +63 -8
- package/lib/entities-generator.js +5 -4
- package/lib/generators/models-generation.js +161 -8
- package/lib/prisma/prisma-data-server.js +38 -4
- package/lib/prisma/prisma-driver.js +277 -735
- package/lib/prisma/prisma-filter-processor.js +146 -0
- package/lib/prisma/prisma-metadata-loader.js +133 -0
- package/lib/prisma/prisma-query-builder.js +42 -0
- package/lib/prisma/prisma-relation-resolver.js +267 -0
- package/lib/prisma/prisma-schema-generator.js +40 -33
- package/lib/prisma/prisma-type-caster.js +260 -0
- package/package.json +1 -1
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { BaseDriver } = require('../base-driver');
|
|
8
|
+
const { PrismaTypeCaster } = require('./prisma-type-caster');
|
|
9
|
+
const { PrismaMetadataLoader } = require('./prisma-metadata-loader');
|
|
10
|
+
const { PrismaRelationResolver } = require('./prisma-relation-resolver');
|
|
11
|
+
const { PrismaFilterProcessor } = require('./prisma-filter-processor');
|
|
12
|
+
const { PrismaQueryBuilder } = require('./prisma-query-builder');
|
|
8
13
|
const { Logger, sc } = require('@reldens/utils');
|
|
9
|
-
const { Prisma } = require('@prisma/client');
|
|
10
14
|
|
|
11
15
|
class PrismaDriver extends BaseDriver
|
|
12
16
|
{
|
|
@@ -24,325 +28,80 @@ class PrismaDriver extends BaseDriver
|
|
|
24
28
|
}
|
|
25
29
|
this.prisma = props.prisma;
|
|
26
30
|
this.model = props.model;
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
-
this.fieldTypes = {};
|
|
30
|
-
this.fieldDefaults = {};
|
|
31
|
-
this.idFieldType = 'String';
|
|
32
|
-
this.referenceFields = {};
|
|
33
|
-
this.relationMetadata = {};
|
|
34
|
-
this.foreignKeyMappings = {};
|
|
35
|
-
this.jsonFields = new Set();
|
|
31
|
+
this.allRelationMappings = sc.get(props, 'allRelationMappings', {});
|
|
32
|
+
this.initHelpers();
|
|
36
33
|
this.initModelMetadata();
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
36
|
+
initHelpers()
|
|
37
|
+
{
|
|
38
|
+
this.metadataLoader = new PrismaMetadataLoader({
|
|
39
|
+
prisma: this.prisma,
|
|
40
|
+
rawModel: this.rawModel
|
|
41
|
+
});
|
|
42
|
+
this.typeCaster = new PrismaTypeCaster({
|
|
43
|
+
idFieldType: 'String',
|
|
44
|
+
jsonFields: new Set(),
|
|
45
|
+
fieldTypes: {},
|
|
46
|
+
fieldDefaults: {},
|
|
47
|
+
requiredFields: [],
|
|
48
|
+
optionalFields: [],
|
|
49
|
+
rawModel: this.rawModel
|
|
50
|
+
});
|
|
51
|
+
this.relationResolver = new PrismaRelationResolver({
|
|
52
|
+
relationMetadata: {},
|
|
53
|
+
metadataLoader: this.metadataLoader,
|
|
54
|
+
allRelationMappings: this.allRelationMappings,
|
|
55
|
+
foreignKeyMappings: {},
|
|
56
|
+
foreignKeyTargetFields: {},
|
|
57
|
+
typeCaster: this.typeCaster
|
|
58
|
+
});
|
|
59
|
+
this.filterProcessor = new PrismaFilterProcessor({
|
|
60
|
+
typeCaster: this.typeCaster,
|
|
61
|
+
fieldTypes: {},
|
|
62
|
+
referenceFields: {},
|
|
63
|
+
jsonFields: new Set()
|
|
64
|
+
});
|
|
65
|
+
this.queryBuilder = new PrismaQueryBuilder();
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
try {
|
|
67
|
-
if(this.prisma._dmmf){
|
|
68
|
-
return this.prisma._dmmf.datamodel;
|
|
69
|
-
}
|
|
70
|
-
if(this.prisma._getDmmf && sc.isFunction(this.prisma._getDmmf)){
|
|
71
|
-
return this.prisma._getDmmf().datamodel;
|
|
72
|
-
}
|
|
73
|
-
if(this.prisma._runtimeDataModel){
|
|
74
|
-
return this.prisma._runtimeDataModel;
|
|
75
|
-
}
|
|
76
|
-
if(Prisma.dmmf && Prisma.dmmf.datamodel){
|
|
77
|
-
return Prisma.dmmf.datamodel;
|
|
78
|
-
}
|
|
79
|
-
return null;
|
|
80
|
-
} catch(error) {
|
|
81
|
-
Logger.warning('Failed to access DMMF: '+error.message);
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
processFieldMetadata(field)
|
|
87
|
-
{
|
|
88
|
-
this.fieldTypes[field.name] = field.type;
|
|
89
|
-
if('Json' === field.type){
|
|
90
|
-
this.jsonFields.add(field.name);
|
|
91
|
-
}
|
|
92
|
-
if(field.isId){
|
|
93
|
-
this.idFieldType = field.type;
|
|
94
|
-
}
|
|
95
|
-
if(field.hasDefaultValue){
|
|
96
|
-
this.fieldDefaults[field.name] = field.default;
|
|
97
|
-
}
|
|
98
|
-
if(field.isRequired && !field.hasDefaultValue && !field.isId && 'object' !== field.kind){
|
|
99
|
-
this.requiredFields.push(field.name);
|
|
100
|
-
}
|
|
101
|
-
if(field.isOptional || field.hasDefaultValue){
|
|
102
|
-
this.optionalFields.push(field.name);
|
|
103
|
-
}
|
|
104
|
-
if(field.kind === 'scalar' && field.isList === false){
|
|
105
|
-
let isNumericType = this.isNumericFieldType(field.type);
|
|
106
|
-
let isReferenceField = field.relationFromFields && 0 < field.relationFromFields.length;
|
|
107
|
-
if(isNumericType || isReferenceField){
|
|
108
|
-
this.referenceFields[field.name] = field.type;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if('object' === field.kind){
|
|
112
|
-
let relationType = field.isList ? 'many' : 'one';
|
|
113
|
-
this.relationMetadata[field.name] = {
|
|
114
|
-
type: relationType,
|
|
115
|
-
model: field.type,
|
|
116
|
-
isList: field.isList,
|
|
117
|
-
isOptional: field.isOptional
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
if('object' === field.kind && sc.hasOwn(field, 'relationFromFields') && sc.isArray(field.relationFromFields)){
|
|
121
|
-
for(let foreignKeyField of field.relationFromFields){
|
|
122
|
-
this.foreignKeyMappings[foreignKeyField] = field.name;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
getAllRelations()
|
|
128
|
-
{
|
|
129
|
-
return Object.keys(this.relationMetadata || {});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
normalizeRelationName(relationName)
|
|
133
|
-
{
|
|
134
|
-
if(sc.hasOwn(this.relationMetadata, relationName)){
|
|
135
|
-
return relationName;
|
|
136
|
-
}
|
|
137
|
-
if(relationName.startsWith('related_')){
|
|
138
|
-
let withoutPrefix = relationName.substring(8);
|
|
139
|
-
if(sc.hasOwn(this.relationMetadata, withoutPrefix)){
|
|
140
|
-
return withoutPrefix;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
let availableRelations = Object.keys(this.relationMetadata);
|
|
144
|
-
for(let availableRelation of availableRelations){
|
|
145
|
-
if(relationName.endsWith(availableRelation)){
|
|
146
|
-
return availableRelation;
|
|
147
|
-
}
|
|
148
|
-
if(availableRelation.endsWith(relationName.replace('related_', ''))){
|
|
149
|
-
return availableRelation;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return relationName;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
isNumericFieldType(fieldType)
|
|
156
|
-
{
|
|
157
|
-
return ('Int' === fieldType || 'BigInt' === fieldType || 'Float' === fieldType || 'Decimal' === fieldType);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
isBooleanFieldType(fieldType)
|
|
161
|
-
{
|
|
162
|
-
return 'Boolean' === fieldType;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
isDateTimeFieldType(fieldType)
|
|
166
|
-
{
|
|
167
|
-
return 'DateTime' === fieldType || 'Date' === fieldType;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
isJsonFieldType(fieldType)
|
|
171
|
-
{
|
|
172
|
-
return 'Json' === fieldType;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
isJsonFieldByName(fieldName)
|
|
176
|
-
{
|
|
177
|
-
if(this.jsonFields.has(fieldName)){
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
if(!this.rawModel || !this.rawModel.properties){
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
return 'json' === sc.get(this.rawModel.properties[fieldName], 'dbType', '');
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
isStringFieldType(fieldType)
|
|
187
|
-
{
|
|
188
|
-
return 'String' === fieldType;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
castValue(value, fieldType, fieldName = null)
|
|
192
|
-
{
|
|
193
|
-
if('id' === fieldName){
|
|
194
|
-
return this.castToIdType(value);
|
|
195
|
-
}
|
|
196
|
-
if(this.isNullOrEmpty(value)){
|
|
197
|
-
if(sc.hasOwn(this.fieldDefaults, fieldName)){
|
|
198
|
-
return undefined;
|
|
199
|
-
}
|
|
200
|
-
if(-1 !== this.optionalFields.indexOf(fieldName)){
|
|
201
|
-
return null;
|
|
202
|
-
}
|
|
203
|
-
if(-1 !== this.requiredFields.indexOf(fieldName)){
|
|
204
|
-
Logger.warning('Required field '+fieldName+' cannot be null or empty');
|
|
205
|
-
return undefined;
|
|
206
|
-
}
|
|
207
|
-
return null;
|
|
208
|
-
}
|
|
209
|
-
if(this.isJsonFieldByName(fieldName)){
|
|
210
|
-
return this.castToJsonType(value);
|
|
211
|
-
}
|
|
212
|
-
if(this.isNumericFieldType(fieldType)){
|
|
213
|
-
return this.castToNumericType(value, fieldType);
|
|
214
|
-
}
|
|
215
|
-
if(this.isBooleanFieldType(fieldType)){
|
|
216
|
-
return this.castToBooleanType(value);
|
|
217
|
-
}
|
|
218
|
-
if(this.isDateTimeFieldType(fieldType)){
|
|
219
|
-
return this.castToDateType(value);
|
|
220
|
-
}
|
|
221
|
-
if(this.isStringFieldType(fieldType)){
|
|
222
|
-
return this.castToStringType(value);
|
|
223
|
-
}
|
|
224
|
-
return value;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
isNullOrEmpty(value)
|
|
228
|
-
{
|
|
229
|
-
return null === value || undefined === value || '' === value;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
castToIdType(value)
|
|
233
|
-
{
|
|
234
|
-
if(this.isNullOrEmpty(value)){
|
|
235
|
-
return value;
|
|
236
|
-
}
|
|
237
|
-
if(this.isNumericFieldType(this.idFieldType)){
|
|
238
|
-
let numeric = Number(value);
|
|
239
|
-
if(!isNaN(numeric)){
|
|
240
|
-
return ('Int' === this.idFieldType || 'BigInt' === this.idFieldType) ? Math.floor(numeric) : numeric;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return String(value);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
castToNumericType(value, fieldType)
|
|
247
|
-
{
|
|
248
|
-
if(this.isNullOrEmpty(value)){
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
let numericValue = Number(value);
|
|
252
|
-
if(isNaN(numericValue)){
|
|
253
|
-
Logger.warning('Cannot convert value to numeric: '+value);
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
if('Int' === fieldType || 'BigInt' === fieldType){
|
|
257
|
-
return Math.floor(numericValue);
|
|
258
|
-
}
|
|
259
|
-
return numericValue;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
castToBooleanType(value)
|
|
263
|
-
{
|
|
264
|
-
if(this.isNullOrEmpty(value)){
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
if('boolean' === typeof value){
|
|
268
|
-
return value;
|
|
269
|
-
}
|
|
270
|
-
if('number' === typeof value){
|
|
271
|
-
return 0 !== value;
|
|
272
|
-
}
|
|
273
|
-
if('string' === typeof value){
|
|
274
|
-
let lowerValue = value.toLowerCase();
|
|
275
|
-
if('true' === lowerValue || '1' === lowerValue || 'yes' === lowerValue){
|
|
276
|
-
return true;
|
|
277
|
-
}
|
|
278
|
-
if('false' === lowerValue || '0' === lowerValue || 'no' === lowerValue){
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return Boolean(value);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
castToDateType(dateValue)
|
|
286
|
-
{
|
|
287
|
-
if(dateValue instanceof Date){
|
|
288
|
-
return dateValue;
|
|
289
|
-
}
|
|
290
|
-
if(this.isNullOrEmpty(dateValue)){
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
let dateString = String(dateValue);
|
|
294
|
-
if(dateString.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/)){
|
|
295
|
-
return new Date(dateString.replace(' ', 'T') + 'Z');
|
|
296
|
-
}
|
|
297
|
-
if(dateString.match(/^\d{4}-\d{2}-\d{2}$/)){
|
|
298
|
-
return new Date(dateString + 'T00:00:00Z');
|
|
299
|
-
}
|
|
300
|
-
try {
|
|
301
|
-
let parsedDate = new Date(dateString);
|
|
302
|
-
if(isNaN(parsedDate.getTime())){
|
|
303
|
-
Logger.warning('Invalid date value: '+dateString);
|
|
304
|
-
return null;
|
|
305
|
-
}
|
|
306
|
-
return parsedDate;
|
|
307
|
-
} catch(error) {
|
|
308
|
-
Logger.warning('Failed to convert date value: '+dateString);
|
|
309
|
-
return null;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
castToJsonType(value)
|
|
314
|
-
{
|
|
315
|
-
if(this.isNullOrEmpty(value)){
|
|
316
|
-
return Prisma.DbNull;
|
|
317
|
-
}
|
|
318
|
-
if('object' === typeof value){
|
|
319
|
-
return value;
|
|
320
|
-
}
|
|
321
|
-
if('string' === typeof value){
|
|
322
|
-
if(value.startsWith('%') && value.endsWith('%')){
|
|
323
|
-
return value;
|
|
324
|
-
}
|
|
325
|
-
try {
|
|
326
|
-
return JSON.parse(value);
|
|
327
|
-
} catch(error) {
|
|
328
|
-
return value;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return value;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
castToStringType(value)
|
|
68
|
+
initModelMetadata()
|
|
335
69
|
{
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if('string' === typeof value){
|
|
340
|
-
if('null' === value){
|
|
341
|
-
return null;
|
|
342
|
-
}
|
|
343
|
-
return value;
|
|
70
|
+
let metadata = this.metadataLoader.loadModelMetadata(this.tableName());
|
|
71
|
+
if(!metadata){
|
|
72
|
+
return;
|
|
344
73
|
}
|
|
345
|
-
|
|
74
|
+
this.requiredFields = metadata.requiredFields;
|
|
75
|
+
this.optionalFields = metadata.optionalFields;
|
|
76
|
+
this.fieldTypes = metadata.fieldTypes;
|
|
77
|
+
this.fieldDefaults = metadata.fieldDefaults;
|
|
78
|
+
this.idFieldType = metadata.idFieldType;
|
|
79
|
+
this.idFieldName = sc.get(metadata, 'idFieldName', 'id');
|
|
80
|
+
this.referenceFields = metadata.referenceFields;
|
|
81
|
+
this.relationMetadata = metadata.relationMetadata;
|
|
82
|
+
this.foreignKeyMappings = metadata.foreignKeyMappings;
|
|
83
|
+
this.foreignKeyTargetFields = sc.get(metadata, 'foreignKeyTargetFields', {});
|
|
84
|
+
this.jsonFields = metadata.jsonFields;
|
|
85
|
+
this.typeCaster.updateMetadata({
|
|
86
|
+
idFieldType: this.idFieldType,
|
|
87
|
+
jsonFields: this.jsonFields,
|
|
88
|
+
fieldTypes: this.fieldTypes,
|
|
89
|
+
fieldDefaults: this.fieldDefaults,
|
|
90
|
+
requiredFields: this.requiredFields,
|
|
91
|
+
optionalFields: this.optionalFields
|
|
92
|
+
});
|
|
93
|
+
this.relationResolver.updateMetadata({
|
|
94
|
+
relationMetadata: this.relationMetadata,
|
|
95
|
+
foreignKeyMappings: this.foreignKeyMappings,
|
|
96
|
+
foreignKeyTargetFields: this.foreignKeyTargetFields
|
|
97
|
+
});
|
|
98
|
+
this.filterProcessor.updateMetadata({
|
|
99
|
+
fieldTypes: this.fieldTypes,
|
|
100
|
+
referenceFields: this.referenceFields,
|
|
101
|
+
jsonFields: this.jsonFields
|
|
102
|
+
});
|
|
103
|
+
let currentModelMappings = sc.get(this.allRelationMappings, this.tableName(), {});
|
|
104
|
+
this.relationResolver.setCurrentModelMappings(currentModelMappings);
|
|
346
105
|
}
|
|
347
106
|
|
|
348
107
|
databaseName()
|
|
@@ -370,178 +129,103 @@ class PrismaDriver extends BaseDriver
|
|
|
370
129
|
return this.rawModel[propertyName] || null;
|
|
371
130
|
}
|
|
372
131
|
|
|
373
|
-
|
|
132
|
+
getAllRelations()
|
|
374
133
|
{
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
134
|
+
return this.relationResolver.getAllRelations();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
getQueryOptions()
|
|
138
|
+
{
|
|
139
|
+
return {
|
|
140
|
+
select: this.select,
|
|
141
|
+
limit: this.limit,
|
|
142
|
+
offset: this.offset,
|
|
143
|
+
sortBy: this.sortBy,
|
|
144
|
+
sortDirection: this.sortDirection
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
prepareData(params, options = {})
|
|
149
|
+
{
|
|
150
|
+
let skipObjects = sc.get(options, 'skipObjects', false);
|
|
151
|
+
let convertRelations = sc.get(options, 'convertRelations', false);
|
|
152
|
+
let isCreate = sc.get(options, 'isCreate', false);
|
|
153
|
+
if(convertRelations){
|
|
154
|
+
let converted = this.relationResolver.convertForeignKeysToRelations(params, isCreate);
|
|
155
|
+
return this.castDataFields(converted, skipObjects);
|
|
386
156
|
}
|
|
387
|
-
return
|
|
157
|
+
return this.castDataFields(params, skipObjects);
|
|
388
158
|
}
|
|
389
159
|
|
|
390
|
-
|
|
160
|
+
castDataFields(params, skipObjects = false)
|
|
391
161
|
{
|
|
392
162
|
let data = {};
|
|
393
|
-
let relations = {};
|
|
394
163
|
for(let key of Object.keys(params)){
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
let value = params[key];
|
|
398
|
-
if(!this.isNullOrEmpty(value)){
|
|
399
|
-
relations[relationName] = {
|
|
400
|
-
connect: {id: this.castToIdType(value)}
|
|
401
|
-
};
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
if(!isCreate){
|
|
405
|
-
relations[relationName] = {
|
|
406
|
-
disconnect: true
|
|
407
|
-
};
|
|
408
|
-
}
|
|
164
|
+
let value = params[key];
|
|
165
|
+
if(skipObjects && sc.isObject(value) && !sc.isArray(value)){
|
|
409
166
|
continue;
|
|
410
167
|
}
|
|
411
168
|
let fieldType = this.fieldTypes[key];
|
|
412
169
|
if(!fieldType){
|
|
413
|
-
if(!this.isNullOrEmpty(
|
|
414
|
-
data[key] =
|
|
170
|
+
if(!skipObjects && !this.typeCaster.isNullOrEmpty(value)){
|
|
171
|
+
data[key] = value;
|
|
415
172
|
}
|
|
416
173
|
continue;
|
|
417
174
|
}
|
|
418
|
-
let castedValue = this.castValue(
|
|
419
|
-
if(
|
|
420
|
-
if(this.isJsonFieldType(fieldType) && null === castedValue){
|
|
175
|
+
let castedValue = this.typeCaster.castValue(value, fieldType, key);
|
|
176
|
+
if(this.typeCaster.isValidCastedValue(castedValue)){
|
|
177
|
+
if(this.typeCaster.isJsonFieldType(fieldType) && null === castedValue && !skipObjects){
|
|
421
178
|
continue;
|
|
422
179
|
}
|
|
423
180
|
data[key] = castedValue;
|
|
424
181
|
}
|
|
425
182
|
}
|
|
426
|
-
return
|
|
183
|
+
return data;
|
|
427
184
|
}
|
|
428
185
|
|
|
429
186
|
ensureRequiredFields(data)
|
|
430
187
|
{
|
|
431
188
|
let missingFields = [];
|
|
432
189
|
for(let field of this.requiredFields){
|
|
433
|
-
if(
|
|
434
|
-
missingFields.push(field);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
if(0 < missingFields.length){
|
|
438
|
-
Logger.warning('Missing required fields for '+this.tableName()+': '+missingFields.join(', '));
|
|
439
|
-
}
|
|
440
|
-
return data;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
processFilters(filters)
|
|
444
|
-
{
|
|
445
|
-
if(!sc.isObject(filters)){
|
|
446
|
-
return filters;
|
|
447
|
-
}
|
|
448
|
-
let processedFilters = {};
|
|
449
|
-
for(let key of Object.keys(filters)){
|
|
450
|
-
let value = filters[key];
|
|
451
|
-
if('OR' === key && sc.isArray(value)){
|
|
452
|
-
processedFilters.OR = value.map(condition => this.processFilters(condition));
|
|
190
|
+
if(sc.hasOwn(data, field)){
|
|
453
191
|
continue;
|
|
454
192
|
}
|
|
455
|
-
if(sc.hasOwn(
|
|
456
|
-
let
|
|
457
|
-
|
|
458
|
-
|
|
193
|
+
if(sc.hasOwn(this.foreignKeyMappings, field)){
|
|
194
|
+
let relationName = this.foreignKeyMappings[field];
|
|
195
|
+
if(sc.hasOwn(data, relationName)){
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
459
198
|
}
|
|
460
|
-
if(sc.
|
|
461
|
-
processedFilters[key] = this.processFilters(value);
|
|
199
|
+
if(sc.hasOwn(this.fieldDefaults, field)){
|
|
462
200
|
continue;
|
|
463
201
|
}
|
|
464
|
-
|
|
202
|
+
missingFields.push(field);
|
|
465
203
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
processFilterValue(value, key)
|
|
470
|
-
{
|
|
471
|
-
if(sc.isArray(value)){
|
|
472
|
-
if('id' === key){
|
|
473
|
-
return value.map(id => this.castToIdType(id));
|
|
474
|
-
}
|
|
475
|
-
let fieldType = this.fieldTypes[key];
|
|
476
|
-
if(fieldType){
|
|
477
|
-
return value.map(val => this.castValue(val, fieldType, key)).filter(val => undefined !== val);
|
|
478
|
-
}
|
|
479
|
-
return value;
|
|
480
|
-
}
|
|
481
|
-
if('id' === key){
|
|
482
|
-
return this.castToIdType(value);
|
|
483
|
-
}
|
|
484
|
-
let fieldType = this.fieldTypes[key];
|
|
485
|
-
if(fieldType){
|
|
486
|
-
let castedValue = this.castValue(value, fieldType, key);
|
|
487
|
-
return undefined !== castedValue ? castedValue : value;
|
|
488
|
-
}
|
|
489
|
-
return value;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
transformRelationResults(result, includeConfig, relationMapping)
|
|
493
|
-
{
|
|
494
|
-
if(!result || !includeConfig){
|
|
495
|
-
return result;
|
|
496
|
-
}
|
|
497
|
-
if(sc.isArray(result)){
|
|
498
|
-
return result.map(item => this.transformSingleResult(item, includeConfig, relationMapping));
|
|
204
|
+
if(0 < missingFields.length){
|
|
205
|
+
Logger.warning('Missing required fields for '+this.tableName()+': '+missingFields.join(', '));
|
|
499
206
|
}
|
|
500
|
-
return
|
|
207
|
+
return data;
|
|
501
208
|
}
|
|
502
209
|
|
|
503
|
-
|
|
210
|
+
async executeWithNormalization(operation, errorMessage, defaultReturn)
|
|
504
211
|
{
|
|
505
|
-
|
|
506
|
-
return
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
if(!sc.hasOwn(transformed, relationName)){
|
|
511
|
-
continue;
|
|
512
|
-
}
|
|
513
|
-
let relationMeta = this.relationMetadata[relationName];
|
|
514
|
-
if(!relationMeta){
|
|
515
|
-
continue;
|
|
516
|
-
}
|
|
517
|
-
let relationValue = transformed[relationName];
|
|
518
|
-
if('one' === relationMeta.type && sc.isArray(relationValue)){
|
|
519
|
-
relationValue = 0 < relationValue.length ? [...relationValue].shift() : null;
|
|
520
|
-
}
|
|
521
|
-
if('many' === relationMeta.type && !sc.isArray(relationValue)){
|
|
522
|
-
relationValue = relationValue ? [relationValue] : [];
|
|
523
|
-
}
|
|
524
|
-
let originalName = sc.get(relationMapping, relationName, relationName);
|
|
525
|
-
transformed[originalName] = relationValue;
|
|
526
|
-
if(originalName !== relationName){
|
|
527
|
-
delete transformed[relationName];
|
|
528
|
-
}
|
|
212
|
+
try {
|
|
213
|
+
return this.typeCaster.normalizeReturnData(await operation());
|
|
214
|
+
} catch(error) {
|
|
215
|
+
Logger.error(errorMessage+error.message);
|
|
216
|
+
return defaultReturn;
|
|
529
217
|
}
|
|
530
|
-
return transformed;
|
|
531
218
|
}
|
|
532
219
|
|
|
533
220
|
async create(params)
|
|
534
221
|
{
|
|
535
|
-
let preparedData = this.
|
|
222
|
+
let preparedData = this.prepareData(params, {convertRelations: true, isCreate: true});
|
|
536
223
|
this.ensureRequiredFields(preparedData);
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
Logger.error('Create error: '+error.message);
|
|
543
|
-
return false;
|
|
544
|
-
}
|
|
224
|
+
return this.executeWithNormalization(
|
|
225
|
+
() => this.model.create({data: preparedData}),
|
|
226
|
+
'Create error: ',
|
|
227
|
+
false
|
|
228
|
+
);
|
|
545
229
|
}
|
|
546
230
|
|
|
547
231
|
async createWithRelations(params, relations)
|
|
@@ -553,121 +237,92 @@ class PrismaDriver extends BaseDriver
|
|
|
553
237
|
this.ensureRequiredFields(preparedData);
|
|
554
238
|
let createData = {data: preparedData};
|
|
555
239
|
if(0 < relations.length){
|
|
556
|
-
let includeData = this.buildIncludeObjectWithMapping(relations);
|
|
240
|
+
let includeData = this.relationResolver.buildIncludeObjectWithMapping(relations);
|
|
557
241
|
createData.include = includeData.include;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
return this.transformRelationResults(await this.model.create(createData), includeData.include, includeData.mapping);
|
|
576
|
-
} catch(error) {
|
|
577
|
-
Logger.error('Create with relations error: '+error.message);
|
|
578
|
-
return false;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
try {
|
|
582
|
-
return await this.model.create(createData);
|
|
583
|
-
} catch(error) {
|
|
584
|
-
Logger.error('Create with relations error: '+error.message);
|
|
585
|
-
return false;
|
|
586
|
-
}
|
|
242
|
+
let relationData = this.relationResolver.buildCreateDataWithRelations(params, relations);
|
|
243
|
+
createData.data = {...createData.data, ...relationData};
|
|
244
|
+
return this.executeWithNormalization(
|
|
245
|
+
async () => this.relationResolver.transformRelationResults(
|
|
246
|
+
await this.model.create(createData),
|
|
247
|
+
includeData.include,
|
|
248
|
+
includeData.mapping
|
|
249
|
+
),
|
|
250
|
+
'Create with relations error: ',
|
|
251
|
+
false
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return this.executeWithNormalization(
|
|
255
|
+
() => this.model.create(createData),
|
|
256
|
+
'Create with relations error: ',
|
|
257
|
+
false
|
|
258
|
+
);
|
|
587
259
|
}
|
|
588
260
|
|
|
589
261
|
async update(filters, updatePatch)
|
|
590
262
|
{
|
|
591
|
-
let preparedData = this.
|
|
592
|
-
let processedFilters = this.processFilters(filters);
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
} catch(error) {
|
|
599
|
-
Logger.error('Update error: '+error.message);
|
|
600
|
-
return false;
|
|
601
|
-
}
|
|
263
|
+
let preparedData = this.prepareData(updatePatch, {skipObjects: true});
|
|
264
|
+
let processedFilters = this.filterProcessor.processFilters(filters);
|
|
265
|
+
return this.executeWithNormalization(
|
|
266
|
+
() => this.model.updateMany({where: processedFilters, data: preparedData}),
|
|
267
|
+
'Update error: ',
|
|
268
|
+
false
|
|
269
|
+
);
|
|
602
270
|
}
|
|
603
271
|
|
|
604
272
|
async updateBy(field, fieldValue, updatePatch, operator = null)
|
|
605
273
|
{
|
|
606
|
-
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
607
|
-
let preparedData = this.
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
} catch(error) {
|
|
614
|
-
Logger.error('Update by error: '+error.message);
|
|
615
|
-
return false;
|
|
616
|
-
}
|
|
274
|
+
let filter = this.filterProcessor.createSingleFilter(field, fieldValue, operator);
|
|
275
|
+
let preparedData = this.prepareData(updatePatch, {skipObjects: true});
|
|
276
|
+
return this.executeWithNormalization(
|
|
277
|
+
() => this.model.updateMany({where: filter, data: preparedData}),
|
|
278
|
+
'Update by error: ',
|
|
279
|
+
false
|
|
280
|
+
);
|
|
617
281
|
}
|
|
618
282
|
|
|
619
283
|
async updateById(id, params)
|
|
620
284
|
{
|
|
621
|
-
let castedId = this.castToIdType(id);
|
|
285
|
+
let castedId = this.typeCaster.castToIdType(id);
|
|
622
286
|
let found = await this.loadById(castedId);
|
|
623
287
|
if(!found){
|
|
624
288
|
return false;
|
|
625
289
|
}
|
|
626
|
-
let preparedData = this.
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
} catch(error) {
|
|
633
|
-
Logger.error('Update by ID error: '+error.message);
|
|
634
|
-
return false;
|
|
635
|
-
}
|
|
290
|
+
let preparedData = this.prepareData(params, {convertRelations: true});
|
|
291
|
+
return this.executeWithNormalization(
|
|
292
|
+
() => this.model.update({where: {[this.idFieldName]: castedId}, data: preparedData}),
|
|
293
|
+
'Update by ID error: ',
|
|
294
|
+
false
|
|
295
|
+
);
|
|
636
296
|
}
|
|
637
297
|
|
|
638
298
|
async upsert(params, filters)
|
|
639
299
|
{
|
|
640
|
-
let preparedData = this.
|
|
641
|
-
let
|
|
642
|
-
if(
|
|
643
|
-
let castedId = this.castToIdType(
|
|
644
|
-
existing = await this.loadById(castedId);
|
|
300
|
+
let preparedData = this.prepareData(params, {convertRelations: true});
|
|
301
|
+
let idValue = params[this.idFieldName];
|
|
302
|
+
if(idValue){
|
|
303
|
+
let castedId = this.typeCaster.castToIdType(idValue);
|
|
304
|
+
let existing = await this.loadById(castedId);
|
|
645
305
|
if(existing){
|
|
646
306
|
let patch = Object.assign({}, preparedData);
|
|
647
|
-
delete patch.
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
} catch(error) {
|
|
654
|
-
Logger.error('Upsert update error: '+error.message);
|
|
655
|
-
return false;
|
|
656
|
-
}
|
|
307
|
+
delete patch[this.idFieldName];
|
|
308
|
+
return this.executeWithNormalization(
|
|
309
|
+
() => this.model.update({where: {[this.idFieldName]: castedId}, data: patch}),
|
|
310
|
+
'Upsert update error: ',
|
|
311
|
+
false
|
|
312
|
+
);
|
|
657
313
|
}
|
|
658
314
|
}
|
|
659
315
|
if(filters){
|
|
660
316
|
let existing = await this.loadOne(filters);
|
|
661
317
|
if(existing){
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
where: {
|
|
318
|
+
return this.executeWithNormalization(
|
|
319
|
+
() => this.model.update({
|
|
320
|
+
where: {[this.idFieldName]: this.typeCaster.castToIdType(existing[this.idFieldName])},
|
|
665
321
|
data: preparedData
|
|
666
|
-
})
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
322
|
+
}),
|
|
323
|
+
'Upsert update by filter error: ',
|
|
324
|
+
false
|
|
325
|
+
);
|
|
671
326
|
}
|
|
672
327
|
}
|
|
673
328
|
return await this.create(preparedData);
|
|
@@ -675,45 +330,36 @@ class PrismaDriver extends BaseDriver
|
|
|
675
330
|
|
|
676
331
|
async delete(filters = {})
|
|
677
332
|
{
|
|
678
|
-
let processedFilters = this.processFilters(filters);
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
Logger.error('Delete error: '+error.message);
|
|
685
|
-
return false;
|
|
686
|
-
}
|
|
333
|
+
let processedFilters = this.filterProcessor.processFilters(filters);
|
|
334
|
+
return this.executeWithNormalization(
|
|
335
|
+
() => this.model.deleteMany({where: processedFilters}),
|
|
336
|
+
'Delete error: ',
|
|
337
|
+
false
|
|
338
|
+
);
|
|
687
339
|
}
|
|
688
340
|
|
|
689
341
|
async deleteById(id)
|
|
690
342
|
{
|
|
691
|
-
let castedId = this.castToIdType(id);
|
|
343
|
+
let castedId = this.typeCaster.castToIdType(id);
|
|
692
344
|
let found = await this.loadById(castedId);
|
|
693
345
|
if(!found){
|
|
694
346
|
return false;
|
|
695
347
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
Logger.error('Delete by ID error: '+error.message);
|
|
702
|
-
return false;
|
|
703
|
-
}
|
|
348
|
+
return this.executeWithNormalization(
|
|
349
|
+
() => this.model.delete({where: {[this.idFieldName]: castedId}}),
|
|
350
|
+
'Delete by ID error: ',
|
|
351
|
+
false
|
|
352
|
+
);
|
|
704
353
|
}
|
|
705
354
|
|
|
706
355
|
async count(filters)
|
|
707
356
|
{
|
|
708
|
-
let processedFilters = this.processFilters(filters);
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
Logger.error('Count error: '+error.message);
|
|
715
|
-
return 0;
|
|
716
|
-
}
|
|
357
|
+
let processedFilters = this.filterProcessor.processFilters(filters);
|
|
358
|
+
return this.executeWithNormalization(
|
|
359
|
+
() => this.model.count({where: processedFilters}),
|
|
360
|
+
'Count error: ',
|
|
361
|
+
0
|
|
362
|
+
);
|
|
717
363
|
}
|
|
718
364
|
|
|
719
365
|
async countWithRelations(filters, relations)
|
|
@@ -721,36 +367,32 @@ class PrismaDriver extends BaseDriver
|
|
|
721
367
|
if(!sc.isArray(relations) || 0 === relations.length){
|
|
722
368
|
relations = this.getAllRelations();
|
|
723
369
|
}
|
|
724
|
-
let processedFilters = this.processFilters(filters);
|
|
725
|
-
let query = {
|
|
726
|
-
where: processedFilters
|
|
727
|
-
};
|
|
370
|
+
let processedFilters = this.filterProcessor.processFilters(filters);
|
|
371
|
+
let query = {where: processedFilters};
|
|
728
372
|
if(0 < relations.length){
|
|
729
|
-
query.include = this.buildIncludeObjectWithMapping(relations).include;
|
|
730
|
-
}
|
|
731
|
-
try {
|
|
732
|
-
return await this.model.count(query);
|
|
733
|
-
} catch(error) {
|
|
734
|
-
Logger.error('Count with relations error: '+error.message);
|
|
735
|
-
return 0;
|
|
373
|
+
query.include = this.relationResolver.buildIncludeObjectWithMapping(relations).include;
|
|
736
374
|
}
|
|
375
|
+
return this.executeWithNormalization(
|
|
376
|
+
() => this.model.count(query),
|
|
377
|
+
'Count with relations error: ',
|
|
378
|
+
0
|
|
379
|
+
);
|
|
737
380
|
}
|
|
738
381
|
|
|
739
382
|
async loadAll()
|
|
740
383
|
{
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
}
|
|
384
|
+
return this.executeWithNormalization(
|
|
385
|
+
() => this.model.findMany(this.queryBuilder.buildQueryOptions(this.getQueryOptions())),
|
|
386
|
+
'Load all error: ',
|
|
387
|
+
[]
|
|
388
|
+
);
|
|
747
389
|
}
|
|
748
390
|
|
|
749
391
|
async loadAllWithRelations(relations)
|
|
750
392
|
{
|
|
751
393
|
return this.executeQueryWithRelations(
|
|
752
394
|
(q) => this.model.findMany(q),
|
|
753
|
-
this.buildQueryOptions(),
|
|
395
|
+
this.queryBuilder.buildQueryOptions(this.getQueryOptions()),
|
|
754
396
|
relations,
|
|
755
397
|
'Load all with relations error: ',
|
|
756
398
|
[]
|
|
@@ -759,21 +401,20 @@ class PrismaDriver extends BaseDriver
|
|
|
759
401
|
|
|
760
402
|
async load(filters)
|
|
761
403
|
{
|
|
762
|
-
let processedFilters = this.processFilters(filters);
|
|
763
|
-
let query = this.buildQueryOptions();
|
|
404
|
+
let processedFilters = this.filterProcessor.processFilters(filters);
|
|
405
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions());
|
|
764
406
|
query.where = processedFilters;
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
}
|
|
407
|
+
return this.executeWithNormalization(
|
|
408
|
+
() => this.model.findMany(query),
|
|
409
|
+
'Load error: ',
|
|
410
|
+
[]
|
|
411
|
+
);
|
|
771
412
|
}
|
|
772
413
|
|
|
773
414
|
async loadWithRelations(filters, relations)
|
|
774
415
|
{
|
|
775
|
-
let query = this.buildQueryOptions();
|
|
776
|
-
query.where = this.processFilters(filters);
|
|
416
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions());
|
|
417
|
+
query.where = this.filterProcessor.processFilters(filters);
|
|
777
418
|
return this.executeQueryWithRelations(
|
|
778
419
|
(q) => this.model.findMany(q),
|
|
779
420
|
query,
|
|
@@ -785,21 +426,20 @@ class PrismaDriver extends BaseDriver
|
|
|
785
426
|
|
|
786
427
|
async loadBy(field, fieldValue, operator = null)
|
|
787
428
|
{
|
|
788
|
-
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
789
|
-
let query = this.buildQueryOptions();
|
|
429
|
+
let filter = this.filterProcessor.createSingleFilter(field, fieldValue, operator);
|
|
430
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions());
|
|
790
431
|
query.where = filter;
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
432
|
+
return this.executeWithNormalization(
|
|
433
|
+
() => this.model.findMany(query),
|
|
434
|
+
'Load by error: ',
|
|
435
|
+
[]
|
|
436
|
+
);
|
|
797
437
|
}
|
|
798
438
|
|
|
799
439
|
async loadByWithRelations(field, fieldValue, relations, operator = null)
|
|
800
440
|
{
|
|
801
|
-
let query = this.buildQueryOptions();
|
|
802
|
-
query.where = this.createSingleFilter(field, fieldValue, operator);
|
|
441
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions());
|
|
442
|
+
query.where = this.filterProcessor.createSingleFilter(field, fieldValue, operator);
|
|
803
443
|
return this.executeQueryWithRelations(
|
|
804
444
|
(q) => this.model.findMany(q),
|
|
805
445
|
query,
|
|
@@ -811,22 +451,19 @@ class PrismaDriver extends BaseDriver
|
|
|
811
451
|
|
|
812
452
|
async loadById(id)
|
|
813
453
|
{
|
|
814
|
-
let castedId = this.castToIdType(id);
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
Logger.error('Load by ID error: '+error.message);
|
|
821
|
-
return null;
|
|
822
|
-
}
|
|
454
|
+
let castedId = this.typeCaster.castToIdType(id);
|
|
455
|
+
return this.executeWithNormalization(
|
|
456
|
+
() => this.model.findUnique({where: {[this.idFieldName]: castedId}}),
|
|
457
|
+
'Load by ID error: ',
|
|
458
|
+
null
|
|
459
|
+
);
|
|
823
460
|
}
|
|
824
461
|
|
|
825
462
|
async loadByIdWithRelations(id, relations)
|
|
826
463
|
{
|
|
827
464
|
return this.executeQueryWithRelations(
|
|
828
465
|
(q) => this.model.findUnique(q),
|
|
829
|
-
{where: {
|
|
466
|
+
{where: {[this.idFieldName]: this.typeCaster.castToIdType(id)}},
|
|
830
467
|
relations,
|
|
831
468
|
'Load by ID with relations error: ',
|
|
832
469
|
null
|
|
@@ -835,36 +472,33 @@ class PrismaDriver extends BaseDriver
|
|
|
835
472
|
|
|
836
473
|
async loadByIds(ids)
|
|
837
474
|
{
|
|
838
|
-
let castedIds = ids.map(id => this.castToIdType(id));
|
|
839
|
-
|
|
840
|
-
return await this.model.findMany({
|
|
841
|
-
where: {
|
|
842
|
-
id: {in: castedIds}
|
|
843
|
-
}
|
|
844
|
-
});
|
|
845
|
-
} catch(error) {
|
|
846
|
-
Logger.error('Load by IDs error: '+error.message);
|
|
475
|
+
let castedIds = ids.map(id => this.typeCaster.castToIdType(id)).filter(id => null !== id);
|
|
476
|
+
if(0 === castedIds.length){
|
|
847
477
|
return [];
|
|
848
478
|
}
|
|
479
|
+
return this.executeWithNormalization(
|
|
480
|
+
() => this.model.findMany({where: {[this.idFieldName]: {in: castedIds}}}),
|
|
481
|
+
'Load by IDs error: ',
|
|
482
|
+
[]
|
|
483
|
+
);
|
|
849
484
|
}
|
|
850
485
|
|
|
851
486
|
async loadOne(filters)
|
|
852
487
|
{
|
|
853
|
-
let processedFilters = this.processFilters(filters);
|
|
854
|
-
let query = this.buildQueryOptions(false);
|
|
488
|
+
let processedFilters = this.filterProcessor.processFilters(filters);
|
|
489
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions(), false);
|
|
855
490
|
query.where = processedFilters;
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
}
|
|
491
|
+
return this.executeWithNormalization(
|
|
492
|
+
() => this.model.findFirst(query),
|
|
493
|
+
'Load one error: ',
|
|
494
|
+
null
|
|
495
|
+
);
|
|
862
496
|
}
|
|
863
497
|
|
|
864
498
|
async loadOneWithRelations(filters, relations)
|
|
865
499
|
{
|
|
866
|
-
let query = this.buildQueryOptions(false);
|
|
867
|
-
query.where = this.processFilters(filters);
|
|
500
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions(), false);
|
|
501
|
+
query.where = this.filterProcessor.processFilters(filters);
|
|
868
502
|
return this.executeQueryWithRelations(
|
|
869
503
|
(q) => this.model.findFirst(q),
|
|
870
504
|
query,
|
|
@@ -876,21 +510,20 @@ class PrismaDriver extends BaseDriver
|
|
|
876
510
|
|
|
877
511
|
async loadOneBy(field, fieldValue, operator = null)
|
|
878
512
|
{
|
|
879
|
-
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
880
|
-
let query = this.buildQueryOptions(false);
|
|
513
|
+
let filter = this.filterProcessor.createSingleFilter(field, fieldValue, operator);
|
|
514
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions(), false);
|
|
881
515
|
query.where = filter;
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
}
|
|
516
|
+
return this.executeWithNormalization(
|
|
517
|
+
() => this.model.findFirst(query),
|
|
518
|
+
'Load one by error: ',
|
|
519
|
+
null
|
|
520
|
+
);
|
|
888
521
|
}
|
|
889
522
|
|
|
890
523
|
async loadOneByWithRelations(field, fieldValue, relations, operator = null)
|
|
891
524
|
{
|
|
892
|
-
let query = this.buildQueryOptions(false);
|
|
893
|
-
query.where = this.createSingleFilter(field, fieldValue, operator);
|
|
525
|
+
let query = this.queryBuilder.buildQueryOptions(this.getQueryOptions(), false);
|
|
526
|
+
query.where = this.filterProcessor.createSingleFilter(field, fieldValue, operator);
|
|
894
527
|
return this.executeQueryWithRelations(
|
|
895
528
|
(q) => this.model.findFirst(q),
|
|
896
529
|
query,
|
|
@@ -900,115 +533,24 @@ class PrismaDriver extends BaseDriver
|
|
|
900
533
|
);
|
|
901
534
|
}
|
|
902
535
|
|
|
903
|
-
buildQueryOptions(useLimit = true)
|
|
904
|
-
{
|
|
905
|
-
let queryOptions = {};
|
|
906
|
-
if(0 < this.select.length){
|
|
907
|
-
queryOptions.select = {};
|
|
908
|
-
for(let field of this.select){
|
|
909
|
-
queryOptions.select[field] = true;
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
if(useLimit && 0 !== this.limit){
|
|
913
|
-
queryOptions.take = this.limit;
|
|
914
|
-
}
|
|
915
|
-
if(0 !== this.offset){
|
|
916
|
-
queryOptions.skip = this.offset;
|
|
917
|
-
}
|
|
918
|
-
if(false !== this.sortBy && false !== this.sortDirection){
|
|
919
|
-
queryOptions.orderBy = {
|
|
920
|
-
[this.sortBy]: this.sortDirection.toLowerCase()
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
return queryOptions;
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
createSingleFilter(field, fieldValue, operator = null)
|
|
927
|
-
{
|
|
928
|
-
let filter = {};
|
|
929
|
-
let processedValue = this.processFilterValue(fieldValue, field);
|
|
930
|
-
if(null === operator){
|
|
931
|
-
filter[field] = processedValue;
|
|
932
|
-
return filter;
|
|
933
|
-
}
|
|
934
|
-
filter[field] = {operator, value: processedValue};
|
|
935
|
-
return this.processFilters(filter);
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
applyOperator(value, operator, fieldName = null)
|
|
939
|
-
{
|
|
940
|
-
let upperOperator = operator ? operator.toUpperCase() : '';
|
|
941
|
-
if('LIKE' === upperOperator){
|
|
942
|
-
return this.handleLikeOperator(value, fieldName);
|
|
943
|
-
}
|
|
944
|
-
let operatorsMap = {
|
|
945
|
-
'=': value,
|
|
946
|
-
'!=': {not: value},
|
|
947
|
-
'>': {gt: value},
|
|
948
|
-
'>=': {gte: value},
|
|
949
|
-
'<': {lt: value},
|
|
950
|
-
'<=': {lte: value},
|
|
951
|
-
'IN': {in: value},
|
|
952
|
-
'NOT IN': {notIn: value}
|
|
953
|
-
};
|
|
954
|
-
return operatorsMap[upperOperator] || value;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
handleLikeOperator(value, fieldName)
|
|
958
|
-
{
|
|
959
|
-
let cleanValue = String(value).replace(/%/g, '');
|
|
960
|
-
if(this.isJsonFieldByName(fieldName) || this.isJsonField(fieldName)){
|
|
961
|
-
return this.handleJsonTextSearch(cleanValue);
|
|
962
|
-
}
|
|
963
|
-
if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
|
|
964
|
-
let numericValue = Number(cleanValue);
|
|
965
|
-
if(!isNaN(numericValue)){
|
|
966
|
-
return numericValue;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
return {contains: cleanValue};
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
handleJsonTextSearch(searchValue)
|
|
973
|
-
{
|
|
974
|
-
return {
|
|
975
|
-
string_contains: searchValue
|
|
976
|
-
};
|
|
977
|
-
}
|
|
978
|
-
|
|
979
536
|
async executeQueryWithRelations(modelMethod, query, relations, errorMessage, defaultReturn)
|
|
980
537
|
{
|
|
981
538
|
if(!sc.isArray(relations) || 0 === relations.length){
|
|
982
539
|
relations = this.getAllRelations();
|
|
983
540
|
}
|
|
984
|
-
let includeData = this.buildIncludeObjectWithMapping(relations);
|
|
541
|
+
let includeData = this.relationResolver.buildIncludeObjectWithMapping(relations);
|
|
985
542
|
if(0 < Object.keys(includeData.include).length){
|
|
986
543
|
query.include = includeData.include;
|
|
987
544
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
{
|
|
998
|
-
let include = {};
|
|
999
|
-
let mapping = {};
|
|
1000
|
-
for(let relation of relations){
|
|
1001
|
-
let normalizedRelation = this.normalizeRelationName(relation);
|
|
1002
|
-
if(!sc.hasOwn(this.relationMetadata, normalizedRelation)){
|
|
1003
|
-
//Logger.debug('Relation "'+relation+'" (normalized: "'+normalizedRelation+'") not found in model '+this.tableName());
|
|
1004
|
-
continue;
|
|
1005
|
-
}
|
|
1006
|
-
include[normalizedRelation] = true;
|
|
1007
|
-
if(relation !== normalizedRelation){
|
|
1008
|
-
mapping[normalizedRelation] = relation;
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
return {include, mapping};
|
|
545
|
+
return this.executeWithNormalization(
|
|
546
|
+
async () => this.relationResolver.transformRelationResults(
|
|
547
|
+
await modelMethod(query),
|
|
548
|
+
includeData.include,
|
|
549
|
+
includeData.mapping
|
|
550
|
+
),
|
|
551
|
+
errorMessage,
|
|
552
|
+
defaultReturn
|
|
553
|
+
);
|
|
1012
554
|
}
|
|
1013
555
|
|
|
1014
556
|
}
|