Add mssql

This commit is contained in:
1ilit 2024-02-14 19:52:58 +02:00
parent 2cc703b9b5
commit 62e3faa6fb
3 changed files with 419 additions and 220 deletions

View File

@ -1012,7 +1012,7 @@ export default function ControlPanel({
}, },
}, },
{ {
"SQL Server": () => { "MSSQL": () => {
setVisible(MODAL.CODE); setVisible(MODAL.CODE);
const src = jsonToSQLServer({ const src = jsonToSQLServer({
tables: tables, tables: tables,

View File

@ -83,14 +83,28 @@ export default function TableOverview() {
<Col span={3}> <Col span={3}>
<Popover <Popover
content={ content={
<div className="w-[300px] text-sm popover-theme"> <div className="w-[240px] text-sm space-y-2 popover-theme">
This feature is meant for object-relational DBMSs like <div>
PostgreSQL. However, if used for relational DBMSs, a JSON type This feature is meant for object-relational databases like{" "}
will be generated with the custom type schema. <strong>PostgreSQL</strong>.
</div>
<div>
If used for <strong>MySQL</strong> or <strong>MariaDB</strong>{" "}
a <code>JSON</code> type will be generated with the
corresponding json validation check.
</div>
<div>
If used for <strong>SQLite</strong> it will be translated to a{" "}
<code>BLOB</code>.
</div>
<div>
If used for <strong>MSSQL</strong> a type alias to the first
field will be generated.
</div>
</div> </div>
} }
showArrow showArrow
position="right" position="rightTop"
> >
<Button theme="borderless" icon={<IconInfoCircle />} /> <Button theme="borderless" icon={<IconInfoCircle />} />
</Popover> </Popover>
@ -217,10 +231,10 @@ export default function TableOverview() {
fields: t.fields.map((e, id) => fields: t.fields.map((e, id) =>
id === j id === j
? { ? {
...f, ...f,
type: value, type: value,
values: f.values ? [...f.values] : [], values: f.values ? [...f.values] : [],
} }
: e : e
), ),
}); });

View File

@ -86,7 +86,7 @@ function generateSchema(type) {
)}\n\t\t\t},\n\t\t\t"additionalProperties": false\n\t\t}`; )}\n\t\t\t},\n\t\t\t"additionalProperties": false\n\t\t}`;
} }
function getTypeString(field, dbms = "mysql") { function getTypeString(field, dbms = "mysql", baseType = false) {
if (dbms === "mysql") { if (dbms === "mysql") {
if (field.type === "UUID") { if (field.type === "UUID") {
return `VARCHAR(36)`; return `VARCHAR(36)`;
@ -131,14 +131,51 @@ function getTypeString(field, dbms = "mysql") {
field.type === "BINARY" field.type === "BINARY"
? "bit" ? "bit"
: field.type === "VARBINARY" : field.type === "VARBINARY"
? "bit varying" ? "bit varying"
: field.type.toLowerCase(); : field.type.toLowerCase();
return `${type}(${field.size})`; return `${type}(${field.size})`;
} }
if (hasPrecision(field.type) && field.size !== "") { if (hasPrecision(field.type) && field.size !== "") {
return `${field.type}${field.size}`; return `${field.type}${field.size}`;
} }
return field.type.toLowerCase(); return field.type.toLowerCase();
} else if (dbms === "mssql") {
let type = field.type;
switch (field.type) {
case "ENUM":
return baseType
? "NVARCHAR(255)"
: `NVARCHAR(255) CHECK([${field.name}] in (${field.values
.map((v) => `'${v}'`)
.join(", ")}))`;
case "VARCHAR":
type = `NVARCHAR`;
break;
case "UUID":
type = "UNIQUEIDENTIFIER";
break;
case "DOUBLE":
type = "FLOAT";
break;
case "BOOLEAN":
return "BIT";
case "SET":
return "NVARCHAR(255)";
case "BLOB":
return "VARBINARY(MAX)";
case "JSON":
return "NVARCHAR(MAX)";
case "TEXT":
return "TEXT";
default:
type = field.type;
break;
}
if (isSized(field.type)) {
return `${type}(${field.size})`;
}
return type;
} }
} }
@ -160,56 +197,68 @@ function jsonToMySQL(obj) {
return `${obj.tables return `${obj.tables
.map( .map(
(table) => (table) =>
`${table.comment === "" ? "" : `/* ${table.comment} */\n` `${
table.comment === "" ? "" : `/* ${table.comment} */\n`
}CREATE TABLE \`${table.name}\` (\n${table.fields }CREATE TABLE \`${table.name}\` (\n${table.fields
.map( .map(
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${field.name `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${
}\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${field.increment ? " AUTO_INCREMENT" : "" field.name
}${field.unique ? " UNIQUE" : ""}${field.default !== "" }\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${
? ` DEFAULT ${hasQuotes(field.type) && field.increment ? " AUTO_INCREMENT" : ""
field.default.toLowerCase() !== "null" }${field.unique ? " UNIQUE" : ""}${
? `"${field.default}"` field.default !== ""
: `${field.default}` ? ` DEFAULT ${
}` hasQuotes(field.type) &&
: "" field.default.toLowerCase() !== "null"
}${field.check === "" || !hasCheck(field.type) ? `"${field.default}"`
? !sqlDataTypes.includes(field.type) : `${field.default}`
? ` CHECK(\n\t\tJSON_SCHEMA_VALID("${generateSchema( }`
obj.types.find(
(t) => t.name === field.type.toLowerCase()
)
)}", \`${field.name}\`))`
: "" : ""
: ` CHECK(${field.check})` }${
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})`
}` }`
) )
.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 ? `,\n\tPRIMARY KEY(${table.fields
.filter((f) => f.primary) .filter((f) => f.primary)
.map((f) => `\`${f.name}\``) .map((f) => `\`${f.name}\``)
.join(", ")})` .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(", ")});`
)}`
: "" : ""
}\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 .join("\n")}\n${obj.references
.map( .map(
(r) => (r) =>
`ALTER TABLE \`${obj.tables[r.startTableId].name `ALTER TABLE \`${
}\`\nADD FOREIGN KEY(\`${obj.tables[r.startTableId].fields[r.startFieldId].name obj.tables[r.startTableId].name
}\`) REFERENCES \`${obj.tables[r.endTableId].name}\`(\`${obj.tables[r.endTableId].fields[r.endFieldId].name }\`\nADD FOREIGN KEY(\`${
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};` obj.tables[r.startTableId].fields[r.startFieldId].name
) }\`) REFERENCES \`${obj.tables[r.endTableId].name}\`(\`${
.join("\n")}`; obj.tables[r.endTableId].fields[r.endFieldId].name
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`
)
.join("\n")}`;
} }
function jsonToPostgreSQL(obj) { function jsonToPostgreSQL(obj) {
@ -225,73 +274,86 @@ function jsonToPostgreSQL(obj) {
if (typeStatements.length > 0) { if (typeStatements.length > 0) {
return ( return (
typeStatements.join("") + typeStatements.join("") +
`${type.comment === "" ? "" : `/**\n${type.comment}\n*/\n` `${
type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
}CREATE TYPE ${type.name} AS (\n${type.fields }CREATE TYPE ${type.name} AS (\n${type.fields
.map((f) => `\t${f.name} ${getTypeString(f, "postgres")}`) .map((f) => `\t${f.name} ${getTypeString(f, "postgres")}`)
.join("\n")}\n);` .join("\n")}\n);`
); );
} else { } else {
return `${type.comment === "" ? "" : `/**\n${type.comment}\n*/\n` return `${
}CREATE TYPE ${type.name} AS (\n${type.fields type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
.map((f) => `\t${f.name} ${getTypeString(f, "postgres")}`) }CREATE TYPE ${type.name} AS (\n${type.fields
.join("\n")}\n);`; .map((f) => `\t${f.name} ${getTypeString(f, "postgres")}`)
.join("\n")}\n);`;
} }
})}\n${obj.tables })}\n${obj.tables
.map( .map(
(table) => (table) =>
`${table.comment === "" ? "" : `/**\n${table.comment}\n*/\n`}${table.fields.filter((f) => f.type === "ENUM" || f.type === "SET") `${table.comment === "" ? "" : `/**\n${table.comment}\n*/\n`}${
.length > 0 table.fields.filter((f) => f.type === "ENUM" || f.type === "SET")
? `${table.fields .length > 0
.filter((f) => f.type === "ENUM" || f.type === "SET") ? `${table.fields
.map( .filter((f) => f.type === "ENUM" || f.type === "SET")
(f) => .map(
`CREATE TYPE "${f.name}_t" AS ENUM (${f.values (f) =>
.map((v) => `'${v}'`) `CREATE TYPE "${f.name}_t" AS ENUM (${f.values
.join(", ")});\n\n` .map((v) => `'${v}'`)
)}` .join(", ")});\n\n`
: "" )}`
: ""
}CREATE TABLE "${table.name}" (\n${table.fields }CREATE TABLE "${table.name}" (\n${table.fields
.map( .map(
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${field.name `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${
}" ${getTypeString(field, "postgres")}${field.notNull ? " NOT NULL" : "" field.name
}${field.default !== "" }" ${getTypeString(field, "postgres")}${
? ` DEFAULT ${hasQuotes(field.type) && field.notNull ? " NOT NULL" : ""
field.default.toLowerCase() !== "null" }${
? `'${field.default}'` field.default !== ""
: `${field.default}` ? ` DEFAULT ${
}` hasQuotes(field.type) &&
: "" field.default.toLowerCase() !== "null"
}${field.check === "" || !hasCheck(field.type) ? `'${field.default}'`
? "" : `${field.default}`
: ` CHECK(${field.check})` }`
: ""
}${
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 ? `,\n\tPRIMARY KEY(${table.fields
.filter((f) => f.primary) .filter((f) => f.primary)
.map((f) => `"${f.name}"`) .map((f) => `"${f.name}"`)
.join(", ")})` .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(", ")});`
)}`
: "" : ""
}\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 .join("\n")}\n${obj.references
.map( .map(
(r) => (r) =>
`ALTER TABLE "${obj.tables[r.startTableId].name}"\nADD FOREIGN KEY("${obj.tables[r.startTableId].fields[r.startFieldId].name `ALTER TABLE "${obj.tables[r.startTableId].name}"\nADD FOREIGN KEY("${
}") REFERENCES "${obj.tables[r.endTableId].name}"("${obj.tables[r.endTableId].fields[r.endFieldId].name obj.tables[r.startTableId].fields[r.startFieldId].name
}")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};` }") REFERENCES "${obj.tables[r.endTableId].name}"("${
) obj.tables[r.endTableId].fields[r.endFieldId].name
.join("\n")}`; }")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`
)
.join("\n")}`;
} }
function getSQLiteType(field) { function getSQLiteType(field) {
@ -319,7 +381,9 @@ function getSQLiteType(field) {
case "VARBINARY": case "VARBINARY":
return "TEXT"; return "TEXT";
case "ENUM": case "ENUM":
return `TEXT CHECK("${field.name}" in (${field.values.map(v => `'${v}'`).join(", ")}))`; return `TEXT CHECK("${field.name}" in (${field.values
.map((v) => `'${v}'`)
.join(", ")}))`;
default: default:
return "BLOB"; return "BLOB";
} }
@ -327,114 +391,210 @@ function getSQLiteType(field) {
function getInlineFK(table, obj) { function getInlineFK(table, obj) {
let fk = ""; let fk = "";
obj.references.forEach(r => { obj.references.forEach((r) => {
if (fk !== "") return; if (fk !== "") return;
if (r.startTableId === table.id) { if (r.startTableId === table.id) {
fk = `FOREIGN KEY ("${table.fields[r.startFieldId].name}") REFERENCES "${obj.tables[r.endTableId].name}"("${obj.tables[r.endTableId].fields[r.endFieldId].name}")\n\tON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()}`; fk = `FOREIGN KEY ("${table.fields[r.startFieldId].name}") REFERENCES "${
obj.tables[r.endTableId].name
}"("${
obj.tables[r.endTableId].fields[r.endFieldId].name
}")\n\tON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()}`;
} }
}) });
return fk; return fk;
} }
function jsonToSQLite(obj) { function jsonToSQLite(obj) {
return obj.tables return obj.tables
.map( .map((table) => {
(table) => { const inlineFK = getInlineFK(table, obj);
const inlineFK = getInlineFK(table, obj); return `${
return `${table.comment === "" ? "" : `/* ${table.comment} */\n` table.comment === "" ? "" : `/* ${table.comment} */\n`
}CREATE TABLE IF NOT EXISTS "${table.name}" (\n${table.fields }CREATE TABLE IF NOT EXISTS "${table.name}" (\n${table.fields
.map( .map(
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${field.name `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${
}" ${getSQLiteType(field)}${field.notNull ? " NOT NULL" : ""}${field.unique ? " UNIQUE" : ""}${field.default !== "" field.name
? ` DEFAULT ${hasQuotes(field.type) && }" ${getSQLiteType(field)}${field.notNull ? " NOT NULL" : ""}${
field.unique ? " UNIQUE" : ""
}${
field.default !== ""
? ` DEFAULT ${
hasQuotes(field.type) &&
field.default.toLowerCase() !== "null" field.default.toLowerCase() !== "null"
? `'${field.default}'` ? `'${field.default}'`
: `${field.default}` : `${field.default}`
}` }`
: "" : ""
}${field.check === "" || !hasCheck(field.type) ? }${
"" : ` CHECK(${field.check})` field.check === "" || !hasCheck(field.type)
}` ? ""
) : ` CHECK(${field.check})`
.join(",\n")}${table.fields.filter((f) => f.primary).length > 0 }`
? `,\n\tPRIMARY KEY(${table.fields )
.filter((f) => f.primary) .join(",\n")}${
.map((f) => `"${f.name}"`) table.fields.filter((f) => f.primary).length > 0
.join(", ")})${inlineFK !== "" ? ',\n' : ''}` ? `,\n\tPRIMARY KEY(${table.fields
: "" .filter((f) => f.primary)
}\t${inlineFK}\n);\n${table.indices.length > 0 .map((f) => `"${f.name}"`)
? `${table.indices.map( .join(", ")})${inlineFK !== "" ? ",\n" : ""}`
(i) => : ""
`\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS "${i.name }\t${inlineFK}\n);\n${
}"\nON "${table.name}" (${i.fields table.indices.length > 0
.map((f) => `"${f}"`) ? `${table.indices
.join(", ")});` .map(
).join("\n")}` (i) =>
: "" `\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS "${
}` i.name
} }"\nON "${table.name}" (${i.fields
).join("\n"); .map((f) => `"${f}"`)
.join(", ")});`
)
.join("\n")}`
: ""
}`;
})
.join("\n");
} }
function jsonToMariaDB(obj) { function jsonToMariaDB(obj) {
return `${obj.tables return `${obj.tables
.map( .map(
(table) => (table) =>
`${table.comment === "" ? "" : `/* ${table.comment} */\n` `${
table.comment === "" ? "" : `/* ${table.comment} */\n`
}CREATE OR REPLACE TABLE \`${table.name}\` (\n${table.fields }CREATE OR REPLACE TABLE \`${table.name}\` (\n${table.fields
.map( .map(
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${field.name `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${
}\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${field.increment ? " AUTO_INCREMENT" : "" field.name
}${field.unique ? " UNIQUE" : ""}${field.default !== "" }\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${
? ` DEFAULT ${hasQuotes(field.type) && field.increment ? " AUTO_INCREMENT" : ""
field.default.toLowerCase() !== "null" }${field.unique ? " UNIQUE" : ""}${
? `"${field.default}"` field.default !== ""
: `${field.default}` ? ` DEFAULT ${
}` hasQuotes(field.type) &&
: "" field.default.toLowerCase() !== "null"
}${field.check === "" || !hasCheck(field.type) ? `"${field.default}"`
? !sqlDataTypes.includes(field.type) : `${field.default}`
? ` CHECK(\n\t\tJSON_SCHEMA_VALID('${generateSchema( }`
obj.types.find(
(t) => t.name === field.type.toLowerCase()
)
)}', \`${field.name}\`))`
: "" : ""
: ` CHECK(${field.check})` }${
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})`
}` }`
) )
.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 ? `,\n\tPRIMARY KEY(${table.fields
.filter((f) => f.primary) .filter((f) => f.primary)
.map((f) => `\`${f.name}\``) .map((f) => `\`${f.name}\``)
.join(", ")})` .join(", ")})`
: ""
}\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(", ")});`
)}`
: "" : ""
}\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 .join("\n")}\n${obj.references
.map( .map(
(r) => (r) =>
`ALTER TABLE \`${obj.tables[r.startTableId].name `ALTER TABLE \`${
}\`\nADD FOREIGN KEY(\`${obj.tables[r.startTableId].fields[r.startFieldId].name obj.tables[r.startTableId].name
}\`) REFERENCES \`${obj.tables[r.endTableId].name}\`(\`${obj.tables[r.endTableId].fields[r.endFieldId].name }\`\nADD FOREIGN KEY(\`${
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};` obj.tables[r.startTableId].fields[r.startFieldId].name
) }\`) REFERENCES \`${obj.tables[r.endTableId].name}\`(\`${
.join("\n")}`; obj.tables[r.endTableId].fields[r.endFieldId].name
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`
)
.join("\n")}`;
} }
function jsonToSQLServer(obj) { function jsonToSQLServer(obj) {
return "TODO"; return `${obj.types
.map((type) => {
return `${
type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
}CREATE TYPE [${type.name}] FROM ${
type.fields.length < 0
? ""
: `${getTypeString(type.fields[0], "mssql", true)}`
};\nGO\n`;
})
.join("\n")}\n${obj.tables
.map(
(table) =>
`${
table.comment === "" ? "" : `/**\n${table.comment}\n*/\n`
}CREATE TABLE [${table.name}] (\n${table.fields
.map(
(field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t[${
field.name
}] ${getTypeString(field, "mssql")}${
field.notNull ? " NOT NULL" : ""
}${field.increment ? " IDENTITY" : ""}${
field.unique ? " UNIQUE" : ""
}${
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
? `,\n\tPRIMARY KEY(${table.fields
.filter((f) => f.primary)
.map((f) => `[${f.name}]`)
.join(", ")})`
: ""
}\n);\nGO\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(", ")});\nGO\n`
)}`
: ""
}`
)
.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()};\nGO`
)
.join("\n")}`;
} }
function arrayIsEqual(arr1, arr2) { function arrayIsEqual(arr1, arr2) {
@ -442,9 +602,7 @@ function arrayIsEqual(arr1, arr2) {
} }
function isSized(type) { function isSized(type) {
return ["CHAR", "VARCHAR", "BINARY", "VARBINARY", "TEXT"].includes( return ["CHAR", "VARCHAR", "BINARY", "VARBINARY", "TEXT"].includes(type);
type
);
} }
function hasPrecision(type) { function hasPrecision(type) {
@ -686,9 +844,11 @@ function validateDiagram(diagram) {
diagram.tables[r.startTableId].fields[r.startFieldId].type !== diagram.tables[r.startTableId].fields[r.startFieldId].type !==
diagram.tables[r.endTableId].fields[r.endFieldId].type diagram.tables[r.endTableId].fields[r.endFieldId].type
) { ) {
issues.push(`Referencing column "${diagram.tables[r.endTableId].fields[r.endFieldId].name issues.push(`Referencing column "${
}" and referenced column "${diagram.tables[r.startTableId].fields[r.startFieldId].name diagram.tables[r.endTableId].fields[r.endFieldId].name
}" are incompatible. }" and referenced column "${
diagram.tables[r.startTableId].fields[r.startFieldId].name
}" are incompatible.
`); `);
} }
}); });
@ -747,56 +907,81 @@ const calcPath = (x1, x2, y1, y2, startFieldId, endFieldId, zoom = 1) => {
if (y1 <= y2) { if (y1 <= y2) {
if (x1 + tableWidth <= x2) { if (x1 + tableWidth <= x2) {
return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${midX - r return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${
} ${y1} A ${r} ${r} 0 0 1 ${midX} ${y1 + r} L ${midX} ${y2 - r midX - r
} A ${r} ${r} 0 0 0 ${midX + r} ${y2} L ${endX} ${y2}`; } ${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) { } else if (x2 <= x1 + tableWidth && x1 <= x2) {
return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x2 + tableWidth return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${
} ${y1} A ${r} ${r} 0 0 1 ${x2 + tableWidth + r} ${y1 + r} L ${x2 + tableWidth + r x2 + tableWidth
} ${y2 - r} A ${r} ${r} 0 0 1 ${x2 + tableWidth} ${y2} L ${x2 + tableWidth - 2 * offsetX } ${y1} A ${r} ${r} 0 0 1 ${x2 + tableWidth + r} ${y1 + r} L ${
} ${y2}`; 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) { } 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 return `M ${x1} ${y1} L ${x2 - r} ${y1} A ${r} ${r} 0 0 0 ${x2 - r - r} ${
} L ${x2 - r - r} ${y2 - r} A ${r} ${r} 0 0 0 ${x2 - r y1 + r
} ${y2} L ${x2} ${y2}`; } L ${x2 - r - r} ${y2 - r} A ${r} ${r} 0 0 0 ${
x2 - r
} ${y2} L ${x2} ${y2}`;
} else { } else {
return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 0 ${midX} ${y1 + r return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 0 ${midX} ${
} L ${midX} ${y2 - r} A ${r} ${r} 0 0 1 ${midX - r y1 + r
} ${y2} L ${endX} ${y2}`; } L ${midX} ${y2 - r} A ${r} ${r} 0 0 1 ${
midX - r
} ${y2} L ${endX} ${y2}`;
} }
} else { } else {
if (x1 + tableWidth <= x2) { if (x1 + tableWidth <= x2) {
return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${midX - r return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${
} ${y1} A ${r} ${r} 0 0 0 ${midX} ${y1 - r} L ${midX} ${y2 + r midX - r
} A ${r} ${r} 0 0 1 ${midX + r} ${y2} L ${endX} ${y2}`; } ${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) { } else if (x1 + tableWidth >= x2 && x1 + tableWidth <= x2 + tableWidth) {
// this for the overlap remember // this for the overlap remember
if (startTableY < y2) { if (startTableY < y2) {
return `M ${x1} ${y1} L ${x1 - r - r} ${y1} A ${r} ${r} 0 0 1 ${x1 - r - r - r return `M ${x1} ${y1} L ${x1 - r - r} ${y1} A ${r} ${r} 0 0 1 ${
} ${y1 - r} L ${x1 - r - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${x1 - r - r x1 - r - r - r
} ${y2} L ${x1 - r - 4} ${y2}`; } ${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 return `M ${x1} ${y1} L ${x1 - r - r} ${y1} A ${r} ${r} 0 0 1 ${
} ${y1 - r} L ${x1 - r - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${x1 - r - r x1 - r - r - r
} ${y2} L ${endX} ${y2}`; } ${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) { } else if (x1 >= x2 && x1 <= x2 + tableWidth) {
// this for the overlap remember // this for the overlap remember
if (startTableY < y2) { if (startTableY < y2) {
return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x1 + tableWidth - 2 * offsetX + r return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${
} ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${y1 - r x1 + tableWidth - 2 * offsetX + r
} L ${x1 + tableWidth - 2 * offsetX + r + r} ${y2 + r } ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${
} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r} ${y2} L ${x1 + tableWidth - 16 y1 - r
} ${y2}`; } L ${x1 + tableWidth - 2 * offsetX + r + r} ${
} y2 + r
return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x1 + tableWidth - 2 * offsetX + r } A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r} ${y2} L ${
} ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${y1 - r x1 + tableWidth - 16
} 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}`; } ${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 { } else {
return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 1 ${midX} ${y1 - r return `M ${x1} ${y1} L ${midX + r} ${y1} A ${r} ${r} 0 0 1 ${midX} ${
} L ${midX} ${y2 + r} A ${r} ${r} 0 0 0 ${midX - r y1 - r
} ${y2} L ${endX} ${y2}`; } L ${midX} ${y2 + r} A ${r} ${r} 0 0 0 ${
midX - r
} ${y2} L ${endX} ${y2}`;
} }
} }
}; };