feat: drop target column map (#4670)
This PR is dropping the column `targetColumnMap` of fieldMetadata entities. The goal of this column was to properly map field to their respecting column in the table. We decide to drop it and instead compute the column name on the fly when we need it, as it's more easier to support. Some parts of the code has been refactored to try making implementation of composite type more easier to understand and maintain. Fix #3760 --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,11 +1,12 @@
|
||||
import { WorkspaceMissingColumnFixer } from 'src/engine/workspace-manager/workspace-health/fixer/workspace-missing-column.fixer';
|
||||
|
||||
import { WorkspaceNullableFixer } from './workspace-nullable.fixer';
|
||||
import { WorkspaceDefaultValueFixer } from './workspace-default-value.fixer';
|
||||
import { WorkspaceTypeFixer } from './workspace-type.fixer';
|
||||
import { WorkspaceTargetColumnMapFixer } from './workspace-target-column-map.fixer';
|
||||
|
||||
export const workspaceFixers = [
|
||||
WorkspaceNullableFixer,
|
||||
WorkspaceDefaultValueFixer,
|
||||
WorkspaceTypeFixer,
|
||||
WorkspaceTargetColumnMapFixer,
|
||||
WorkspaceMissingColumnFixer,
|
||||
];
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { EntityManager } from 'typeorm';
|
||||
|
||||
import {
|
||||
WorkspaceHealthColumnIssue,
|
||||
WorkspaceHealthIssueType,
|
||||
} from 'src/engine/workspace-manager/workspace-health/interfaces/workspace-health-issue.interface';
|
||||
import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
|
||||
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
|
||||
import {
|
||||
FieldMetadataUpdate,
|
||||
WorkspaceMigrationFieldFactory,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory';
|
||||
|
||||
import { AbstractWorkspaceFixer } from './abstract-workspace.fixer';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceMissingColumnFixer extends AbstractWorkspaceFixer<WorkspaceHealthIssueType.MISSING_COLUMN> {
|
||||
constructor(
|
||||
private readonly workspaceMigrationFieldFactory: WorkspaceMigrationFieldFactory,
|
||||
) {
|
||||
super(WorkspaceHealthIssueType.MISSING_COLUMN);
|
||||
}
|
||||
|
||||
async createWorkspaceMigrations(
|
||||
manager: EntityManager,
|
||||
objectMetadataCollection: ObjectMetadataEntity[],
|
||||
issues: WorkspaceHealthColumnIssue<WorkspaceHealthIssueType.MISSING_COLUMN>[],
|
||||
): Promise<Partial<WorkspaceMigrationEntity>[]> {
|
||||
if (issues.length <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.fixMissingColumnIssues(objectMetadataCollection, issues);
|
||||
}
|
||||
|
||||
private async fixMissingColumnIssues(
|
||||
objectMetadataCollection: ObjectMetadataEntity[],
|
||||
issues: WorkspaceHealthColumnIssue<WorkspaceHealthIssueType.MISSING_COLUMN>[],
|
||||
): Promise<Partial<WorkspaceMigrationEntity>[]> {
|
||||
const fieldMetadataUpdateCollection: FieldMetadataUpdate[] = [];
|
||||
|
||||
for (const issue of issues) {
|
||||
if (!issue.columnStructures) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the column is prefixed with an underscore as it was the old convention
|
||||
*/
|
||||
const oldColumnName = `_${issue.fieldMetadata.name}`;
|
||||
const oldColumnStructure = issue.columnStructures.find(
|
||||
(columnStructure) => columnStructure.columnName === oldColumnName,
|
||||
);
|
||||
|
||||
if (!oldColumnStructure) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fieldMetadataUpdateCollection.push({
|
||||
current: {
|
||||
...issue.fieldMetadata,
|
||||
name: oldColumnName,
|
||||
},
|
||||
altered: issue.fieldMetadata,
|
||||
});
|
||||
}
|
||||
|
||||
if (fieldMetadataUpdateCollection.length <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.workspaceMigrationFieldFactory.create(
|
||||
objectMetadataCollection,
|
||||
fieldMetadataUpdateCollection,
|
||||
WorkspaceMigrationBuilderAction.UPDATE,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,174 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { EntityManager } from 'typeorm';
|
||||
import isEqual from 'lodash.isequal';
|
||||
|
||||
import {
|
||||
WorkspaceHealthColumnIssue,
|
||||
WorkspaceHealthIssueType,
|
||||
} from 'src/engine/workspace-manager/workspace-health/interfaces/workspace-health-issue.interface';
|
||||
import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
|
||||
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { generateTargetColumnMap } from 'src/engine/metadata-modules/field-metadata/utils/generate-target-column-map.util';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
|
||||
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
|
||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { DatabaseStructureService } from 'src/engine/workspace-manager/workspace-health/services/database-structure.service';
|
||||
import { WorkspaceMigrationFieldFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
|
||||
import {
|
||||
AbstractWorkspaceFixer,
|
||||
CompareEntity,
|
||||
} from './abstract-workspace.fixer';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceTargetColumnMapFixer extends AbstractWorkspaceFixer<
|
||||
WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID,
|
||||
FieldMetadataEntity
|
||||
> {
|
||||
constructor(
|
||||
private readonly workspaceMigrationFieldFactory: WorkspaceMigrationFieldFactory,
|
||||
private readonly databaseStructureService: DatabaseStructureService,
|
||||
) {
|
||||
super(WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID);
|
||||
}
|
||||
|
||||
async createWorkspaceMigrations(
|
||||
manager: EntityManager,
|
||||
objectMetadataCollection: ObjectMetadataEntity[],
|
||||
issues: WorkspaceHealthColumnIssue<WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID>[],
|
||||
): Promise<Partial<WorkspaceMigrationEntity>[]> {
|
||||
if (issues.length <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.fixStructureTargetColumnMapIssues(
|
||||
manager,
|
||||
objectMetadataCollection,
|
||||
issues,
|
||||
);
|
||||
}
|
||||
|
||||
async createMetadataUpdates(
|
||||
manager: EntityManager,
|
||||
objectMetadataCollection: ObjectMetadataEntity[],
|
||||
issues: WorkspaceHealthColumnIssue<WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID>[],
|
||||
): Promise<CompareEntity<FieldMetadataEntity>[]> {
|
||||
if (issues.length <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.fixMetadataTargetColumnMapIssues(manager, issues);
|
||||
}
|
||||
|
||||
private async fixStructureTargetColumnMapIssues(
|
||||
manager: EntityManager,
|
||||
objectMetadataCollection: ObjectMetadataEntity[],
|
||||
issues: WorkspaceHealthColumnIssue<WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID>[],
|
||||
): Promise<Partial<WorkspaceMigrationEntity>[]> {
|
||||
const workspaceMigrationCollection: Partial<WorkspaceMigrationEntity>[] =
|
||||
[];
|
||||
const dataSourceRepository = manager.getRepository(DataSourceEntity);
|
||||
|
||||
for (const issue of issues) {
|
||||
const objectMetadata = objectMetadataCollection.find(
|
||||
(metadata) => metadata.id === issue.fieldMetadata.objectMetadataId,
|
||||
);
|
||||
const targetColumnMap = generateTargetColumnMap(
|
||||
issue.fieldMetadata.type,
|
||||
issue.fieldMetadata.isCustom,
|
||||
issue.fieldMetadata.name,
|
||||
);
|
||||
|
||||
// Skip composite fields, too complicated to fix for now
|
||||
if (isCompositeFieldMetadataType(issue.fieldMetadata.type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!objectMetadata) {
|
||||
throw new Error(
|
||||
`Object metadata with id ${issue.fieldMetadata.objectMetadataId} not found`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isEqual(issue.fieldMetadata.targetColumnMap, targetColumnMap)) {
|
||||
// Retrieve the data source to get the schema name
|
||||
const dataSource = await dataSourceRepository.findOne({
|
||||
where: {
|
||||
id: objectMetadata.dataSourceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!dataSource) {
|
||||
throw new Error(
|
||||
`Data source with id ${objectMetadata.dataSourceId} not found`,
|
||||
);
|
||||
}
|
||||
|
||||
const columnName = issue.fieldMetadata.targetColumnMap?.value;
|
||||
const columnExist =
|
||||
await this.databaseStructureService.workspaceColumnExist(
|
||||
dataSource.schema,
|
||||
computeObjectTargetTable(objectMetadata),
|
||||
columnName,
|
||||
);
|
||||
|
||||
if (!columnExist) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const workspaceMigration =
|
||||
await this.workspaceMigrationFieldFactory.create(
|
||||
objectMetadataCollection,
|
||||
[
|
||||
{
|
||||
current: issue.fieldMetadata,
|
||||
altered: {
|
||||
...issue.fieldMetadata,
|
||||
targetColumnMap,
|
||||
},
|
||||
},
|
||||
],
|
||||
WorkspaceMigrationBuilderAction.UPDATE,
|
||||
);
|
||||
|
||||
workspaceMigrationCollection.push(workspaceMigration[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return workspaceMigrationCollection;
|
||||
}
|
||||
|
||||
private async fixMetadataTargetColumnMapIssues(
|
||||
manager: EntityManager,
|
||||
issues: WorkspaceHealthColumnIssue<WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID>[],
|
||||
): Promise<CompareEntity<FieldMetadataEntity>[]> {
|
||||
const fieldMetadataRepository = manager.getRepository(FieldMetadataEntity);
|
||||
const updatedEntities: CompareEntity<FieldMetadataEntity>[] = [];
|
||||
|
||||
for (const issue of issues) {
|
||||
await fieldMetadataRepository.update(issue.fieldMetadata.id, {
|
||||
targetColumnMap: generateTargetColumnMap(
|
||||
issue.fieldMetadata.type,
|
||||
issue.fieldMetadata.isCustom,
|
||||
issue.fieldMetadata.name,
|
||||
),
|
||||
});
|
||||
const alteredEntity = await fieldMetadataRepository.findOne({
|
||||
where: {
|
||||
id: issue.fieldMetadata.id,
|
||||
},
|
||||
});
|
||||
|
||||
updatedEntities.push({
|
||||
current: issue.fieldMetadata,
|
||||
altered: alteredEntity as FieldMetadataEntity | null,
|
||||
});
|
||||
}
|
||||
|
||||
return updatedEntities;
|
||||
}
|
||||
}
|
||||
@ -2,5 +2,5 @@ export enum WorkspaceHealthFixKind {
|
||||
Nullable = 'nullable',
|
||||
Type = 'type',
|
||||
DefaultValue = 'default-value',
|
||||
TargetColumnMap = 'target-column-map',
|
||||
MissingColumn = 'missing-column',
|
||||
}
|
||||
|
||||
@ -15,8 +15,7 @@ export enum WorkspaceHealthIssueType {
|
||||
MISSING_FOREIGN_KEY = 'MISSING_FOREIGN_KEY',
|
||||
MISSING_COMPOSITE_TYPE = 'MISSING_COMPOSITE_TYPE',
|
||||
COLUMN_NAME_SHOULD_NOT_BE_PREFIXED = 'COLUMN_NAME_SHOULD_NOT_BE_PREFIXED',
|
||||
COLUMN_TARGET_COLUMN_MAP_NOT_VALID = 'COLUMN_TARGET_COLUMN_MAP_NOT_VALID',
|
||||
COLUMN_NAME_SHOULD_BE_CUSTOM = 'COLUMN_NAME_SHOULD_BE_CUSTOM',
|
||||
COLUMN_NAME_SHOULD_NOT_BE_CUSTOM = 'COLUMN_NAME_SHOULD_NOT_BE_CUSTOM',
|
||||
COLUMN_OBJECT_REFERENCE_INVALID = 'COLUMN_OBJECT_REFERENCE_INVALID',
|
||||
COLUMN_NAME_NOT_VALID = 'COLUMN_NAME_NOT_VALID',
|
||||
COLUMN_TYPE_NOT_VALID = 'COLUMN_TYPE_NOT_VALID',
|
||||
@ -58,8 +57,7 @@ export type WorkspaceColumnIssueTypes =
|
||||
| WorkspaceHealthIssueType.MISSING_FOREIGN_KEY
|
||||
| WorkspaceHealthIssueType.MISSING_COMPOSITE_TYPE
|
||||
| WorkspaceHealthIssueType.COLUMN_NAME_SHOULD_NOT_BE_PREFIXED
|
||||
| WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID
|
||||
| WorkspaceHealthIssueType.COLUMN_NAME_SHOULD_BE_CUSTOM
|
||||
| WorkspaceHealthIssueType.COLUMN_NAME_SHOULD_NOT_BE_CUSTOM
|
||||
| WorkspaceHealthIssueType.COLUMN_OBJECT_REFERENCE_INVALID
|
||||
| WorkspaceHealthIssueType.COLUMN_NAME_NOT_VALID
|
||||
| WorkspaceHealthIssueType.COLUMN_TYPE_NOT_VALID
|
||||
@ -75,6 +73,7 @@ export interface WorkspaceHealthColumnIssue<
|
||||
type: T;
|
||||
fieldMetadata: FieldMetadataEntity;
|
||||
columnStructure?: WorkspaceTableStructure;
|
||||
columnStructures?: WorkspaceTableStructure[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-
|
||||
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
|
||||
import { isFunctionDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/is-function-default-value.util';
|
||||
import { FieldMetadataDefaultValueFunctionNames } from 'src/engine/metadata-modules/field-metadata/dtos/default-value.input';
|
||||
import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
|
||||
@Injectable()
|
||||
export class DatabaseStructureService {
|
||||
@ -156,22 +157,40 @@ export class DatabaseStructureService {
|
||||
return results.length >= 1;
|
||||
}
|
||||
|
||||
getPostgresDataType(fieldMetadata: FieldMetadataEntity): string {
|
||||
const typeORMType = fieldMetadataTypeToColumnType(fieldMetadata.type);
|
||||
getPostgresDataTypes(fieldMetadata: FieldMetadataEntity): string[] {
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
|
||||
// Compute enum name to compare data type properly
|
||||
if (typeORMType === 'enum') {
|
||||
const objectName = fieldMetadata.object?.nameSingular;
|
||||
const prefix = fieldMetadata.isCustom ? '_' : '';
|
||||
const fieldName = fieldMetadata.name;
|
||||
const normalizer = (type: FieldMetadataType, columnName: string) => {
|
||||
const typeORMType = fieldMetadataTypeToColumnType(type);
|
||||
|
||||
return `${objectName}_${prefix}${fieldName}_enum`;
|
||||
// Compute enum name to compare data type properly
|
||||
if (typeORMType === 'enum') {
|
||||
const objectName = fieldMetadata.object?.nameSingular;
|
||||
const prefix = fieldMetadata.isCustom ? '_' : '';
|
||||
|
||||
return `${objectName}_${prefix}${columnName}_enum`;
|
||||
}
|
||||
|
||||
return mainDataSource.driver.normalizeType({
|
||||
type: typeORMType,
|
||||
});
|
||||
};
|
||||
|
||||
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
|
||||
const compositeType = compositeTypeDefintions.get(fieldMetadata.type);
|
||||
|
||||
if (!compositeType) {
|
||||
throw new Error(
|
||||
`Composite type definition not found for ${fieldMetadata.type}`,
|
||||
);
|
||||
}
|
||||
|
||||
return compositeType.properties.map((compositeProperty) =>
|
||||
normalizer(compositeProperty.type, compositeProperty.name),
|
||||
);
|
||||
}
|
||||
|
||||
return mainDataSource.driver.normalizeType({
|
||||
type: typeORMType,
|
||||
});
|
||||
return [normalizer(fieldMetadata.type, fieldMetadata.name)];
|
||||
}
|
||||
|
||||
getFieldMetadataTypeFromPostgresDataType(
|
||||
@ -207,57 +226,84 @@ export class DatabaseStructureService {
|
||||
return null;
|
||||
}
|
||||
|
||||
getPostgresDefault(
|
||||
getPostgresDefaults(
|
||||
fieldMetadataType: FieldMetadataType,
|
||||
defaultValue:
|
||||
initialDefaultValue:
|
||||
| FieldMetadataDefaultValue
|
||||
// Old format for default values
|
||||
// TODO: Should be removed once all default values are migrated
|
||||
| { type: FieldMetadataDefaultValueFunctionNames }
|
||||
| null,
|
||||
): string | null | undefined {
|
||||
const typeORMType = fieldMetadataTypeToColumnType(
|
||||
fieldMetadataType,
|
||||
) as ColumnType;
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
): (string | null | undefined)[] {
|
||||
const normalizer = (
|
||||
type: FieldMetadataType,
|
||||
defaultValue:
|
||||
| FieldMetadataDefaultValue
|
||||
| { type: FieldMetadataDefaultValueFunctionNames }
|
||||
| null,
|
||||
) => {
|
||||
const typeORMType = fieldMetadataTypeToColumnType(type) as ColumnType;
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
|
||||
let value: any =
|
||||
// Old formart default values
|
||||
defaultValue &&
|
||||
typeof defaultValue === 'object' &&
|
||||
'value' in defaultValue
|
||||
? defaultValue.value
|
||||
: defaultValue;
|
||||
let value: any =
|
||||
// Old formart default values
|
||||
defaultValue &&
|
||||
typeof defaultValue === 'object' &&
|
||||
'value' in defaultValue
|
||||
? defaultValue.value
|
||||
: defaultValue;
|
||||
|
||||
// Old format for default values
|
||||
// TODO: Should be removed once all default values are migrated
|
||||
if (
|
||||
defaultValue &&
|
||||
typeof defaultValue === 'object' &&
|
||||
'type' in defaultValue
|
||||
) {
|
||||
return this.computeFunctionDefaultValue(defaultValue.type);
|
||||
// Old format for default values
|
||||
// TODO: Should be removed once all default values are migrated
|
||||
if (
|
||||
defaultValue &&
|
||||
typeof defaultValue === 'object' &&
|
||||
'type' in defaultValue
|
||||
) {
|
||||
return this.computeFunctionDefaultValue(defaultValue.type);
|
||||
}
|
||||
|
||||
if (isFunctionDefaultValue(value)) {
|
||||
return this.computeFunctionDefaultValue(value);
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
// Remove leading and trailing single quotes for string default values as it's already handled by TypeORM
|
||||
if (typeof value === 'string' && value.match(/^'.*'$/)) {
|
||||
value = value.replace(/^'/, '').replace(/'$/, '');
|
||||
}
|
||||
|
||||
return mainDataSource.driver.normalizeDefault({
|
||||
type: typeORMType,
|
||||
default: value,
|
||||
isArray: false,
|
||||
// Workaround to use normalizeDefault without a complete ColumnMetadata object
|
||||
} as ColumnMetadata);
|
||||
};
|
||||
|
||||
if (isCompositeFieldMetadataType(fieldMetadataType)) {
|
||||
const compositeType = compositeTypeDefintions.get(fieldMetadataType);
|
||||
|
||||
if (!compositeType) {
|
||||
throw new Error(
|
||||
`Composite type definition not found for ${fieldMetadataType}`,
|
||||
);
|
||||
}
|
||||
|
||||
return compositeType.properties.map((compositeProperty) =>
|
||||
normalizer(
|
||||
compositeProperty.type,
|
||||
typeof initialDefaultValue === 'object'
|
||||
? initialDefaultValue?.[compositeProperty.name]
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isFunctionDefaultValue(value)) {
|
||||
return this.computeFunctionDefaultValue(value);
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
// Remove leading and trailing single quotes for string default values as it's already handled by TypeORM
|
||||
if (typeof value === 'string' && value.match(/^'.*'$/)) {
|
||||
value = value.replace(/^'/, '').replace(/'$/, '');
|
||||
}
|
||||
|
||||
return mainDataSource.driver.normalizeDefault({
|
||||
type: typeORMType,
|
||||
default: value,
|
||||
isArray: false,
|
||||
// Workaround to use normalizeDefault without a complete ColumnMetadata object
|
||||
} as ColumnMetadata);
|
||||
return [normalizer(fieldMetadataType, initialDefaultValue)];
|
||||
}
|
||||
|
||||
private computeFunctionDefaultValue(
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import isEqual from 'lodash.isequal';
|
||||
|
||||
import {
|
||||
WorkspaceHealthIssue,
|
||||
WorkspaceHealthIssueType,
|
||||
@ -17,7 +15,6 @@ import {
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { DatabaseStructureService } from 'src/engine/workspace-manager/workspace-health/services/database-structure.service';
|
||||
import { validName } from 'src/engine/workspace-manager/workspace-health/utils/valid-name.util';
|
||||
import { compositeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import { validateDefaultValueForType } from 'src/engine/metadata-modules/field-metadata/utils/validate-default-value-for-type.util';
|
||||
import {
|
||||
EnumFieldMetadataUnionType,
|
||||
@ -25,10 +22,13 @@ import {
|
||||
} from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util';
|
||||
import { validateOptionsForType } from 'src/engine/metadata-modules/field-metadata/utils/validate-options-for-type.util';
|
||||
import { serializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-default-value';
|
||||
import { computeCompositeFieldMetadata } from 'src/engine/workspace-manager/workspace-health/utils/compute-composite-field-metadata.util';
|
||||
import { generateTargetColumnMap } from 'src/engine/metadata-modules/field-metadata/utils/generate-target-column-map.util';
|
||||
import { customNamePrefix } from 'src/engine/utils/compute-custom-name.util';
|
||||
import { customNamePrefix } from 'src/engine/utils/compute-table-name.util';
|
||||
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
|
||||
import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import {
|
||||
computeColumnName,
|
||||
computeCompositeColumnName,
|
||||
} from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
|
||||
@Injectable()
|
||||
export class FieldMetadataHealthService {
|
||||
@ -50,58 +50,14 @@ export class FieldMetadataHealthService {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
|
||||
const compositeFieldMetadataCollection =
|
||||
compositeDefinitions.get(fieldMetadata.type)?.(fieldMetadata) ?? [];
|
||||
const fieldIssues = await this.healthCheckField(
|
||||
tableName,
|
||||
workspaceTableColumns,
|
||||
fieldMetadata,
|
||||
options,
|
||||
);
|
||||
|
||||
if (options.mode === 'metadata' || options.mode === 'all') {
|
||||
const targetColumnMapIssue = this.targetColumnMapCheck(fieldMetadata);
|
||||
|
||||
if (targetColumnMapIssue) {
|
||||
issues.push(targetColumnMapIssue);
|
||||
}
|
||||
|
||||
const defaultValueIssues =
|
||||
this.defaultValueHealthCheck(fieldMetadata);
|
||||
|
||||
issues.push(...defaultValueIssues);
|
||||
}
|
||||
|
||||
// Only check structure on nested composite fields
|
||||
if (options.mode === 'structure' || options.mode === 'all') {
|
||||
for (const compositeFieldMetadata of compositeFieldMetadataCollection) {
|
||||
const compositeFieldStructureIssues = this.structureFieldCheck(
|
||||
tableName,
|
||||
workspaceTableColumns,
|
||||
computeCompositeFieldMetadata(
|
||||
compositeFieldMetadata,
|
||||
fieldMetadata,
|
||||
),
|
||||
);
|
||||
|
||||
issues.push(...compositeFieldStructureIssues);
|
||||
}
|
||||
}
|
||||
|
||||
// Only check metadata on the parent composite field
|
||||
if (options.mode === 'metadata' || options.mode === 'all') {
|
||||
const compositeFieldMetadataIssues = this.metadataFieldCheck(
|
||||
tableName,
|
||||
fieldMetadata,
|
||||
);
|
||||
|
||||
issues.push(...compositeFieldMetadataIssues);
|
||||
}
|
||||
} else {
|
||||
const fieldIssues = await this.healthCheckField(
|
||||
tableName,
|
||||
workspaceTableColumns,
|
||||
fieldMetadata,
|
||||
options,
|
||||
);
|
||||
|
||||
issues.push(...fieldIssues);
|
||||
}
|
||||
issues.push(...fieldIssues);
|
||||
}
|
||||
|
||||
return issues;
|
||||
@ -139,78 +95,105 @@ export class FieldMetadataHealthService {
|
||||
workspaceTableColumns: WorkspaceTableStructure[],
|
||||
fieldMetadata: FieldMetadataEntity,
|
||||
): WorkspaceHealthIssue[] {
|
||||
const dataTypes =
|
||||
this.databaseStructureService.getPostgresDataTypes(fieldMetadata);
|
||||
const issues: WorkspaceHealthIssue[] = [];
|
||||
const columnName = fieldMetadata.targetColumnMap.value;
|
||||
let columnNames: string[] = [];
|
||||
|
||||
const dataType =
|
||||
this.databaseStructureService.getPostgresDataType(fieldMetadata);
|
||||
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
|
||||
const compositeType = compositeTypeDefintions.get(fieldMetadata.type);
|
||||
|
||||
const defaultValue = this.databaseStructureService.getPostgresDefault(
|
||||
if (!compositeType) {
|
||||
throw new Error(`Composite type ${fieldMetadata.type} is not defined`);
|
||||
}
|
||||
|
||||
columnNames = compositeType.properties.map((compositeProperty) =>
|
||||
computeCompositeColumnName(fieldMetadata, compositeProperty),
|
||||
);
|
||||
} else {
|
||||
columnNames = [computeColumnName(fieldMetadata)];
|
||||
}
|
||||
|
||||
const defaultValues = this.databaseStructureService.getPostgresDefaults(
|
||||
fieldMetadata.type,
|
||||
fieldMetadata.defaultValue,
|
||||
);
|
||||
|
||||
// Check if column exist in database
|
||||
const columnStructure = workspaceTableColumns.find(
|
||||
(tableDefinition) => tableDefinition.columnName === columnName,
|
||||
const columnStructureMap = workspaceTableColumns.reduce(
|
||||
(acc, workspaceTableColumn) => {
|
||||
const columnName = workspaceTableColumn.columnName;
|
||||
|
||||
if (columnNames.includes(columnName)) {
|
||||
acc[columnName] = workspaceTableColumn;
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as { [key: string]: WorkspaceTableStructure },
|
||||
);
|
||||
|
||||
if (!columnStructure) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.MISSING_COLUMN,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} not found in table ${tableName}`,
|
||||
});
|
||||
for (const [index, columnName] of columnNames.entries()) {
|
||||
const columnStructure = columnStructureMap[columnName];
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
const columnDefaultValue = columnStructure.columnDefault?.split('::')?.[0];
|
||||
|
||||
// Check if column data type is the same
|
||||
if (columnStructure.dataType !== dataType) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_DATA_TYPE_CONFLICT,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} type is not the same as the field metadata type "${columnStructure.dataType}" !== "${dataType}"`,
|
||||
});
|
||||
}
|
||||
|
||||
if (columnStructure.isNullable !== fieldMetadata.isNullable) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_NULLABILITY_CONFLICT,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} is expected to be ${
|
||||
fieldMetadata.isNullable ? 'nullable' : 'not nullable'
|
||||
} but is ${columnStructure.isNullable ? 'nullable' : 'not nullable'}`,
|
||||
});
|
||||
}
|
||||
|
||||
if (columnDefaultValue && isEnumFieldMetadataType(fieldMetadata.type)) {
|
||||
const enumValues = fieldMetadata.options?.map((option) =>
|
||||
serializeDefaultValue(`'${option.value}'`),
|
||||
);
|
||||
|
||||
if (!enumValues.includes(columnDefaultValue)) {
|
||||
if (!columnStructure) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_DEFAULT_VALUE_NOT_VALID,
|
||||
type: WorkspaceHealthIssueType.MISSING_COLUMN,
|
||||
fieldMetadata,
|
||||
columnStructures: workspaceTableColumns,
|
||||
message: `Column ${columnName} not found in table ${tableName}`,
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const columnDefaultValue =
|
||||
columnStructure.columnDefault?.split('::')?.[0];
|
||||
|
||||
// Check if column data type is the same
|
||||
if (!dataTypes[index] || columnStructure.dataType !== dataTypes[index]) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_DATA_TYPE_CONFLICT,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} default value is not in the enum values "${columnDefaultValue}" NOT IN "${enumValues}"`,
|
||||
message: `Column ${columnName} type is not the same as the field metadata type "${columnStructure.dataType}" !== "${dataTypes[index]}"`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (columnDefaultValue !== defaultValue) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_DEFAULT_VALUE_CONFLICT,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} default value is not the same as the field metadata default value "${columnStructure.columnDefault}" !== "${defaultValue}"`,
|
||||
});
|
||||
if (columnStructure.isNullable !== fieldMetadata.isNullable) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_NULLABILITY_CONFLICT,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} is expected to be ${
|
||||
fieldMetadata.isNullable ? 'nullable' : 'not nullable'
|
||||
} but is ${columnStructure.isNullable ? 'nullable' : 'not nullable'}`,
|
||||
});
|
||||
}
|
||||
|
||||
if (columnDefaultValue && isEnumFieldMetadataType(fieldMetadata.type)) {
|
||||
const enumValues = fieldMetadata.options?.map((option) =>
|
||||
serializeDefaultValue(`'${option.value}'`),
|
||||
);
|
||||
|
||||
if (!enumValues.includes(columnDefaultValue)) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_DEFAULT_VALUE_NOT_VALID,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} default value is not in the enum values "${columnDefaultValue}" NOT IN "${enumValues}"`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (columnDefaultValue !== defaultValues[index]) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_DEFAULT_VALUE_CONFLICT,
|
||||
fieldMetadata,
|
||||
columnStructure,
|
||||
message: `Column ${columnName} default value is not the same as the field metadata default value "${columnStructure.columnDefault}" !== "${defaultValues[index]}"`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return issues;
|
||||
@ -221,14 +204,9 @@ export class FieldMetadataHealthService {
|
||||
fieldMetadata: FieldMetadataEntity,
|
||||
): WorkspaceHealthIssue[] {
|
||||
const issues: WorkspaceHealthIssue[] = [];
|
||||
const columnName = fieldMetadata.targetColumnMap.value;
|
||||
const targetColumnMapIssue = this.targetColumnMapCheck(fieldMetadata);
|
||||
const columnName = fieldMetadata.name;
|
||||
const defaultValueIssues = this.defaultValueHealthCheck(fieldMetadata);
|
||||
|
||||
if (targetColumnMapIssue) {
|
||||
issues.push(targetColumnMapIssue);
|
||||
}
|
||||
|
||||
if (fieldMetadata.name.startsWith(customNamePrefix)) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_NAME_SHOULD_NOT_BE_PREFIXED,
|
||||
@ -237,11 +215,11 @@ export class FieldMetadataHealthService {
|
||||
});
|
||||
}
|
||||
|
||||
if (fieldMetadata.isCustom && !columnName?.startsWith(customNamePrefix)) {
|
||||
if (fieldMetadata.isCustom && columnName?.startsWith(customNamePrefix)) {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_NAME_SHOULD_BE_CUSTOM,
|
||||
type: WorkspaceHealthIssueType.COLUMN_NAME_SHOULD_NOT_BE_CUSTOM,
|
||||
fieldMetadata,
|
||||
message: `Column ${columnName} is marked as custom in table ${tableName} but doesn't start with "_"`,
|
||||
message: `Column ${columnName} is marked as custom in table ${tableName} but and start with "_", this behavior has been removed. Please remove the prefix.`,
|
||||
});
|
||||
}
|
||||
|
||||
@ -280,7 +258,7 @@ export class FieldMetadataHealthService {
|
||||
issues.push({
|
||||
type: WorkspaceHealthIssueType.COLUMN_OPTIONS_NOT_VALID,
|
||||
fieldMetadata,
|
||||
message: `Column options of ${fieldMetadata.targetColumnMap?.value} is not valid`,
|
||||
message: `Column options of ${fieldMetadata.name} is not valid`,
|
||||
});
|
||||
}
|
||||
|
||||
@ -289,33 +267,6 @@ export class FieldMetadataHealthService {
|
||||
return issues;
|
||||
}
|
||||
|
||||
private targetColumnMapCheck(
|
||||
fieldMetadata: FieldMetadataEntity,
|
||||
): WorkspaceHealthIssue | null {
|
||||
const targetColumnMap = generateTargetColumnMap(
|
||||
fieldMetadata.type,
|
||||
fieldMetadata.isCustom,
|
||||
fieldMetadata.name,
|
||||
);
|
||||
|
||||
if (
|
||||
!fieldMetadata.targetColumnMap ||
|
||||
!isEqual(targetColumnMap, fieldMetadata.targetColumnMap)
|
||||
) {
|
||||
return {
|
||||
type: WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID,
|
||||
fieldMetadata,
|
||||
message: `Column targetColumnMap "${JSON.stringify(
|
||||
fieldMetadata.targetColumnMap,
|
||||
)}" is not the same as the generated one "${JSON.stringify(
|
||||
targetColumnMap,
|
||||
)}"`,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private defaultValueHealthCheck(
|
||||
fieldMetadata: FieldMetadataEntity,
|
||||
): WorkspaceHealthIssue[] {
|
||||
|
||||
@ -20,10 +20,10 @@ import {
|
||||
deduceRelationDirection,
|
||||
} from 'src/engine/utils/deduce-relation-direction.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { createRelationForeignKeyColumnName } from 'src/engine/metadata-modules/relation-metadata/utils/create-relation-foreign-key-column-name.util';
|
||||
import { createRelationForeignKeyFieldMetadataName } from 'src/engine/metadata-modules/relation-metadata/utils/create-relation-foreign-key-field-metadata-name.util';
|
||||
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
|
||||
import { convertOnDeleteActionToOnDelete } from 'src/engine/workspace-manager/workspace-migration-runner/utils/convert-on-delete-action-to-on-delete.util';
|
||||
import { camelCase } from 'src/utils/camel-case';
|
||||
|
||||
@Injectable()
|
||||
export class RelationMetadataHealthService {
|
||||
@ -145,11 +145,7 @@ export class RelationMetadataHealthService {
|
||||
return [];
|
||||
}
|
||||
|
||||
const isCustom = toFieldMetadata.isCustom ?? false;
|
||||
const foreignKeyColumnName = createRelationForeignKeyColumnName(
|
||||
toFieldMetadata.name,
|
||||
isCustom,
|
||||
);
|
||||
const foreignKeyColumnName = `${camelCase(toFieldMetadata.name)}Id`;
|
||||
const relationColumn = workspaceTableColumns.find(
|
||||
(column) => column.columnName === foreignKeyColumnName,
|
||||
);
|
||||
|
||||
@ -10,8 +10,8 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
|
||||
import { WorkspaceNullableFixer } from 'src/engine/workspace-manager/workspace-health/fixer/workspace-nullable.fixer';
|
||||
import { WorkspaceDefaultValueFixer } from 'src/engine/workspace-manager/workspace-health/fixer/workspace-default-value.fixer';
|
||||
import { WorkspaceTypeFixer } from 'src/engine/workspace-manager/workspace-health/fixer/workspace-type.fixer';
|
||||
import { WorkspaceTargetColumnMapFixer } from 'src/engine/workspace-manager/workspace-health/fixer/workspace-target-column-map.fixer';
|
||||
import { CompareEntity } from 'src/engine/workspace-manager/workspace-health/fixer/abstract-workspace.fixer';
|
||||
import { WorkspaceMissingColumnFixer } from 'src/engine/workspace-manager/workspace-health/fixer/workspace-missing-column.fixer';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceFixService {
|
||||
@ -19,7 +19,7 @@ export class WorkspaceFixService {
|
||||
private readonly workspaceNullableFixer: WorkspaceNullableFixer,
|
||||
private readonly workspaceDefaultValueFixer: WorkspaceDefaultValueFixer,
|
||||
private readonly workspaceTypeFixer: WorkspaceTypeFixer,
|
||||
private readonly workspaceTargetColumnMapFixer: WorkspaceTargetColumnMapFixer,
|
||||
private readonly workspaceMissingColumnFixer: WorkspaceMissingColumnFixer,
|
||||
) {}
|
||||
|
||||
async createWorkspaceMigrations(
|
||||
@ -57,11 +57,11 @@ export class WorkspaceFixService {
|
||||
filteredIssues,
|
||||
);
|
||||
}
|
||||
case WorkspaceHealthFixKind.TargetColumnMap: {
|
||||
case WorkspaceHealthFixKind.MissingColumn: {
|
||||
const filteredIssues =
|
||||
this.workspaceTargetColumnMapFixer.filterIssues(issues);
|
||||
this.workspaceMissingColumnFixer.filterIssues(issues);
|
||||
|
||||
return this.workspaceTargetColumnMapFixer.createWorkspaceMigrations(
|
||||
return this.workspaceMissingColumnFixer.createWorkspaceMigrations(
|
||||
manager,
|
||||
objectMetadataCollection,
|
||||
filteredIssues,
|
||||
@ -77,19 +77,10 @@ export class WorkspaceFixService {
|
||||
manager: EntityManager,
|
||||
objectMetadataCollection: ObjectMetadataEntity[],
|
||||
type: WorkspaceHealthFixKind,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
issues: WorkspaceHealthIssue[],
|
||||
): Promise<CompareEntity<unknown>[]> {
|
||||
switch (type) {
|
||||
case WorkspaceHealthFixKind.TargetColumnMap: {
|
||||
const filteredIssues =
|
||||
this.workspaceTargetColumnMapFixer.filterIssues(issues);
|
||||
|
||||
return this.workspaceTargetColumnMapFixer.createMetadataUpdates(
|
||||
manager,
|
||||
objectMetadataCollection,
|
||||
filteredIssues,
|
||||
);
|
||||
}
|
||||
case WorkspaceHealthFixKind.DefaultValue: {
|
||||
const filteredIssues =
|
||||
this.workspaceDefaultValueFixer.filterIssues(issues);
|
||||
|
||||
@ -17,9 +17,3 @@ export const isWorkspaceHealthDefaultValueIssue = (
|
||||
): type is WorkspaceHealthIssueType.COLUMN_DEFAULT_VALUE_CONFLICT => {
|
||||
return type === WorkspaceHealthIssueType.COLUMN_DEFAULT_VALUE_CONFLICT;
|
||||
};
|
||||
|
||||
export const isWorkspaceHealthTargetColumnMapIssue = (
|
||||
type: WorkspaceHealthIssueType,
|
||||
): type is WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID => {
|
||||
return type === WorkspaceHealthIssueType.COLUMN_TARGET_COLUMN_MAP_NOT_VALID;
|
||||
};
|
||||
|
||||
@ -16,7 +16,6 @@ describe('WorkspaceFieldComparator', () => {
|
||||
type: 'TEXT',
|
||||
name: 'DefaultFieldName',
|
||||
label: 'Default Field Label',
|
||||
targetColumnMap: 'default_column',
|
||||
defaultValue: null,
|
||||
description: 'Default description',
|
||||
isCustom: false,
|
||||
|
||||
@ -25,7 +25,7 @@ const commonFieldPropertiesToIgnore = [
|
||||
'options',
|
||||
];
|
||||
|
||||
const fieldPropertiesToStringify = ['targetColumnMap', 'defaultValue'] as const;
|
||||
const fieldPropertiesToStringify = ['defaultValue'] as const;
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceFieldComparator {
|
||||
|
||||
@ -6,7 +6,6 @@ import { GateDecoratorParams } from 'src/engine/workspace-manager/workspace-sync
|
||||
import { FieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { generateTargetColumnMap } from 'src/engine/metadata-modules/field-metadata/utils/generate-target-column-map.util';
|
||||
import { generateDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/generate-default-value';
|
||||
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||
import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
|
||||
@ -70,7 +69,6 @@ function generateFieldMetadata<T extends FieldMetadataType>(
|
||||
isSystem: boolean,
|
||||
gate: GateDecoratorParams | undefined = undefined,
|
||||
): ReflectFieldMetadata[string] {
|
||||
const targetColumnMap = generateTargetColumnMap(params.type, false, fieldKey);
|
||||
const defaultValue = (params.defaultValue ??
|
||||
generateDefaultValue(
|
||||
params.type,
|
||||
@ -79,7 +77,6 @@ function generateFieldMetadata<T extends FieldMetadataType>(
|
||||
return {
|
||||
name: fieldKey,
|
||||
...params,
|
||||
targetColumnMap,
|
||||
isNullable: params.type === FieldMetadataType.RELATION ? true : isNullable,
|
||||
isSystem,
|
||||
isCustom: false,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { FieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
import { GateDecoratorParams } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/gate-decorator.interface';
|
||||
import { FieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-options.interface';
|
||||
import { FieldMetadataTargetColumnMap } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-target-column-map.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
@ -26,7 +25,6 @@ export interface ReflectFieldMetadata {
|
||||
> & {
|
||||
name: string;
|
||||
type: FieldMetadataType;
|
||||
targetColumnMap: FieldMetadataTargetColumnMap<'default'>;
|
||||
isNullable: boolean;
|
||||
isSystem: boolean;
|
||||
isCustom: boolean;
|
||||
|
||||
@ -5,7 +5,6 @@ import {
|
||||
import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { generateTargetColumnMap } from 'src/engine/metadata-modules/field-metadata/utils/generate-target-column-map.util';
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import {
|
||||
createForeignKeyDeterministicUuid,
|
||||
@ -42,7 +41,6 @@ export const computeStandardObject = (
|
||||
...rest,
|
||||
standardId: relationStandardId,
|
||||
defaultValue: null,
|
||||
targetColumnMap: {},
|
||||
});
|
||||
|
||||
// Foreign key
|
||||
@ -55,11 +53,6 @@ export const computeStandardObject = (
|
||||
description: `${data.description} id foreign key`,
|
||||
defaultValue: null,
|
||||
icon: undefined,
|
||||
targetColumnMap: generateTargetColumnMap(
|
||||
FieldMetadataType.UUID,
|
||||
rest.isCustom,
|
||||
joinColumn,
|
||||
),
|
||||
isSystem: true,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user