mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-05-24 10:29:11 +00:00
Add export and import functions
This commit is contained in:
parent
e3877ef982
commit
81b5a73972
53
package-lock.json
generated
53
package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/lang-sql": "^6.6.3",
|
||||
"@dbml/core": "^3.9.7-alpha.0",
|
||||
"@douyinfe/semi-ui": "^2.51.3",
|
||||
"@lexical/react": "^0.12.5",
|
||||
"@uiw/codemirror-theme-github": "^4.21.25",
|
||||
@ -536,6 +537,34 @@
|
||||
"w3c-keyname": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@dbml/core": {
|
||||
"version": "3.9.7-alpha.0",
|
||||
"resolved": "https://registry.npmjs.org/@dbml/core/-/core-3.9.7-alpha.0.tgz",
|
||||
"integrity": "sha512-KGXr7p80XuoqQJumOs2+RHRBBH703gNxM0uiEvT1FF945+H4LriNK4ZgbXqe2ObmRNbwF2/TYFou+lqkh+tbUw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@dbml/parse": "^3.9.7-alpha.0",
|
||||
"antlr4": "^4.13.1",
|
||||
"lodash": "^4.17.15",
|
||||
"parsimmon": "^1.13.0",
|
||||
"pluralize": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@dbml/parse": {
|
||||
"version": "3.9.7-alpha.0",
|
||||
"resolved": "https://registry.npmjs.org/@dbml/parse/-/parse-3.9.7-alpha.0.tgz",
|
||||
"integrity": "sha512-QT0rmbbnjn6hKbGXMhvdw62Gn8YgXjvG5a+0+9EoZFpFdl/Y8VSPlHqpHbdMas2kOpusMgpa1YRFaTMApZM7Mw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/accessibility": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz",
|
||||
@ -2351,6 +2380,15 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/antlr4": {
|
||||
"version": "4.13.2",
|
||||
"resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz",
|
||||
"integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
@ -5065,6 +5103,12 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parsimmon": {
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.18.1.tgz",
|
||||
"integrity": "sha512-u7p959wLfGAhJpSDJVYXoyMCXWYwHia78HhRBWqk7AIbxdmlrfdp5wX0l3xv/iTSH5HvhN9K7o26hwwpgS5Nmw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@ -5139,6 +5183,15 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/pluralize": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
|
||||
"integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.41",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
|
||||
|
@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/lang-sql": "^6.6.3",
|
||||
"@dbml/core": "^3.9.7-alpha.0",
|
||||
"@douyinfe/semi-ui": "^2.51.3",
|
||||
"@lexical/react": "^0.12.5",
|
||||
"@uiw/codemirror-theme-github": "^4.21.25",
|
||||
|
@ -74,6 +74,7 @@ import { isRtl } from "../../i18n/utils/rtl";
|
||||
import { jsonToDocumentation } from "../../utils/exportAs/documentation";
|
||||
import { IdContext } from "../Workspace";
|
||||
import { socials } from "../../data/socials";
|
||||
import { toDBML } from "../../utils/exportAs/dbml";
|
||||
|
||||
export default function ControlPanel({
|
||||
diagramId,
|
||||
@ -963,6 +964,21 @@ export default function ControlPanel({
|
||||
setModal(MODAL.IMG);
|
||||
},
|
||||
},
|
||||
{
|
||||
SVG: () => {
|
||||
const filter = (node) => node.tagName !== "i";
|
||||
toSvg(document.getElementById("canvas"), { filter: filter }).then(
|
||||
function (dataUrl) {
|
||||
setExportData((prev) => ({
|
||||
...prev,
|
||||
data: dataUrl,
|
||||
extension: "svg",
|
||||
}));
|
||||
},
|
||||
);
|
||||
setModal(MODAL.IMG);
|
||||
},
|
||||
},
|
||||
{
|
||||
JSON: () => {
|
||||
setModal(MODAL.CODE);
|
||||
@ -988,19 +1004,19 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
SVG: () => {
|
||||
const filter = (node) => node.tagName !== "i";
|
||||
toSvg(document.getElementById("canvas"), { filter: filter }).then(
|
||||
function (dataUrl) {
|
||||
DBML: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const result = toDBML({
|
||||
tables,
|
||||
relationships,
|
||||
enums,
|
||||
});
|
||||
setExportData((prev) => ({
|
||||
...prev,
|
||||
data: dataUrl,
|
||||
extension: "svg",
|
||||
data: result,
|
||||
extension: "dbml",
|
||||
}));
|
||||
},
|
||||
);
|
||||
setModal(MODAL.IMG);
|
||||
},
|
||||
},
|
||||
{
|
||||
PDF: () => {
|
||||
|
102
src/utils/exportAs/dbml.js
Normal file
102
src/utils/exportAs/dbml.js
Normal file
@ -0,0 +1,102 @@
|
||||
import { Cardinality } from "../../data/constants";
|
||||
import { parseDefault } from "../exportSQL/shared";
|
||||
|
||||
function hasColumnSettings(field) {
|
||||
return (
|
||||
field.primary ||
|
||||
field.notNull ||
|
||||
field.increment ||
|
||||
field.unique ||
|
||||
(field.comment && field.comment.trim() != "") ||
|
||||
(field.default && field.default.trim() != "")
|
||||
);
|
||||
}
|
||||
|
||||
function columnDefault(field, database) {
|
||||
if (!field.default || field.default.trim() === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
return `default: ${parseDefault(field, database)}`;
|
||||
}
|
||||
|
||||
function columnComment(field) {
|
||||
if (!field.comment || field.comment.trim() === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
return `note: '${field.comment}'`;
|
||||
}
|
||||
|
||||
function columnSettings(field, database) {
|
||||
if (!hasColumnSettings(field)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ` [ ${field.primary ? "pk " : ""}${
|
||||
field.increment ? "increment " : ""
|
||||
}${field.notNull ? "not null " : ""}${
|
||||
field.unique ? "unique " : ""
|
||||
}${columnDefault(field, database)}${columnComment(field, database)}]`;
|
||||
}
|
||||
|
||||
function cardinality(rel) {
|
||||
switch (rel.cardinality) {
|
||||
case Cardinality.ONE_TO_ONE:
|
||||
return "-";
|
||||
case Cardinality.ONE_TO_MANY:
|
||||
return "<";
|
||||
case Cardinality.MANY_TO_ONE:
|
||||
return ">";
|
||||
}
|
||||
}
|
||||
|
||||
export function toDBML(diagram) {
|
||||
return `${diagram.enums
|
||||
.map(
|
||||
(en) =>
|
||||
`enum ${en.name} {\n${en.values.map((v) => `\t${v}`).join("\n")}\n}\n\n`,
|
||||
)
|
||||
.join("\n\n")}${diagram.tables
|
||||
.map(
|
||||
(table) =>
|
||||
`Table ${table.name} {\n${table.fields
|
||||
.map(
|
||||
(field) =>
|
||||
`\t${field.name} ${field.type.toLowerCase()}${columnSettings(
|
||||
field,
|
||||
diagram.database,
|
||||
)}`,
|
||||
)
|
||||
.join("\n")}${
|
||||
table.indices.length > 0
|
||||
? "\n\n\tindexes {\n" +
|
||||
table.indices
|
||||
.map(
|
||||
(index) =>
|
||||
`\t\t(${index.fields.join(", ")}) [ name: '${
|
||||
index.name
|
||||
}'${index.unique ? " unique" : ""} ]`,
|
||||
)
|
||||
.join("\n") +
|
||||
"\n\t}"
|
||||
: ""
|
||||
}${
|
||||
table.comment && table.comment.trim() !== ""
|
||||
? `\n\n\tNote: '${table.comment}'`
|
||||
: ""
|
||||
}\n}`,
|
||||
)
|
||||
.join("\n\n")}\n\n${diagram.relationships
|
||||
.map(
|
||||
(rel) =>
|
||||
`Ref ${rel.name} {\n\t${
|
||||
diagram.tables[rel.startTableId].name
|
||||
}.${diagram.tables[rel.startTableId].fields[rel.startFieldId].name} ${cardinality(
|
||||
rel,
|
||||
)} ${diagram.tables[rel.endTableId].name}.${
|
||||
diagram.tables[rel.endTableId].fields[rel.endFieldId].name
|
||||
} [ delete: ${rel.deleteConstraint.toLowerCase()}, on update: ${rel.updateConstraint.toLowerCase()} ]\n}`,
|
||||
)
|
||||
.join("\n\n")}`;
|
||||
}
|
69
src/utils/importFrom/dbml.js
Normal file
69
src/utils/importFrom/dbml.js
Normal file
@ -0,0 +1,69 @@
|
||||
import { Parser } from "@dbml/core";
|
||||
import { arrangeTables } from "../arrangeTables";
|
||||
|
||||
const parser = new Parser();
|
||||
|
||||
export function fromDBML(src) {
|
||||
const ast = parser.parse(src, "dbml");
|
||||
|
||||
const tables = [];
|
||||
const enums = [];
|
||||
|
||||
for (const schema of ast.schemas) {
|
||||
for (const table of schema.tables) {
|
||||
let parsedTable = {};
|
||||
parsedTable.id = tables.length;
|
||||
parsedTable.name = table.name;
|
||||
parsedTable.comment = table.note ?? "";
|
||||
parsedTable.color = "#175e7a";
|
||||
parsedTable.fields = [];
|
||||
parsedTable.indices = [];
|
||||
|
||||
for (const column of table.fields) {
|
||||
const field = {};
|
||||
|
||||
field.id = parsedTable.fields.length;
|
||||
field.name = column.name;
|
||||
field.type = column.type.type_name.toUpperCase();
|
||||
field.default = column.dbdefault ?? "";
|
||||
field.check = "";
|
||||
field.primary = !!column.pk;
|
||||
field.unique = !!column.pk;
|
||||
field.notNull = !!column.not_null;
|
||||
field.increment = !!column.increment;
|
||||
field.comment = column.note ?? "";
|
||||
|
||||
parsedTable.fields.push(field);
|
||||
}
|
||||
|
||||
for (const idx of table.indexes) {
|
||||
const parsedIndex = {};
|
||||
|
||||
parsedIndex.id = idx.id - 1;
|
||||
parsedIndex.fields = idx.columns.map((x) => x.value);
|
||||
parsedIndex.name =
|
||||
idx.name ?? `${parsedTable.name}_index_${parsedIndex.id}`;
|
||||
parsedIndex.unique = !!idx.unique;
|
||||
|
||||
parsedTable.indices.push(parsedIndex);
|
||||
}
|
||||
|
||||
tables.push(parsedTable);
|
||||
}
|
||||
|
||||
for (const schemaEnum of schema.enums) {
|
||||
const parsedEnum = {};
|
||||
|
||||
parsedEnum.name = schemaEnum.name;
|
||||
parsedEnum.values = schemaEnum.values.map((x) => x.name);
|
||||
|
||||
enums.push(parsedEnum);
|
||||
}
|
||||
}
|
||||
|
||||
const diagram = { tables, enums };
|
||||
|
||||
arrangeTables(diagram);
|
||||
|
||||
return diagram;
|
||||
}
|
Loading…
Reference in New Issue
Block a user