@reldens/storage 0.56.0 → 0.58.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.
|
@@ -53,6 +53,7 @@ class EntitiesGenerator
|
|
|
53
53
|
this.existingEntities = {};
|
|
54
54
|
this.existingEntityFields = {};
|
|
55
55
|
this.existingModels = {};
|
|
56
|
+
this.prismaRelationsMetadata = {};
|
|
56
57
|
this.entitiesGeneration = new EntitiesGeneration({
|
|
57
58
|
entitiesFolder: this.entitiesFolder,
|
|
58
59
|
templatePath: this.templates['entity']
|
|
@@ -164,6 +165,125 @@ class EntitiesGenerator
|
|
|
164
165
|
return false;
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
extractPrismaRelationsMetadata()
|
|
169
|
+
{
|
|
170
|
+
if(!this.prismaClient){
|
|
171
|
+
Logger.warning('Missing PrismaClient.');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if(!this.server || !(this.server instanceof PrismaDataServer)){
|
|
175
|
+
Logger.warning('Server is not a PrismaDataServer instance.');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
let dmmf = this.prismaClient._runtimeDataModel || this.prismaClient._dmmf?.datamodel;
|
|
180
|
+
if(!dmmf || !dmmf.models){
|
|
181
|
+
Logger.warning('Could not extract Prisma DMMF data for relations metadata.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if(sc.isArray(dmmf.models)){
|
|
185
|
+
this.processArrayModels(dmmf.models);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.processObjectModels(dmmf.models);
|
|
189
|
+
} catch(error) {
|
|
190
|
+
Logger.warning('Failed to extract Prisma relations metadata: ' + error.message);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
processArrayModels(models)
|
|
195
|
+
{
|
|
196
|
+
for(let model of models){
|
|
197
|
+
if(!model){
|
|
198
|
+
Logger.error('Missing model.');
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if(!model.name){
|
|
202
|
+
Logger.error('Missing model name.', model);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if(!sc.isArray(model.fields)){
|
|
206
|
+
Logger.error('Model fields not an array.', model);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
this.processModelForRelations(model.name, model, models);
|
|
210
|
+
}
|
|
211
|
+
Logger.info('Extracted relations metadata for ' + Object.keys(this.prismaRelationsMetadata).length + ' models.');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
processObjectModels(models)
|
|
215
|
+
{
|
|
216
|
+
for(let modelName of Object.keys(models)){
|
|
217
|
+
let model = models[modelName];
|
|
218
|
+
if(!model){
|
|
219
|
+
Logger.error('Missing model.');
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if(!sc.isArray(model.fields)){
|
|
223
|
+
Logger.error('Model fields not an array.', model);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
this.processModelForRelations(modelName, model, models);
|
|
227
|
+
}
|
|
228
|
+
Logger.info('Extracted relations metadata for ' + Object.keys(this.prismaRelationsMetadata).length + ' models.');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
processModelForRelations(modelName, model, allModels)
|
|
232
|
+
{
|
|
233
|
+
let tableName = modelName.toLowerCase();
|
|
234
|
+
this.prismaRelationsMetadata[tableName] = {};
|
|
235
|
+
for(let field of model.fields){
|
|
236
|
+
if('object' !== field.kind){
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
let relationType = 'many';
|
|
240
|
+
if(!field.isList){
|
|
241
|
+
relationType = this.inferRelationType(field, model, allModels, modelName);
|
|
242
|
+
}
|
|
243
|
+
this.prismaRelationsMetadata[tableName][field.name] = {
|
|
244
|
+
type: relationType,
|
|
245
|
+
model: field.type,
|
|
246
|
+
isList: field.isList,
|
|
247
|
+
isOptional: field.isOptional,
|
|
248
|
+
relationName: field.relationName
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
inferRelationType(field, model, allModels, modelName)
|
|
254
|
+
{
|
|
255
|
+
if(field.isList){
|
|
256
|
+
return 'many';
|
|
257
|
+
}
|
|
258
|
+
let relatedModel = this.findRelatedModel(allModels, field.type);
|
|
259
|
+
if(!relatedModel){
|
|
260
|
+
return 'one';
|
|
261
|
+
}
|
|
262
|
+
let backReference = relatedModel.fields.find(f =>
|
|
263
|
+
'object' === f.kind &&
|
|
264
|
+
f.type === modelName &&
|
|
265
|
+
f.relationName === field.relationName
|
|
266
|
+
);
|
|
267
|
+
if(!backReference){
|
|
268
|
+
return 'one';
|
|
269
|
+
}
|
|
270
|
+
if(field.relationFromFields && 0 < field.relationFromFields.length){
|
|
271
|
+
return 'one';
|
|
272
|
+
}
|
|
273
|
+
if(backReference.relationFromFields && 0 < backReference.relationFromFields.length){
|
|
274
|
+
return 'one';
|
|
275
|
+
}
|
|
276
|
+
return 'one';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
findRelatedModel(allModels, fieldType)
|
|
280
|
+
{
|
|
281
|
+
if(sc.isArray(allModels)){
|
|
282
|
+
return allModels.find(m => m.name === fieldType);
|
|
283
|
+
}
|
|
284
|
+
return allModels[fieldType];
|
|
285
|
+
}
|
|
286
|
+
|
|
167
287
|
filterTablesToGenerate(tables, driverKey)
|
|
168
288
|
{
|
|
169
289
|
let filteredTables = {};
|
|
@@ -254,6 +374,18 @@ class EntitiesGenerator
|
|
|
254
374
|
Logger.critical('Failed to connect to database: '+error.message);
|
|
255
375
|
return false;
|
|
256
376
|
}
|
|
377
|
+
let driverKey = sc.get(
|
|
378
|
+
this.connectionData,
|
|
379
|
+
'driver',
|
|
380
|
+
(this.server ? sc.get(this.driversClassMap, this.server.constructor.name, false) : false)
|
|
381
|
+
);
|
|
382
|
+
if('prisma' === driverKey){
|
|
383
|
+
if(!this.prismaClient && this.server.prisma){
|
|
384
|
+
this.prismaClient = this.server.prisma;
|
|
385
|
+
}
|
|
386
|
+
Logger.debug('Extract Prisma relations metadata.');
|
|
387
|
+
this.extractPrismaRelationsMetadata();
|
|
388
|
+
}
|
|
257
389
|
let tables = await this.server.fetchEntitiesFromDatabase();
|
|
258
390
|
if(!tables){
|
|
259
391
|
Logger.critical('EntitiesGenerator tables fetch failed.');
|
|
@@ -264,15 +396,13 @@ class EntitiesGenerator
|
|
|
264
396
|
}
|
|
265
397
|
this.detectExistingEntities();
|
|
266
398
|
this.detectExistingModels();
|
|
267
|
-
let driverKey = sc.get(
|
|
268
|
-
this.connectionData,
|
|
269
|
-
'driver',
|
|
270
|
-
(this.server ? sc.get(this.driversClassMap, this.server.constructor.name, false) : false)
|
|
271
|
-
);
|
|
272
399
|
if(!driverKey){
|
|
273
400
|
Logger.critical('Failed to fetch driver key.');
|
|
274
401
|
return false;
|
|
275
402
|
}
|
|
403
|
+
if('objection-js' === driverKey){
|
|
404
|
+
this.modelsGeneration.setAllTablesData(tables);
|
|
405
|
+
}
|
|
276
406
|
let tablesToGenerate = this.filterTablesToGenerate(tables, driverKey);
|
|
277
407
|
if(0 === Object.keys(tablesToGenerate).length && !this.isOverride){
|
|
278
408
|
return true;
|
|
@@ -284,11 +414,13 @@ class EntitiesGenerator
|
|
|
284
414
|
continue;
|
|
285
415
|
}
|
|
286
416
|
let entityInfo = this.entitiesGeneration.generatedEntities[tableName];
|
|
417
|
+
let relationMetadata = sc.get(this.prismaRelationsMetadata, tableName, {});
|
|
287
418
|
let modelGenerated = await this.modelsGeneration.generateModelFile(
|
|
288
419
|
tableName,
|
|
289
420
|
tableData,
|
|
290
421
|
driverKey,
|
|
291
|
-
entityInfo
|
|
422
|
+
entityInfo,
|
|
423
|
+
relationMetadata
|
|
292
424
|
);
|
|
293
425
|
if(modelGenerated){
|
|
294
426
|
let modelInfo = this.modelsGeneration.generatedModels[tableName];
|
|
@@ -18,9 +18,10 @@ class ModelsGeneration extends BaseGenerator
|
|
|
18
18
|
this.modelsFolder = sc.get(props, 'modelsFolder', '');
|
|
19
19
|
this.templates = sc.get(props, 'templates', {});
|
|
20
20
|
this.generatedModels = {};
|
|
21
|
+
this.allTablesData = {};
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
async generateModelFile(tableName, tableData, driverKey, entityInfo)
|
|
24
|
+
async generateModelFile(tableName, tableData, driverKey, entityInfo, relationMetadata = {})
|
|
24
25
|
{
|
|
25
26
|
let modelTemplatePath = this.templates[driverKey];
|
|
26
27
|
if(!FileHandler.exists(modelTemplatePath)){
|
|
@@ -37,7 +38,7 @@ class ModelsGeneration extends BaseGenerator
|
|
|
37
38
|
let modelPropertiesConstructor = Object.keys(tableData.columns)
|
|
38
39
|
.map(columnName => 'this.'+columnName+' = '+columnName+';')
|
|
39
40
|
.join('\n ');
|
|
40
|
-
let modelRelations =
|
|
41
|
+
let modelRelations = this.generateModelRelations(tableName, tableData, relationMetadata, driverKey);
|
|
41
42
|
let entityPropertiesDefinition = this.getEntityPropertiesDefinition(tableData.columns, driverKey);
|
|
42
43
|
let replacements = {
|
|
43
44
|
modelClassName,
|
|
@@ -65,6 +66,147 @@ class ModelsGeneration extends BaseGenerator
|
|
|
65
66
|
return true;
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
setAllTablesData(allTablesData)
|
|
70
|
+
{
|
|
71
|
+
this.allTablesData = allTablesData;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
generateModelRelations(tableName, tableData, relationMetadata, driverKey)
|
|
75
|
+
{
|
|
76
|
+
if('prisma' === driverKey){
|
|
77
|
+
return this.generatePrismaRelations(relationMetadata);
|
|
78
|
+
}
|
|
79
|
+
if('objection-js' === driverKey){
|
|
80
|
+
return this.generateObjectionJsRelations(tableName, tableData);
|
|
81
|
+
}
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
generatePrismaRelations(relationMetadata)
|
|
86
|
+
{
|
|
87
|
+
if(!relationMetadata || 0 === Object.keys(relationMetadata).length){
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
let relationTypesArray = [];
|
|
91
|
+
for(let relationName of Object.keys(relationMetadata)){
|
|
92
|
+
let relation = relationMetadata[relationName];
|
|
93
|
+
relationTypesArray.push(' '+relationName+': \''+relation.type+'\'');
|
|
94
|
+
}
|
|
95
|
+
if(0 === relationTypesArray.length){
|
|
96
|
+
return '';
|
|
97
|
+
}
|
|
98
|
+
return '\n\n static get relationTypes()\n {\n return {\n '+relationTypesArray.join(',\n ')+'\n };\n }';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
generateObjectionJsRelations(tableName, tableData)
|
|
102
|
+
{
|
|
103
|
+
let relations = this.detectObjectionJsRelations(tableName, tableData);
|
|
104
|
+
let reverseRelations = this.detectReverseObjectionJsRelations(tableName);
|
|
105
|
+
let allRelations = Object.assign({}, relations, reverseRelations);
|
|
106
|
+
if(0 === Object.keys(allRelations).length){
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
let relationMappings = [];
|
|
110
|
+
let requiredModels = [];
|
|
111
|
+
for(let relationKey of Object.keys(allRelations)){
|
|
112
|
+
let relation = allRelations[relationKey];
|
|
113
|
+
let tableReference = relation.referencedTable || relation.referencingTable;
|
|
114
|
+
let relatedModelClass = sc.capitalizedCamelCase(tableReference)+'Model';
|
|
115
|
+
if(!requiredModels.find(m => m.modelClass === relatedModelClass)){
|
|
116
|
+
requiredModels.push({
|
|
117
|
+
modelClass: relatedModelClass,
|
|
118
|
+
fileName: sc.kebabCase(tableReference)+'-model'
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
let relationMapping = ' '+relationKey+': {\n';
|
|
122
|
+
relationMapping += ' relation: this.'+relation.relationType+',\n';
|
|
123
|
+
relationMapping += ' modelClass: '+relatedModelClass+',\n';
|
|
124
|
+
relationMapping += ' join: {\n';
|
|
125
|
+
relationMapping += ' from: this.tableName+\'.'+relation.fromColumn+'\',\n';
|
|
126
|
+
relationMapping += ' to: '+relatedModelClass+'.tableName+\'.'+relation.toColumn+'\'\n';
|
|
127
|
+
relationMapping += ' }\n';
|
|
128
|
+
relationMapping += ' }';
|
|
129
|
+
relationMappings.push(relationMapping);
|
|
130
|
+
}
|
|
131
|
+
if(0 === relationMappings.length){
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
let requireStatements = [];
|
|
135
|
+
for(let modelInfo of requiredModels){
|
|
136
|
+
requireStatements.push(' const { '+modelInfo.modelClass+' } = require(\'./'+modelInfo.fileName+'\');');
|
|
137
|
+
}
|
|
138
|
+
let relationMappingsMethod = '\n\n static get relationMappings()\n {\n';
|
|
139
|
+
relationMappingsMethod += requireStatements.join('\n')+'\n';
|
|
140
|
+
relationMappingsMethod += ' return {\n';
|
|
141
|
+
relationMappingsMethod += relationMappings.join(',\n');
|
|
142
|
+
relationMappingsMethod += '\n };\n';
|
|
143
|
+
relationMappingsMethod += ' }';
|
|
144
|
+
return relationMappingsMethod;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
detectObjectionJsRelations(tableName, tableData)
|
|
148
|
+
{
|
|
149
|
+
let relations = {};
|
|
150
|
+
for(let columnName of Object.keys(tableData.columns)){
|
|
151
|
+
let column = tableData.columns[columnName];
|
|
152
|
+
if(!sc.hasOwn(column, 'referencedTable')){
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
let relationKey = 'related_'+column.referencedTable;
|
|
156
|
+
let relationType = this.determineRelationType(column, true);
|
|
157
|
+
relations[relationKey] = {
|
|
158
|
+
fromColumn: columnName,
|
|
159
|
+
toColumn: column.referencedColumn,
|
|
160
|
+
referencedTable: column.referencedTable,
|
|
161
|
+
relationType: relationType
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return relations;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
detectReverseObjectionJsRelations(tableName)
|
|
168
|
+
{
|
|
169
|
+
let reverseRelations = {};
|
|
170
|
+
for(let otherTableName of Object.keys(this.allTablesData)){
|
|
171
|
+
if(otherTableName === tableName){
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
let otherTableData = this.allTablesData[otherTableName];
|
|
175
|
+
for(let columnName of Object.keys(otherTableData.columns)){
|
|
176
|
+
let column = otherTableData.columns[columnName];
|
|
177
|
+
if(!sc.hasOwn(column, 'referencedTable')){
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if(column.referencedTable !== tableName){
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
let relationKey = 'related_'+otherTableName;
|
|
184
|
+
let relationType = this.determineRelationType(column, false);
|
|
185
|
+
reverseRelations[relationKey] = {
|
|
186
|
+
fromColumn: column.referencedColumn,
|
|
187
|
+
toColumn: columnName,
|
|
188
|
+
referencingTable: otherTableName,
|
|
189
|
+
relationType: relationType
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return reverseRelations;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
determineRelationType(column, isForwardRelation)
|
|
197
|
+
{
|
|
198
|
+
if(isForwardRelation){
|
|
199
|
+
if('PRI' === column.key){
|
|
200
|
+
return 'HasOneRelation';
|
|
201
|
+
}
|
|
202
|
+
return 'BelongsToOneRelation';
|
|
203
|
+
}
|
|
204
|
+
if('PRI' === column.key){
|
|
205
|
+
return 'HasOneRelation';
|
|
206
|
+
}
|
|
207
|
+
return 'HasManyRelation';
|
|
208
|
+
}
|
|
209
|
+
|
|
68
210
|
getEntityPropertiesDefinition(columns, driverKey)
|
|
69
211
|
{
|
|
70
212
|
if('mikro-orm' === driverKey){
|
|
@@ -93,14 +93,14 @@ class PrismaDataServer extends BaseDataServer
|
|
|
93
93
|
try {
|
|
94
94
|
let result = await this.executeStatement(cleanStatement);
|
|
95
95
|
results.push(result);
|
|
96
|
-
Logger.debug('Statement executed, result: ' + JSON.stringify(result));
|
|
96
|
+
//Logger.debug('Statement executed, result: ' + JSON.stringify(result));
|
|
97
97
|
} catch(stmtError) {
|
|
98
98
|
Logger.error('Statement "'+cleanStatement+'" execution failed: '+stmtError.message);
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
if(0 === results.length){
|
|
103
|
-
Logger.error('Statement results length is zero.', results);
|
|
103
|
+
//Logger.error('Statement results length is zero.', results);
|
|
104
104
|
return false;
|
|
105
105
|
}
|
|
106
106
|
return 1 === results.length ? results[0] : results;
|
|
@@ -33,7 +33,9 @@ class PrismaDriver extends BaseDriver
|
|
|
33
33
|
this.fieldTypes = {};
|
|
34
34
|
this.idFieldType = 'String';
|
|
35
35
|
this.referenceFields = {};
|
|
36
|
+
this.relationMetadata = {};
|
|
36
37
|
this.initFieldMetadata();
|
|
38
|
+
this.initRelationMetadata();
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
initFieldMetadata()
|
|
@@ -69,6 +71,44 @@ class PrismaDriver extends BaseDriver
|
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
initRelationMetadata()
|
|
75
|
+
{
|
|
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
|
+
}
|
|
99
|
+
}
|
|
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
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} catch(error) {
|
|
108
|
+
Logger.warning('Could not initialize relation metadata: '+error.message);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
72
112
|
castIdValue(id)
|
|
73
113
|
{
|
|
74
114
|
if(null === id || undefined === id){
|
|
@@ -211,7 +251,7 @@ class PrismaDriver extends BaseDriver
|
|
|
211
251
|
if(sc.hasOwn(this.referenceFields, key) && !sc.isArray(operatorValue)){
|
|
212
252
|
operatorValue = this.castNumericValue(operatorValue, this.referenceFields[key]);
|
|
213
253
|
}
|
|
214
|
-
processedFilters[key] = this.applyOperator(operatorValue, value.operator);
|
|
254
|
+
processedFilters[key] = this.applyOperator(operatorValue, value.operator, key);
|
|
215
255
|
continue;
|
|
216
256
|
}
|
|
217
257
|
if(sc.isObject(value) && !sc.isArray(value)){
|
|
@@ -239,6 +279,43 @@ class PrismaDriver extends BaseDriver
|
|
|
239
279
|
return processedFilters;
|
|
240
280
|
}
|
|
241
281
|
|
|
282
|
+
transformRelationResults(result, includeConfig)
|
|
283
|
+
{
|
|
284
|
+
if(!result || !includeConfig){
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
if(sc.isArray(result)){
|
|
288
|
+
return result.map(item => this.transformSingleResult(item, includeConfig));
|
|
289
|
+
}
|
|
290
|
+
return this.transformSingleResult(result, includeConfig);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
transformSingleResult(item, includeConfig)
|
|
294
|
+
{
|
|
295
|
+
if(!item || !sc.isObject(item)){
|
|
296
|
+
return item;
|
|
297
|
+
}
|
|
298
|
+
let transformed = {...item};
|
|
299
|
+
for(let relationName of Object.keys(includeConfig)){
|
|
300
|
+
if(!sc.hasOwn(transformed, relationName)){
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
let relationMeta = this.relationMetadata[relationName];
|
|
304
|
+
if(!relationMeta){
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
let relationValue = transformed[relationName];
|
|
308
|
+
if('one' === relationMeta.type && sc.isArray(relationValue)){
|
|
309
|
+
transformed[relationName] = 0 < relationValue.length ? relationValue[0] : null;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if('many' === relationMeta.type && !sc.isArray(relationValue)){
|
|
313
|
+
transformed[relationName] = relationValue ? [relationValue] : [];
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return transformed;
|
|
317
|
+
}
|
|
318
|
+
|
|
242
319
|
async create(params)
|
|
243
320
|
{
|
|
244
321
|
try {
|
|
@@ -439,10 +516,13 @@ class PrismaDriver extends BaseDriver
|
|
|
439
516
|
{
|
|
440
517
|
try {
|
|
441
518
|
let query = this.buildQueryOptions();
|
|
519
|
+
let includeConfig = {};
|
|
442
520
|
if(sc.isArray(relations) && 0 < relations.length){
|
|
443
|
-
|
|
521
|
+
includeConfig = this.buildIncludeObject(relations);
|
|
522
|
+
query.include = includeConfig;
|
|
444
523
|
}
|
|
445
|
-
|
|
524
|
+
let results = await this.model.findMany(query);
|
|
525
|
+
return this.transformRelationResults(results, includeConfig);
|
|
446
526
|
} catch(error) {
|
|
447
527
|
Logger.error('Load all with relations error: '+error.message);
|
|
448
528
|
return [];
|
|
@@ -468,10 +548,13 @@ class PrismaDriver extends BaseDriver
|
|
|
468
548
|
let processedFilters = this.processFilters(filters);
|
|
469
549
|
let query = this.buildQueryOptions();
|
|
470
550
|
query.where = processedFilters;
|
|
551
|
+
let includeConfig = {};
|
|
471
552
|
if(sc.isArray(relations) && 0 < relations.length){
|
|
472
|
-
|
|
553
|
+
includeConfig = this.buildIncludeObject(relations);
|
|
554
|
+
query.include = includeConfig;
|
|
473
555
|
}
|
|
474
|
-
|
|
556
|
+
let results = await this.model.findMany(query);
|
|
557
|
+
return this.transformRelationResults(results, includeConfig);
|
|
475
558
|
} catch(error) {
|
|
476
559
|
Logger.error('Load with relations error: '+error.message);
|
|
477
560
|
return [];
|
|
@@ -497,10 +580,13 @@ class PrismaDriver extends BaseDriver
|
|
|
497
580
|
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
498
581
|
let query = this.buildQueryOptions();
|
|
499
582
|
query.where = filter;
|
|
583
|
+
let includeConfig = {};
|
|
500
584
|
if(sc.isArray(relations) && 0 < relations.length){
|
|
501
|
-
|
|
585
|
+
includeConfig = this.buildIncludeObject(relations);
|
|
586
|
+
query.include = includeConfig;
|
|
502
587
|
}
|
|
503
|
-
|
|
588
|
+
let results = await this.model.findMany(query);
|
|
589
|
+
return this.transformRelationResults(results, includeConfig);
|
|
504
590
|
} catch(error) {
|
|
505
591
|
Logger.error('Load by with relations error: '+error.message);
|
|
506
592
|
return [];
|
|
@@ -527,10 +613,13 @@ class PrismaDriver extends BaseDriver
|
|
|
527
613
|
let query = {
|
|
528
614
|
where: {id: castedId}
|
|
529
615
|
};
|
|
616
|
+
let includeConfig = {};
|
|
530
617
|
if(sc.isArray(relations) && 0 < relations.length){
|
|
531
|
-
|
|
618
|
+
includeConfig = this.buildIncludeObject(relations);
|
|
619
|
+
query.include = includeConfig;
|
|
532
620
|
}
|
|
533
|
-
|
|
621
|
+
let result = await this.model.findUnique(query);
|
|
622
|
+
return this.transformRelationResults(result, includeConfig);
|
|
534
623
|
} catch(error) {
|
|
535
624
|
Logger.error('Load by ID with relations error: '+error.message);
|
|
536
625
|
return null;
|
|
@@ -571,10 +660,13 @@ class PrismaDriver extends BaseDriver
|
|
|
571
660
|
let processedFilters = this.processFilters(filters);
|
|
572
661
|
let query = this.buildQueryOptions(false);
|
|
573
662
|
query.where = processedFilters;
|
|
663
|
+
let includeConfig = {};
|
|
574
664
|
if(sc.isArray(relations) && 0 < relations.length){
|
|
575
|
-
|
|
665
|
+
includeConfig = this.buildIncludeObject(relations);
|
|
666
|
+
query.include = includeConfig;
|
|
576
667
|
}
|
|
577
|
-
|
|
668
|
+
let result = await this.model.findFirst(query);
|
|
669
|
+
return this.transformRelationResults(result, includeConfig);
|
|
578
670
|
} catch(error) {
|
|
579
671
|
Logger.error('Load one with relations error: '+error.message);
|
|
580
672
|
return null;
|
|
@@ -600,10 +692,13 @@ class PrismaDriver extends BaseDriver
|
|
|
600
692
|
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
601
693
|
let query = this.buildQueryOptions(false);
|
|
602
694
|
query.where = filter;
|
|
695
|
+
let includeConfig = {};
|
|
603
696
|
if(sc.isArray(relations) && 0 < relations.length){
|
|
604
|
-
|
|
697
|
+
includeConfig = this.buildIncludeObject(relations);
|
|
698
|
+
query.include = includeConfig;
|
|
605
699
|
}
|
|
606
|
-
|
|
700
|
+
let result = await this.model.findFirst(query);
|
|
701
|
+
return this.transformRelationResults(result, includeConfig);
|
|
607
702
|
} catch(error) {
|
|
608
703
|
Logger.error('Load one by with relations error: '+error.message);
|
|
609
704
|
return null;
|
|
@@ -647,11 +742,11 @@ class PrismaDriver extends BaseDriver
|
|
|
647
742
|
filter[field] = processedValue;
|
|
648
743
|
return filter;
|
|
649
744
|
}
|
|
650
|
-
filter[field] = this.applyOperator(processedValue, operator);
|
|
745
|
+
filter[field] = this.applyOperator(processedValue, operator, field);
|
|
651
746
|
return filter;
|
|
652
747
|
}
|
|
653
748
|
|
|
654
|
-
applyOperator(value, operator)
|
|
749
|
+
applyOperator(value, operator, fieldName = null)
|
|
655
750
|
{
|
|
656
751
|
let operatorsMap = {
|
|
657
752
|
'=': value,
|
|
@@ -660,13 +755,24 @@ class PrismaDriver extends BaseDriver
|
|
|
660
755
|
'>=': {gte: value},
|
|
661
756
|
'<': {lt: value},
|
|
662
757
|
'<=': {lte: value},
|
|
663
|
-
'LIKE':
|
|
758
|
+
'LIKE': this.handleLikeOperator(value, fieldName),
|
|
664
759
|
'IN': {in: value},
|
|
665
760
|
'NOT IN': {notIn: value}
|
|
666
761
|
};
|
|
667
762
|
return operatorsMap[operator] || value;
|
|
668
763
|
}
|
|
669
764
|
|
|
765
|
+
handleLikeOperator(value, fieldName)
|
|
766
|
+
{
|
|
767
|
+
if('id' === fieldName || (this.referenceFields && sc.hasOwn(this.referenceFields, fieldName))){
|
|
768
|
+
let numericValue = Number(value.replace(/%/g, ''));
|
|
769
|
+
if(!isNaN(numericValue)){
|
|
770
|
+
return numericValue;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return {contains: value};
|
|
774
|
+
}
|
|
775
|
+
|
|
670
776
|
buildIncludeObject(relations)
|
|
671
777
|
{
|
|
672
778
|
let include = {};
|
|
@@ -62,19 +62,19 @@ class PrismaSchemaGenerator
|
|
|
62
62
|
async waitForSchemaGeneration()
|
|
63
63
|
{
|
|
64
64
|
let clientPath = this.clientOutputPath || 'node_modules/.prisma/client';
|
|
65
|
-
let generatedClientPath =
|
|
66
|
-
? FileHandler.joinPaths(process.cwd(), clientPath)
|
|
67
|
-
: FileHandler.joinPaths(this.prismaSchemaPath, clientPath);
|
|
65
|
+
let generatedClientPath = this.resolveClientPath(clientPath);
|
|
68
66
|
let clientIndexPath = FileHandler.joinPaths(generatedClientPath, 'index.js');
|
|
69
67
|
let startTime = Date.now();
|
|
70
68
|
return new Promise((resolve) => {
|
|
71
69
|
let interval = setInterval(() => {
|
|
70
|
+
let awaitTime = Date.now() - startTime;
|
|
71
|
+
Logger.info('Awaiting on schema generation: ' + clientIndexPath, (awaitTime/1000).toFixed(0));
|
|
72
72
|
if(FileHandler.exists(clientIndexPath)){
|
|
73
73
|
clearInterval(interval);
|
|
74
74
|
resolve();
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
-
if(
|
|
77
|
+
if(awaitTime > this.maxWaitTime){
|
|
78
78
|
clearInterval(interval);
|
|
79
79
|
Logger.warning('Schema generation wait timeout reached.');
|
|
80
80
|
resolve();
|
|
@@ -83,6 +83,17 @@ class PrismaSchemaGenerator
|
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
resolveClientPath(clientPath)
|
|
87
|
+
{
|
|
88
|
+
if(clientPath.match(/^[a-zA-Z]:/) || clientPath.startsWith('/')){
|
|
89
|
+
return clientPath;
|
|
90
|
+
}
|
|
91
|
+
if(clientPath.startsWith('node_modules')){
|
|
92
|
+
return FileHandler.joinPaths(process.cwd(), clientPath);
|
|
93
|
+
}
|
|
94
|
+
return FileHandler.joinPaths(this.prismaSchemaPath, clientPath);
|
|
95
|
+
}
|
|
96
|
+
|
|
86
97
|
generateSchemaFile()
|
|
87
98
|
{
|
|
88
99
|
let datasourceProvider = this.getDatasourceProvider();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reldens/storage",
|
|
3
3
|
"scope": "@reldens",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.58.0",
|
|
5
5
|
"description": "Reldens - Storage",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -45,13 +45,13 @@
|
|
|
45
45
|
"@mikro-orm/core": "^6.4.16",
|
|
46
46
|
"@mikro-orm/mongodb": "^6.4.16",
|
|
47
47
|
"@mikro-orm/mysql": "^6.4.16",
|
|
48
|
-
"@prisma/client": "^6.
|
|
48
|
+
"@prisma/client": "^6.10.0",
|
|
49
49
|
"@reldens/server-utils": "^0.19.0",
|
|
50
50
|
"@reldens/utils": "^0.50.0",
|
|
51
51
|
"knex": "^3.1.0",
|
|
52
52
|
"mysql": "^2.18.1",
|
|
53
53
|
"mysql2": "^3.14.1",
|
|
54
54
|
"objection": "^3.1.5",
|
|
55
|
-
"prisma": "^6.
|
|
55
|
+
"prisma": "^6.10.0"
|
|
56
56
|
}
|
|
57
57
|
}
|