This commit is contained in:
yassine belkaid 2025-02-06 20:27:18 +08:00 committed by GitHub
commit 39aa78f4d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 128 additions and 0 deletions

View File

@ -73,6 +73,7 @@ import { jsonToMermaid } from "../../utils/exportAs/mermaid";
import { isRtl } from "../../i18n/utils/rtl"; import { isRtl } from "../../i18n/utils/rtl";
import { jsonToDocumentation } from "../../utils/exportAs/documentation"; import { jsonToDocumentation } from "../../utils/exportAs/documentation";
import { IdContext } from "../Workspace"; import { IdContext } from "../Workspace";
import { jsonToDBML } from "../../utils/exportAs/dbml";
export default function ControlPanel({ export default function ControlPanel({
diagramId, diagramId,
@ -1086,6 +1087,26 @@ export default function ControlPanel({
})); }));
}, },
}, },
{
DBML: () => {
setModal(MODAL.CODE);
const result = jsonToDBML({
tables: tables,
references: relationships,
notes: notes,
subjectAreas: areas,
database: database,
title: title,
...(databases[database].hasTypes && { types: types }),
...(databases[database].hasEnums && { enums: enums }),
});
setExportData((prev) => ({
...prev,
data: result,
extension: "dbml",
}));
},
},
], ],
function: () => {}, function: () => {},
}, },

107
src/utils/exportAs/dbml.js Normal file
View File

@ -0,0 +1,107 @@
import { toPostgres } from "../exportSQL/postgres";
import { DB } from '../../data/constants';
export function jsonToDBML(obj) {
let dbml = "Not supported yet.";
switch (obj.database) {
case DB.POSTGRES:
dbml = convertPostgresToDBML(toPostgres(obj));
break;
}
return dbml;
}
function convertPostgresToDBML(postgresSchema) {
function mapDataType(type) {
const typeMap = {
'character varying': 'varchar',
'character': 'char',
'text': 'text',
'integer': 'int',
'bigint': 'bigint',
'smallint': 'smallint',
'decimal': 'decimal',
'numeric': 'decimal',
'real': 'float',
'double precision': 'double',
'boolean': 'boolean',
'date': 'date',
'timestamp without time zone': 'datetime',
'timestamp with time zone': 'datetime',
'smallserial': 'smallserial',
'serial': 'serial',
'bigserial': 'bigserial',
};
return typeMap[type] || type; // Fallback to the original type if not mapped
}
let dbmlOutput = '';
const tableDefinitions = postgresSchema.split(/;\s*CREATE TABLE/i).filter(Boolean);
if (!tableDefinitions) {
return dbmlOutput;
}
tableDefinitions.forEach(definition => {
const tableNameMatch = definition.match(/"([^"]+)"/);
const columnsMatch = definition.match(/\(([^)]+)\)/);
if (!tableNameMatch || !columnsMatch) return;
const tableName = tableNameMatch[1];
const columns = columnsMatch[1].trim();
dbmlOutput += `Table ${tableName} {\n`;
// Split column definitions by comma, allowing for potential whitespace
const columnDefinitions = columns.split(/\s*,\s*(?![^()]*\))/);
columnDefinitions.forEach(colDef => {
// Match the column name and type, and check for additional attributes
const colMatch = colDef.match(/"([^"]+)"\s+(\w+)/);
if (!colMatch) return;
const colName = colMatch[1];
const colType = mapDataType(colMatch[2]);
const colDefExtras = [];
let colExtras = '';
if (/DEFAULT\s+([^)]+)/i.test(colDef)) {
const defaultValue = colDef.match(/DEFAULT\s+([^)]+)/i)[1];
colDefExtras.push(`default: '${defaultValue}'`);
}
if (/NOT NULL/i.test(colDef)) {
colDefExtras.push('not null');
}
if (/UNIQUE/i.test(colDef)) {
colDefExtras.push('unique');
}
if (colDefExtras.length > 0) {
colExtras = ` [${colDefExtras.join(', ')}]`;
}
dbmlOutput += ` ${colName} ${colType}${colExtras}\n`;
});
dbmlOutput += `}\n\n`;
});
// Handle foreign keys
const foreignKeyMatches = postgresSchema.match(/ALTER TABLE "([^"]+)"\s+ADD FOREIGN KEY\("([^"]+)"\)\s+REFERENCES "([^"]+)"\("([^"]+)"\)/g);
if (foreignKeyMatches) {
foreignKeyMatches.forEach(fk => {
const match = fk.match(/ALTER TABLE "([^"]+)"\s+ADD FOREIGN KEY\("([^"]+)"\)\s+REFERENCES "([^"]+)"\("([^"]+)"\)/);
if (match) {
dbmlOutput += `Ref: ${match[1]}.${match[2]} > ${match[3]}.${match[4]}\n`;
}
});
}
return dbmlOutput;
}