fix: resolve N+1 query issue in view name resolver with DataLoaders (#14037)

## What
Fixed N+1 query issue where each view's name resolution triggered a
separate DB query to fetch objectMetadataId, even though it was already
available in the parent view object.

## How
- Added `objectMetadataLoader` to DataloaderService to batch metadata
lookups
- Updated ViewResolver to use context.loaders (following existing
pattern from other metadata
  resolvers)
  - Removed unused `getObjectMetadataByViewId` method and its tests

Now uses the already-loaded `view.objectMetadataId` directly instead of
making unnecessary
  queries.

  Much cleaner!
This commit is contained in:
nitin
2025-08-22 13:15:50 +05:30
committed by GitHub
parent 96fd12ec7c
commit 7bd6d27c0d
5 changed files with 42 additions and 135 deletions
@@ -5,6 +5,7 @@ import {
type IndexFieldMetadataLoaderPayload,
type IndexMetadataLoaderPayload,
type MorphRelationLoaderPayload,
type ObjectMetadataLoaderPayload,
type RelationLoaderPayload,
} from 'src/engine/dataloaders/dataloader.service';
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
@@ -12,6 +13,7 @@ import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-meta
import { type IndexFieldMetadataDTO } from 'src/engine/metadata-modules/index-metadata/dtos/index-field-metadata.dto';
import { type IndexMetadataDTO } from 'src/engine/metadata-modules/index-metadata/dtos/index-metadata.dto';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
export interface IDataloaders {
relationLoader: DataLoader<
@@ -48,4 +50,9 @@ export interface IDataloaders {
IndexFieldMetadataLoaderPayload,
IndexFieldMetadataDTO[]
>;
objectMetadataLoader: DataLoader<
ObjectMetadataLoaderPayload,
ObjectMetadataItemWithFieldMaps | null
>;
}
@@ -8,6 +8,7 @@ import { type IndexMetadataInterface } from 'src/engine/metadata-modules/index-m
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
import { type IDataloaders } from 'src/engine/dataloaders/dataloader.interface';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { filterMorphRelationDuplicateFieldsDTO } from 'src/engine/dataloaders/utils/filter-morph-relation-duplicate-fields.util';
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@@ -67,6 +68,11 @@ export type IndexFieldMetadataLoaderPayload = {
indexMetadata: Pick<IndexMetadataInterface, 'id'>;
};
export type ObjectMetadataLoaderPayload = {
workspaceId: string;
objectMetadataId: string;
};
@Injectable()
export class DataloaderService {
constructor(
@@ -82,6 +88,7 @@ export class DataloaderService {
const fieldMetadataLoader = this.createFieldMetadataLoader();
const indexMetadataLoader = this.createIndexMetadataLoader();
const indexFieldMetadataLoader = this.createIndexFieldMetadataLoader();
const objectMetadataLoader = this.createObjectMetadataLoader();
return {
relationLoader,
@@ -89,6 +96,7 @@ export class DataloaderService {
fieldMetadataLoader,
indexMetadataLoader,
indexFieldMetadataLoader,
objectMetadataLoader,
};
}
@@ -308,4 +316,25 @@ export class DataloaderService {
);
});
}
private createObjectMetadataLoader() {
return new DataLoader<
ObjectMetadataLoaderPayload,
ObjectMetadataItemWithFieldMaps | null
>(async (dataLoaderParams: ObjectMetadataLoaderPayload[]) => {
const workspaceId = dataLoaderParams[0].workspaceId;
const objectMetadataIds = dataLoaderParams.map(
(dataLoaderParam) => dataLoaderParam.objectMetadataId,
);
const { objectMetadataMaps } =
await this.workspaceMetadataCacheService.getExistingOrRecomputeMetadataMaps(
{ workspaceId },
);
return objectMetadataIds.map((objectMetadataId) => {
return objectMetadataMaps.byId[objectMetadataId] || null;
});
});
}
}