Catch empty or duplacate fields, indices, names, relationships

This commit is contained in:
1ilit 2023-09-19 15:51:16 +03:00
parent 794ecdba08
commit 1016c3536e
4 changed files with 81 additions and 14 deletions

View File

@ -337,8 +337,10 @@ export default function Canvas(props) {
endFieldId: onRect.field, endFieldId: onRect.field,
endX: tables[onRect.tableId].x + 15, endX: tables[onRect.tableId].x + 15,
endY: tables[onRect.tableId].y + onRect.field * 36 + 69, endY: tables[onRect.tableId].y + onRect.field * 36 + 69,
name: `${tables[line.startTableId].name}_to_${ name: `${tables[line.startTableId].name}_FK_${
tables[onRect.tableId].name tables[line.startTableId].fields[line.startFieldId].name
}_to_${
tables[onRect.tableId].fields[onRect.field].name
}`, }`,
id: relationships.length, id: relationships.length,
}); });

View File

@ -1,5 +1,5 @@
import React, { useContext, useState, useEffect } from "react"; import React, { useContext, useState, useEffect } from "react";
import { Collapse } from "@douyinfe/semi-ui"; import { Collapse, Badge } from "@douyinfe/semi-ui";
import { SettingsContext, TableContext } from "../pages/editor"; import { SettingsContext, TableContext } from "../pages/editor";
import { validateDiagram, arrayIsEqual } from "../utils"; import { validateDiagram, arrayIsEqual } from "../utils";
@ -7,7 +7,7 @@ export default function Issues() {
const { settings } = useContext(SettingsContext); const { settings } = useContext(SettingsContext);
const { tables, relationships } = useContext(TableContext); const { tables, relationships } = useContext(TableContext);
const [issues, setIssues] = useState([]); const [issues, setIssues] = useState([]);
useEffect(() => { useEffect(() => {
const findIssues = async () => { const findIssues = async () => {
const newIssues = validateDiagram({ const newIssues = validateDiagram({
@ -27,10 +27,17 @@ export default function Issues() {
<Collapse style={{ width: "100%" }}> <Collapse style={{ width: "100%" }}>
<Collapse.Panel <Collapse.Panel
header={ header={
<div> <Badge
<i className="fa-solid fa-triangle-exclamation me-1 text-yellow-500"></i>{" "} type={issues.length > 0 ? "danger" : "primary"}
Issues count={settings.strictMode ? null : issues.length}
</div> overflowCount={99}
className="mt-1"
>
<div className="pe-3">
<i className="fa-solid fa-triangle-exclamation me-2 text-yellow-500"></i>
Issues
</div>
</Badge>
} }
itemKey="1" itemKey="1"
> >
@ -39,14 +46,16 @@ export default function Issues() {
<div className="mb-1"> <div className="mb-1">
Strict mode is off so no issues will be displayed. Strict mode is off so no issues will be displayed.
</div> </div>
) : ( ) : issues.length > 0 ? (
<div> <>
{issues.map((e, i) => ( {issues.map((e, i) => (
<div key={i} className="py-2"> <div key={i} className="py-2">
{e} {e}
</div> </div>
))} ))}
</div> </>
) : (
<div>No issues were detected.</div>
)} )}
</div> </div>
</Collapse.Panel> </Collapse.Panel>

View File

@ -13,9 +13,13 @@ export default function Relationship(props) {
r = Math.abs(y2 - y1) / 3; r = Math.abs(y2 - y1) / 3;
if (r <= 2) { if (r <= 2) {
if (x1 + tableWidth <= x2) if (x1 + tableWidth <= x2)
return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x2} ${y2}`; return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${x2 + 0.1} ${
y2 + 0.1
}`;
else if (x2 + tableWidth < x1) else if (x2 + tableWidth < x1)
return `M ${x2 + tableWidth - 2 * offsetX} ${y2} L ${x1} ${y1}`; return `M ${x2 + tableWidth - 2 * offsetX} ${y2} L ${x1 + 0.1} ${
y1 + 0.1
}`;
} }
} }

View File

@ -120,11 +120,63 @@ function validateDiagram(diagram) {
const duplicateTableNames = {}; const duplicateTableNames = {};
diagram.tables.forEach((table) => { diagram.tables.forEach((table) => {
if (table.name === "") {
issues.push(`Declared a table with no name`);
}
if (duplicateTableNames[table.name]) { if (duplicateTableNames[table.name]) {
issues.push(`Duplicate table name: "${table.name}"`); issues.push(`Duplicate table by the name "${table.name}"`);
} else { } else {
duplicateTableNames[table.name] = true; duplicateTableNames[table.name] = true;
} }
const duplicateFieldNames = {};
let hasPrimaryKey = false;
table.fields.forEach((field) => {
if (field.primary) {
hasPrimaryKey = true;
}
if (field.name === "") {
issues.push(`Empty field name in table "${table.name}"`);
}
if (field.type === "") {
issues.push(`Empty field type in table "${table.name}"`);
}
if (duplicateFieldNames[field.name]) {
issues.push(`Duplicate table fields in table "${table.name}"`);
} else {
duplicateFieldNames[field.name] = true;
}
});
const duplicateIndices = {};
table.indices.forEach((index) => {
if (duplicateIndices[index.name]) {
issues.push(`Duplicate index by the name "${index.name}"`);
} else {
duplicateIndices[index.name] = true;
}
});
table.indices.forEach((index) => {
if (index.fields.length === 0) {
issues.push(`Empty index type in table "${table.name}"`);
}
});
if (!hasPrimaryKey) {
issues.push(`Table "${table.name}" has no primary key`);
}
});
const duplicateFKName = {};
diagram.relationships.forEach((relationship) => {
if (duplicateFKName[relationship.name]) {
issues.push(`Duplicate relationship by the name "${relationship.name}"`);
} else {
duplicateFKName[relationship.name] = true;
}
}); });
const visitedTables = new Set(); const visitedTables = new Set();