Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions src/components/EditorCanvas/Canvas.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -619,14 +619,28 @@ export default function Canvas() {

const cardinality = getCardinality(startField, endField);

// Normalize direction: startTable must always be the FK holder (many side).
// When the user drags from the PK side (one) to the FK side (many), the
// result is ONE_TO_MANY with startTable = PK. Swap so that startTable = FK.
const isInverted = cardinality === Cardinality.ONE_TO_MANY;
const fkTableId = isInverted ? hoveredTable.tableId : linkingLine.startTableId;
const fkFieldId = isInverted ? hoveredTable.fieldId : linkingLine.startFieldId;
const refTableId = isInverted ? linkingLine.startTableId : hoveredTable.tableId;
const refFieldId = isInverted ? linkingLine.startFieldId : hoveredTable.fieldId;
const fkTableName = isInverted ? endTableName : startTableName;
const fkField = isInverted ? endField : startField;
const refTableName = isInverted ? startTableName : endTableName;

const newRelationship = {
...linkingLine,
cardinality,
endTableId: hoveredTable.tableId,
endFieldId: hoveredTable.fieldId,
cardinality: isInverted ? Cardinality.MANY_TO_ONE : cardinality,
startTableId: fkTableId,
startFieldId: fkFieldId,
endTableId: refTableId,
endFieldId: refFieldId,
updateConstraint: Constraint.NONE,
deleteConstraint: Constraint.NONE,
name: `fk_${startTableName}_${startField.name}_${endTableName}`,
name: `fk_${fkTableName}_${fkField.name}_${refTableName}`,
id: nanoid(),
};
delete newRelationship.startX;
Expand Down
92 changes: 46 additions & 46 deletions src/utils/exportSQL/generic.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DB } from "../../data/constants";
import { dbToTypes, defaultTypes } from "../../data/datatypes";
import { escapeQuotes, getInlineFK, parseDefault } from "./shared";
import { escapeQuotes, getInlineFK, parseDefault, resolveFKDirection } from "./shared";

export function getJsonType(f) {
if (!Object.keys(defaultTypes).includes(f.type)) {
Expand Down Expand Up @@ -229,17 +229,17 @@ export function jsonToMySQL(obj) {
)
.join("\n")}\n${obj.references
.map((r) => {
const { name: startName, fields: startFields } = obj.tables.find(
(t) => t.id === r.startTableId,
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const { name: fkName, fields: fkFields } = obj.tables.find(
(t) => t.id === fkTableId,
);

const { name: endName, fields: endFields } = obj.tables.find(
(t) => t.id === r.endTableId,
const { name: refName, fields: refFields } = obj.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE \`${startName}\`\nADD FOREIGN KEY(\`${
startFields.find((f) => f.id === r.startFieldId).name
}\`) REFERENCES \`${endName}\`(\`${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE \`${fkName}\`\nADD FOREIGN KEY(\`${
fkFields.find((f) => f.id === fkFieldId).name
}\`) REFERENCES \`${refName}\`(\`${
refFields.find((f) => f.id === refFieldId).name
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
})
.join("\n")}`;
Expand Down Expand Up @@ -336,17 +336,17 @@ export function jsonToPostgreSQL(obj) {
)
.join("\n")}\n${obj.references
.map((r) => {
const { name: startName, fields: startFields } = obj.tables.find(
(t) => t.id === r.startTableId,
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const { name: fkName, fields: fkFields } = obj.tables.find(
(t) => t.id === fkTableId,
);

const { name: endName, fields: endFields } = obj.tables.find(
(t) => t.id === r.endTableId,
const { name: refName, fields: refFields } = obj.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE "${startName}"\nADD FOREIGN KEY("${
startFields.find((f) => f.id === r.startFieldId).name
}") REFERENCES "${endName}"("${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE "${fkName}"\nADD FOREIGN KEY("${
fkFields.find((f) => f.id === fkFieldId).name
}") REFERENCES "${refName}"("${
refFields.find((f) => f.id === refFieldId).name
}")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
})
.join("\n")}`;
Expand Down Expand Up @@ -474,17 +474,17 @@ export function jsonToMariaDB(obj) {
)
.join("\n")}\n${obj.references
.map((r) => {
const { name: startName, fields: startFields } = obj.tables.find(
(t) => t.id === r.startTableId,
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const { name: fkName, fields: fkFields } = obj.tables.find(
(t) => t.id === fkTableId,
);

const { name: endName, fields: endFields } = obj.tables.find(
(t) => t.id === r.endTableId,
const { name: refName, fields: refFields } = obj.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE \`${startName}\`\nADD FOREIGN KEY(\`${
startFields.find((f) => f.id === r.startFieldId).name
}\`) REFERENCES \`${endName}\`(\`${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE \`${fkName}\`\nADD FOREIGN KEY(\`${
fkFields.find((f) => f.id === fkFieldId).name
}\`) REFERENCES \`${refName}\`(\`${
refFields.find((f) => f.id === refFieldId).name
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
})
.join("\n")}`;
Expand Down Expand Up @@ -546,17 +546,17 @@ export function jsonToSQLServer(obj) {
)
.join("\n")}\n${obj.references
.map((r) => {
const { name: startName, fields: startFields } = obj.tables.find(
(t) => t.id === r.startTableId,
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const { name: fkName, fields: fkFields } = obj.tables.find(
(t) => t.id === fkTableId,
);

const { name: endName, fields: endFields } = obj.tables.find(
(t) => t.id === r.endTableId,
const { name: refName, fields: refFields } = obj.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE [${startName}]\nADD FOREIGN KEY([${
startFields.find((f) => f.id === r.startFieldId).name
}]) REFERENCES [${endName}]([${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE [${fkName}]\nADD FOREIGN KEY([${
fkFields.find((f) => f.id === fkFieldId).name
}]) REFERENCES [${refName}]([${
refFields.find((f) => f.id === refFieldId).name
}])\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};\nGO`;
})
.join("\n")}`;
Expand Down Expand Up @@ -619,17 +619,17 @@ export function jsonToOracleSQL(obj) {
)
.join("\n\n")}\n${obj.references
.map((r) => {
const { name: startName, fields: startFields } = obj.tables.find(
(t) => t.id === r.startTableId,
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const { name: fkName, fields: fkFields } = obj.tables.find(
(t) => t.id === fkTableId,
);

const { name: endName, fields: endFields } = obj.tables.find(
(t) => t.id === r.endTableId,
const { name: refName, fields: refFields } = obj.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE "${startName}"\nADD CONSTRAINT "${r.name}" FOREIGN KEY ("${
startFields.find((f) => f.id === r.startFieldId).name
}") REFERENCES "${endName}"("${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE "${fkName}"\nADD CONSTRAINT "${r.name}" FOREIGN KEY ("${
fkFields.find((f) => f.id === fkFieldId).name
}") REFERENCES "${refName}"("${
refFields.find((f) => f.id === refFieldId).name
}");`;
})
.join("\n")}`;
Expand Down
20 changes: 10 additions & 10 deletions src/utils/exportSQL/mariadb.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { escapeQuotes, parseDefault } from "./shared";
import { escapeQuotes, parseDefault, resolveFKDirection } from "./shared";

import { dbToTypes } from "../../data/datatypes";
import { DB } from "../../data/constants";
Expand Down Expand Up @@ -60,17 +60,17 @@ export function toMariaDB(diagram) {
)
.join("\n")}\n${diagram.references
.map((r) => {
const { name: startName, fields: startFields } = diagram.tables.find(
(t) => t.id === r.startTableId,
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const { name: fkName, fields: fkFields } = diagram.tables.find(
(t) => t.id === fkTableId,
);

const { name: endName, fields: endFields } = diagram.tables.find(
(t) => t.id === r.endTableId,
const { name: refName, fields: refFields } = diagram.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE \`${startName}\`\nADD FOREIGN KEY(\`${
startFields.find((f) => f.id === r.startFieldId).name
}\`) REFERENCES \`${endName}\`(\`${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE \`${fkName}\`\nADD FOREIGN KEY(\`${
fkFields.find((f) => f.id === fkFieldId).name
}\`) REFERENCES \`${refName}\`(\`${
refFields.find((f) => f.id === refFieldId).name
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
})
.join("\n")}`;
Expand Down
21 changes: 11 additions & 10 deletions src/utils/exportSQL/mssql.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parseDefault, escapeQuotes } from "./shared";
import { parseDefault, escapeQuotes, resolveFKDirection } from "./shared";

import { dbToTypes } from "../../data/datatypes";
import { DB } from "../../data/constants";
Expand Down Expand Up @@ -94,19 +94,20 @@ export function toMSSQL(diagram) {

const referencesSql = diagram.references
.map((r) => {
const startTable = diagram.tables.find((t) => t.id === r.startTableId);
const endTable = diagram.tables.find((t) => t.id === r.endTableId);
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const fkTable = diagram.tables.find((t) => t.id === fkTableId);
const refTable = diagram.tables.find((t) => t.id === refTableId);

if (!startTable || !endTable) return "";
if (!fkTable || !refTable) return "";

const startField = startTable.fields.find((f) => f.id === r.startFieldId);
const endField = endTable.fields.find((f) => f.id === r.endFieldId);
const fkField = fkTable.fields.find((f) => f.id === fkFieldId);
const refField = refTable.fields.find((f) => f.id === refFieldId);

if (!startField || !endField) return "";
if (!fkField || !refField) return "";

return `\nALTER TABLE [${startTable.name}]
ADD FOREIGN KEY([${startField.name}])
REFERENCES [${endTable.name}]([${endField.name}])
return `\nALTER TABLE [${fkTable.name}]
ADD FOREIGN KEY([${fkField.name}])
REFERENCES [${refTable.name}]([${refField.name}])
ON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};
GO`;
})
Expand Down
25 changes: 15 additions & 10 deletions src/utils/exportSQL/mysql.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { escapeQuotes, parseDefault } from "./shared";

import { dbToTypes } from "../../data/datatypes";
import { DB } from "../../data/constants";
import { Cardinality, DB } from "../../data/constants";

function parseType(field) {
let res = field.type;
Expand Down Expand Up @@ -64,17 +64,22 @@ export function toMySQL(diagram) {
)
.join("\n")}\n${diagram.references
.map((r) => {
const { name: startName, fields: startFields } = diagram.tables.find(
(t) => t.id === r.startTableId,
);
const isInverted = r.cardinality === Cardinality.ONE_TO_MANY;
const fkTableId = isInverted ? r.endTableId : r.startTableId;
const fkFieldId = isInverted ? r.endFieldId : r.startFieldId;
const refTableId = isInverted ? r.startTableId : r.endTableId;
const refFieldId = isInverted ? r.startFieldId : r.endFieldId;

const { name: endName, fields: endFields } = diagram.tables.find(
(t) => t.id === r.endTableId,
const { name: fkName, fields: fkFields } = diagram.tables.find(
(t) => t.id === fkTableId,
);
const { name: refName, fields: refFields } = diagram.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE \`${startName}\`\nADD FOREIGN KEY(\`${
startFields.find((f) => f.id === r.startFieldId).name
}\`) REFERENCES \`${endName}\`(\`${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE \`${fkName}\`\nADD FOREIGN KEY(\`${
fkFields.find((f) => f.id === fkFieldId).name
}\`) REFERENCES \`${refName}\`(\`${
refFields.find((f) => f.id === refFieldId).name
}\`)\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
})
.join("\n")}`;
Expand Down
19 changes: 10 additions & 9 deletions src/utils/exportSQL/oraclesql.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { dbToTypes } from "../../data/datatypes";
import { parseDefault } from "./shared";
import { parseDefault, resolveFKDirection } from "./shared";

export function toOracleSQL(diagram) {
return `${diagram.tables
Expand Down Expand Up @@ -47,16 +47,17 @@ export function toOracleSQL(diagram) {
)
.join("\n")}\n${diagram.references
.map((r) => {
const { name: startName, fields: startFields } = diagram.tables.find(
(t) => t.id === r.startTableId,
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const { name: fkName, fields: fkFields } = diagram.tables.find(
(t) => t.id === fkTableId,
);
const { name: endName, fields: endFields } = diagram.tables.find(
(t) => t.id === r.endTableId,
const { name: refName, fields: refFields } = diagram.tables.find(
(t) => t.id === refTableId,
);
return `ALTER TABLE "${startName}"\nADD CONSTRAINT "${r.name}" FOREIGN KEY ("${
startFields.find((f) => f.id === r.startFieldId).name
}") REFERENCES "${endName}" ("${
endFields.find((f) => f.id === r.endFieldId).name
return `ALTER TABLE "${fkName}"\nADD CONSTRAINT "${r.name}" FOREIGN KEY ("${
fkFields.find((f) => f.id === fkFieldId).name
}") REFERENCES "${refName}" ("${
refFields.find((f) => f.id === refFieldId).name
}")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
})
.join("\n")}`;
Expand Down
17 changes: 8 additions & 9 deletions src/utils/exportSQL/postgres.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { escapeQuotes, exportFieldComment, parseDefault } from "./shared";
import { escapeQuotes, exportFieldComment, parseDefault, resolveFKDirection } from "./shared";
import { dbToTypes } from "../../data/datatypes";

export function toPostgres(diagram) {
Expand Down Expand Up @@ -87,16 +87,15 @@ export function toPostgres(diagram) {

const foreignKeyStatements = diagram.references
.map((r) => {
const startTable = diagram.tables.find((t) => t.id === r.startTableId);
const endTable = diagram.tables.find((t) => t.id === r.endTableId);
const startField = startTable?.fields.find(
(f) => f.id === r.startFieldId,
);
const endField = endTable?.fields.find((f) => f.id === r.endFieldId);
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
const fkTable = diagram.tables.find((t) => t.id === fkTableId);
const refTable = diagram.tables.find((t) => t.id === refTableId);
const fkField = fkTable?.fields.find((f) => f.id === fkFieldId);
const refField = refTable?.fields.find((f) => f.id === refFieldId);

if (!startTable || !endTable || !startField || !endField) return "";
if (!fkTable || !refTable || !fkField || !refField) return "";

return `ALTER TABLE "${startTable.name}"\nADD FOREIGN KEY("${startField.name}") REFERENCES "${endTable.name}"("${endField.name}")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
return `ALTER TABLE "${fkTable.name}"\nADD FOREIGN KEY("${fkField.name}") REFERENCES "${refTable.name}"("${refField.name}")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`;
})
.filter(Boolean)
.join("\n");
Expand Down
23 changes: 17 additions & 6 deletions src/utils/exportSQL/shared.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isFunction, isKeyword } from "../utils";

import { DB } from "../../data/constants";
import { Cardinality, DB } from "../../data/constants";
import { dbToTypes } from "../../data/datatypes";

export function parseDefault(field, database = DB.GENERIC) {
Expand Down Expand Up @@ -30,17 +30,28 @@ export function exportFieldComment(comment) {
.join("");
}

export function resolveFKDirection(r) {
const isInverted = r.cardinality === Cardinality.ONE_TO_MANY;
return {
fkTableId: isInverted ? r.endTableId : r.startTableId,
fkFieldId: isInverted ? r.endFieldId : r.startFieldId,
refTableId: isInverted ? r.startTableId : r.endTableId,
refFieldId: isInverted ? r.startFieldId : r.endFieldId,
};
}

export function getInlineFK(table, obj) {
let fks = [];
obj.references.forEach((r) => {
if (r.startTableId === table.id) {
const { fkTableId, fkFieldId, refTableId, refFieldId } = resolveFKDirection(r);
if (fkTableId === table.id) {
fks.push(
`\tFOREIGN KEY ("${table.fields.find((f) => f.id === r.startFieldId)?.name}") REFERENCES "${
obj.tables.find((t) => t.id === r.endTableId)?.name
`\tFOREIGN KEY ("${table.fields.find((f) => f.id === fkFieldId)?.name}") REFERENCES "${
obj.tables.find((t) => t.id === refTableId)?.name
}"("${
obj.tables
.find((t) => t.id === r.endTableId)
.fields.find((f) => f.id === r.endFieldId)?.name
.find((t) => t.id === refTableId)
.fields.find((f) => f.id === refFieldId)?.name
}")\n\tON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()}`,
);
}
Expand Down
Loading