@clairejs/server 3.28.13 → 3.28.14

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/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## Change Log
2
2
 
3
+ #### 3.28.14
4
+
5
+ - implement @Expand and paralel run in getMany
6
+
3
7
  #### 3.28.13
4
8
 
5
9
  - fix update records handle undefined result
@@ -572,8 +572,13 @@ export class ModelRepository extends AbstractRepository {
572
572
  //-- check if there is any multi-local fields in projection
573
573
  const multiLocaleFields = this.modelMetadata.fields.filter((f) => f.isMultiLocale && (!queries?.projection || queries.projection.includes(f.name)));
574
574
  const localeOfFields = this.modelMetadata.fields.filter((f) => multiLocaleFields.find((locale) => locale.name === f.multiLocaleColumn));
575
+ const expandFields = this.modelMetadata.fields.filter((f) => f.expand && (!queries?.projection || queries.projection.includes(f.name)));
575
576
  const finalProjection = queries?.projection && [
576
- ...queries.projection.filter((fieldName) => !this.modelMetadata.fields.find((f) => f.name === fieldName && !!f.hasMany)),
577
+ ...queries.projection.filter((fieldName) => !this.modelMetadata.fields.find((f) => f.name === fieldName && (!!f.hasMany || !!f.expand))),
578
+ //-- include FK columns for expand fields so we can resolve them
579
+ ...expandFields
580
+ .map((f) => f.expand.column)
581
+ .filter((col) => !queries.projection.includes(col)),
577
582
  ...localeOfFields.map((f) => f.name),
578
583
  ];
579
584
  const result = await this.db.use(this.model, tx).getMany(conditions.length ? { _and: conditions } : {}, {
@@ -590,65 +595,93 @@ export class ModelRepository extends AbstractRepository {
590
595
  .flatMap((ids) => ids)
591
596
  .filter((id) => id);
592
597
  const systemLocale = getSystemLocale();
593
- const translations = !allLocaleEntries.length
594
- ? []
598
+ //-- fetch translations, has many, and expand fields in parallel
599
+ const hasManyFields = this.modelMetadata.fields.filter((f) => f.hasMany && (!queries?.projection || queries.projection.includes(f.name)));
600
+ const translationsPromise = !allLocaleEntries.length
601
+ ? Promise.resolve([])
595
602
  : !queries?.locale
596
603
  ? //-- if locale is not specified then get translation for all locales
597
- await this.db.use(LocaleTranslation, tx).getRecords({
604
+ this.db.use(LocaleTranslation, tx).getRecords({
598
605
  _in: { entryId: allLocaleEntries },
599
606
  }, { projection: ["entryId", "localeCode", "translation"] })
600
607
  : //-- if locale is specified then get only the translation of that locale
601
608
  queries.locale.toLowerCase() !== systemLocale
602
- ? await this.db.use(LocaleTranslation, tx).getRecords({
609
+ ? this.db.use(LocaleTranslation, tx).getRecords({
603
610
  _in: { entryId: allLocaleEntries },
604
611
  _eq: { localeCode: queries.locale },
605
612
  }, { projection: ["entryId", "localeCode", "translation"] })
606
613
  : //-- locale is system locale, no need to fetch translation
607
- [];
608
- for (const record of result.records) {
609
- for (const field of localeOfFields) {
610
- //-- map back translation
611
- if (!queries?.locale) {
612
- //-- map as object
613
- const fieldTranslations = translations
614
- .filter((t) => t.entryId === record[field.name])
615
- .map((t) => [t.localeCode, t.translation]);
616
- if (systemLocale) {
617
- fieldTranslations.push([systemLocale, record[field.multiLocaleColumn]]);
614
+ Promise.resolve([]);
615
+ await Promise.all([
616
+ //-- translations
617
+ translationsPromise.then((translations) => {
618
+ for (const record of result.records) {
619
+ for (const field of localeOfFields) {
620
+ //-- map back translation
621
+ if (!queries?.locale) {
622
+ //-- map as object
623
+ const fieldTranslations = translations
624
+ .filter((t) => t.entryId === record[field.name])
625
+ .map((t) => [t.localeCode, t.translation]);
626
+ if (systemLocale) {
627
+ fieldTranslations.push([systemLocale, record[field.multiLocaleColumn]]);
628
+ }
629
+ record[field.name] = Object.fromEntries(fieldTranslations);
630
+ }
631
+ else {
632
+ //-- replace value
633
+ const translation = translations.find((t) => t.localeCode === queries.locale && t.entryId === record[field.name]);
634
+ if (translation) {
635
+ record[field.multiLocaleColumn] = translation.translation;
636
+ }
637
+ }
618
638
  }
619
- record[field.name] = Object.fromEntries(fieldTranslations);
620
639
  }
621
- else {
622
- //-- replace value
623
- const translation = translations.find((t) => t.localeCode === queries.locale && t.entryId === record[field.name]);
624
- if (translation) {
625
- record[field.multiLocaleColumn] = translation.translation;
626
- }
640
+ }),
641
+ //-- has many
642
+ ...hasManyFields.map(async (field) => {
643
+ const model = getModelById(field.hasMany.relationDto.id);
644
+ if (!model) {
645
+ throw Errors.NOT_FOUND(`Model not found by id: ${field.hasMany.relationDto.id}`);
627
646
  }
628
- }
629
- }
630
- //-- get has many fields
631
- for (const field of this.modelMetadata.fields) {
632
- if (!field.hasMany || (queries?.projection && !queries.projection.includes(field.name))) {
633
- continue;
634
- }
635
- const model = getModelById(field.hasMany.relationDto.id);
636
- if (!model) {
637
- throw Errors.NOT_FOUND(`Model not found by id: ${field.hasMany.relationDto.id}`);
638
- }
639
- const service = new ModelRepository(model, this.db);
640
- const innerRecords = !recordIds.length
641
- ? { records: [] }
642
- : await service.getMany({
643
- queries: { fields: { [field.hasMany.column]: recordIds }, limit: field.hasMany.single ? 1 : 0 },
644
- tx,
645
- });
646
- //-- filter corresponding inner records for each master record
647
- for (const record of result.records) {
648
- const finalRecords = innerRecords.records.filter((r) => r[field.hasMany.column] === record.id);
649
- record[field.name] = (field.hasMany.single ? finalRecords[0] : finalRecords);
650
- }
651
- }
647
+ const service = new ModelRepository(model, this.db);
648
+ const innerRecords = !recordIds.length
649
+ ? { records: [] }
650
+ : await service.getMany({
651
+ queries: { fields: { [field.hasMany.column]: recordIds }, limit: field.hasMany.single ? 1 : 0 },
652
+ tx,
653
+ });
654
+ //-- filter corresponding inner records for each master record
655
+ for (const record of result.records) {
656
+ const finalRecords = innerRecords.records.filter((r) => r[field.hasMany.column] === record.id);
657
+ record[field.name] = (field.hasMany.single ? finalRecords[0] : finalRecords);
658
+ }
659
+ }),
660
+ //-- expand
661
+ ...expandFields.map(async (field) => {
662
+ const model = getModelById(field.expand.relationDto.id);
663
+ if (!model) {
664
+ throw Errors.NOT_FOUND(`Model not found by id: ${field.expand.relationDto.id}`);
665
+ }
666
+ //-- collect unique FK values from current records
667
+ const fkValues = result.records
668
+ .map((r) => r[field.expand.column])
669
+ .filter((v) => v !== undefined && v !== null)
670
+ .reduce(uniqueReducer, []);
671
+ const service = new ModelRepository(model, this.db);
672
+ const expandedRecords = !fkValues.length
673
+ ? { records: [] }
674
+ : await service.getMany({
675
+ queries: { fields: { id: fkValues } },
676
+ tx,
677
+ });
678
+ //-- assign expanded record to each master record
679
+ for (const record of result.records) {
680
+ const fkValue = record[field.expand.column];
681
+ record[field.name] = expandedRecords.records.find((r) => r.id === fkValue);
682
+ }
683
+ }),
684
+ ]);
652
685
  await this.beforeReturning(result.records);
653
686
  return {
654
687
  total: result.total,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clairejs/server",
3
- "version": "3.28.13",
3
+ "version": "3.28.14",
4
4
  "description": "Claire server NodeJs framework written in Typescript.",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
@@ -35,8 +35,8 @@
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@clairejs/client": "^3.5.1",
38
- "@clairejs/core": "^3.9.4",
39
- "@clairejs/orm": "^3.17.2"
38
+ "@clairejs/core": "^3.9.5",
39
+ "@clairejs/orm": "^3.19.11"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/cookie-parser": "^1.4.3",