@solidstarters/solid-core 1.2.36 → 1.2.37

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.36",
3
+ "version": "1.2.37",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -141,7 +141,7 @@ export class CrudHelperService {
141
141
  }, {});
142
142
  }
143
143
 
144
- private normalize(value: string | string[]): string[] {
144
+ normalize(value: string | string[]): string[] {
145
145
  if (!value) return [];// if the value is nullish, then return an empty array
146
146
  return Array.isArray(value) ? value : [value]; // if the value is an array, return it as is, otherwise return it as an array
147
147
  }
@@ -428,13 +428,19 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
428
428
  }
429
429
  }
430
430
 
431
+ // Exclude one-to-many and many-to-one relations from the initial filter query, since they will be queried separately
432
+ const relationsExcludedFromInitialQuery = this.relationsExcludedFromInitialQuery(model, basicFilterDto.populate);
433
+ basicFilterDto = this.getRevisedFilterDto(basicFilterDto, relationsExcludedFromInitialQuery);
434
+
431
435
  // Create above query on pincode table using query builder
432
436
  var qb: SelectQueryBuilder<T> = this.repo.createQueryBuilder(alias)
433
437
  qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
434
-
438
+
435
439
  if (basicFilterDto.groupBy) {
440
+ const relationsExcludedFromInitialQuery = this.relationsExcludedFromInitialQuery(model, groupFilter.populate);
441
+ groupFilter = this.getRevisedFilterDto(groupFilter, relationsExcludedFromInitialQuery);
436
442
  // Get the records and the count
437
- const { groupMeta, groupRecords } = await this.handleGroupFind(qb, groupFilter, populateGroup, alias, populateMedia);
443
+ const { groupMeta, groupRecords } = await this.handleGroupFind(qb, groupFilter, populateGroup, alias, populateMedia, relationsExcludedFromInitialQuery);
438
444
  return {
439
445
  groupMeta,
440
446
  groupRecords,
@@ -442,7 +448,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
442
448
  }
443
449
  else {
444
450
  // Get the records and the count
445
- const { meta, records } = await this.handleNonGroupFind(qb, populateMedia, offset, limit);
451
+ const { meta, records } = await this.handleNonGroupFind(qb, populateMedia, offset, limit, alias, relationsExcludedFromInitialQuery);
446
452
  return {
447
453
  meta,
448
454
  records,
@@ -450,9 +456,28 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
450
456
  }
451
457
  }
452
458
 
453
- private async handleNonGroupFind(qb: SelectQueryBuilder<T>, populateMedia: string[], offset: number, limit: number) {
459
+ private getRevisedFilterDto(basicFilterDto: BasicFilterDto, relationsExcludedFromInitialQuery: string[]): BasicFilterDto {
460
+ const normalizedPopulate = this.crudHelperService.normalize(basicFilterDto.populate);
461
+ if (normalizedPopulate.length === 0 || relationsExcludedFromInitialQuery.length === 0) return basicFilterDto;
462
+ return { ...basicFilterDto, populate: normalizedPopulate.filter(populate => !relationsExcludedFromInitialQuery.includes(populate)) };
463
+ }
464
+
465
+ private relationsExcludedFromInitialQuery(model: ModelMetadata, relationsToBePopulated: string[] = []): string[] {
466
+ const relationToBeExcluded =
467
+ model.fields
468
+ .filter(field => field.type === 'relation' && [RelationType.manyTomany, RelationType.oneToMany].includes(field.relationType as RelationType))
469
+ .map(field => field.name);
470
+ return relationsToBePopulated.filter(relation => relationToBeExcluded.includes(relation));
471
+ }
472
+
473
+ private async handleNonGroupFind(qb: SelectQueryBuilder<T>, populateMedia: string[], offset: number, limit: number, alias: string, relationsExcludedFromInitialQuery: string[]) {
454
474
  const [entities, count] = await qb.getManyAndCount();
455
475
 
476
+ // Populate the excluded relations for the entities
477
+ if (relationsExcludedFromInitialQuery.length > 0) {
478
+ await this.populateExcludedRelations(entities, relationsExcludedFromInitialQuery, alias);
479
+ }
480
+
456
481
  // Populate the entity with the media
457
482
  if (populateMedia && populateMedia.length > 0) {
458
483
  await this.handlePopulateMedia(populateMedia, entities);
@@ -461,7 +486,36 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
461
486
  return this.wrapFindResponse(offset, limit, count, entities);
462
487
  }
463
488
 
464
- private async handleGroupFind(qb: SelectQueryBuilder<T>, groupFilter: BasicFilterDto, populateGroup: boolean, alias: string, populateMedia: string[]) {
489
+ private async populateExcludedRelations(entities: T[], relationsExcludedFromInitialQuery: string[], alias: string) {
490
+ //@ts-ignore
491
+ const ids = entities.map(entity => entity.id);
492
+
493
+ // Fire a query to get the records from the relation entity which match the ids
494
+ // Create a map with key as the entity id and value as the qb records
495
+ const relationEntitiesMap = {};
496
+ for (const relation of relationsExcludedFromInitialQuery) {
497
+ const qb = this.repo.createQueryBuilder(`${alias}`)
498
+ .leftJoinAndSelect(`${alias}.${relation}`, relation)
499
+ .where(`${alias}.id IN (:...ids)`, { ids })
500
+ // .limit(DEFAULT_LIMIT)
501
+ // .offset(DEFAULT_OFFSET);
502
+ const relationEntities = await qb.getMany();
503
+ relationEntitiesMap[relation] = relationEntities;
504
+ }
505
+
506
+ // Iterate over the map and assign the relation entities to the entity
507
+ for (const relation of relationsExcludedFromInitialQuery) {
508
+ for (const entity of entities) {
509
+ const entityRelations = relationEntitiesMap[relation]
510
+ //@ts-ignore
511
+ .filter((joinedEntity: T) => joinedEntity.id === entity.id)
512
+ .flatMap((joinedEntity: T) => joinedEntity[relation]);
513
+ entity[relation] = entityRelations;
514
+ }
515
+ }
516
+ }
517
+
518
+ private async handleGroupFind(qb: SelectQueryBuilder<T>, groupFilter: BasicFilterDto, populateGroup: boolean, alias: string, populateMedia: string[], relationsExcludedFromInitialQuery: string[]) {
465
519
  const groupByResult = await qb.getRawMany();
466
520
 
467
521
  const groupMeta = [];
@@ -470,15 +524,14 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
470
524
  for (const group of groupByResult) {
471
525
  if (populateGroup) {
472
526
  let groupByQb: SelectQueryBuilder<T> = this.repo.createQueryBuilder(alias);
473
- // For the group by records, apply the basic filter
474
- // const basicFilterDto = {
475
- // limit: DEFAULT_LIMIT,
476
- // offset: DEFAULT_OFFSET,
477
- // };
478
527
  groupByQb = this.crudHelperService.buildFilterQuery(groupByQb, groupFilter, alias);
479
528
  groupByQb = this.crudHelperService.buildGroupByRecordsQuery(groupByQb, group, alias);
480
529
  const [entities, count] = await groupByQb.getManyAndCount();
481
530
 
531
+ // Populate the excluded relations for the entities
532
+ if (relationsExcludedFromInitialQuery.length > 0) {
533
+ await this.populateExcludedRelations(entities, relationsExcludedFromInitialQuery, alias);
534
+ }
482
535
 
483
536
  // Populate the entity with the media
484
537
  if (populateMedia && populateMedia.length > 0) {