Add unique indexes and indexes for composite types (#7162)
Add support for indexes on composite fields and unicity constraint on indexes This pull request includes several changes across multiple files to improve error handling, enforce unique constraints, and update database migrations. The most important changes include updating error messages for snack bars, adding a new command to enforce unique constraints, and updating database migrations to include new fields and constraints. ### Error Handling Improvements: * [`packages/twenty-front/src/modules/error-handler/components/PromiseRejectionEffect.tsx`](diffhunk://#diff-e7dc05ced8e4730430f5c7fcd0c75b3aa723da438c26e0bef8130b614427dd9aL23-R23): Updated error messages in `enqueueSnackBar` to use `error.message` directly. * [`packages/twenty-front/src/modules/object-metadata/hooks/useFindManyObjectMetadataItems.ts`](diffhunk://#diff-74c126d6bc7a5ed6b63be994d298df6669058034bfbc367b11045f9f31a3abe6L44-R46): Simplified error messages in `enqueueSnackBar`. * [`packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts`](diffhunk://#diff-af23a1d99639a66c251f87473e63e2b7bceaa4ee4f70fedfa0fcffe5c7d79181L56-R58): Simplified error messages in `enqueueSnackBar`. * [`packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts`](diffhunk://#diff-da04296cbe280202a1eaf6b1244a30490d4f400411bee139651172c59719088eL22-R24): Simplified error messages in `enqueueSnackBar`. ### New Command for Unique Constraints: * [`packages/twenty-server/src/database/commands/upgrade-version/0-31/0-31-enforce-unique-constraints.command.ts`](diffhunk://#diff-8337096c8c80dd2619a5ba691ae5145101f8ae0368a75192a050047e8c6ab7cbR1-R159): Added a new command to enforce unique constraints on company domain names and person emails. * [`packages/twenty-server/src/database/commands/upgrade-version/0-31/0-31-upgrade-version.command.ts`](diffhunk://#diff-20215e9981a53c7566e9cbff96715685125878f5bcb84fe461a7440f2e68f6fcR13-R14): Integrated the new `EnforceUniqueConstraintsCommand` into the upgrade process. [[1]](diffhunk://#diff-20215e9981a53c7566e9cbff96715685125878f5bcb84fe461a7440f2e68f6fcR13-R14) [[2]](diffhunk://#diff-20215e9981a53c7566e9cbff96715685125878f5bcb84fe461a7440f2e68f6fcR31) [[3]](diffhunk://#diff-20215e9981a53c7566e9cbff96715685125878f5bcb84fe461a7440f2e68f6fcR64-R68) * [`packages/twenty-server/src/database/commands/upgrade-version/0-31/0-31-upgrade-version.module.ts`](diffhunk://#diff-da52814efc674c25ed55645f8ee2561013641a407f88423e705dd6c77b405527R7): Registered the new `EnforceUniqueConstraintsCommand` in the module. [[1]](diffhunk://#diff-da52814efc674c25ed55645f8ee2561013641a407f88423e705dd6c77b405527R7) [[2]](diffhunk://#diff-da52814efc674c25ed55645f8ee2561013641a407f88423e705dd6c77b405527R24) ### Database Migrations: * [`packages/twenty-server/src/database/typeorm/metadata/migrations/1726757368824-migrationDebt.ts`](diffhunk://#diff-c450aeae7bc0ef4416a0ade2dc613ca3f688629f35d2a32f90a09c3f494febdcR1-R53): Added a migration to update the `relationMetadata_ondeleteaction_enum` and set default values. * [`packages/twenty-server/src/database/typeorm/metadata/migrations/1726757368825-addIsUniqueToIndexMetadata.ts`](diffhunk://#diff-8f1e14bd7f6835ec2c3bb39bcc51e3c318a3008d576a981e682f4c985e746fbfR1-R19): Added a migration to include the `isUnique` field in `indexMetadata`. * [`packages/twenty-server/src/database/typeorm/metadata/migrations/1726762935841-addCompostiveColumnToIndexFieldMetadata.ts`](diffhunk://#diff-7c96b7276c7722d41ff31de23b2de4d6e09adfdc74815356ba63bc96a2669440R1-R19): Added a migration to include the `compositeColumn` field in `indexFieldMetadata`. * [`packages/twenty-server/src/database/typeorm/metadata/migrations/1726766871572-addWhereToIndexMetadata.ts`](diffhunk://#diff-26651295a975eb50e672dce0e4e274e861f66feb1b68105eee5a04df32796190R1-R14): Added a migration to include the `indexWhereClause` field in `indexMetadata`. ### GraphQL Exception Handling: * [`packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util.ts`](diffhunk://#diff-58445eb362dc89e31107777d39b592d7842d2ab09a223012ccd055da325270a8R1-R4): Enhanced exception handling for `QueryFailedError` to provide more specific error messages for unique constraint violations. [[1]](diffhunk://#diff-58445eb362dc89e31107777d39b592d7842d2ab09a223012ccd055da325270a8R1-R4) [[2]](diffhunk://#diff-58445eb362dc89e31107777d39b592d7842d2ab09a223012ccd055da325270a8R23-R59) * [`packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts`](diffhunk://#diff-233d58ab2333586dd45e46e33d4f07e04a4b8adde4a11a48e25d86985e5a7943L58-R58): Updated the `workspaceQueryRunnerGraphqlApiExceptionHandler` call to include context. * [`packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts`](diffhunk://#diff-68b803f0762c407f5d2d1f5f8d389655a60654a2dd2394a81318655dcd44dc43L58-R58): Updated the `workspaceQueryRunnerGraphqlApiExceptionHandler` call to include context. --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -5,9 +5,9 @@ export interface WorkspaceTableStructure {
|
||||
dataType: string;
|
||||
columnDefault: string;
|
||||
isNullable: boolean;
|
||||
isUnique: boolean;
|
||||
isPrimaryKey: boolean;
|
||||
isForeignKey: boolean;
|
||||
isUnique: boolean;
|
||||
isArray: boolean;
|
||||
onUpdateAction: string;
|
||||
onDeleteAction: string;
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { CompositeType } from 'src/engine/metadata-modules/field-metadata/interfaces/composite-type.interface';
|
||||
import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
|
||||
|
||||
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
|
||||
@ -77,10 +81,8 @@ export class WorkspaceMigrationIndexFactory {
|
||||
objectMetadata.fields.map((field) => [field.id, field]),
|
||||
);
|
||||
|
||||
const indexes = indexMetadataCollection.map((indexMetadata) => ({
|
||||
name: indexMetadata.name,
|
||||
action: WorkspaceMigrationIndexActionType.CREATE,
|
||||
columns: indexMetadata.indexFieldMetadatas
|
||||
const indexes = indexMetadataCollection.map((indexMetadata) => {
|
||||
const columns = indexMetadata.indexFieldMetadatas
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((indexFieldMetadata) => {
|
||||
const fieldMetadata =
|
||||
@ -92,10 +94,35 @@ export class WorkspaceMigrationIndexFactory {
|
||||
);
|
||||
}
|
||||
|
||||
return fieldMetadata.name;
|
||||
}),
|
||||
type: indexMetadata.indexType,
|
||||
}));
|
||||
if (!isCompositeFieldMetadataType(fieldMetadata.type)) {
|
||||
return fieldMetadata.name;
|
||||
}
|
||||
|
||||
const compositeType = compositeTypeDefinitions.get(
|
||||
fieldMetadata.type,
|
||||
) as CompositeType;
|
||||
|
||||
return compositeType.properties
|
||||
.filter((property) => property.isIncludedInUniqueConstraint)
|
||||
.map((property) =>
|
||||
computeCompositeColumnName(fieldMetadata, property),
|
||||
);
|
||||
})
|
||||
.flat();
|
||||
|
||||
const defaultWhereClause = indexMetadata.isUnique
|
||||
? `${columns.map((column) => `"${column}"`).join(" != '' AND ")} != '' AND "deletedAt" IS NULL`
|
||||
: null;
|
||||
|
||||
return {
|
||||
name: indexMetadata.name,
|
||||
action: WorkspaceMigrationIndexActionType.CREATE,
|
||||
isUnique: indexMetadata.isUnique,
|
||||
columns,
|
||||
type: indexMetadata.indexType,
|
||||
where: indexMetadata.indexWhereClause ?? defaultWhereClause,
|
||||
};
|
||||
});
|
||||
|
||||
workspaceMigrations.push({
|
||||
workspaceId: objectMetadata.workspaceId,
|
||||
@ -134,6 +161,7 @@ export class WorkspaceMigrationIndexFactory {
|
||||
name: indexMetadata.name,
|
||||
action: WorkspaceMigrationIndexActionType.DROP,
|
||||
columns: [],
|
||||
isUnique: indexMetadata.isUnique,
|
||||
}));
|
||||
|
||||
workspaceMigrations.push({
|
||||
|
||||
@ -77,6 +77,7 @@ export class WorkspaceMigrationEnumService {
|
||||
enumName: newEnumTypeName,
|
||||
isArray: columnDefinition.isArray,
|
||||
isNullable: columnDefinition.isNullable,
|
||||
isUnique: columnDefinition.isUnique,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
import {
|
||||
QueryRunner,
|
||||
Table,
|
||||
@ -9,6 +10,7 @@ import {
|
||||
TableUnique,
|
||||
} from 'typeorm';
|
||||
|
||||
import { IndexType } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import {
|
||||
WorkspaceMigrationColumnAction,
|
||||
WorkspaceMigrationColumnActionType,
|
||||
@ -27,7 +29,6 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work
|
||||
import { WorkspaceMigrationEnumService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service';
|
||||
import { convertOnDeleteActionToOnDelete } from 'src/engine/workspace-manager/workspace-migration-runner/utils/convert-on-delete-action-to-on-delete.util';
|
||||
import { tableDefaultColumns } from 'src/engine/workspace-manager/workspace-migration-runner/utils/table-default-column.util';
|
||||
import { isDefined } from 'src/utils/is-defined';
|
||||
|
||||
import { WorkspaceMigrationTypeService } from './services/workspace-migration-type.service';
|
||||
|
||||
@ -200,7 +201,7 @@ export class WorkspaceMigrationRunnerService {
|
||||
for (const index of indexes) {
|
||||
switch (index.action) {
|
||||
case WorkspaceMigrationIndexActionType.CREATE:
|
||||
if (isDefined(index.type)) {
|
||||
if (isDefined(index.type) && index.type !== IndexType.BTREE) {
|
||||
const quotedColumns = index.columns.map((column) => `"${column}"`);
|
||||
|
||||
await queryRunner.query(`
|
||||
@ -212,6 +213,8 @@ export class WorkspaceMigrationRunnerService {
|
||||
new TableIndex({
|
||||
name: index.name,
|
||||
columnNames: index.columns,
|
||||
isUnique: index.isUnique,
|
||||
where: index.where ?? undefined,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -404,6 +407,7 @@ export class WorkspaceMigrationRunnerService {
|
||||
enumName: enumName,
|
||||
isArray: migrationColumn.isArray,
|
||||
isNullable: migrationColumn.isNullable,
|
||||
isUnique: migrationColumn.isUnique,
|
||||
asExpression: migrationColumn.asExpression,
|
||||
generatedType: migrationColumn.generatedType,
|
||||
}),
|
||||
@ -459,6 +463,7 @@ export class WorkspaceMigrationRunnerService {
|
||||
),
|
||||
isArray: migrationColumn.currentColumnDefinition.isArray,
|
||||
isNullable: migrationColumn.currentColumnDefinition.isNullable,
|
||||
isUnique: migrationColumn.currentColumnDefinition.isUnique,
|
||||
}),
|
||||
new TableColumn({
|
||||
name: migrationColumn.alteredColumnDefinition.columnName,
|
||||
@ -469,6 +474,7 @@ export class WorkspaceMigrationRunnerService {
|
||||
),
|
||||
isArray: migrationColumn.alteredColumnDefinition.isArray,
|
||||
isNullable: migrationColumn.alteredColumnDefinition.isNullable,
|
||||
isUnique: migrationColumn.alteredColumnDefinition.isUnique,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ import { Injectable } from '@nestjs/common';
|
||||
import diff from 'microdiff';
|
||||
|
||||
import {
|
||||
IndexComparatorResult,
|
||||
ComparatorAction,
|
||||
IndexComparatorResult,
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface';
|
||||
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import diff from 'microdiff';
|
||||
import omit from 'lodash.omit';
|
||||
import diff from 'microdiff';
|
||||
|
||||
import {
|
||||
ComparatorAction,
|
||||
@ -9,8 +9,8 @@ import {
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface';
|
||||
import { ComputedPartialWorkspaceEntity } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||
|
||||
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||
|
||||
const objectPropertiesToIgnore = [
|
||||
'id',
|
||||
@ -28,7 +28,10 @@ export class WorkspaceObjectComparator {
|
||||
|
||||
public compare(
|
||||
originalObjectMetadata: Omit<ObjectMetadataEntity, 'fields'> | undefined,
|
||||
standardObjectMetadata: Omit<ComputedPartialWorkspaceEntity, 'fields'>,
|
||||
standardObjectMetadata: Omit<
|
||||
ComputedPartialWorkspaceEntity,
|
||||
'fields' | 'indexMetadatas'
|
||||
>,
|
||||
): ObjectComparatorResult {
|
||||
// If the object doesn't exist in the original metadata, we need to create it
|
||||
if (!originalObjectMetadata) {
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util';
|
||||
@ -163,6 +164,7 @@ export class StandardFieldFactory {
|
||||
settings: workspaceFieldMetadataArgs.settings,
|
||||
workspaceId: context.workspaceId,
|
||||
isNullable: workspaceFieldMetadataArgs.isNullable,
|
||||
isUnique: workspaceFieldMetadataArgs.isUnique,
|
||||
isCustom: workspaceFieldMetadataArgs.isDeprecated ? true : false,
|
||||
isSystem: workspaceFieldMetadataArgs.isSystem ?? false,
|
||||
isActive: workspaceFieldMetadataArgs.isActive ?? true,
|
||||
@ -218,6 +220,9 @@ export class StandardFieldFactory {
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isNullable: workspaceRelationMetadataArgs.isNullable,
|
||||
isUnique:
|
||||
workspaceRelationMetadataArgs.type ===
|
||||
RelationMetadataType.ONE_TO_ONE,
|
||||
isActive: workspaceRelationMetadataArgs.isActive ?? true,
|
||||
});
|
||||
}
|
||||
@ -236,6 +241,8 @@ export class StandardFieldFactory {
|
||||
workspaceEntityMetadataArgs?.isSystem ||
|
||||
workspaceRelationMetadataArgs.isSystem,
|
||||
isNullable: true,
|
||||
isUnique:
|
||||
workspaceRelationMetadataArgs.type === RelationMetadataType.ONE_TO_ONE,
|
||||
isActive: workspaceRelationMetadataArgs.isActive ?? true,
|
||||
});
|
||||
|
||||
|
||||
@ -88,7 +88,9 @@ export class StandardIndexFactory {
|
||||
objectMetadataId: objectMetadata.id,
|
||||
name: workspaceIndexMetadataArgs.name,
|
||||
columns: workspaceIndexMetadataArgs.columns,
|
||||
isUnique: workspaceIndexMetadataArgs.isUnique,
|
||||
isCustom: false,
|
||||
indexWhereClause: workspaceIndexMetadataArgs.whereClause,
|
||||
indexType: workspaceIndexMetadataArgs.type,
|
||||
};
|
||||
|
||||
@ -130,7 +132,9 @@ export class StandardIndexFactory {
|
||||
name: `IDX_${generateDeterministicIndexName([computeTableName(customObjectName, true), ...workspaceIndexMetadataArgs.columns])}`,
|
||||
columns: workspaceIndexMetadataArgs.columns,
|
||||
isCustom: false,
|
||||
isUnique: workspaceIndexMetadataArgs.isUnique,
|
||||
indexType: workspaceIndexMetadataArgs.type,
|
||||
indexWhereClause: workspaceIndexMetadataArgs.whereClause,
|
||||
};
|
||||
|
||||
return indexMetadata;
|
||||
|
||||
@ -14,7 +14,7 @@ export class StandardObjectFactory {
|
||||
standardObjectMetadataDefinitions: (typeof BaseWorkspaceEntity)[],
|
||||
context: WorkspaceSyncContext,
|
||||
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||
): Omit<PartialWorkspaceEntity, 'fields'>[] {
|
||||
): Omit<PartialWorkspaceEntity, 'fields' | 'indexMetadatas'>[] {
|
||||
return standardObjectMetadataDefinitions
|
||||
.map((metadata) =>
|
||||
this.createObjectMetadata(metadata, context, workspaceFeatureFlagsMap),
|
||||
@ -26,7 +26,7 @@ export class StandardObjectFactory {
|
||||
target: typeof BaseWorkspaceEntity,
|
||||
context: WorkspaceSyncContext,
|
||||
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||
): Omit<PartialWorkspaceEntity, 'fields'> | undefined {
|
||||
): Omit<PartialWorkspaceEntity, 'fields' | 'indexMetadatas'> | undefined {
|
||||
const workspaceEntityMetadataArgs =
|
||||
metadataArgsStorage.filterEntities(target);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
|
||||
import { ComputedPartialFieldMetadata } from './partial-field-metadata.interface';
|
||||
import { ComputedPartialWorkspaceEntity } from './partial-object-metadata.interface';
|
||||
@ -33,9 +33,15 @@ export interface ComparatorDeleteResult<T> {
|
||||
|
||||
export type ObjectComparatorResult =
|
||||
| ComparatorSkipResult
|
||||
| ComparatorCreateResult<Omit<ComputedPartialWorkspaceEntity, 'fields'>>
|
||||
| ComparatorCreateResult<
|
||||
Omit<ComputedPartialWorkspaceEntity, 'fields' | 'indexMetadatas'>
|
||||
>
|
||||
| ComparatorUpdateResult<
|
||||
Partial<Omit<ComputedPartialWorkspaceEntity, 'fields'>> & { id: string }
|
||||
Partial<
|
||||
Omit<ComputedPartialWorkspaceEntity, 'fields' | 'indexMetadatas'>
|
||||
> & {
|
||||
id: string;
|
||||
}
|
||||
>;
|
||||
|
||||
export type FieldComparatorResult =
|
||||
|
||||
@ -13,17 +13,22 @@ import { v4 as uuidV4 } from 'uuid';
|
||||
import { PartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||
import { PartialIndexMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface';
|
||||
|
||||
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import { FieldMetadataComplexOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
|
||||
import {
|
||||
FieldMetadataEntity,
|
||||
FieldMetadataType,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory';
|
||||
import { FieldMetadataUpdate } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory';
|
||||
import { ObjectMetadataUpdate } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-object.factory';
|
||||
import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage';
|
||||
import { capitalize } from 'src/utils/capitalize';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceMetadataUpdaterService {
|
||||
@ -241,10 +246,42 @@ export class WorkspaceMetadataUpdaterService {
|
||||
const convertIndexFieldMetadataForSaving = (
|
||||
column: string,
|
||||
order: number,
|
||||
) => {
|
||||
): DeepPartial<IndexFieldMetadataEntity> => {
|
||||
// Ensure correct type
|
||||
const fieldMetadata = originalObjectMetadataCollection
|
||||
.find((object) => object.id === indexMetadata.objectMetadataId)
|
||||
?.fields.find((field) => column === field.name);
|
||||
?.fields.find((field) => {
|
||||
if (field.name === column) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isCompositeFieldMetadataType(field.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const compositeType = compositeTypeDefinitions.get(
|
||||
field.type as CompositeFieldMetadataType,
|
||||
);
|
||||
|
||||
if (!compositeType) {
|
||||
throw new Error(
|
||||
`Composite type definition not found for type: ${field.type}`,
|
||||
);
|
||||
}
|
||||
|
||||
const columnNames = compositeType.properties.reduce(
|
||||
(acc, column) => {
|
||||
acc.push(`${field.name}${capitalize(column.name)}`);
|
||||
|
||||
return acc;
|
||||
},
|
||||
[] as string[],
|
||||
);
|
||||
|
||||
if (columnNames.includes(column)) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!fieldMetadata) {
|
||||
throw new Error(`
|
||||
|
||||
@ -51,7 +51,7 @@ export class WorkspaceSyncIndexMetadataService {
|
||||
// We're only interested in standard fields
|
||||
fields: { isCustom: false },
|
||||
},
|
||||
relations: ['dataSource', 'fields', 'indexes'],
|
||||
relations: ['dataSource', 'fields', 'indexMetadatas'],
|
||||
});
|
||||
|
||||
// Create map of object metadata & field metadata by unique identifier
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import { ComputedPartialWorkspaceEntity } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||
import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||
import { ComputedPartialWorkspaceEntity } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-object-metadata.interface';
|
||||
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
|
||||
export class WorkspaceSyncStorage {
|
||||
// Object metadata
|
||||
private readonly _objectMetadataCreateCollection: Omit<
|
||||
ComputedPartialWorkspaceEntity,
|
||||
'fields'
|
||||
'fields' | 'indexMetadatas'
|
||||
>[] = [];
|
||||
private readonly _objectMetadataUpdateCollection: (Partial<
|
||||
Omit<ComputedPartialWorkspaceEntity, 'fields'>
|
||||
Omit<ComputedPartialWorkspaceEntity, 'fields' | 'indexMetadatas'>
|
||||
> & {
|
||||
id: string;
|
||||
})[] = [];
|
||||
@ -89,7 +89,7 @@ export class WorkspaceSyncStorage {
|
||||
}
|
||||
|
||||
addCreateObjectMetadata(
|
||||
object: Omit<ComputedPartialWorkspaceEntity, 'fields'>,
|
||||
object: Omit<ComputedPartialWorkspaceEntity, 'fields' | 'indexMetadatas'>,
|
||||
) {
|
||||
this._objectMetadataCreateCollection.push(object);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user