imoprt Postgres database features implemented

This commit is contained in:
KarimTamani
2025-06-22 18:17:12 +01:00
parent f33d6f5123
commit ea275f0a92
6 changed files with 204 additions and 52 deletions
+22 -9
View File
@@ -48,7 +48,7 @@ export const DatabaseToAst = (database: DatabaseType, data_types: DataType[]) =>
}, table));
};
} catch (error) {
throw error ;
throw error;
}
return dbAst;
@@ -78,13 +78,13 @@ export const TableToAst = (table: TableType, data_types: DataType[], isPostgresD
const filed_definitions = table.fields.map((field: FieldType) => {
const isPostgresEnum: boolean = isPostgresDialect && field.type.name == "enum";
return FieldToAst({
...field,
type: !(isPostgresEnum) ?
data_types.find((dataType: DataType) => dataType.id == field.typeId) as DataType :
{ name: `${field.name.toLowerCase()}_enum` } as DataType,
}, multiPrimaryKeys , !isPostgresEnum)
}, multiPrimaryKeys, !isPostgresEnum)
})
@@ -122,7 +122,7 @@ export const FieldToAst = (field: FieldType, ignorePrimaryKey: boolean = false,
let valuesExpr: any | null;
let default_val: any | null = null;
let dataType: string | undefined = upperCaseType ? field.type?.name?.toLocaleUpperCase() : field.type?.name as string | undefined ;
let dataType: string | undefined = upperCaseType ? field.type?.name?.toLocaleUpperCase() : field.type?.name as string | undefined;
if (modifiers.includes(Modifiers.PRECISION) && field.precision) {
length = field.precision;
@@ -211,7 +211,21 @@ export const FieldToAst = (field: FieldType, ignorePrimaryKey: boolean = false,
}
}
// field.type?.name == "varchar" && (field.type?.dialect == DatabaseDialect.MYSQL || field.type?.dialect == DatabaseDialect.MARIADB) ? 255 : null
let auto_increment: string | undefined;
if (modifiers.includes(Modifiers.AUTO_INCREMENT) && field.autoIncrement && field.type.dialect != DatabaseDialect.POSTGRES) {
auto_increment = "auto_increment"
} else if (modifiers.includes(Modifiers.AUTO_INCREMENT) && field.autoIncrement && field.type.dialect == DatabaseDialect.POSTGRES) {
if (dataType == "INTEGER")
dataType = "SERIAL";
else
dataType = dataType?.replace("INT", "SERIAL");
} else {
auto_increment = undefined;
}
return {
column: {
type: "column_ref",
@@ -225,8 +239,7 @@ export const FieldToAst = (field: FieldType, ignorePrimaryKey: boolean = false,
character_set,
default_val,
unique: field.unique ? "unique" : null,
auto_increment: (modifiers.includes(Modifiers.AUTO_INCREMENT) && field.autoIncrement && field.type.dialect != DatabaseDialect.POSTGRES) ? "auto_increment" : null,
auto_increment,
nullable: {
type: field.nullable ? "null" : "not null",
value: field.nullable ? "null" : "not null",
@@ -264,9 +277,9 @@ export const IndexToAst = (index: IndexType, table: TableType) => {
export const PotgresEnumToAst = (field: FieldType) => {
const jsonValues = field.values ? JSON.parse(field.values) : [];
return {
as : "as" ,
as: "as",
type: "create",
resource: "enum",
name: {
+123 -27
View File
@@ -8,6 +8,9 @@ import { parse } from 'pgsql-ast-parser';
import { DatabaseDialect } from "@/lib/database";
import { randomColor } from "@/lib/colors";
import { Cardinality, RelationshipInsertType } from "@/lib/schemas/relationship-schema";
import { IndexInsertType } from "@/lib/schemas/index-schema";
import { relationshipToAst } from "./database_to_ast";
import { DatabaseInsertType } from "@/lib/schemas/database-schema";
export const SqlToDatabase = (sql: string, data_types: DataType[], dialect: DatabaseDialect) => {
@@ -16,8 +19,11 @@ export const SqlToDatabase = (sql: string, data_types: DataType[], dialect: Data
const alterTableStatements: string[] = [];
const createIndexStatements: string[] = [];
const createPostgresTypesStatements: string[] = [];
const tables: TableInsertType[] = [];
let relationships: RelationshipInsertType[] = [];
const indices: IndexInsertType[] = []
const postgresTypes: any[] = [];
// Clean up SQL: remove comments and normalize
const cleanedSql = sql
@@ -39,7 +45,7 @@ export const SqlToDatabase = (sql: string, data_types: DataType[], dialect: Data
createTableStatements.push(stmt);
} else if (upper.startsWith('ALTER TABLE')) {
alterTableStatements.push(stmt);
} else if (upper.startsWith('CREATE INDEX')) {
} else if (upper.startsWith('CREATE INDEX') || upper.startsWith('CREATE UNIQUE INDEX')) {
createIndexStatements.push(stmt);
} else if (upper.startsWith('CREATE TYPE')) {
createPostgresTypesStatements.push(stmt);
@@ -60,27 +66,38 @@ export const SqlToDatabase = (sql: string, data_types: DataType[], dialect: Data
if (dialect == DatabaseDialect.POSTGRES)
for (const createTable of createTableStatements) {
try {
const instructionAst = parse(createTable);
if (Array.isArray(instructionAst) && instructionAst.length > 0) {
tables.push(postgresAstToTable(instructionAst[0], data_types, postgresTypes));
const table: TableInsertType = postgresAstToTable(instructionAst[0], data_types, postgresTypes);
tables.push(table);
if ((instructionAst[0] as any).constraints && (instructionAst[0] as any).constraints.length > 0) {
const relationshipAst: any = foreignKeyConstraintToAlterTableAst((instructionAst[0] as any).constraints, table)
try {
const newRelationships = astToRelationship(relationshipAst, tables);
relationships = relationships.concat(newRelationships);
} catch (error) {
if ((error as any).relationships && (error as any).relationships.length > 0)
relationships = relationships.concat((error as any).relationships);
}
}
}
/*
const instructionAst = parser.astify(createTable, {
database: "MySql"
});
if (Array.isArray(instructionAst) && instructionAst.length > 0) {
tables.push(astToTable(instructionAst[0], data_types));
}*/
} catch (error) {
console.log(error);
}
}
for (const createIndex of createIndexStatements) {
try {
const instructionAst = parse(createIndex);
if (Array.isArray(instructionAst) && instructionAst.length > 0) {
indices.push(astToIndex(instructionAst[0], tables));
}
} catch (error) {
continue;
}
}
for (const alterTable of alterTableStatements) {
try {
const instructionAst = parse(alterTable);
@@ -93,9 +110,9 @@ export const SqlToDatabase = (sql: string, data_types: DataType[], dialect: Data
relationships = relationships.concat((error as any).relationships);
}
}
return {tables , relationships};
return { tables, relationships, indices };
}
@@ -105,6 +122,7 @@ export const SqlToDatabase = (sql: string, data_types: DataType[], dialect: Data
export const postgresAstToTable = (ast: any, data_types: DataType[], postgresTypes: any[]): TableInsertType => {
// console.log(ast);
return {
id: v4(),
name: ast.name.name,
@@ -123,9 +141,9 @@ export const postgresAstToField = (ast: any, data_types: DataType[], sequence: n
});
let values: string | undefined;
let autoIncrement: boolean = false;
if (!dataType && postgresTypes && postgresTypes.length > 0) {
const postgresType: any = postgresTypes.find((type: any) => type.name.name == ast.dataType.name);
if (postgresType) {
dataType = data_types.find((dataType: DataType) => dataType.name == "enum") as DataType;
@@ -133,16 +151,27 @@ export const postgresAstToField = (ast: any, data_types: DataType[], sequence: n
};
}
if (ast.dataType.name?.toLowerCase().includes("serial")) {
let baseType: string = ast.dataType.name?.toLowerCase() == "serial" ? "integer" : ast.dataType.name?.toLowerCase().replace("serial", "int");
dataType = data_types.find((dataType: DataType) => {
return dataType.name == baseType;
});
autoIncrement = true;
}
const modifiers: string[] = dataType?.modifiers ? JSON.parse(dataType.modifiers) : [];
let length: number | undefined;
let scale: number | undefined;
if (ast.dataType.config && ast.dataType.config.length > 0)
if (ast.dataType.config.length == 1)
let unique: boolean = false;
let primaryKey: boolean = false;
if (ast.dataType.config && ast.dataType.config.length > 0) {
if (ast.dataType.config.length >= 1)
length = ast.dataType.config[0];
else if (ast.dataType.config.length == 2)
if (ast.dataType.config.length == 2)
scale = ast.dataType.config[1];
}
let maxLength: number | null = null;
@@ -173,6 +202,14 @@ export const postgresAstToField = (ast: any, data_types: DataType[], sequence: n
else
defaultValue = String(defaultValueConstraints.default.value);
}
const uniqueConstraints: any | undefined = constraints.find((c: any) => c.type == "unique");
const primryKeyConstraints: any | undefined = constraints.find((c: any) => c.type == "primary key");
if (uniqueConstraints)
unique = true;
if (primryKeyConstraints)
primaryKey = true;
}
return {
@@ -181,12 +218,14 @@ export const postgresAstToField = (ast: any, data_types: DataType[], sequence: n
defaultValue,
typeId: dataType?.id,
nullable,
unique: ast.unique,
unique,
maxLength,
precision,
scale,
isPrimary: primaryKey,
sequence,
values
values,
autoIncrement
} as FieldInsertType;
}
@@ -204,6 +243,7 @@ const astToTable = (ast: any, data_types: DataType[]): TableInsertType => {
export const astToField = (ast: any, data_types: DataType[]): FieldInsertType => {
const dataType: DataType | undefined = data_types.find((dataType: DataType) => dataType.name == ast.definition.dataType?.toLowerCase());
const modifiers: string[] = dataType?.modifiers ? JSON.parse(dataType.modifiers) : [];
@@ -237,11 +277,10 @@ export const astToField = (ast: any, data_types: DataType[]): FieldInsertType =>
export const astToRelationship = (ast: any, tables: TableInsertType[]): RelationshipInsertType[] => {
const relationships: RelationshipInsertType[] = [];
const changes = ast.changes;
const targetTable: TableInsertType | undefined = tables.find((table: TableInsertType) => table.name == ast.table.name);
if (!targetTable)
@@ -255,9 +294,7 @@ export const astToRelationship = (ast: any, tables: TableInsertType[]): Relation
const targetField: FieldInsertType | undefined = targetTable.fields?.find((field: FieldInsertType) => field.name == foreignKeyConstraint.localColumns[0]?.name)
const sourceField : FieldInsertType | undefined = sourceTable?.fields?.find((field: FieldInsertType) => field.name == foreignKeyConstraint.foreignColumns[0]?.name)
const sourceField: FieldInsertType | undefined = sourceTable?.fields?.find((field: FieldInsertType) => field.name == foreignKeyConstraint.foreignColumns[0]?.name)
if (!sourceField || !targetField || !sourceTable)
continue;
@@ -283,4 +320,63 @@ export const astToRelationship = (ast: any, tables: TableInsertType[]): Relation
} as any)
}
}
const foreignKeyConstraintToAlterTableAst = (constraints: any[], table: TableInsertType) => {
const changes: any[] = constraints.map((constraint: any) => ({
type: "add constraint",
constraint: {
type: "foreign key",
localColumns: [
{
name: constraint.localColumns?.[0].name
}
],
foreignTable: {
name: constraint.foreignTable.name,
},
foreignColumns: [
{
name: constraint.foreignColumns?.[0].name
}
]
}
}))
return {
type: "alter table",
only: true,
table: {
name: table.name
},
changes
}
}
export const astToIndex = (ast: any, tables: TableInsertType[]): IndexInsertType => {
const table: TableInsertType | undefined = tables.find((table: TableInsertType) => table.name == ast.table.name);
if (!table)
throw Error("table not found");
const fieldNames: string[] = ast.expressions.map((expression: any) => expression.expression.name);
const fieldIds: string[] | undefined = table.fields?.filter((field: FieldInsertType) => fieldNames.includes(field.name))
.map((field: FieldInsertType) => field.id);
return {
id: v4(),
name: ast.indexName.name,
tableId: table.id,
unique: ast.unique,
fieldIndices: fieldIds?.map((id: string) => ({
id: v4(),
fieldId: id
}))
} as IndexInsertType
}