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:
Félix Malfait
2024-10-13 10:21:03 +02:00
committed by GitHub
parent d1d4af0c63
commit b792d2a4d3
137 changed files with 22351 additions and 17974 deletions

View File

@ -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;

View File

@ -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({

View File

@ -77,6 +77,7 @@ export class WorkspaceMigrationEnumService {
enumName: newEnumTypeName,
isArray: columnDefinition.isArray,
isNullable: columnDefinition.isNullable,
isUnique: columnDefinition.isUnique,
}),
);

View File

@ -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,
}),
);
}

View File

@ -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';

View File

@ -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) {

View File

@ -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,
});

View File

@ -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;

View File

@ -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);

View File

@ -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 =

View File

@ -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(`

View File

@ -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

View File

@ -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);
}