diff --git a/package-lock.json b/package-lock.json
index ec9886b..66c6f1b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,10 +15,12 @@
"dexie": "^3.2.4",
"dexie-react-hooks": "^1.1.7",
"file-saver": "^2.0.5",
+ "framer-motion": "^10.18.0",
"html-to-image": "^1.11.11",
"jsonschema": "^1.4.1",
"jspdf": "^2.5.1",
"lexical": "^0.12.5",
+ "node-sql-parser": "^4.17.0",
"react": "^18.2.0",
"react-cookie": "^7.0.1",
"react-dom": "^18.2.0",
@@ -563,6 +565,21 @@
"react-dom": ">=16.0.0"
}
},
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
+ "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
+ "optional": true,
+ "dependencies": {
+ "@emotion/memoize": "0.7.4"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
+ "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
+ "optional": true
+ },
"node_modules/@esbuild/android-arm": {
"version": "0.19.9",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.9.tgz",
@@ -1959,6 +1976,14 @@
"resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
"integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig=="
},
+ "node_modules/big-integer": {
+ "version": "1.6.52",
+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
+ "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -3103,6 +3128,29 @@
"url": "https://github.com/sponsors/rawify"
}
},
+ "node_modules/framer-motion": {
+ "version": "10.18.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.18.0.tgz",
+ "integrity": "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w==",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ },
+ "optionalDependencies": {
+ "@emotion/is-prop-valid": "^0.8.2"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -4083,6 +4131,17 @@
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
"dev": true
},
+ "node_modules/node-sql-parser": {
+ "version": "4.17.0",
+ "resolved": "https://registry.npmjs.org/node-sql-parser/-/node-sql-parser-4.17.0.tgz",
+ "integrity": "sha512-3IhovpmUBpcETnoKK/KBdkz2mz53kVG5E1dnqz1QuYvtzdxYZW5xaGGEvW9u6Yyy2ivwR3eUZrn9inmEVef02w==",
+ "dependencies": {
+ "big-integer": "^1.6.48"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
diff --git a/package.json b/package.json
index 4c3508e..1edc03a 100644
--- a/package.json
+++ b/package.json
@@ -17,10 +17,12 @@
"dexie": "^3.2.4",
"dexie-react-hooks": "^1.1.7",
"file-saver": "^2.0.5",
+ "framer-motion": "^10.18.0",
"html-to-image": "^1.11.11",
"jsonschema": "^1.4.1",
"jspdf": "^2.5.1",
"lexical": "^0.12.5",
+ "node-sql-parser": "^4.17.0",
"react": "^18.2.0",
"react-cookie": "^7.0.1",
"react-dom": "^18.2.0",
diff --git a/src/animations/Reveal.jsx b/src/animations/Reveal.jsx
new file mode 100644
index 0000000..5ef2a40
--- /dev/null
+++ b/src/animations/Reveal.jsx
@@ -0,0 +1,30 @@
+import { useRef, useEffect } from "react";
+import { motion, useInView, useAnimation } from "framer-motion";
+
+export default function Reveal({ children }) {
+ const ref = useRef(null);
+ const isInView = useInView(ref, { once: true });
+ const mainControls = useAnimation();
+
+ useEffect(() => {
+ if (isInView) {
+ mainControls.start("visible");
+ }
+ }, [isInView, mainControls]);
+
+ return (
+
+
+ {children}
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/ControlPanel.jsx b/src/components/ControlPanel.jsx
index 86d647a..e67c57f 100644
--- a/src/components/ControlPanel.jsx
+++ b/src/components/ControlPanel.jsx
@@ -29,6 +29,8 @@ import {
Toast,
SideSheet,
List,
+ Select,
+ Checkbox,
} from "@douyinfe/semi-ui";
import timeLine from "../assets/process.png";
import timeLineDark from "../assets/process_dark.png";
@@ -64,6 +66,7 @@ import { areaSchema, noteSchema, tableSchema } from "../data/schemas";
import { Editor } from "@monaco-editor/react";
import { db } from "../data/db";
import { useLiveQuery } from "dexie-react-hooks";
+import { Parser } from "node-sql-parser";
import Todo from "./Todo";
export default function ControlPanel({
@@ -84,6 +87,7 @@ export default function ControlPanel({
OPEN: 5,
SAVEAS: 6,
NEW: 7,
+ IMPORT_SRC: 8,
};
const STATUS = {
NONE: 0,
@@ -823,10 +827,16 @@ export default function ControlPanel({
.catch(() => Toast.error("Oops! Something went wrong."));
},
},
- Import: {
+ "Import diagram": {
function: fileImport,
shortcut: "Ctrl+I",
},
+ "Import from source": {
+ function: () => {
+ setData({ src: "", overwrite: true, dbms: "MySQL" });
+ setVisible(MODAL.IMPORT_SRC)
+ }
+ },
"Export as": {
children: [
{
@@ -1172,6 +1182,7 @@ export default function ControlPanel({
const getModalTitle = () => {
switch (visible) {
case MODAL.IMPORT:
+ case MODAL.IMPORT_SRC:
return "Import diagram";
case MODAL.CODE:
return "Export source";
@@ -1193,6 +1204,7 @@ export default function ControlPanel({
const getOkText = () => {
switch (visible) {
case MODAL.IMPORT:
+ case MODAL.IMPORT_SRC:
return "Import";
case MODAL.CODE:
case MODAL.IMG:
@@ -1210,6 +1222,165 @@ export default function ControlPanel({
}
};
+ /**
+ *
+ * {
+ "id": 0,
+ "name": "table_4",
+ "x": 50,
+ "y": 83,
+ "fields": [
+ {
+ "name": "id",
+ "type": "INT",
+ "default": "",
+ "check": "",
+ "primary": true,
+ "unique": true,
+ "notNull": true,
+ "increment": true,
+ "comment": "",
+ "id": 0
+ },
+ {
+ "name": "name",
+ "type": "NUMERIC",
+ "default": "",
+ "check": "",
+ "primary": false,
+ "unique": false,
+ "notNull": false,
+ "increment": false,
+ "comment": "",
+ "id": 1,
+ "size": ""
+ }
+ ],
+ "comment": "",
+ "indices": [],
+ "color": "#175e7a"
+ },
+ {
+ "id": 1,
+ "name": "table_1",
+ "x": 360,
+ "y": 181,
+ "fields": [
+ {
+ "name": "id",
+ "type": "INT",
+ "default": "",
+ "check": "",
+ "primary": true,
+ "unique": true,
+ "notNull": true,
+ "increment": true,
+ "comment": "",
+ "id": 0
+ },
+ {
+ "name": "kk",
+ "type": "INT",
+ "default": "",
+ "check": "",
+ "primary": false,
+ "unique": false,
+ "notNull": false,
+ "increment": false,
+ "comment": "",
+ "id": 1
+ },
+ {
+ "id": 2,
+ "size": "12"
+ }
+ ],
+ "comment": "",
+ "indices": [],
+ "color": "#175e7a"
+ }
+ */
+
+ const parseSQLAndLoadDiagram = () => {
+ const parser = new Parser();
+ let ast = null;
+ try {
+ console.log(data.dbms)
+ ast = parser.astify(data.src, { database: data.dbms });
+ } catch (err) {
+ Toast.error("Could not parse the sql file. Make sure there are no syntax errors.");
+ console.log(err);
+ return;
+ }
+ const tables = [];
+
+ ast.forEach(((e) => {
+ console.log(JSON.stringify(e))
+ if (e.type === "create" && e.keyword === "table") {
+ const table = {};
+ table.name = e.table[0].table;
+ table.color = "#175e7a";
+ table.fields = [];
+ table.indices = [];
+ table.x = 0;
+ table.y = 0;
+ e.create_definitions.forEach((d) => {
+ if (d.resource === "column") {
+ const field = {};
+ field.name = d.column.column;
+ field.type = d.definition.dataType;
+ field.comment = "";
+ field.unique = false;
+ if (d.unique) field.unique = true;
+ field.auto_increment = false;
+ if (d.auto_increment) field.auto_increment = true;
+ field.notNull = false;
+ if (d.nullable) field.notNull = true;
+ field.primary = false;
+ if (d.primary_key) field.primary = true;
+ field.default = "";
+ if (d.default_val) field.default = d.default_val.value.value;
+ if (d.definition["length"]) field.size = d.definition["length"];
+
+ if (d.check) {
+ let check = "";
+ if (d.check.definition[0].left.column) {
+ check = d.check.definition[0].left.column + " " + d.check.definition[0].operator + " " + d.check.definition[0].right.value;
+ } else {
+ check = d.check.definition[0].left.value + " " + d.check.definition[0].operator + " " + d.check.definition[0].right.column;
+ }
+ field.check = check;
+ }
+
+ table.fields.push(field);
+ } else if (d.resource === "constraint") {
+ if (d.constraint_type === "primary key") {
+ d.definition.forEach(c => {
+ table.fields.forEach((f) => {
+ if (f.name === c.column && !f.primary) {
+ f.primary = true;
+ }
+ })
+ });
+ }
+ }
+ });
+
+ tables.push(table);
+ }
+ }))
+
+ tables.forEach((e, i) => {
+ e.id = i;
+ e.fields.forEach((f, j) => {
+ f.id = j;
+ })
+ })
+
+ setTables(tables)
+ console.log(tables);
+ }
+
const getModalOnOk = async () => {
switch (visible) {
case MODAL.IMG:
@@ -1235,6 +1406,10 @@ export default function ControlPanel({
setRedoStack([]);
}
return;
+ case MODAL.IMPORT_SRC:
+ parseSQLAndLoadDiagram();
+ setVisible(MODAL.NONE)
+ return;
case MODAL.OPEN:
if (selectedDiagramId === 0) return;
loadDiagram(selectedDiagramId);
@@ -1373,6 +1548,70 @@ export default function ControlPanel({
);
};
+ const importSrcModalBody = () => {
+ return (
+ <>
+ {
+ const f = fileList[0].fileInstance;
+ if (!f) {
+ return;
+ }
+ const reader = new FileReader();
+ reader.onload = async (e) => {
+ setData(prev => ({ ...prev, src: e.target.result }))
+ };
+ reader.readAsText(f);
+
+ return {
+ autoRemove: false,
+ fileInstance: file.fileInstance,
+ status: "success",
+ shouldUpload: false,
+ };
+ }}
+ draggable={true}
+ dragMainText="Drag and drop the file here or click to upload."
+ dragSubText="Upload an sql file to autogenerate your tables and columns."
+ accept=".sql"
+ onRemove={() => {
+ setError({
+ type: STATUS.NONE,
+ message: "",
+ });
+ setData(prev => ({ ...prev, src: "" }));
+ }
+ }
+ onFileChange={() =>
+ setError({
+ type: STATUS.NONE,
+ message: "",
+ })
+ }
+ limit={1}
+ >
+
+
Select DBMS
+
+
setData(prev => ({ ...prev, overwrite: e.target.checked }))}
+ className="my-2">
+ Overwrite existing diagram
+
+
+ >
+ );
+ };
+
const newModalBody = () => (
@@ -1408,6 +1647,8 @@ export default function ControlPanel({
switch (visible) {
case MODAL.IMPORT:
return importModalBody();
+ case MODAL.IMPORT_SRC:
+ return importSrcModalBody();
case MODAL.NEW:
return newModalBody();
case MODAL.RENAME:
@@ -1560,13 +1801,14 @@ export default function ControlPanel({
closeOnEsc={true}
okText={getOkText()}
okButtonProps={{
- disabled:
+ disabled: (error && error.type && error.type === STATUS.ERROR) ||
(visible === MODAL.IMPORT &&
(error.type === STATUS.ERROR || !data)) ||
((visible === MODAL.IMG || visible === MODAL.CODE) &&
!exportData.data) ||
(visible === MODAL.RENAME && title === "") ||
- (visible === MODAL.SAVEAS && saveAsTitle === ""),
+ (visible === MODAL.SAVEAS && saveAsTitle === "") ||
+ (visible === MODAL.IMPORT_SRC && data.src === ""),
}}
cancelText="Cancel"
width={600}
diff --git a/src/components/SimpleCanvas.jsx b/src/components/SimpleCanvas.jsx
index d1965fb..ad6587e 100644
--- a/src/components/SimpleCanvas.jsx
+++ b/src/components/SimpleCanvas.jsx
@@ -19,9 +19,8 @@ function Table({ table, grab }) {
onMouseLeave={() => setIsHovered(false)}
>
(
setHoveredField(i)}
onMouseLeave={() => setHoveredField(-1)}
>
@@ -139,7 +137,7 @@ function Relationship({ relationship }) {
);
}
-export default function Canvas({ diagram }) {
+export default function SimpleCanvas({ diagram, zoom }) {
const [tables, setTables] = useState(diagram.tables);
const [relationships, setRelationships] = useState(diagram.relationships);
const [dragging, setDragging] = useState(-1);
@@ -233,12 +231,17 @@ export default function Canvas({ diagram }) {
height="100%"
fill="url(#pattern-circles)"
>
- {tables.map((t, i) => (
-
grabTable(e, i)} />
- ))}
- {relationships.map((r, i) => (
-
- ))}
+
+ {tables.map((t, i) => (
+ grabTable(e, i)} />
+ ))}
+ {relationships.map((r, i) => (
+
+ ))}
+
);
}
diff --git a/src/data/loginDiagram.js b/src/data/heroDiagram.js
similarity index 98%
rename from src/data/loginDiagram.js
rename to src/data/heroDiagram.js
index 9c02131..8d2268a 100644
--- a/src/data/loginDiagram.js
+++ b/src/data/heroDiagram.js
@@ -1,4 +1,4 @@
-const xOffset = window.innerWidth * 0.57 * 0.09;
+const xOffset = window.innerWidth * 0.65;
export const diagram = {
tables: [
{
diff --git a/src/pages/LandingPage.jsx b/src/pages/LandingPage.jsx
index 6dcb0eb..fa53b03 100644
--- a/src/pages/LandingPage.jsx
+++ b/src/pages/LandingPage.jsx
@@ -1,7 +1,10 @@
import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { IconCrossStroked } from "@douyinfe/semi-icons";
+import SimpleCanvas from "../components/SimpleCanvas"
import Navbar from "../components/Navbar";
+import { diagram } from "../data/heroDiagram"
+import Reveal from "../animations/Reveal";
export default function LandingPage() {
const [showSurvey, setShowSurvey] = useState(true);
@@ -14,19 +17,51 @@ export default function LandingPage() {
return (
- {showSurvey && (
-
-
- Help us improve! Share your feedback.
-
-
-
+
+ {showSurvey && (
+
+
+ Help us improve! Share your feedback.
+
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ Draw, Copy, and Paste
+
+
+
+ Free, simple, and intuitive database design tool and SQL generator.
+
+
+
+
+
+ Try it for yourself
+
+
- )}
-
+
+
+ more stuff
+
);
}
diff --git a/src/utils/index.js b/src/utils/index.js
index 8a152ce..243cfb6 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -95,8 +95,8 @@ function getTypeString(field, dbms = "mysql") {
if (isSized(field.type)) {
return `${field.type}(${field.size})`;
}
- if (hasPrecision(field.type) && field.size !== "") {
- return `${field.type}${field.size}`;
+ if (hasPrecision(field.type)) {
+ return `${field.type}${field.size ? `(${field.size})` : ""}`;
}
if (field.type === "SET" || field.type === "ENUM") {
return `${field.type}(${field.values.map((v) => `"${v}"`).join(", ")})`;
@@ -132,8 +132,8 @@ function getTypeString(field, dbms = "mysql") {
field.type === "BINARY"
? "bit"
: field.type === "VARBINARY"
- ? "bit varying"
- : field.type.toLowerCase();
+ ? "bit varying"
+ : field.type.toLowerCase();
return `${type}(${field.size})`;
}
if (hasPrecision(field.type) && field.size !== "") {
@@ -161,68 +161,56 @@ function jsonToMySQL(obj) {
return `${obj.tables
.map(
(table) =>
- `${
- table.comment === "" ? "" : `/* ${table.comment} */\n`
+ `${table.comment === "" ? "" : `/* ${table.comment} */\n`
}CREATE TABLE \`${table.name}\` (\n${table.fields
.map(
(field) =>
- `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${
- field.name
- }\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${
- field.increment ? " AUTO_INCREMENT" : ""
- }${field.unique ? " UNIQUE" : ""}${
- field.default !== ""
- ? ` DEFAULT ${
- hasQuotes(field.type) &&
- field.default.toLowerCase() !== "null"
- ? `"${field.default}"`
- : `${field.default}`
- }`
+ `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${field.name
+ }\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${field.increment ? " AUTO_INCREMENT" : ""
+ }${field.unique ? " UNIQUE" : ""}${field.default !== ""
+ ? ` DEFAULT ${hasQuotes(field.type) &&
+ field.default.toLowerCase() !== "null"
+ ? `"${field.default}"`
+ : `${field.default}`
+ }`
+ : ""
+ }${field.check === "" || !hasCheck(field.type)
+ ? !sqlDataTypes.includes(field.type)
+ ? ` CHECK(\n\t\tJSON_SCHEMA_VALID("${generateSchema(
+ obj.types.find(
+ (t) => t.name === field.type.toLowerCase()
+ )
+ )}", \`${field.name}\`))`
: ""
- }${
- field.check === "" || !hasCheck(field.type)
- ? !sqlDataTypes.includes(field.type)
- ? ` CHECK(\n\t\tJSON_SCHEMA_VALID("${generateSchema(
- obj.types.find(
- (t) => t.name === field.type.toLowerCase()
- )
- )}", \`${field.name}\`))`
- : ""
- : ` CHECK(${field.check})`
+ : ` CHECK(${field.check})`
}`
)
- .join(",\n")}${
- table.fields.filter((f) => f.primary).length > 0
+ .join(",\n")}${table.fields.filter((f) => f.primary).length > 0
? `,\n\tPRIMARY KEY(${table.fields
- .filter((f) => f.primary)
- .map((f) => `\`${f.name}\``)
- .join(", ")})`
- : ""
- }\n);\n${
- table.indices.length > 0
- ? `\n${table.indices.map(
- (i) =>
- `\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX \`${
- i.name
- }\`\nON \`${table.name}\` (${i.fields
- .map((f) => `\`${f}\``)
- .join(", ")});`
- )}`
+ .filter((f) => f.primary)
+ .map((f) => `\`${f.name}\``)
+ .join(", ")})`
: ""
+ }\n);\n${table.indices.length > 0
+ ? `\n${table.indices.map(
+ (i) =>
+ `\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX \`${i.name
+ }\`\nON \`${table.name}\` (${i.fields
+ .map((f) => `\`${f}\``)
+ .join(", ")});`
+ )}`
+ : ""
}`
)
.join("\n")}\n${obj.references
- .map(
- (r) =>
- `ALTER TABLE \`${
- obj.tables[r.startTableId].name
- }\`\nADD FOREIGN KEY(\`${
- obj.tables[r.startTableId].fields[r.startFieldId].name
- }\`) REFERENCES \`${obj.tables[r.endTableId].name}\`(\`${
- obj.tables[r.endTableId].fields[r.endFieldId].name
- }\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`
- )
- .join("\n")}`;
+ .map(
+ (r) =>
+ `ALTER TABLE \`${obj.tables[r.startTableId].name
+ }\`\nADD FOREIGN KEY(\`${obj.tables[r.startTableId].fields[r.startFieldId].name
+ }\`) REFERENCES \`${obj.tables[r.endTableId].name}\`(\`${obj.tables[r.endTableId].fields[r.endFieldId].name
+ }\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`
+ )
+ .join("\n")}`;
}
function jsonToPostgreSQL(obj) {
@@ -238,86 +226,73 @@ function jsonToPostgreSQL(obj) {
if (typeStatements.length > 0) {
return (
typeStatements.join("") +
- `${
- type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
+ `${type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
}CREATE TYPE ${type.name} AS (\n${type.fields
.map((f) => `\t${f.name} ${getTypeString(f, "postgres")}`)
.join("\n")}\n);`
);
} else {
- return `${
- type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
- }CREATE TYPE ${type.name} AS (\n${type.fields
- .map((f) => `\t${f.name} ${getTypeString(f, "postgres")}`)
- .join("\n")}\n);`;
+ return `${type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
+ }CREATE TYPE ${type.name} AS (\n${type.fields
+ .map((f) => `\t${f.name} ${getTypeString(f, "postgres")}`)
+ .join("\n")}\n);`;
}
})}\n${obj.tables
.map(
(table) =>
- `${table.comment === "" ? "" : `/**\n${table.comment}\n*/\n`}${
- table.fields.filter((f) => f.type === "ENUM" || f.type === "SET")
- .length > 0
- ? `${table.fields
- .filter((f) => f.type === "ENUM" || f.type === "SET")
- .map(
- (f) =>
- `CREATE TYPE "${f.name}_t" AS ENUM (${f.values
- .map((v) => `'${v}'`)
- .join(", ")});\n\n`
- )}`
- : ""
+ `${table.comment === "" ? "" : `/**\n${table.comment}\n*/\n`}${table.fields.filter((f) => f.type === "ENUM" || f.type === "SET")
+ .length > 0
+ ? `${table.fields
+ .filter((f) => f.type === "ENUM" || f.type === "SET")
+ .map(
+ (f) =>
+ `CREATE TYPE "${f.name}_t" AS ENUM (${f.values
+ .map((v) => `'${v}'`)
+ .join(", ")});\n\n`
+ )}`
+ : ""
}CREATE TABLE "${table.name}" (\n${table.fields
.map(
(field) =>
- `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${
- field.name
- }" ${getTypeString(field, "postgres")}${
- field.notNull ? " NOT NULL" : ""
- }${
- field.default !== ""
- ? ` DEFAULT ${
- hasQuotes(field.type) &&
- field.default.toLowerCase() !== "null"
- ? `'${field.default}'`
- : `${field.default}`
- }`
- : ""
- }${
- field.check === "" || !hasCheck(field.type)
- ? ""
- : ` CHECK(${field.check})`
+ `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${field.name
+ }" ${getTypeString(field, "postgres")}${field.notNull ? " NOT NULL" : ""
+ }${field.default !== ""
+ ? ` DEFAULT ${hasQuotes(field.type) &&
+ field.default.toLowerCase() !== "null"
+ ? `'${field.default}'`
+ : `${field.default}`
+ }`
+ : ""
+ }${field.check === "" || !hasCheck(field.type)
+ ? ""
+ : ` CHECK(${field.check})`
}`
)
- .join(",\n")}${
- table.fields.filter((f) => f.primary).length > 0
+ .join(",\n")}${table.fields.filter((f) => f.primary).length > 0
? `,\n\tPRIMARY KEY(${table.fields
- .filter((f) => f.primary)
- .map((f) => `"${f.name}"`)
- .join(", ")})`
- : ""
- }\n);\n${
- table.indices.length > 0
- ? `${table.indices.map(
- (i) =>
- `\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX "${
- i.name
- }"\nON "${table.name}" (${i.fields
- .map((f) => `"${f}"`)
- .join(", ")});`
- )}`
+ .filter((f) => f.primary)
+ .map((f) => `"${f.name}"`)
+ .join(", ")})`
: ""
+ }\n);\n${table.indices.length > 0
+ ? `${table.indices.map(
+ (i) =>
+ `\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX "${i.name
+ }"\nON "${table.name}" (${i.fields
+ .map((f) => `"${f}"`)
+ .join(", ")});`
+ )}`
+ : ""
}`
)
.join("\n")}\n${obj.references
- .map(
- (r) =>
- `ALTER TABLE "${obj.tables[r.startTableId].name}"\nADD FOREIGN KEY("${
- obj.tables[r.startTableId].fields[r.startFieldId].name
- }") REFERENCES "${obj.tables[r.endTableId].name}"("${
- obj.tables[r.endTableId].fields[r.endFieldId].name
- }")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`
- )
- .join("\n")}`;
+ .map(
+ (r) =>
+ `ALTER TABLE "${obj.tables[r.startTableId].name}"\nADD FOREIGN KEY("${obj.tables[r.startTableId].fields[r.startFieldId].name
+ }") REFERENCES "${obj.tables[r.endTableId].name}"("${obj.tables[r.endTableId].fields[r.endFieldId].name
+ }")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`
+ )
+ .join("\n")}`;
}
function arrayIsEqual(arr1, arr2) {
@@ -325,13 +300,13 @@ function arrayIsEqual(arr1, arr2) {
}
function isSized(type) {
- return ["CHAR", "VARCHAR", "BINARY", "VARBINARY", "TEXT", "FLOAT"].includes(
+ return ["CHAR", "VARCHAR", "BINARY", "VARBINARY", "TEXT"].includes(
type
);
}
function hasPrecision(type) {
- return ["DOUBLE", "NUMERIC", "DECIMAL"].includes(type);
+ return ["DOUBLE", "NUMERIC", "DECIMAL", "FLOAT"].includes(type);
}
function hasCheck(type) {
@@ -569,11 +544,9 @@ function validateDiagram(diagram) {
diagram.tables[r.startTableId].fields[r.startFieldId].type !==
diagram.tables[r.endTableId].fields[r.endFieldId].type
) {
- issues.push(`Referencing column "${
- diagram.tables[r.endTableId].fields[r.endFieldId].name
- }" and referenced column "${
- diagram.tables[r.startTableId].fields[r.startFieldId].name
- }" are incompatible.
+ issues.push(`Referencing column "${diagram.tables[r.endTableId].fields[r.endFieldId].name
+ }" and referenced column "${diagram.tables[r.startTableId].fields[r.startFieldId].name
+ }" are incompatible.
`);
}
});
@@ -632,81 +605,56 @@ const calcPath = (x1, x2, y1, y2, startFieldId, endFieldId, zoom = 1) => {
if (y1 <= y2) {
if (x1 + tableWidth <= x2) {
- return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${
- midX - r
- } ${y1} A ${r} ${r} 0 0 1 ${midX} ${y1 + r} L ${midX} ${
- y2 - r
- } A ${r} ${r} 0 0 0 ${midX + r} ${y2} L ${endX} ${y2}`;
+ return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${midX - r
+ } ${y1} A ${r} ${r} 0 0 1 ${midX} ${y1 + r} L ${midX} ${y2 - r
+ } A ${r} ${r} 0 0 0 ${midX + r} ${y2} L ${endX} ${y2}`;
} else if (x2 <= x1 + tableWidth && x1 <= x2) {
- return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${
- x2 + tableWidth
- } ${y1} A ${r} ${r} 0 0 1 ${x2 + tableWidth + r} ${y1 + r} L ${
- x2 + tableWidth + r
- } ${y2 - r} A ${r} ${r} 0 0 1 ${x2 + tableWidth} ${y2} L ${
- x2 + tableWidth - 2 * offsetX
- } ${y2}`;
+ return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x2 + tableWidth
+ } ${y1} A ${r} ${r} 0 0 1 ${x2 + tableWidth + r} ${y1 + r} L ${x2 + tableWidth + r
+ } ${y2 - r} A ${r} ${r} 0 0 1 ${x2 + tableWidth} ${y2} L ${x2 + tableWidth - 2 * offsetX
+ } ${y2}`;
} else if (x2 + tableWidth >= x1 && x2 + tableWidth <= x1 + tableWidth) {
- return `M ${x1} ${y1} L ${x2 - r} ${y1} A ${r} ${r} 0 0 0 ${x2 - r - r} ${
- y1 + r
- } L ${x2 - r - r} ${y2 - r} A ${r} ${r} 0 0 0 ${
- x2 - r
- } ${y2} L ${x2} ${y2}`;
+ return `M ${x1} ${y1} L ${x2 - r} ${y1} A ${r} ${r} 0 0 0 ${x2 - r - r} ${y1 + r
+ } L ${x2 - r - r} ${y2 - r} A ${r} ${r} 0 0 0 ${x2 - r
+ } ${y2} L ${x2} ${y2}`;
} else {
- return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 0 ${midX} ${
- y1 + r
- } L ${midX} ${y2 - r} A ${r} ${r} 0 0 1 ${
- midX - r
- } ${y2} L ${endX} ${y2}`;
+ return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 0 ${midX} ${y1 + r
+ } L ${midX} ${y2 - r} A ${r} ${r} 0 0 1 ${midX - r
+ } ${y2} L ${endX} ${y2}`;
}
} else {
if (x1 + tableWidth <= x2) {
- return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${
- midX - r
- } ${y1} A ${r} ${r} 0 0 0 ${midX} ${y1 - r} L ${midX} ${
- y2 + r
- } A ${r} ${r} 0 0 1 ${midX + r} ${y2} L ${endX} ${y2}`;
+ return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${midX - r
+ } ${y1} A ${r} ${r} 0 0 0 ${midX} ${y1 - r} L ${midX} ${y2 + r
+ } A ${r} ${r} 0 0 1 ${midX + r} ${y2} L ${endX} ${y2}`;
} else if (x1 + tableWidth >= x2 && x1 + tableWidth <= x2 + tableWidth) {
// this for the overlap remember
if (startTableY < y2) {
- return `M ${x1} ${y1} L ${x1 - r - r} ${y1} A ${r} ${r} 0 0 1 ${
- x1 - r - r - r
- } ${y1 - r} L ${x1 - r - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${
- x1 - r - r
- } ${y2} L ${x1 - r - 4} ${y2}`;
+ return `M ${x1} ${y1} L ${x1 - r - r} ${y1} A ${r} ${r} 0 0 1 ${x1 - r - r - r
+ } ${y1 - r} L ${x1 - r - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${x1 - r - r
+ } ${y2} L ${x1 - r - 4} ${y2}`;
}
- return `M ${x1} ${y1} L ${x1 - r - r} ${y1} A ${r} ${r} 0 0 1 ${
- x1 - r - r - r
- } ${y1 - r} L ${x1 - r - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${
- x1 - r - r
- } ${y2} L ${endX} ${y2}`;
+ return `M ${x1} ${y1} L ${x1 - r - r} ${y1} A ${r} ${r} 0 0 1 ${x1 - r - r - r
+ } ${y1 - r} L ${x1 - r - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${x1 - r - r
+ } ${y2} L ${endX} ${y2}`;
} else if (x1 >= x2 && x1 <= x2 + tableWidth) {
// this for the overlap remember
if (startTableY < y2) {
- return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${
- x1 + tableWidth - 2 * offsetX + r
- } ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${
- y1 - r
- } L ${x1 + tableWidth - 2 * offsetX + r + r} ${
- y2 + r
- } A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r} ${y2} L ${
- x1 + tableWidth - 16
- } ${y2}`;
+ return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x1 + tableWidth - 2 * offsetX + r
+ } ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${y1 - r
+ } L ${x1 + tableWidth - 2 * offsetX + r + r} ${y2 + r
+ } A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r} ${y2} L ${x1 + tableWidth - 16
+ } ${y2}`;
}
- return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${
- x1 + tableWidth - 2 * offsetX + r
- } ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${
- y1 - r
- } L ${x1 + tableWidth - 2 * offsetX + r + r} ${
- y2 + r
- } A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r} ${y2} L ${
- x2 + tableWidth - 2 * offsetX
- } ${y2}`;
+ return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x1 + tableWidth - 2 * offsetX + r
+ } ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${y1 - r
+ } L ${x1 + tableWidth - 2 * offsetX + r + r} ${y2 + r
+ } A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r} ${y2} L ${x2 + tableWidth - 2 * offsetX
+ } ${y2}`;
} else {
- return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 1 ${midX} ${
- y1 - r
- } L ${midX} ${y2 + r} A ${r} ${r} 0 0 0 ${
- midX - r
- } ${y2} L ${endX} ${y2}`;
+ return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 1 ${midX} ${y1 - r
+ } L ${midX} ${y2 + r} A ${r} ${r} 0 0 0 ${midX - r
+ } ${y2} L ${endX} ${y2}`;
}
}
};