@reldens/storage 0.117.0 → 0.119.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/test-architecture.md +27 -17
- package/CLAUDE.md +67 -11
- package/README.md +204 -22
- package/bin/reldens-storage.js +43 -10
- package/index.js +53 -12
- package/lib/drizzle/drizzle-data-server.js +123 -0
- package/lib/drizzle/drizzle-driver.js +228 -0
- package/lib/drizzle/drizzle-models-generation.js +49 -0
- package/lib/drizzle/drizzle-modules-loader.js +32 -0
- package/lib/drizzle/drizzle-modules-validator.js +74 -0
- package/lib/entities-generator.js +36 -7
- package/lib/entity-templates/drizzle-model.template +28 -0
- package/lib/entity-templates/query-builder-model.template +17 -0
- package/lib/generators/base-generator.js +13 -0
- package/lib/generators/entities-generation.js +0 -13
- package/lib/generators/models-generation.js +179 -680
- package/lib/generators/relations-detection.js +171 -0
- package/lib/knex/knex-data-server.js +128 -0
- package/lib/knex/knex-driver.js +157 -0
- package/lib/knex/knex-modules-loader.js +28 -0
- package/lib/knex/knex-modules-validator.js +45 -0
- package/lib/kysely/kysely-data-server.js +128 -0
- package/lib/kysely/kysely-driver.js +176 -0
- package/lib/kysely/kysely-modules-loader.js +28 -0
- package/lib/kysely/kysely-modules-validator.js +53 -0
- package/lib/mikro-orm/mikro-orm-data-server.js +48 -29
- package/lib/mikro-orm/mikro-orm-driver.js +317 -108
- package/lib/mikro-orm/mikro-orm-models-generation.js +178 -0
- package/lib/mikro-orm/mikro-orm-modules-loader.js +50 -0
- package/lib/mikro-orm/mikro-orm-modules-validator.js +46 -0
- package/lib/mysql2-connection-config.js +38 -0
- package/lib/objection-js/objection-js-data-server.js +71 -125
- package/lib/objection-js/objection-js-driver.js +4 -1
- package/lib/objection-js/objection-js-models-generation.js +98 -0
- package/lib/objection-js/objection-modules-loader.js +28 -0
- package/lib/objection-js/objection-modules-validator.js +31 -0
- package/lib/package-resolver.js +45 -0
- package/lib/prisma/prisma-client-loader.js +11 -1
- package/lib/prisma/prisma-driver.js +16 -2
- package/lib/prisma/prisma-filter-processor.js +5 -6
- package/lib/prisma/prisma-models-generation.js +236 -0
- package/lib/prisma/prisma-schema-generator.js +5 -1
- package/lib/prisma/prisma-type-caster.js +14 -0
- package/lib/query-builder-driver.js +210 -0
- package/lib/query-builder-models-generation.js +80 -0
- package/lib/relations-loader.js +192 -0
- package/lib/type-mapper.js +38 -0
- package/package.json +8 -8
- package/tests/.env.test.example +6 -0
- package/tests/fixtures/categories-fixtures.js +8 -0
- package/tests/fixtures/expected-entities/entities/test-product-details-entity.js +10 -1
- package/tests/fixtures/expected-entities/entities-translations.js +2 -0
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-categories-model.js +13 -8
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-product-details-model.js +30 -10
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-products-model.js +15 -14
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-reviews-model.js +13 -12
- package/tests/fixtures/expected-entities-prisma/models/prisma/test-product-details-model.js +3 -1
- package/tests/fixtures/product-details-fixtures.js +4 -1
- package/tests/fixtures/reviews-fixtures.js +2 -1
- package/tests/fixtures/sql/test-schema.sql +11 -2
- package/tests/fixtures/table-columns-fixtures.js +97 -0
- package/tests/integration/test-cross-driver-equivalence.js +286 -0
- package/tests/integration/test-nested-filters.js +265 -408
- package/tests/integration/test-relations.js +135 -0
- package/tests/integration/test-reldens-sample-data.js +255 -0
- package/tests/integration/test-reldens-shape-relations.js +292 -0
- package/tests/run-tests.js +111 -65
- package/tests/unit/test-drivers.js +7 -1
- package/tests/unit/test-models-generation.js +28 -18
- package/tests/utils/column-value-assert.js +139 -0
- package/tests/utils/entity-projection.js +111 -0
- package/tests/utils/observed-value.js +41 -0
- package/tests/utils/projection-difference.js +151 -0
- package/tests/utils/relations-shape-support.js +104 -0
- package/tests/utils/reldens-schema-loader.js +274 -0
- package/tests/utils/test-helpers.js +143 -13
- package/tests/utils/test-runner.js +26 -5
- package/tests/utils/whole-result-assert.js +243 -0
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
const { BaseDriver } = require('../base-driver');
|
|
8
8
|
const { Logger, sc } = require('@reldens/utils');
|
|
9
|
-
const { Collection } = require('@mikro-orm/core');
|
|
10
9
|
|
|
11
10
|
class MikroOrmDriver extends BaseDriver
|
|
12
11
|
{
|
|
@@ -26,6 +25,12 @@ class MikroOrmDriver extends BaseDriver
|
|
|
26
25
|
Logger.critical('Missing raw entity on Mikro ORM driver.');
|
|
27
26
|
return false;
|
|
28
27
|
}
|
|
28
|
+
this.mikroOrmModules = sc.get(props, 'mikroOrmModules', false);
|
|
29
|
+
if(!this.mikroOrmModules){
|
|
30
|
+
Logger.critical('Missing Mikro ORM modules on Mikro ORM driver.');
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
this.Collection = this.mikroOrmModules.Collection;
|
|
29
34
|
this.orm = props.orm;
|
|
30
35
|
this.server = props.server;
|
|
31
36
|
this.entitySchema = (sc.isObject(this.rawModel) && sc.hasOwn(this.rawModel, 'schema')) ? this.rawModel.schema : this.rawModel;
|
|
@@ -134,21 +139,51 @@ class MikroOrmDriver extends BaseDriver
|
|
|
134
139
|
return prop.joinColumns[0] || false;
|
|
135
140
|
}
|
|
136
141
|
|
|
137
|
-
|
|
142
|
+
removeRelationsFromParams(params)
|
|
138
143
|
{
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
if(!params || 'object' !== typeof params){
|
|
145
|
+
return params;
|
|
146
|
+
}
|
|
147
|
+
let columnsOnly = {...params};
|
|
148
|
+
for(let relationName of this.getAllRelations()){
|
|
149
|
+
delete columnsOnly[relationName];
|
|
150
|
+
}
|
|
151
|
+
return columnsOnly;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async createEntity(params)
|
|
155
|
+
{
|
|
156
|
+
let writeManager = this.orm.em.fork();
|
|
157
|
+
let newInstance = await writeManager.create(this.entitySchema, this.removeRelationsFromParams(params));
|
|
158
|
+
await writeManager.upsert(newInstance);
|
|
159
|
+
await writeManager.flush();
|
|
143
160
|
return newInstance;
|
|
144
161
|
}
|
|
145
162
|
|
|
146
|
-
async
|
|
163
|
+
async create(params)
|
|
147
164
|
{
|
|
148
|
-
|
|
149
|
-
|
|
165
|
+
return this.withoutUninitializedCollections(await this.createEntity(params));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
withoutUninitializedCollections(entity)
|
|
169
|
+
{
|
|
170
|
+
if(!entity || !this.Collection){
|
|
171
|
+
return entity;
|
|
172
|
+
}
|
|
173
|
+
let result = {};
|
|
174
|
+
for(let key of Object.keys(entity)){
|
|
175
|
+
if(entity[key] instanceof this.Collection && !entity[key].isInitialized()){
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
result[key] = entity[key];
|
|
150
179
|
}
|
|
151
|
-
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async createWithRelations(params, relations)
|
|
184
|
+
{
|
|
185
|
+
relations = this.normalizeRelations(relations);
|
|
186
|
+
let newInstance = await this.createEntity(params);
|
|
152
187
|
await this.createNested(newInstance, params, relations);
|
|
153
188
|
return await this.appendRelationsToCollection(newInstance, relations);
|
|
154
189
|
}
|
|
@@ -159,9 +194,9 @@ class MikroOrmDriver extends BaseDriver
|
|
|
159
194
|
if(0 === entities.length){
|
|
160
195
|
return false;
|
|
161
196
|
}
|
|
162
|
-
let
|
|
197
|
+
let columnsOnly = this.removeRelationsFromParams(updatePatch);
|
|
163
198
|
for(let entity of entities){
|
|
164
|
-
Object.assign(entity,
|
|
199
|
+
Object.assign(entity, columnsOnly);
|
|
165
200
|
await this.orm.em.upsert(entity);
|
|
166
201
|
await this.orm.em.flush();
|
|
167
202
|
}
|
|
@@ -190,7 +225,7 @@ class MikroOrmDriver extends BaseDriver
|
|
|
190
225
|
if(1 < entities.length){
|
|
191
226
|
Logger.warning('Multiple entities updated by ID: '+entities.map(e => e.id).join(', '));
|
|
192
227
|
}
|
|
193
|
-
return entities.shift();
|
|
228
|
+
return this.withoutUninitializedCollections(entities.shift());
|
|
194
229
|
}
|
|
195
230
|
|
|
196
231
|
async upsert(params, filters)
|
|
@@ -206,8 +241,7 @@ class MikroOrmDriver extends BaseDriver
|
|
|
206
241
|
if(filters){
|
|
207
242
|
let existent = await this.loadOne(filters);
|
|
208
243
|
if(existent){
|
|
209
|
-
|
|
210
|
-
return this.updateById(existent.id, transformed);
|
|
244
|
+
return this.updateById(existent.id, params);
|
|
211
245
|
}
|
|
212
246
|
}
|
|
213
247
|
return this.create(params);
|
|
@@ -224,18 +258,18 @@ class MikroOrmDriver extends BaseDriver
|
|
|
224
258
|
await this.orm.em.remove(entry);
|
|
225
259
|
}
|
|
226
260
|
await this.orm.em.flush();
|
|
227
|
-
return
|
|
261
|
+
return entries.length;
|
|
228
262
|
}
|
|
229
263
|
|
|
230
264
|
async deleteById(id)
|
|
231
265
|
{
|
|
232
|
-
let entity = await this.
|
|
266
|
+
let entity = await this.repository.findOne(this.processFilters({id}));
|
|
233
267
|
if(!entity){
|
|
234
268
|
return false;
|
|
235
269
|
}
|
|
236
270
|
await this.orm.em.remove(entity);
|
|
237
271
|
await this.orm.em.flush();
|
|
238
|
-
return
|
|
272
|
+
return 1;
|
|
239
273
|
}
|
|
240
274
|
|
|
241
275
|
async count(filters)
|
|
@@ -246,9 +280,7 @@ class MikroOrmDriver extends BaseDriver
|
|
|
246
280
|
|
|
247
281
|
async countWithRelations(filters, relations)
|
|
248
282
|
{
|
|
249
|
-
|
|
250
|
-
relations = this.getAllRelations();
|
|
251
|
-
}
|
|
283
|
+
relations = this.normalizeRelations(relations);
|
|
252
284
|
let processedFilters = this.processFilters(filters);
|
|
253
285
|
if(0 === relations.length || !this.entitySchema.meta || !this.entitySchema.meta.properties){
|
|
254
286
|
return this.repository.count(processedFilters);
|
|
@@ -261,7 +293,7 @@ class MikroOrmDriver extends BaseDriver
|
|
|
261
293
|
if(!prop || !prop.kind || (!this.isOwningRelation(prop) && !this.isInverseRelation(prop))){
|
|
262
294
|
continue;
|
|
263
295
|
}
|
|
264
|
-
let relationDriver = this.
|
|
296
|
+
let relationDriver = this.relationDriverFor(prop);
|
|
265
297
|
if(!relationDriver || !relationDriver.entitySchema){
|
|
266
298
|
continue;
|
|
267
299
|
}
|
|
@@ -281,106 +313,180 @@ class MikroOrmDriver extends BaseDriver
|
|
|
281
313
|
return queryBuilder.getCount();
|
|
282
314
|
}
|
|
283
315
|
|
|
284
|
-
loadAll()
|
|
316
|
+
async loadAll()
|
|
285
317
|
{
|
|
286
|
-
return this.repository.findAll();
|
|
318
|
+
return this.toPlainResult(await this.repository.findAll());
|
|
287
319
|
}
|
|
288
320
|
|
|
289
|
-
|
|
321
|
+
normalizeRelations(relations)
|
|
290
322
|
{
|
|
323
|
+
if(sc.isString(relations)){
|
|
324
|
+
relations = this.parseRelationsString(relations);
|
|
325
|
+
}
|
|
291
326
|
if(!sc.isArray(relations) || 0 === relations.length){
|
|
292
|
-
|
|
327
|
+
return this.getAllRelations();
|
|
293
328
|
}
|
|
294
|
-
|
|
295
|
-
return await this.appendRelationsToCollection(entities, relations);
|
|
329
|
+
return relations;
|
|
296
330
|
}
|
|
297
331
|
|
|
298
|
-
|
|
332
|
+
toPlainResult(result, populatedPaths, ancestors)
|
|
299
333
|
{
|
|
300
|
-
|
|
301
|
-
|
|
334
|
+
if(!result || 'object' !== typeof result || result instanceof Date){
|
|
335
|
+
return result;
|
|
336
|
+
}
|
|
337
|
+
if(!ancestors){
|
|
338
|
+
ancestors = new Set();
|
|
339
|
+
}
|
|
340
|
+
if(!populatedPaths){
|
|
341
|
+
populatedPaths = {};
|
|
342
|
+
}
|
|
343
|
+
if(result instanceof this.Collection){
|
|
344
|
+
if(!result.isInitialized()){
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
347
|
+
return this.toPlainList(result.getItems(), populatedPaths, ancestors);
|
|
348
|
+
}
|
|
349
|
+
if(sc.isArray(result)){
|
|
350
|
+
return this.toPlainList(result, populatedPaths, ancestors);
|
|
351
|
+
}
|
|
352
|
+
return this.toPlainEntity(result, populatedPaths, ancestors);
|
|
302
353
|
}
|
|
303
354
|
|
|
304
|
-
|
|
355
|
+
toPlainList(result, populatedPaths, ancestors)
|
|
305
356
|
{
|
|
306
|
-
|
|
307
|
-
|
|
357
|
+
ancestors.add(result);
|
|
358
|
+
let plainList = [];
|
|
359
|
+
for(let item of result){
|
|
360
|
+
if(ancestors.has(item)){
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
plainList.push(this.toPlainResult(item, populatedPaths, ancestors));
|
|
308
364
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
return await this.appendRelationsToCollection(entitiesCollection, relations);
|
|
365
|
+
ancestors.delete(result);
|
|
366
|
+
return plainList;
|
|
312
367
|
}
|
|
313
368
|
|
|
314
|
-
|
|
369
|
+
toPlainEntity(result, populatedPaths, ancestors)
|
|
315
370
|
{
|
|
316
|
-
|
|
317
|
-
let
|
|
318
|
-
|
|
371
|
+
ancestors.add(result);
|
|
372
|
+
let relationKeys = this.getAllRelations();
|
|
373
|
+
let plainEntity = {};
|
|
374
|
+
for(let key of Object.keys(result)){
|
|
375
|
+
if(ancestors.has(result[key])){
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if(-1 === relationKeys.indexOf(key)){
|
|
379
|
+
plainEntity[key] = result[key];
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if(!populatedPaths[key]){
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
plainEntity[key] = this.toPlainRelation(key, result[key], populatedPaths[key], ancestors);
|
|
386
|
+
}
|
|
387
|
+
ancestors.delete(result);
|
|
388
|
+
return plainEntity;
|
|
319
389
|
}
|
|
320
390
|
|
|
321
|
-
|
|
391
|
+
toPlainRelation(propName, relationValue, populatedPaths, ancestors)
|
|
322
392
|
{
|
|
323
|
-
|
|
324
|
-
|
|
393
|
+
let relationDriver = this.relationDriverFor(this.entitySchema.meta.properties[propName]);
|
|
394
|
+
if(!relationDriver){
|
|
395
|
+
return this.toPlainResult(relationValue, populatedPaths, ancestors);
|
|
325
396
|
}
|
|
397
|
+
return relationDriver.toPlainResult(relationValue, populatedPaths, ancestors);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async plainRelationsResult(entitiesCollection, relations)
|
|
401
|
+
{
|
|
402
|
+
return this.toPlainResult(
|
|
403
|
+
await this.appendRelationsToCollection(entitiesCollection, relations),
|
|
404
|
+
this.populatedPathsTree(relations)
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
findEntities(filters)
|
|
409
|
+
{
|
|
410
|
+
return this.repository.find(this.processFilters(filters), this.queryBuilder(true, true, true));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
findOneEntity(filters)
|
|
414
|
+
{
|
|
415
|
+
return this.repository.findOne(this.processFilters(filters), this.queryBuilder(false, true, true));
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async loadAllWithRelations(relations)
|
|
419
|
+
{
|
|
420
|
+
relations = this.normalizeRelations(relations);
|
|
421
|
+
let entities = await this.repository.findAll();
|
|
422
|
+
return this.plainRelationsResult(entities, relations);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async load(filters)
|
|
426
|
+
{
|
|
427
|
+
return this.toPlainResult(await this.findEntities(filters));
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async loadWithRelations(filters, relations)
|
|
431
|
+
{
|
|
432
|
+
relations = this.normalizeRelations(relations);
|
|
433
|
+
let entitiesCollection = await this.findEntities(filters);
|
|
434
|
+
return this.plainRelationsResult(entitiesCollection, relations);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async loadBy(field, fieldValue, operator = null)
|
|
438
|
+
{
|
|
439
|
+
return this.toPlainResult(await this.findEntities(this.createSingleFilter(field, fieldValue, operator)));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async loadByWithRelations(field, fieldValue, relations, operator = null)
|
|
443
|
+
{
|
|
444
|
+
relations = this.normalizeRelations(relations);
|
|
326
445
|
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
327
|
-
let
|
|
328
|
-
|
|
329
|
-
return await this.appendRelationsToCollection(entitiesCollection, relations);
|
|
446
|
+
let entitiesCollection = await this.findEntities(filter);
|
|
447
|
+
return this.plainRelationsResult(entitiesCollection, relations);
|
|
330
448
|
}
|
|
331
449
|
|
|
332
|
-
loadById(id)
|
|
450
|
+
async loadById(id)
|
|
333
451
|
{
|
|
334
|
-
return this.
|
|
452
|
+
return this.toPlainResult(await this.findOneEntity({id}));
|
|
335
453
|
}
|
|
336
454
|
|
|
337
455
|
async loadByIdWithRelations(id, relations)
|
|
338
456
|
{
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
let entity = await this.loadOneBy('id', id);
|
|
343
|
-
return await this.appendRelationsToCollection(entity, relations);
|
|
457
|
+
relations = this.normalizeRelations(relations);
|
|
458
|
+
let entity = await this.findOneEntity({id});
|
|
459
|
+
return this.plainRelationsResult(entity, relations);
|
|
344
460
|
}
|
|
345
461
|
|
|
346
|
-
loadByIds(ids)
|
|
462
|
+
async loadByIds(ids)
|
|
347
463
|
{
|
|
348
|
-
|
|
349
|
-
return this.repository.find(processedFilters);
|
|
464
|
+
return this.toPlainResult(await this.repository.find(this.processFilters({id: {$in: ids}})));
|
|
350
465
|
}
|
|
351
466
|
|
|
352
|
-
loadOne(filters)
|
|
467
|
+
async loadOne(filters)
|
|
353
468
|
{
|
|
354
|
-
|
|
355
|
-
return this.repository.findOne(processedFilters, this.queryBuilder(false, true, true));
|
|
469
|
+
return this.toPlainResult(await this.findOneEntity(filters));
|
|
356
470
|
}
|
|
357
471
|
|
|
358
472
|
async loadOneWithRelations(filters, relations)
|
|
359
473
|
{
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
let processedFilters = this.processFilters(filters);
|
|
364
|
-
let entitiesCollection = await this.repository.findOne(processedFilters, this.queryBuilder(false, true, true));
|
|
365
|
-
return this.appendRelationsToCollection(entitiesCollection, relations);
|
|
474
|
+
relations = this.normalizeRelations(relations);
|
|
475
|
+
let entitiesCollection = await this.findOneEntity(filters);
|
|
476
|
+
return this.plainRelationsResult(entitiesCollection, relations);
|
|
366
477
|
}
|
|
367
478
|
|
|
368
|
-
loadOneBy(field, fieldValue, operator = null)
|
|
479
|
+
async loadOneBy(field, fieldValue, operator = null)
|
|
369
480
|
{
|
|
370
|
-
|
|
371
|
-
let processedFilters = this.processFilters(filter);
|
|
372
|
-
return this.repository.findOne(processedFilters, this.queryBuilder(false, true, true));
|
|
481
|
+
return this.toPlainResult(await this.findOneEntity(this.createSingleFilter(field, fieldValue, operator)));
|
|
373
482
|
}
|
|
374
483
|
|
|
375
484
|
async loadOneByWithRelations(field, fieldValue, relations, operator = null)
|
|
376
485
|
{
|
|
377
|
-
|
|
378
|
-
relations = this.getAllRelations();
|
|
379
|
-
}
|
|
486
|
+
relations = this.normalizeRelations(relations);
|
|
380
487
|
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
381
|
-
let
|
|
382
|
-
|
|
383
|
-
return this.appendRelationsToCollection(entitiesCollection, relations);
|
|
488
|
+
let entitiesCollection = await this.findOneEntity(filter);
|
|
489
|
+
return this.plainRelationsResult(entitiesCollection, relations);
|
|
384
490
|
}
|
|
385
491
|
|
|
386
492
|
processFilters(filters)
|
|
@@ -391,6 +497,9 @@ class MikroOrmDriver extends BaseDriver
|
|
|
391
497
|
let processedFilters = {};
|
|
392
498
|
for(let key of Object.keys(filters)){
|
|
393
499
|
let value = filters[key];
|
|
500
|
+
if(('AND' === key || 'OR' === key) && sc.isArray(value) && 0 === value.length){
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
394
503
|
if('AND' === key && sc.isArray(value)){
|
|
395
504
|
processedFilters.$and = value.map(condition => this.processFilters(condition));
|
|
396
505
|
continue;
|
|
@@ -467,15 +576,39 @@ class MikroOrmDriver extends BaseDriver
|
|
|
467
576
|
return filter;
|
|
468
577
|
}
|
|
469
578
|
|
|
470
|
-
|
|
579
|
+
populatedPathsTree(relations)
|
|
580
|
+
{
|
|
581
|
+
let tree = {};
|
|
582
|
+
if(!sc.isArray(relations)){
|
|
583
|
+
return tree;
|
|
584
|
+
}
|
|
585
|
+
for(let relationPath of relations){
|
|
586
|
+
let node = tree;
|
|
587
|
+
for(let pathPart of String(relationPath).split('.')){
|
|
588
|
+
if(!node[pathPart]){
|
|
589
|
+
node[pathPart] = {};
|
|
590
|
+
}
|
|
591
|
+
node = node[pathPart];
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return tree;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
convertCollectionsToArrays(entity, populatedPaths)
|
|
471
598
|
{
|
|
472
599
|
if(!entity){
|
|
473
600
|
return entity;
|
|
474
601
|
}
|
|
475
|
-
for(let key of Object.keys(
|
|
476
|
-
if(entity[key]
|
|
477
|
-
|
|
602
|
+
for(let key of Object.keys(populatedPaths)){
|
|
603
|
+
if(!entity[key] || !(entity[key] instanceof this.Collection)){
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
if(!entity[key].isInitialized()){
|
|
607
|
+
Logger.warning('Relation "'+key+'" was not populated on '+this.tableName()+', it will be empty.');
|
|
608
|
+
entity[key] = [];
|
|
609
|
+
continue;
|
|
478
610
|
}
|
|
611
|
+
entity[key] = entity[key].getItems();
|
|
479
612
|
}
|
|
480
613
|
return entity;
|
|
481
614
|
}
|
|
@@ -511,13 +644,104 @@ class MikroOrmDriver extends BaseDriver
|
|
|
511
644
|
return entitiesCollection;
|
|
512
645
|
}
|
|
513
646
|
await this.orm.em.populate(entitiesCollection, relations);
|
|
647
|
+
let populatedPaths = this.populatedPathsTree(relations);
|
|
514
648
|
if(sc.isArray(entitiesCollection)){
|
|
515
649
|
for(let entity of entitiesCollection){
|
|
516
|
-
this.
|
|
650
|
+
this.restoreRelatedForeignKeys(entity, new Set(), populatedPaths);
|
|
651
|
+
await this.resolveKeyMappedRelations(entity, populatedPaths);
|
|
517
652
|
}
|
|
518
653
|
return entitiesCollection;
|
|
519
654
|
}
|
|
520
|
-
|
|
655
|
+
this.restoreRelatedForeignKeys(entitiesCollection, new Set(), populatedPaths);
|
|
656
|
+
await this.resolveKeyMappedRelations(entitiesCollection, populatedPaths);
|
|
657
|
+
return entitiesCollection;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
async resolveKeyMappedRelations(entity, populatedPaths)
|
|
661
|
+
{
|
|
662
|
+
if(!entity || !this.entitySchema.meta || !this.entitySchema.meta.properties){
|
|
663
|
+
return entity;
|
|
664
|
+
}
|
|
665
|
+
for(let propName of Object.keys(populatedPaths)){
|
|
666
|
+
let prop = this.entitySchema.meta.properties[propName];
|
|
667
|
+
if(!prop || !prop.mapToPk || !prop.targetKey || sc.isObject(entity[propName])){
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if(null === entity[propName] || 'undefined' === typeof entity[propName]){
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
let relationDriver = this.relationDriverFor(prop);
|
|
674
|
+
if(!relationDriver){
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
entity[propName] = await relationDriver.loadOneBy(prop.targetKey, entity[propName]);
|
|
678
|
+
}
|
|
679
|
+
return entity;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
restoreRelatedForeignKeys(entity, visited, populatedPaths)
|
|
683
|
+
{
|
|
684
|
+
if(!entity || visited.has(entity)){
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
visited.add(entity);
|
|
688
|
+
this.convertCollectionsToArrays(entity, populatedPaths);
|
|
689
|
+
this.addFkFieldsFromRelations(entity);
|
|
690
|
+
if(!this.entitySchema.meta || !this.entitySchema.meta.properties){
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
for(let propName of Object.keys(populatedPaths)){
|
|
694
|
+
let relationDriver = this.relationDriverFor(this.entitySchema.meta.properties[propName]);
|
|
695
|
+
if(!relationDriver){
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
relationDriver.restoreRelatedEntities(entity[propName], visited, populatedPaths[propName]);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
restoreRelatedEntities(relatedValue, visited, populatedPaths)
|
|
703
|
+
{
|
|
704
|
+
if(!relatedValue || relatedValue instanceof this.Collection){
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if(sc.isArray(relatedValue)){
|
|
708
|
+
for(let relatedEntity of relatedValue){
|
|
709
|
+
this.restoreRelatedForeignKeys(relatedEntity, visited, populatedPaths);
|
|
710
|
+
}
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
this.restoreRelatedForeignKeys(relatedValue, visited, populatedPaths);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
relationTargetClass(prop)
|
|
717
|
+
{
|
|
718
|
+
if(!sc.isFunction(prop?.entity)){
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
return prop.entity();
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
relationDriverFor(prop)
|
|
725
|
+
{
|
|
726
|
+
let targetClass = this.relationTargetClass(prop);
|
|
727
|
+
let targetClassName = (prop && prop.targetMeta) ? prop.targetMeta.className : false;
|
|
728
|
+
if(!targetClass && !targetClassName){
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
let entities = this.server.entityManager.entities;
|
|
732
|
+
for(let entityKey of Object.keys(entities)){
|
|
733
|
+
let candidate = entities[entityKey];
|
|
734
|
+
if(!candidate || !candidate.entitySchema || !candidate.entitySchema.meta){
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
if(targetClass && candidate.entitySchema.meta.class === targetClass){
|
|
738
|
+
return candidate;
|
|
739
|
+
}
|
|
740
|
+
if(targetClassName && candidate.entitySchema.meta.className === targetClassName){
|
|
741
|
+
return candidate;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return false;
|
|
521
745
|
}
|
|
522
746
|
|
|
523
747
|
async createNested(newInstance, params, relations)
|
|
@@ -534,12 +758,12 @@ class MikroOrmDriver extends BaseDriver
|
|
|
534
758
|
if(sc.isArray(relations) && 0 < relations.length && -1 === relations.indexOf(relationName)){
|
|
535
759
|
continue;
|
|
536
760
|
}
|
|
537
|
-
|
|
538
|
-
if(!relationDriver){
|
|
539
|
-
Logger.warning('Entity not found for relation:', prop.entity);
|
|
761
|
+
if(!sc.hasOwn(params, relationName)){
|
|
540
762
|
continue;
|
|
541
763
|
}
|
|
542
|
-
|
|
764
|
+
let relationDriver = this.relationDriverFor(prop);
|
|
765
|
+
if(!relationDriver){
|
|
766
|
+
Logger.warning('Entity not found for relation: '+relationName);
|
|
543
767
|
continue;
|
|
544
768
|
}
|
|
545
769
|
if(this.isOwningRelation(prop)){
|
|
@@ -558,12 +782,12 @@ class MikroOrmDriver extends BaseDriver
|
|
|
558
782
|
|
|
559
783
|
async createOne(params, relationName, relationDriver, newInstance, prop)
|
|
560
784
|
{
|
|
561
|
-
let nestedData = params[relationName];
|
|
785
|
+
let nestedData = Object.assign({}, params[relationName]);
|
|
562
786
|
let fkColumn = this.nestedFkColumn(prop, relationDriver);
|
|
563
787
|
if(fkColumn){
|
|
564
788
|
nestedData[fkColumn] = newInstance.id;
|
|
565
789
|
}
|
|
566
|
-
let nestedObject = await relationDriver.
|
|
790
|
+
let nestedObject = await relationDriver.createEntity(nestedData);
|
|
567
791
|
await this.orm.em.flush();
|
|
568
792
|
newInstance[relationName] = nestedObject;
|
|
569
793
|
}
|
|
@@ -571,34 +795,19 @@ class MikroOrmDriver extends BaseDriver
|
|
|
571
795
|
async createMany(params, relationName, relationDriver, newInstance, prop)
|
|
572
796
|
{
|
|
573
797
|
let nestedArray = [];
|
|
798
|
+
let fkColumn = this.nestedFkColumn(prop, relationDriver);
|
|
574
799
|
for(let objectData of params[relationName]){
|
|
575
|
-
|
|
576
|
-
|
|
800
|
+
let nestedData = Object.assign({}, objectData);
|
|
801
|
+
if(fkColumn){
|
|
802
|
+
nestedData[fkColumn] = newInstance.id;
|
|
577
803
|
}
|
|
578
|
-
let nestedObject = await relationDriver.
|
|
804
|
+
let nestedObject = await relationDriver.createEntity(nestedData);
|
|
579
805
|
await this.orm.em.flush();
|
|
580
806
|
nestedArray.push(nestedObject);
|
|
581
807
|
}
|
|
582
808
|
newInstance[relationName] = nestedArray;
|
|
583
809
|
}
|
|
584
810
|
|
|
585
|
-
transformFkToRelations(params)
|
|
586
|
-
{
|
|
587
|
-
if(!params || 'object' !== typeof params){
|
|
588
|
-
return params;
|
|
589
|
-
}
|
|
590
|
-
let transformed = {...params};
|
|
591
|
-
for(let fkColumn of Object.keys(this.fkMappings)){
|
|
592
|
-
if(!sc.hasOwn(params, fkColumn) || null === params[fkColumn]){
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
let mapping = this.fkMappings[fkColumn];
|
|
596
|
-
transformed[mapping.relationKey] = this.orm.em.getReference(mapping.entityName, params[fkColumn]);
|
|
597
|
-
delete transformed[fkColumn];
|
|
598
|
-
}
|
|
599
|
-
return transformed;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
811
|
}
|
|
603
812
|
|
|
604
813
|
module.exports.MikroOrmDriver = MikroOrmDriver;
|