First step of https://github.com/twentyhq/twenty/issues/6868 Adds min.., max.. queries for DATETIME fields adds min.., max.., avg.., sum.. queries for NUMBER fields (count distinct operation and composite fields such as CURRENCY handling will be dealt with in a future PR) <img width="1422" alt="Capture d’écran 2024-11-06 à 15 48 46" src="https://github.com/user-attachments/assets/4bcdece0-ad3e-4536-9720-fe4044a36719"> --------- Co-authored-by: Charles Bochet <charles@twenty.com> Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
@ -467,13 +467,13 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
);
|
||||
}
|
||||
|
||||
const objectMetadataMap =
|
||||
await this.workspaceCacheStorageService.getObjectMetadataMap(
|
||||
const objectMetadataMaps =
|
||||
await this.workspaceCacheStorageService.getObjectMetadataMaps(
|
||||
workspaceId,
|
||||
metadataVersion,
|
||||
);
|
||||
|
||||
if (!objectMetadataMap) {
|
||||
if (!objectMetadataMaps) {
|
||||
throw new NotFoundException(
|
||||
`Object metadata map not found for workspace ${workspaceId} and metadata version ${metadataVersion}`,
|
||||
);
|
||||
@ -481,9 +481,9 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
|
||||
const mappedResult = fieldMetadataItems.map((fieldMetadataItem) => {
|
||||
const objectMetadata =
|
||||
objectMetadataMap[fieldMetadataItem.objectMetadataId];
|
||||
objectMetadataMaps.byId[fieldMetadataItem.objectMetadataId];
|
||||
|
||||
const fieldMetadata = objectMetadata.fields[fieldMetadataItem.id];
|
||||
const fieldMetadata = objectMetadata.fieldsById[fieldMetadataItem.id];
|
||||
|
||||
const relationMetadata =
|
||||
fieldMetadata.fromRelationMetadata ?? fieldMetadata.toRelationMetadata;
|
||||
@ -495,18 +495,18 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
}
|
||||
|
||||
const fromObjectMetadata =
|
||||
objectMetadataMap[relationMetadata.fromObjectMetadataId];
|
||||
objectMetadataMaps.byId[relationMetadata.fromObjectMetadataId];
|
||||
|
||||
const toObjectMetadata =
|
||||
objectMetadataMap[relationMetadata.toObjectMetadataId];
|
||||
objectMetadataMaps.byId[relationMetadata.toObjectMetadataId];
|
||||
|
||||
const fromFieldMetadata =
|
||||
objectMetadataMap[fromObjectMetadata.id].fields[
|
||||
objectMetadataMaps.byId[fromObjectMetadata.id].fieldsById[
|
||||
relationMetadata.fromFieldMetadataId
|
||||
];
|
||||
|
||||
const toFieldMetadata =
|
||||
objectMetadataMap[toObjectMetadata.id].fields[
|
||||
objectMetadataMaps.byId[toObjectMetadata.id].fieldsById[
|
||||
relationMetadata.toFieldMetadataId
|
||||
];
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
|
||||
export type FieldMetadataMap = Record<string, FieldMetadataInterface>;
|
||||
@ -0,0 +1,8 @@
|
||||
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
|
||||
|
||||
import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map';
|
||||
|
||||
export type ObjectMetadataItemWithFieldMaps = ObjectMetadataInterface & {
|
||||
fieldsById: FieldMetadataMap;
|
||||
fieldsByName: FieldMetadataMap;
|
||||
};
|
||||
@ -0,0 +1,7 @@
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
|
||||
export type ObjectMetadataMaps = {
|
||||
byId: Record<string, ObjectMetadataItemWithFieldMaps>;
|
||||
byNameSingular: Record<string, ObjectMetadataItemWithFieldMaps>;
|
||||
byNamePlural: Record<string, ObjectMetadataItemWithFieldMaps>;
|
||||
};
|
||||
@ -1,36 +0,0 @@
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
|
||||
|
||||
export type FieldMetadataMap = Record<string, FieldMetadataInterface>;
|
||||
|
||||
export type ObjectMetadataMapItem = Omit<ObjectMetadataInterface, 'fields'> & {
|
||||
fields: FieldMetadataMap;
|
||||
};
|
||||
|
||||
export type ObjectMetadataMap = Record<string, ObjectMetadataMapItem>;
|
||||
|
||||
export const generateObjectMetadataMap = (
|
||||
objectMetadataCollection: ObjectMetadataInterface[],
|
||||
): ObjectMetadataMap => {
|
||||
const objectMetadataMap: ObjectMetadataMap = {};
|
||||
|
||||
for (const objectMetadata of objectMetadataCollection) {
|
||||
const fieldsMap: FieldMetadataMap = {};
|
||||
|
||||
for (const fieldMetadata of objectMetadata.fields) {
|
||||
fieldsMap[fieldMetadata.name] = fieldMetadata;
|
||||
fieldsMap[fieldMetadata.id] = fieldMetadata;
|
||||
}
|
||||
|
||||
const processedObjectMetadata: ObjectMetadataMapItem = {
|
||||
...objectMetadata,
|
||||
fields: fieldsMap,
|
||||
};
|
||||
|
||||
objectMetadataMap[objectMetadata.id] = processedObjectMetadata;
|
||||
objectMetadataMap[objectMetadata.nameSingular] = processedObjectMetadata;
|
||||
objectMetadataMap[objectMetadata.namePlural] = processedObjectMetadata;
|
||||
}
|
||||
|
||||
return objectMetadataMap;
|
||||
};
|
||||
@ -0,0 +1,39 @@
|
||||
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
|
||||
|
||||
import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map';
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
|
||||
export const generateObjectMetadataMaps = (
|
||||
objectMetadataCollection: ObjectMetadataInterface[],
|
||||
): ObjectMetadataMaps => {
|
||||
const objectMetadataMaps: ObjectMetadataMaps = {
|
||||
byId: {},
|
||||
byNameSingular: {},
|
||||
byNamePlural: {},
|
||||
};
|
||||
|
||||
for (const objectMetadata of objectMetadataCollection) {
|
||||
const fieldsByIdMap: FieldMetadataMap = {};
|
||||
const fieldsByNameMap: FieldMetadataMap = {};
|
||||
|
||||
for (const fieldMetadata of objectMetadata.fields) {
|
||||
fieldsByNameMap[fieldMetadata.name] = fieldMetadata;
|
||||
fieldsByIdMap[fieldMetadata.id] = fieldMetadata;
|
||||
}
|
||||
|
||||
const processedObjectMetadata: ObjectMetadataItemWithFieldMaps = {
|
||||
...objectMetadata,
|
||||
fieldsById: fieldsByIdMap,
|
||||
fieldsByName: fieldsByNameMap,
|
||||
};
|
||||
|
||||
objectMetadataMaps.byId[objectMetadata.id] = processedObjectMetadata;
|
||||
objectMetadataMaps.byNameSingular[objectMetadata.nameSingular] =
|
||||
processedObjectMetadata;
|
||||
objectMetadataMaps.byNamePlural[objectMetadata.namePlural] =
|
||||
processedObjectMetadata;
|
||||
}
|
||||
|
||||
return objectMetadataMaps;
|
||||
};
|
||||
@ -1,12 +1,14 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import console from 'console';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { LogExecutionTime } from 'src/engine/decorators/observability/log-execution-time.decorator';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { generateObjectMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
|
||||
import { generateObjectMetadataMaps } from 'src/engine/metadata-modules/utils/generate-object-metadata-maps.util';
|
||||
import {
|
||||
WorkspaceMetadataCacheException,
|
||||
WorkspaceMetadataCacheExceptionCode,
|
||||
@ -85,15 +87,15 @@ export class WorkspaceMetadataCacheService {
|
||||
console.timeEnd('fetching object metadata');
|
||||
|
||||
console.time('generating object metadata map');
|
||||
const freshObjectMetadataMap =
|
||||
generateObjectMetadataMap(objectMetadataItems);
|
||||
const freshObjectMetadataMaps =
|
||||
generateObjectMetadataMaps(objectMetadataItems);
|
||||
|
||||
console.timeEnd('generating object metadata map');
|
||||
|
||||
await this.workspaceCacheStorageService.setObjectMetadataMap(
|
||||
await this.workspaceCacheStorageService.setObjectMetadataMaps(
|
||||
workspaceId,
|
||||
currentDatabaseVersion,
|
||||
freshObjectMetadataMap,
|
||||
freshObjectMetadataMaps,
|
||||
);
|
||||
|
||||
await this.workspaceCacheStorageService.removeObjectMetadataOngoingCachingLock(
|
||||
|
||||
Reference in New Issue
Block a user