Handle defaults and sizes for all datatypes
This commit is contained in:
parent
9311c1fbaf
commit
10fae6d518
@ -41,6 +41,7 @@ import {
|
||||
TableContext,
|
||||
UndoRedoContext,
|
||||
} from "../pages/editor";
|
||||
import { getSize, hasPrecision, isSized } from "../utils";
|
||||
|
||||
export default function Table(props) {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
@ -380,34 +381,35 @@ export default function Table(props) {
|
||||
if (value === "ENUM" || value === "SET") {
|
||||
updateField(props.tableData.id, j, {
|
||||
type: value,
|
||||
default: "",
|
||||
values: [],
|
||||
increment: incr,
|
||||
});
|
||||
} else if (value === "VARCHAR") {
|
||||
} else if (isSized(value) || hasPrecision(value)) {
|
||||
updateField(props.tableData.id, j, {
|
||||
type: value,
|
||||
length: 255,
|
||||
size: getSize(value),
|
||||
increment: incr,
|
||||
});
|
||||
} else if (
|
||||
f.type === "BLOB" ||
|
||||
f.type === "JSON" ||
|
||||
f.type === "GEOMETRY" ||
|
||||
f.type === "TEXT" ||
|
||||
value === "BLOB" ||
|
||||
value === "JSON" ||
|
||||
value === "UUID" ||
|
||||
value === "TEXT" ||
|
||||
incr
|
||||
) {
|
||||
updateField(props.tableData.id, j, {
|
||||
type: value,
|
||||
increment: incr,
|
||||
default: "",
|
||||
length: "",
|
||||
size: "",
|
||||
values: [],
|
||||
});
|
||||
} else {
|
||||
updateField(props.tableData.id, j, {
|
||||
type: value,
|
||||
increment: incr,
|
||||
length: "",
|
||||
size: "",
|
||||
values: [],
|
||||
});
|
||||
}
|
||||
@ -481,8 +483,8 @@ export default function Table(props) {
|
||||
disabled={
|
||||
f.type === "BLOB" ||
|
||||
f.type === "JSON" ||
|
||||
f.type === "GEOMETRY" ||
|
||||
f.type === "TEXT" ||
|
||||
f.type === "UUID" ||
|
||||
f.increment
|
||||
}
|
||||
onChange={(value) =>
|
||||
@ -556,26 +558,23 @@ export default function Table(props) {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{(f.type === "VARCHAR" || f.type === "CHAR") && (
|
||||
{isSized(f.type) && (
|
||||
<>
|
||||
<div className="font-semibold">Length</div>
|
||||
<div className="font-semibold">Size</div>
|
||||
<InputNumber
|
||||
className="my-2 w-full"
|
||||
placeholder="Set length"
|
||||
value={f.length}
|
||||
validateStatus={
|
||||
f.length === "" ? "error" : "default"
|
||||
}
|
||||
value={f.size}
|
||||
onChange={(value) =>
|
||||
updateField(props.tableData.id, j, {
|
||||
length: value,
|
||||
size: value,
|
||||
})
|
||||
}
|
||||
onFocus={(e) =>
|
||||
setEditField({ length: e.target.value })
|
||||
setEditField({ size: e.target.value })
|
||||
}
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === editField.length) return;
|
||||
if (e.target.value === editField.size) return;
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
{
|
||||
@ -585,8 +584,48 @@ export default function Table(props) {
|
||||
tid: props.tableData.id,
|
||||
fid: j,
|
||||
undo: editField,
|
||||
redo: { length: e.target.value },
|
||||
message: `Edit table field length to "${e.target.value}"`,
|
||||
redo: { size: e.target.value },
|
||||
message: `Edit table field size to ${e.target.value}`,
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{hasPrecision(f.type) && (
|
||||
<>
|
||||
<div className="font-semibold">Precision</div>
|
||||
<Input
|
||||
className="my-2 w-full"
|
||||
placeholder="Set precision: (size, d)"
|
||||
validateStatus={
|
||||
/^\(\d+,\s*\d+\)$|^$/.test(f.size)
|
||||
? "default"
|
||||
: "error"
|
||||
}
|
||||
value={f.size}
|
||||
onChange={(value) =>
|
||||
updateField(props.tableData.id, j, {
|
||||
size: value,
|
||||
})
|
||||
}
|
||||
onFocus={(e) =>
|
||||
setEditField({ size: e.target.value })
|
||||
}
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === editField.size) return;
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
{
|
||||
action: Action.EDIT,
|
||||
element: ObjectType.TABLE,
|
||||
component: "field",
|
||||
tid: props.tableData.id,
|
||||
fid: j,
|
||||
undo: editField,
|
||||
redo: { size: e.target.value },
|
||||
message: `Edit table field precision to ${e.target.value}`,
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
|
@ -36,6 +36,7 @@ import {
|
||||
IllustrationNoContentDark,
|
||||
} from "@douyinfe/semi-illustrations";
|
||||
import { SelectContext, TableContext, UndoRedoContext } from "../pages/editor";
|
||||
import { getSize, hasPrecision, isSized } from "../utils";
|
||||
|
||||
export default function TableOverview(props) {
|
||||
const [indexActiveKey, setIndexActiveKey] = useState("");
|
||||
@ -226,34 +227,35 @@ export default function TableOverview(props) {
|
||||
if (value === "ENUM" || value === "SET") {
|
||||
updateField(i, j, {
|
||||
type: value,
|
||||
default: "",
|
||||
values: [],
|
||||
increment: incr,
|
||||
});
|
||||
} else if (value === "VARCHAR") {
|
||||
} else if (isSized(value) || hasPrecision(value)) {
|
||||
updateField(i, j, {
|
||||
type: value,
|
||||
length: 255,
|
||||
size: getSize(value),
|
||||
increment: incr,
|
||||
});
|
||||
} else if (
|
||||
f.type === "BLOB" ||
|
||||
f.type === "JSON" ||
|
||||
f.type === "GEOMETRY" ||
|
||||
f.type === "TEXT" ||
|
||||
value === "BLOB" ||
|
||||
value === "JSON" ||
|
||||
value === "UUID" ||
|
||||
value === "TEXT" ||
|
||||
incr
|
||||
) {
|
||||
updateField(props.tableData.id, j, {
|
||||
updateField(t.id, j, {
|
||||
type: value,
|
||||
increment: incr,
|
||||
default: "",
|
||||
length: "",
|
||||
size: "",
|
||||
values: [],
|
||||
});
|
||||
} else {
|
||||
updateField(i, j, {
|
||||
type: value,
|
||||
increment: incr,
|
||||
length: "",
|
||||
size: "",
|
||||
values: [],
|
||||
});
|
||||
}
|
||||
@ -327,8 +329,8 @@ export default function TableOverview(props) {
|
||||
disabled={
|
||||
f.type === "BLOB" ||
|
||||
f.type === "JSON" ||
|
||||
f.type === "GEOMETRY" ||
|
||||
f.type === "TEXT" ||
|
||||
f.type === "UUID" ||
|
||||
f.increment
|
||||
}
|
||||
onChange={(value) =>
|
||||
@ -403,24 +405,21 @@ export default function TableOverview(props) {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{(f.type === "VARCHAR" || f.type === "CHAR") && (
|
||||
{isSized(f.type) && (
|
||||
<>
|
||||
<div className="font-semibold">Length</div>
|
||||
<div className="font-semibold">Size</div>
|
||||
<InputNumber
|
||||
className="my-2 w-full"
|
||||
placeholder="Set length"
|
||||
validateStatus={
|
||||
f.length === "" ? "error" : "default"
|
||||
}
|
||||
value={f.length}
|
||||
value={f.size}
|
||||
onChange={(value) =>
|
||||
updateField(i, j, { length: value })
|
||||
updateField(i, j, { size: value })
|
||||
}
|
||||
onFocus={(e) =>
|
||||
setEditField({ length: e.target.value })
|
||||
setEditField({ size: e.target.value })
|
||||
}
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === editField.length)
|
||||
if (e.target.value === editField.size)
|
||||
return;
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
@ -431,8 +430,47 @@ export default function TableOverview(props) {
|
||||
tid: i,
|
||||
fid: j,
|
||||
undo: editField,
|
||||
redo: { length: e.target.value },
|
||||
message: `Edit table field length to ${e.target.value}`,
|
||||
redo: { size: e.target.value },
|
||||
message: `Edit table field size to ${e.target.value}`,
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{hasPrecision(f.type) && (
|
||||
<>
|
||||
<div className="font-semibold">Precision</div>
|
||||
<Input
|
||||
className="my-2 w-full"
|
||||
placeholder="Set precision: (size, d)"
|
||||
validateStatus={
|
||||
/^\(\d+,\s*\d+\)$|^$/.test(f.size)
|
||||
? "default"
|
||||
: "error"
|
||||
}
|
||||
value={f.size}
|
||||
onChange={(value) =>
|
||||
updateField(i, j, { size: value })
|
||||
}
|
||||
onFocus={(e) =>
|
||||
setEditField({ size: e.target.value })
|
||||
}
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === editField.size)
|
||||
return;
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
{
|
||||
action: Action.EDIT,
|
||||
element: ObjectType.TABLE,
|
||||
component: "field",
|
||||
tid: i,
|
||||
fid: j,
|
||||
undo: editField,
|
||||
redo: { size: e.target.value },
|
||||
message: `Edit table field precision to ${e.target.value}`,
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
@ -601,11 +639,9 @@ export default function TableOverview(props) {
|
||||
.filter(
|
||||
(e) =>
|
||||
!(
|
||||
(e.startTableId ===
|
||||
props.tableData.id &&
|
||||
(e.startTableId === t.id &&
|
||||
e.startFieldId === j) ||
|
||||
(e.endTableId ===
|
||||
props.tableData.id &&
|
||||
(e.endTableId === t.id &&
|
||||
e.endFieldId === j)
|
||||
)
|
||||
)
|
||||
|
@ -5,20 +5,21 @@ const sqlDataTypes = [
|
||||
"DECIMAL",
|
||||
"NUMERIC",
|
||||
"FLOAT",
|
||||
"DOUBLE",
|
||||
"REAL",
|
||||
"DOUBLE PRECISION",
|
||||
"CHAR",
|
||||
"VARCHAR",
|
||||
"TEXT",
|
||||
"DATE",
|
||||
"TIME",
|
||||
"TIMESTAMP",
|
||||
"INTERVAL",
|
||||
"DATETIME",
|
||||
"BOOLEAN",
|
||||
"BINARY",
|
||||
"VARBINARY",
|
||||
"BLOB",
|
||||
"JSON",
|
||||
"UUID",
|
||||
"ENUM",
|
||||
"SET",
|
||||
];
|
||||
|
@ -47,6 +47,36 @@ function dataURItoBlob(dataUrl) {
|
||||
return new Blob([intArray], { type: mimeString });
|
||||
}
|
||||
|
||||
function getTypeString(field) {
|
||||
if (field.type === "UUID") {
|
||||
return `VARCHAR(36)`;
|
||||
}
|
||||
if (isSized(field.type)) {
|
||||
return `${field.type}(${field.size})`;
|
||||
}
|
||||
if (hasPrecision(field.type) && field.size !== "") {
|
||||
return `${field.type}${field.size}`;
|
||||
}
|
||||
if (field.type === "SET" || field.type === "ENUM") {
|
||||
return `${field.type}(${field.values.map((v) => `"${v}"`).join(", ")})`;
|
||||
}
|
||||
return field.type;
|
||||
}
|
||||
|
||||
function hasQuotes(type) {
|
||||
return [
|
||||
"CHAR",
|
||||
"VARCHAR",
|
||||
"BINARY",
|
||||
"VARBINARY",
|
||||
"ENUM",
|
||||
"DATE",
|
||||
"TIME",
|
||||
"TIMESTAMP",
|
||||
"DATETIME",
|
||||
].includes(type);
|
||||
}
|
||||
|
||||
function jsonToSQL(obj) {
|
||||
return `${obj.tables
|
||||
.map(
|
||||
@ -58,18 +88,12 @@ function jsonToSQL(obj) {
|
||||
(field) =>
|
||||
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${
|
||||
field.name
|
||||
}\` ${field.type}${
|
||||
field.type === "VARCHAR"
|
||||
? `(${field.length})`
|
||||
: field.type === "ENUM" || field.type === "SET"
|
||||
? `(${field.values.map((v) => `"${v}"`).join(", ")})`
|
||||
: ""
|
||||
}${field.notNull ? " NOT NULL" : ""}${
|
||||
}\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${
|
||||
field.increment ? " AUTO_INCREMENT" : ""
|
||||
}${field.unique ? " UNIQUE" : ""}${
|
||||
field.default !== ""
|
||||
? ` DEFAULT ${
|
||||
(field.type === "VARCHAR" || field.type === "ENUM") &&
|
||||
hasQuotes(field.type) &&
|
||||
field.default.toLowerCase() !== "null"
|
||||
? `"${field.default}"`
|
||||
: `${field.default}`
|
||||
@ -115,6 +139,37 @@ function arrayIsEqual(arr1, arr2) {
|
||||
return JSON.stringify(arr1) === JSON.stringify(arr2);
|
||||
}
|
||||
|
||||
function isSized(type) {
|
||||
return ["CHAR", "VARCHAR", "BINARY", "VARBINARY", "TEXT", "FLOAT"].includes(
|
||||
type
|
||||
);
|
||||
}
|
||||
|
||||
function hasPrecision(type) {
|
||||
return ["DOUBLE", "NUMERIC", "DECIMAL"].includes(type);
|
||||
}
|
||||
|
||||
function getSize(type) {
|
||||
switch (type) {
|
||||
case "CHAR":
|
||||
case "BINARY":
|
||||
return 1;
|
||||
case "VARCHAR":
|
||||
case "VARBINARY":
|
||||
return 255;
|
||||
case "TEXT":
|
||||
return 65535;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function validateDateStr(str) {
|
||||
return /^(?!0000)(?!00)(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[01])|(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31))$/.test(
|
||||
str
|
||||
);
|
||||
}
|
||||
|
||||
function checkDefault(field) {
|
||||
if (field.default === "") return true;
|
||||
|
||||
@ -122,17 +177,51 @@ function checkDefault(field) {
|
||||
case "INT":
|
||||
case "BIGINT":
|
||||
case "SMALLINT":
|
||||
return /^\d*$/.test(field.default);
|
||||
return /^-?\d*$/.test(field.default);
|
||||
case "ENUM":
|
||||
case "SET":
|
||||
return field.values.includes(field.default);
|
||||
case "CHAR":
|
||||
case "VARCHAR":
|
||||
return field.default.length <= field.length;
|
||||
return field.default.length <= field.size;
|
||||
case "BINARY":
|
||||
case "VARBINARY":
|
||||
return (
|
||||
field.default.length <= field.size && /^[01]+$/.test(field.default)
|
||||
);
|
||||
case "BOOLEAN":
|
||||
return (
|
||||
field.default.trim() === "false" || field.default.trim() === "true"
|
||||
);
|
||||
case "FLOAT":
|
||||
case "DECIMAL":
|
||||
case "DOUBLE":
|
||||
case "NUMERIC":
|
||||
case "REAL":
|
||||
return /^-?\d*.?\d+$/.test(field.default);
|
||||
case "DATE":
|
||||
return validateDateStr(field.default);
|
||||
case "TIME":
|
||||
return /^(?:[01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d$/.test(field.default);
|
||||
case "TIMESTAMP":
|
||||
if (field.default.toUpperCase() === "CURRENT_TIMESTAMP") {
|
||||
return true;
|
||||
}
|
||||
if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(field.default)) {
|
||||
return false;
|
||||
}
|
||||
const content = field.default.split(" ");
|
||||
const date = content[0].split("-");
|
||||
|
||||
return parseInt(date[0]) >= 1970 && parseInt(date[0]) <= 2038;
|
||||
case "DATETIME":
|
||||
if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(field.default)) {
|
||||
return false;
|
||||
}
|
||||
const c = field.default.split(" ");
|
||||
const d = c[0].split("-");
|
||||
|
||||
return parseInt(d[0]) >= 1000 && parseInt(d[0]) <= 9999;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@ -180,6 +269,18 @@ function validateDiagram(diagram) {
|
||||
);
|
||||
}
|
||||
|
||||
if (field.notNull && field.default.toLowerCase() === "null") {
|
||||
issues.push(
|
||||
`"${field.name}" field of table "${table.name}" is NOT NULL but has default NULL`
|
||||
);
|
||||
}
|
||||
|
||||
if (field.type === "DOUBLE" && field.size !== "") {
|
||||
issues.push(
|
||||
`Specifying number of digits for floating point data types is deprecated.`
|
||||
);
|
||||
}
|
||||
|
||||
if (duplicateFieldNames[field.name]) {
|
||||
issues.push(`Duplicate table fields in table "${table.name}"`);
|
||||
} else {
|
||||
@ -254,4 +355,8 @@ export {
|
||||
jsonToSQL,
|
||||
validateDiagram,
|
||||
arrayIsEqual,
|
||||
isSized,
|
||||
getSize,
|
||||
hasPrecision,
|
||||
validateDateStr,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user