Fix 'name' column wrongly added in standard objects (#7428)
## Context Name shouldn't be added to all tables, especially standard objects because they already have their own labelIdentifierFieldMetadata specified in the workspace-entity schema. This PR removes this column from the "base" list of columns to add when creating a new object/table and moves it to the object-metadata service that is, as of today, only used for custom objects. Also had to modify the migration-runner to handle column creation in a table creation migration (this was available in the migration definition already but was not doing anything) This also fixes an issue in standard objects that already have a "name" field defined with a different field type, this is even more important when the said field is a composite field. For example people already has a FULL_NAME name field which clashes with the default TEXT name field meaning it was only creating 1 field metadata for 'name' but 3 columns were created: `name, nameFirstName, nameLastName`. This inconsistency with metadata (which is our source of truth everywhere) brought some issues (lately, converting back typeorm response to gql (including composition) was broken).
This commit is contained in:
@ -66,8 +66,7 @@ export class GraphqlQueryUpdateManyResolverService
|
|||||||
const data = formatData(args.data, objectMetadataMapItem);
|
const data = formatData(args.data, objectMetadataMapItem);
|
||||||
|
|
||||||
const result = await withFilterQueryBuilder
|
const result = await withFilterQueryBuilder
|
||||||
.update()
|
.update(data)
|
||||||
.set(data)
|
|
||||||
.returning('*')
|
.returning('*')
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
|||||||
@ -61,13 +61,11 @@ export class GraphqlQueryUpdateOneResolverService
|
|||||||
objectMetadataMapItem.nameSingular,
|
objectMetadataMapItem.nameSingular,
|
||||||
);
|
);
|
||||||
|
|
||||||
const withFilterQueryBuilder = queryBuilder.where({ id: args.id });
|
|
||||||
|
|
||||||
const data = formatData(args.data, objectMetadataMapItem);
|
const data = formatData(args.data, objectMetadataMapItem);
|
||||||
|
|
||||||
const result = await withFilterQueryBuilder
|
const result = await queryBuilder
|
||||||
.update()
|
.update(data)
|
||||||
.set(data)
|
.where({ id: args.id })
|
||||||
.returning('*')
|
.returning('*')
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
|||||||
@ -49,8 +49,10 @@ import { generateMigrationName } from 'src/engine/metadata-modules/workspace-mig
|
|||||||
import {
|
import {
|
||||||
WorkspaceMigrationColumnActionType,
|
WorkspaceMigrationColumnActionType,
|
||||||
WorkspaceMigrationColumnDrop,
|
WorkspaceMigrationColumnDrop,
|
||||||
|
WorkspaceMigrationTableAction,
|
||||||
WorkspaceMigrationTableActionType,
|
WorkspaceMigrationTableActionType,
|
||||||
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
|
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
|
||||||
|
import { WorkspaceMigrationFactory } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.factory';
|
||||||
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
|
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
|
||||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||||
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
|
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
|
||||||
@ -103,6 +105,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||||
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
|
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
|
||||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||||
|
private readonly workspaceMigrationFactory: WorkspaceMigrationFactory,
|
||||||
) {
|
) {
|
||||||
super(objectMetadataRepository);
|
super(objectMetadataRepository);
|
||||||
}
|
}
|
||||||
@ -563,9 +566,39 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
objectMetadataInput.primaryKeyFieldMetadataSettings,
|
objectMetadataInput.primaryKeyFieldMetadataSettings,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.workspaceMigrationService.createCustomMigration(
|
await this.workspaceMigrationService.createCustomMigration(
|
||||||
generateMigrationName(`create-${createdObjectMetadata.nameSingular}`),
|
generateMigrationName(`create-${createdObjectMetadata.nameSingular}`),
|
||||||
createdObjectMetadata.workspaceId,
|
createdObjectMetadata.workspaceId,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: computeObjectTargetTable(createdObjectMetadata),
|
||||||
|
action: WorkspaceMigrationTableActionType.CREATE,
|
||||||
|
} satisfies WorkspaceMigrationTableAction,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const fieldMetadata of createdObjectMetadata.fields) {
|
||||||
|
await this.workspaceMigrationService.createCustomMigration(
|
||||||
|
generateMigrationName(`create-${fieldMetadata.name}`),
|
||||||
|
createdObjectMetadata.workspaceId,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: computeObjectTargetTable(createdObjectMetadata),
|
||||||
|
action: WorkspaceMigrationTableActionType.ALTER,
|
||||||
|
columns: this.workspaceMigrationFactory.createColumnActions(
|
||||||
|
WorkspaceMigrationColumnActionType.CREATE,
|
||||||
|
fieldMetadata,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
] satisfies WorkspaceMigrationTableAction[],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.workspaceMigrationService.createCustomMigration(
|
||||||
|
generateMigrationName(
|
||||||
|
`create-${createdObjectMetadata.nameSingular}-relations`,
|
||||||
|
),
|
||||||
|
createdObjectMetadata.workspaceId,
|
||||||
buildMigrationsForCustomObjectRelations(
|
buildMigrationsForCustomObjectRelations(
|
||||||
createdObjectMetadata,
|
createdObjectMetadata,
|
||||||
activityTargetObjectMetadata,
|
activityTargetObjectMetadata,
|
||||||
@ -611,7 +644,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.workspaceMigrationService.createCustomMigration(
|
this.workspaceMigrationService.createCustomMigration(
|
||||||
generateMigrationName(`create-${createdObjectMetadata.nameSingular}`),
|
generateMigrationName(
|
||||||
|
`update-${createdObjectMetadata.nameSingular}-add-searchVector`,
|
||||||
|
),
|
||||||
createdObjectMetadata.workspaceId,
|
createdObjectMetadata.workspaceId,
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|||||||
@ -18,10 +18,6 @@ export const buildMigrationsForCustomObjectRelations = (
|
|||||||
noteTargetObjectMetadata: ObjectMetadataEntity,
|
noteTargetObjectMetadata: ObjectMetadataEntity,
|
||||||
taskTargetObjectMetadata: ObjectMetadataEntity,
|
taskTargetObjectMetadata: ObjectMetadataEntity,
|
||||||
): WorkspaceMigrationTableAction[] => [
|
): WorkspaceMigrationTableAction[] => [
|
||||||
{
|
|
||||||
name: computeObjectTargetTable(createdObjectMetadata),
|
|
||||||
action: WorkspaceMigrationTableActionType.CREATE,
|
|
||||||
} satisfies WorkspaceMigrationTableAction,
|
|
||||||
// Add activity target relation
|
// Add activity target relation
|
||||||
{
|
{
|
||||||
name: computeObjectTargetTable(activityTargetObjectMetadata),
|
name: computeObjectTargetTable(activityTargetObjectMetadata),
|
||||||
|
|||||||
@ -55,5 +55,5 @@ export abstract class BaseWorkspaceEntity {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
@WorkspaceIsNullable()
|
@WorkspaceIsNullable()
|
||||||
deletedAt?: string | null;
|
deletedAt: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
import { TableColumnOptions } from 'typeorm';
|
|
||||||
|
|
||||||
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
|
||||||
|
|
||||||
export const customTableDefaultColumns = (
|
|
||||||
tableName: string,
|
|
||||||
): TableColumnOptions[] => [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'uuid',
|
|
||||||
isPrimary: true,
|
|
||||||
default: 'public.uuid_generate_v4()',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'createdAt',
|
|
||||||
type: 'timestamptz',
|
|
||||||
default: 'now()',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'updatedAt',
|
|
||||||
type: 'timestamptz',
|
|
||||||
default: 'now()',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'deletedAt',
|
|
||||||
type: 'timestamptz',
|
|
||||||
isNullable: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'position',
|
|
||||||
type: 'float',
|
|
||||||
isNullable: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
type: 'text',
|
|
||||||
isNullable: false,
|
|
||||||
default: "'Untitled'",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'createdBySource',
|
|
||||||
type: 'enum',
|
|
||||||
enumName: `${tableName}_createdBySource_enum`,
|
|
||||||
enum: Object.values(FieldActorSource),
|
|
||||||
isNullable: false,
|
|
||||||
default: `'${FieldActorSource.MANUAL}'`,
|
|
||||||
},
|
|
||||||
{ name: 'createdByWorkspaceMemberId', type: 'uuid', isNullable: true },
|
|
||||||
{
|
|
||||||
name: 'createdByName',
|
|
||||||
type: 'text',
|
|
||||||
isNullable: false,
|
|
||||||
default: "''",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { TableColumnOptions } from 'typeorm';
|
||||||
|
|
||||||
|
export const tableDefaultColumns = (): TableColumnOptions[] => [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'uuid',
|
||||||
|
isPrimary: true,
|
||||||
|
default: 'public.uuid_generate_v4()',
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -26,10 +26,10 @@ import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace
|
|||||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||||
import { WorkspaceMigrationEnumService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service';
|
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 { 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 { isDefined } from 'src/utils/is-defined';
|
||||||
|
|
||||||
import { WorkspaceMigrationTypeService } from './services/workspace-migration-type.service';
|
import { WorkspaceMigrationTypeService } from './services/workspace-migration-type.service';
|
||||||
import { customTableDefaultColumns } from './utils/custom-table-default-column.util';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceMigrationRunnerService {
|
export class WorkspaceMigrationRunnerService {
|
||||||
@ -121,7 +121,12 @@ export class WorkspaceMigrationRunnerService {
|
|||||||
) {
|
) {
|
||||||
switch (tableMigration.action) {
|
switch (tableMigration.action) {
|
||||||
case WorkspaceMigrationTableActionType.CREATE:
|
case WorkspaceMigrationTableActionType.CREATE:
|
||||||
await this.createTable(queryRunner, schemaName, tableMigration.name);
|
await this.createTable(
|
||||||
|
queryRunner,
|
||||||
|
schemaName,
|
||||||
|
tableMigration.name,
|
||||||
|
tableMigration.columns,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case WorkspaceMigrationTableActionType.ALTER: {
|
case WorkspaceMigrationTableActionType.ALTER: {
|
||||||
if (tableMigration.newName) {
|
if (tableMigration.newName) {
|
||||||
@ -244,16 +249,26 @@ export class WorkspaceMigrationRunnerService {
|
|||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
schemaName: string,
|
schemaName: string,
|
||||||
tableName: string,
|
tableName: string,
|
||||||
|
columns?: WorkspaceMigrationColumnAction[],
|
||||||
) {
|
) {
|
||||||
await queryRunner.createTable(
|
await queryRunner.createTable(
|
||||||
new Table({
|
new Table({
|
||||||
name: tableName,
|
name: tableName,
|
||||||
schema: schemaName,
|
schema: schemaName,
|
||||||
columns: customTableDefaultColumns(tableName),
|
columns: tableDefaultColumns(),
|
||||||
}),
|
}),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (columns && columns.length > 0) {
|
||||||
|
await this.handleColumnChanges(
|
||||||
|
queryRunner,
|
||||||
|
schemaName,
|
||||||
|
tableName,
|
||||||
|
columns,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Enable totalCount for the table
|
// Enable totalCount for the table
|
||||||
await queryRunner.query(`
|
await queryRunner.query(`
|
||||||
COMMENT ON TABLE "${schemaName}"."${tableName}" IS '@graphql({"totalCount": {"enabled": true}})';
|
COMMENT ON TABLE "${schemaName}"."${tableName}" IS '@graphql({"totalCount": {"enabled": true}})';
|
||||||
|
|||||||
@ -5,6 +5,7 @@ export type CalendarEvent = Omit<
|
|||||||
CalendarEventWorkspaceEntity,
|
CalendarEventWorkspaceEntity,
|
||||||
| 'createdAt'
|
| 'createdAt'
|
||||||
| 'updatedAt'
|
| 'updatedAt'
|
||||||
|
| 'deletedAt'
|
||||||
| 'calendarChannelEventAssociations'
|
| 'calendarChannelEventAssociations'
|
||||||
| 'calendarEventParticipants'
|
| 'calendarEventParticipants'
|
||||||
| 'conferenceLink'
|
| 'conferenceLink'
|
||||||
@ -19,6 +20,7 @@ export type CalendarEventParticipant = Omit<
|
|||||||
| 'id'
|
| 'id'
|
||||||
| 'createdAt'
|
| 'createdAt'
|
||||||
| 'updatedAt'
|
| 'updatedAt'
|
||||||
|
| 'deletedAt'
|
||||||
| 'personId'
|
| 'personId'
|
||||||
| 'workspaceMemberId'
|
| 'workspaceMemberId'
|
||||||
| 'person'
|
| 'person'
|
||||||
|
|||||||
@ -6,6 +6,7 @@ export type Message = Omit<
|
|||||||
MessageWorkspaceEntity,
|
MessageWorkspaceEntity,
|
||||||
| 'createdAt'
|
| 'createdAt'
|
||||||
| 'updatedAt'
|
| 'updatedAt'
|
||||||
|
| 'deletedAt'
|
||||||
| 'messageChannelMessageAssociations'
|
| 'messageChannelMessageAssociations'
|
||||||
| 'messageParticipants'
|
| 'messageParticipants'
|
||||||
| 'messageThread'
|
| 'messageThread'
|
||||||
@ -25,6 +26,7 @@ export type MessageParticipant = Omit<
|
|||||||
| 'id'
|
| 'id'
|
||||||
| 'createdAt'
|
| 'createdAt'
|
||||||
| 'updatedAt'
|
| 'updatedAt'
|
||||||
|
| 'deletedAt'
|
||||||
| 'personId'
|
| 'personId'
|
||||||
| 'workspaceMemberId'
|
| 'workspaceMemberId'
|
||||||
| 'person'
|
| 'person'
|
||||||
|
|||||||
Reference in New Issue
Block a user