Improve health check command (#3553)

* Improve health check command

* Fix health check

* Fix health check
This commit is contained in:
Charles Bochet
2024-01-19 16:54:43 +01:00
committed by GitHub
parent 7607ecaac6
commit 2cf4bd746a
7 changed files with 60 additions and 18 deletions

View File

@ -101,7 +101,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
}, },
icon: 'Icon123', icon: 'Icon123',
description: 'Id', description: 'Id',
isNullable: true, isNullable: false,
isActive: true, isActive: true,
isCustom: false, isCustom: false,
isSystem: true, isSystem: true,
@ -117,7 +117,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
}, },
icon: 'IconAbc', icon: 'IconAbc',
description: 'Name', description: 'Name',
isNullable: true, isNullable: false,
isActive: true, isActive: true,
isCustom: false, isCustom: false,
workspaceId: objectMetadataInput.workspaceId, workspaceId: objectMetadataInput.workspaceId,
@ -132,7 +132,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
}, },
icon: 'IconCalendar', icon: 'IconCalendar',
description: 'Creation date', description: 'Creation date',
isNullable: true, isNullable: false,
isActive: true, isActive: true,
isCustom: false, isCustom: false,
workspaceId: objectMetadataInput.workspaceId, workspaceId: objectMetadataInput.workspaceId,
@ -147,7 +147,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
}, },
icon: 'IconCalendar', icon: 'IconCalendar',
description: 'Update date', description: 'Update date',
isNullable: true, isNullable: false,
isActive: true, isActive: true,
isCustom: false, isCustom: false,
isSystem: true, isSystem: true,
@ -245,7 +245,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
{ {
action: WorkspaceMigrationColumnActionType.CREATE, action: WorkspaceMigrationColumnActionType.CREATE,
columnName: 'name', columnName: 'name',
columnType: 'varchar', columnType: 'text',
defaultValue: "'Untitled'", defaultValue: "'Untitled'",
} satisfies WorkspaceMigrationColumnCreate, } satisfies WorkspaceMigrationColumnCreate,
], ],
@ -330,6 +330,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
) { ) {
return this.objectMetadataRepository.find({ return this.objectMetadataRepository.find({
relations: [ relations: [
'fields.object',
'fields', 'fields',
'fields.fromRelationMetadata', 'fields.fromRelationMetadata',
'fields.toRelationMetadata', 'fields.toRelationMetadata',

View File

@ -20,14 +20,13 @@ import { WorkspaceMigrationColumnActionType } from 'src/metadata/workspace-migra
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity'; import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
import { createCustomColumnName } from 'src/metadata/utils/create-custom-column-name.util'; import { createCustomColumnName } from 'src/metadata/utils/create-custom-column-name.util';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util'; import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
import { createRelationForeignKeyColumnName } from 'src/metadata/relation-metadata/utils/create-relation-foreign-key-column-name.util';
import { import {
RelationMetadataEntity, RelationMetadataEntity,
RelationMetadataType, RelationMetadataType,
} from './relation-metadata.entity'; } from './relation-metadata.entity';
import { createRelationMetadataForeignKey } from './utils/create-relation-metadata-foreign-key.util';
@Injectable() @Injectable()
export class RelationMetadataService extends TypeOrmQueryService<RelationMetadataEntity> { export class RelationMetadataService extends TypeOrmQueryService<RelationMetadataEntity> {
constructor( constructor(
@ -56,7 +55,7 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
// NOTE: this logic is called to create relation through metadata graphql endpoint (so only for custom field relations) // NOTE: this logic is called to create relation through metadata graphql endpoint (so only for custom field relations)
const isCustom = true; const isCustom = true;
const baseColumnName = `${camelCase(relationMetadataInput.toName)}Id`; const baseColumnName = `${camelCase(relationMetadataInput.toName)}Id`;
const foreignKeyColumnName = createRelationMetadataForeignKey( const foreignKeyColumnName = createRelationForeignKeyColumnName(
relationMetadataInput.toName, relationMetadataInput.toName,
isCustom, isCustom,
); );

View File

@ -1,9 +1,9 @@
import { createCustomColumnName } from 'src/metadata/utils/create-custom-column-name.util'; import { createCustomColumnName } from 'src/metadata/utils/create-custom-column-name.util';
import { camelCase } from 'src/utils/camel-case'; import { camelCase } from 'src/utils/camel-case';
export const createRelationMetadataForeignKey = ( export const createRelationForeignKeyColumnName = (
name: string, name: string,
isCustom?: boolean, isCustom: boolean,
) => { ) => {
const baseColumnName = `${camelCase(name)}Id`; const baseColumnName = `${camelCase(name)}Id`;

View File

@ -0,0 +1,5 @@
import { camelCase } from 'src/utils/camel-case';
export const createRelationForeignKeyFieldMetadataName = (name: string) => {
return `${camelCase(name)}Id`;
};

View File

@ -63,7 +63,10 @@ export class DatabaseStructureService {
c.table_schema AS "tableSchema", c.table_schema AS "tableSchema",
c.table_name AS "tableName", c.table_name AS "tableName",
c.column_name AS "columnName", c.column_name AS "columnName",
c.data_type AS "dataType", CASE
WHEN (c.data_type = 'USER-DEFINED') THEN c.udt_name
ELSE data_type
END AS "dataType",
c.is_nullable AS "isNullable", c.is_nullable AS "isNullable",
c.column_default AS "columnDefault", c.column_default AS "columnDefault",
CASE CASE
@ -116,10 +119,19 @@ export class DatabaseStructureService {
})); }));
} }
getPostgresDataType(fieldMetadataType: FieldMetadataType): string { getPostgresDataType(
fieldMetadataType: FieldMetadataType,
fieldMetadataName: string,
objectMetadataNameSingular: string,
): string {
const typeORMType = fieldMetadataTypeToColumnType(fieldMetadataType); const typeORMType = fieldMetadataTypeToColumnType(fieldMetadataType);
const mainDataSource = this.typeORMService.getMainDataSource(); const mainDataSource = this.typeORMService.getMainDataSource();
// TODO: remove special case for enum type, should we include this to fieldMetadataTypeToColumnType?
if (typeORMType === 'enum') {
return `${objectMetadataNameSingular}_${fieldMetadataName}_enum`;
}
return mainDataSource.driver.normalizeType({ return mainDataSource.driver.normalizeType({
type: typeORMType, type: typeORMType,
}); });

View File

@ -117,9 +117,13 @@ export class FieldMetadataHealthService {
): WorkspaceHealthIssue[] { ): WorkspaceHealthIssue[] {
const issues: WorkspaceHealthIssue[] = []; const issues: WorkspaceHealthIssue[] = [];
const columnName = fieldMetadata.targetColumnMap.value; const columnName = fieldMetadata.targetColumnMap.value;
const dataType = this.databaseStructureService.getPostgresDataType( const dataType = this.databaseStructureService.getPostgresDataType(
fieldMetadata.type, fieldMetadata.type,
fieldMetadata.name,
fieldMetadata.object?.nameSingular,
); );
const defaultValue = this.databaseStructureService.getPostgresDefault( const defaultValue = this.databaseStructureService.getPostgresDefault(
fieldMetadata.type, fieldMetadata.type,
fieldMetadata.defaultValue, fieldMetadata.defaultValue,
@ -155,7 +159,9 @@ export class FieldMetadataHealthService {
type: WorkspaceHealthIssueType.COLUMN_NULLABILITY_CONFLICT, type: WorkspaceHealthIssueType.COLUMN_NULLABILITY_CONFLICT,
fieldMetadata, fieldMetadata,
columnStructure, columnStructure,
message: `Column ${columnName} is not nullable as expected`, message: `Column ${columnName} is expected to be ${
fieldMetadata.isNullable ? 'nullable' : 'not nullable'
} but is ${columnStructure.isNullable ? 'nullable' : 'not nullable'}`,
}); });
} }

View File

@ -18,12 +18,13 @@ import {
RelationMetadataEntity, RelationMetadataEntity,
RelationMetadataType, RelationMetadataType,
} from 'src/metadata/relation-metadata/relation-metadata.entity'; } from 'src/metadata/relation-metadata/relation-metadata.entity';
import { createRelationMetadataForeignKey } from 'src/metadata/relation-metadata/utils/create-relation-metadata-foreign-key.util';
import { import {
RelationDirection, RelationDirection,
deduceRelationDirection, deduceRelationDirection,
} from 'src/workspace/utils/deduce-relation-direction.util'; } from 'src/workspace/utils/deduce-relation-direction.util';
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity'; import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
import { createRelationForeignKeyColumnName } from 'src/metadata/relation-metadata/utils/create-relation-foreign-key-column-name.util';
import { createRelationForeignKeyFieldMetadataName } from 'src/metadata/relation-metadata/utils/create-relation-foreign-key-field-metadata-name.util';
@Injectable() @Injectable()
export class RelationMetadataHealthService { export class RelationMetadataHealthService {
@ -136,7 +137,7 @@ export class RelationMetadataHealthService {
} }
const isCustom = toFieldMetadata.isCustom ?? false; const isCustom = toFieldMetadata.isCustom ?? false;
const foreignKeyColumnName = createRelationMetadataForeignKey( const foreignKeyColumnName = createRelationForeignKeyColumnName(
toFieldMetadata.name, toFieldMetadata.name,
isCustom, isCustom,
); );
@ -144,16 +145,34 @@ export class RelationMetadataHealthService {
(column) => column.columnName === foreignKeyColumnName, (column) => column.columnName === foreignKeyColumnName,
); );
const relationFieldMetadata = toObjectMetadataFields.find( const relationFieldMetadata = toObjectMetadataFields.find(
(fieldMetadata) => fieldMetadata.name === foreignKeyColumnName, (fieldMetadata) =>
fieldMetadata.name ===
createRelationForeignKeyFieldMetadataName(toFieldMetadata.name),
); );
if (!relationColumn || !relationFieldMetadata) { if (!relationFieldMetadata) {
issues.push({ issues.push({
type: WorkspaceHealthIssueType.RELATION_FOREIGN_KEY_NOT_VALID, type: WorkspaceHealthIssueType.RELATION_FOREIGN_KEY_NOT_VALID,
fromFieldMetadata, fromFieldMetadata,
toFieldMetadata, toFieldMetadata,
relationMetadata, relationMetadata,
message: `Relation ${relationMetadata.id} doesn't have a valid foreign key`, message: `Relation ${
relationMetadata.id
} doesn't have a valid foreign key (expected fieldMetadata.name to be ${createRelationForeignKeyFieldMetadataName(
toFieldMetadata.name,
)}`,
});
return issues;
}
if (!relationColumn) {
issues.push({
type: WorkspaceHealthIssueType.RELATION_FOREIGN_KEY_NOT_VALID,
fromFieldMetadata,
toFieldMetadata,
relationMetadata,
message: `Relation ${relationMetadata.id} doesn't have a valid foreign key (expected column name to be ${foreignKeyColumnName}`,
}); });
return issues; return issues;