Move all type data to datatypes.js

This commit is contained in:
1ilit
2024-06-10 02:17:43 +03:00
parent 0908d040e0
commit 9c31e2be52
8 changed files with 514 additions and 426 deletions

View File

@@ -94,6 +94,7 @@ export default function ControlPanel({
setRelationships, setRelationships,
addRelationship, addRelationship,
deleteRelationship, deleteRelationship,
database,
} = useTables(); } = useTables();
const { types, addType, deleteType, updateType, setTypes } = useTypes(); const { types, addType, deleteType, updateType, setTypes } = useTypes();
const { notes, setNotes, updateNote, addNote, deleteNote } = useNotes(); const { notes, setNotes, updateNote, addNote, deleteNote } = useNotes();
@@ -858,6 +859,7 @@ export default function ControlPanel({
tables: tables, tables: tables,
references: relationships, references: relationships,
types: types, types: types,
database: database,
}); });
setExportData((prev) => ({ setExportData((prev) => ({
...prev, ...prev,
@@ -873,6 +875,7 @@ export default function ControlPanel({
tables: tables, tables: tables,
references: relationships, references: relationships,
types: types, types: types,
database: database,
}); });
setExportData((prev) => ({ setExportData((prev) => ({
...prev, ...prev,
@@ -888,6 +891,7 @@ export default function ControlPanel({
tables: tables, tables: tables,
references: relationships, references: relationships,
types: types, types: types,
database: database,
}); });
setExportData((prev) => ({ setExportData((prev) => ({
...prev, ...prev,
@@ -903,6 +907,7 @@ export default function ControlPanel({
tables: tables, tables: tables,
references: relationships, references: relationships,
types: types, types: types,
database: database,
}); });
setExportData((prev) => ({ setExportData((prev) => ({
...prev, ...prev,
@@ -918,6 +923,7 @@ export default function ControlPanel({
tables: tables, tables: tables,
references: relationships, references: relationships,
types: types, types: types,
database: database,
}); });
setExportData((prev) => ({ setExportData((prev) => ({
...prev, ...prev,

View File

@@ -9,7 +9,7 @@ export default function Issues() {
const { types } = useTypes(); const { types } = useTypes();
const { t } = useTranslation(); const { t } = useTranslation();
const { settings } = useSettings(); const { settings } = useSettings();
const { tables, relationships } = useTables(); const { tables, relationships, database } = useTables();
const [issues, setIssues] = useState([]); const [issues, setIssues] = useState([]);
useEffect(() => { useEffect(() => {
@@ -18,6 +18,7 @@ export default function Issues() {
tables: tables, tables: tables,
relationships: relationships, relationships: relationships,
types: types, types: types,
database: database,
}); });
if (!arrayIsEqual(newIssues, issues)) { if (!arrayIsEqual(newIssues, issues)) {
@@ -26,7 +27,7 @@ export default function Issues() {
}; };
findIssues(); findIssues();
}, [tables, relationships, issues, types]); }, [tables, relationships, issues, types, database]);
return ( return (
<Collapse keepDOM lazyRender style={{ width: "100%" }}> <Collapse keepDOM lazyRender style={{ width: "100%" }}>

View File

@@ -9,13 +9,13 @@ import {
} from "@douyinfe/semi-ui"; } from "@douyinfe/semi-ui";
import { Action, ObjectType } from "../../../data/constants"; import { Action, ObjectType } from "../../../data/constants";
import { IconDeleteStroked } from "@douyinfe/semi-icons"; import { IconDeleteStroked } from "@douyinfe/semi-icons";
import { hasCheck, hasPrecision, isSized } from "../../../utils/toSQL";
import { useTables, useUndoRedo } from "../../../hooks"; import { useTables, useUndoRedo } from "../../../hooks";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { dbToTypes } from "../../../data/datatypes";
export default function FieldDetails({ data, tid, index }) { export default function FieldDetails({ data, tid, index }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { tables } = useTables(); const { tables, database } = useTables();
const { setUndoStack, setRedoStack } = useUndoRedo(); const { setUndoStack, setRedoStack } = useUndoRedo();
const { updateField, deleteField } = useTables(); const { updateField, deleteField } = useTables();
const [editField, setEditField] = useState({}); const [editField, setEditField] = useState({});
@@ -99,7 +99,7 @@ export default function FieldDetails({ data, tid, index }) {
/> />
</> </>
)} )}
{isSized(data.type) && ( {dbToTypes[database][data.type].isSized && (
<> <>
<div className="font-semibold">{t("size")}</div> <div className="font-semibold">{t("size")}</div>
<InputNumber <InputNumber
@@ -131,7 +131,7 @@ export default function FieldDetails({ data, tid, index }) {
/> />
</> </>
)} )}
{hasPrecision(data.type) && ( {dbToTypes[database][data.type].hasPrecision && (
<> <>
<div className="font-semibold">{t("precision")}</div> <div className="font-semibold">{t("precision")}</div>
<Input <Input
@@ -168,7 +168,7 @@ export default function FieldDetails({ data, tid, index }) {
/> />
</> </>
)} )}
{hasCheck(data.type) && ( {dbToTypes[database][data.type].hasCheck && (
<> <>
<div className="font-semibold">{t("check")}</div> <div className="font-semibold">{t("check")}</div>
<Input <Input

View File

@@ -1,7 +1,6 @@
import { Action, ObjectType } from "../../../data/constants"; import { Action, ObjectType } from "../../../data/constants";
import { Row, Col, Input, Button, Popover, Select } from "@douyinfe/semi-ui"; import { Row, Col, Input, Button, Popover, Select } from "@douyinfe/semi-ui";
import { IconMore, IconKeyStroked } from "@douyinfe/semi-icons"; import { IconMore, IconKeyStroked } from "@douyinfe/semi-icons";
import { getSize, hasCheck, hasPrecision, isSized } from "../../../utils/toSQL";
import { useTables, useTypes, useUndoRedo } from "../../../hooks"; import { useTables, useTypes, useUndoRedo } from "../../../hooks";
import { useState } from "react"; import { useState } from "react";
import FieldDetails from "./FieldDetails"; import FieldDetails from "./FieldDetails";
@@ -51,7 +50,7 @@ export default function TableField({ data, tid, index }) {
<Select <Select
className="w-full" className="w-full"
optionList={[ optionList={[
...dbToTypes[database].map((value) => ({ ...Object.keys(dbToTypes[database]).map((value) => ({
label: value, label: value,
value: value, value: value,
})), })),
@@ -93,10 +92,13 @@ export default function TableField({ data, tid, index }) {
values: data.values ? [...data.values] : [], values: data.values ? [...data.values] : [],
increment: incr, increment: incr,
}); });
} else if (isSized(value) || hasPrecision(value)) { } else if (
dbToTypes[database][value].isSized ||
dbToTypes[database][value].hasPrecision
) {
updateField(tid, index, { updateField(tid, index, {
type: value, type: value,
size: getSize(value), size: dbToTypes[database][value].defaultSize,
increment: incr, increment: incr,
}); });
} else if ( } else if (
@@ -113,7 +115,7 @@ export default function TableField({ data, tid, index }) {
size: "", size: "",
values: [], values: [],
}); });
} else if (hasCheck(value)) { } else if (dbToTypes[database][value].hasCheck) {
updateField(tid, index, { updateField(tid, index, {
type: value, type: value,
check: "", check: "",

View File

@@ -11,7 +11,6 @@ import {
Popover, Popover,
} from "@douyinfe/semi-ui"; } from "@douyinfe/semi-ui";
import { IconDeleteStroked, IconMore } from "@douyinfe/semi-icons"; import { IconDeleteStroked, IconMore } from "@douyinfe/semi-icons";
import { isSized, hasPrecision, getSize } from "../../../utils/toSQL";
import { useUndoRedo, useTypes, useTables } from "../../../hooks"; import { useUndoRedo, useTypes, useTables } from "../../../hooks";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { dbToTypes } from "../../../data/datatypes"; import { dbToTypes } from "../../../data/datatypes";
@@ -64,7 +63,7 @@ export default function TypeField({ data, tid, fid }) {
<Select <Select
className="w-full" className="w-full"
optionList={[ optionList={[
...dbToTypes[database].map((value) => ({ ...Object.keys(dbToTypes[database]).map((value) => ({
label: value, label: value,
value: value, value: value,
})), })),
@@ -112,11 +111,14 @@ export default function TypeField({ data, tid, fid }) {
: e, : e,
), ),
}); });
} else if (isSized(value) || hasPrecision(value)) { } else if (
dbToTypes[database][value].isSized ||
dbToTypes[database][value].hasPrecision
) {
updateType(tid, { updateType(tid, {
fields: types[tid].fields.map((e, id) => fields: types[tid].fields.map((e, id) =>
id === fid id === fid
? { ...data, type: value, size: getSize(value) } ? { ...data, type: value, size: dbToTypes[database][value].defaultSize }
: e, : e,
), ),
}); });
@@ -184,7 +186,7 @@ export default function TypeField({ data, tid, fid }) {
/> />
</> </>
)} )}
{isSized(data.type) && ( {dbToTypes[database][data.type].isSized && (
<> <>
<div className="font-semibold">{t("size")}</div> <div className="font-semibold">{t("size")}</div>
<InputNumber <InputNumber
@@ -222,7 +224,7 @@ export default function TypeField({ data, tid, fid }) {
/> />
</> </>
)} )}
{hasPrecision(data.type) && ( {dbToTypes[database][data.type].hasPrecision && (
<> <>
<div className="font-semibold">{t("precision")}</div> <div className="font-semibold">{t("precision")}</div>
<Input <Input

View File

@@ -1,280 +1,451 @@
export const defaultTypes = [ import { strHasQuotes } from "../utils/utils";
"INT",
"SMALLINT",
"BIGINT",
"DECIMAL",
"NUMERIC",
"FLOAT",
"DOUBLE",
"REAL",
"CHAR",
"VARCHAR",
"TEXT",
"DATE",
"TIME",
"TIMESTAMP",
"DATETIME",
"BOOLEAN",
"BINARY",
"VARBINARY",
"BLOB",
"JSON",
"UUID",
"ENUM",
"SET",
];
export const mysqlTypes = [ const intRegex = /^-?\d*$/;
// Numeric Data Types const doubleRegex = /^-?\d*.?\d+$/;
"TINYINT", const binaryRegex = /^[01]+$/;
"SMALLINT",
"MEDIUMINT",
"INT",
"INTEGER",
"BIGINT",
"DECIMAL",
"NUMERIC",
"FLOAT",
"DOUBLE",
"BIT",
"BOOLEAN",
// Date and Time Data Types /* eslint-disable no-unused-vars */
"DATE", export const defaultTypes = {
"DATETIME", INT: {
"TIMESTAMP", type: "INT",
"TIME", checkDefault: (field) => {
"YEAR", return intRegex.test(field.default);
},
hasCheck: true,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
SMALLINT: {
type: "SMALLINT",
checkDefault: (field) => {
return intRegex.test(field.default);
},
hasCheck: true,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
BIGINT: {
type: "BIGINT",
checkDefault: (field) => {
return intRegex.test(field.default);
},
isSized: false,
hasCheck: true,
hasPrecision: false,
defaultSize: null,
},
DECIMAL: {
type: "DECIMAL",
checkDefault: (field) => {
return doubleRegex.test(field.default);
},
hasCheck: true,
isSized: false,
hasPrecision: true,
defaultSize: null,
},
NUMERIC: {
type: "NUMERIC",
checkDefault: (field) => {
return doubleRegex.test(field.default);
},
hasCheck: true,
isSized: false,
hasPrecision: true,
defaultSize: null,
},
FLOAT: {
type: "FLOAT",
checkDefault: (field) => {
return doubleRegex.test(field.default);
},
hasCheck: true,
isSized: false,
hasPrecision: true,
defaultSize: null,
},
DOUBLE: {
type: "DOUBLE",
checkDefault: (field) => {
return doubleRegex.test(field.default);
},
hasCheck: true,
isSized: false,
hasPrecision: true,
defaultSize: null,
},
REAL: {
type: "REAL",
checkDefault: (field) => {
return doubleRegex.test(field.default);
},
hasCheck: true,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
CHAR: {
type: "CHAR",
checkDefault: (field) => {
if (strHasQuotes(field.default)) {
return field.default.length - 2 <= field.size;
}
return field.default.length <= field.size;
},
hasCheck: true,
isSized: true,
hasPrecision: false,
defaultSize: 1,
},
VARCHAR: {
type: "VARCHAR",
checkDefault: (field) => {
if (strHasQuotes(field.default)) {
return field.default.length - 2 <= field.size;
}
return field.default.length <= field.size;
},
hasCheck: true,
isSized: true,
hasPrecision: false,
defaultSize: 255,
},
TEXT: {
type: "TEXT",
checkDefault: (field) => false,
hasCheck: false,
isSized: true,
hasPrecision: false,
defaultSize: 65535,
},
DATE: {
type: "DATE",
checkDefault: (field) => {
return /^\d{4}-\d{2}-\d{2}$/.test(field.default);
},
hasCheck: false,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
TIME: {
type: "TIME",
checkDefault: (field) => {
return /^(?:[01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d$/.test(field.default);
},
hasCheck: false,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
TIMESTAMP: {
type: "TIMESTAMP",
checkDefault: (field) => {
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;
},
hasCheck: false,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
DATETIME: {
type: "DATETIME",
checkDefault: (field) => {
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 c = field.default.split(" ");
const d = c[0].split("-");
return parseInt(d[0]) >= 1000 && parseInt(d[0]) <= 9999;
},
hasCheck: false,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
BOOLEAN: {
type: "BOOLEAN",
checkDefault: (field) => {
return (
field.default.trim().toLowerCase() === "false" ||
field.default.trim().toLowerCase() === "true"
);
},
hasCheck: false,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
BINARY: {
type: "BINARY",
checkDefault: (field) => {
return (
field.default.length <= field.size && binaryRegex.test(field.default)
);
},
hasCheck: false,
isSized: true,
hasPrecision: false,
defaultSize: 1,
},
VARBINARY: {
type: "VARBINARY",
checkDefault: (field) => {
return (
field.default.length <= field.size && binaryRegex.test(field.default)
);
},
hasCheck: false,
isSized: true,
hasPrecision: false,
defaultSize: 255,
},
BLOB: {
type: "BLOB",
checkDefault: (field) => false,
isSized: false,
hasCheck: false,
hasPrecision: false,
defaultSize: null,
},
JSON: {
type: "JSON",
checkDefault: (field) => false,
isSized: false,
hasCheck: false,
hasPrecision: false,
defaultSize: null,
},
UUID: {
type: "UUID",
checkDefault: (field) => false,
isSized: false,
hasCheck: false,
hasPrecision: false,
defaultSize: null,
},
ENUM: {
type: "ENUM",
checkDefault: (field) => {
return field.values.includes(field.default);
},
hasCheck: false,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
SET: {
type: "SET",
checkDefault: (field) => {
const defaultValues = field.default.split(",");
for (let i = 0; i < defaultValues.length; i++) {
if (!field.values.includes(defaultValues[i].trim())) return false;
}
return true;
},
hasCheck: false,
isSized: false,
hasPrecision: false,
defaultSize: null,
},
};
// String Data Types export const mysqlTypes = {
"CHAR", TINYINT: { type: "TINYINT", checkDefault: (field) => {} },
"VARCHAR", SMALLINT: { type: "SMALLINT", checkDefault: (field) => {} },
"BINARY", MEDIUMINT: { type: "MEDIUMINT", checkDefault: (field) => {} },
"VARBINARY", INT: { type: "INT", checkDefault: (field) => {} },
"TINYBLOB", INTEGER: { type: "INTEGER", checkDefault: (field) => {} },
"BLOB", BIGINT: { type: "BIGINT", checkDefault: (field) => {} },
"MEDIUMBLOB", DECIMAL: { type: "DECIMAL", checkDefault: (field) => {} },
"LONGBLOB", NUMERIC: { type: "NUMERIC", checkDefault: (field) => {} },
"TINYTEXT", FLOAT: { type: "FLOAT", checkDefault: (field) => {} },
"TEXT", DOUBLE: { type: "DOUBLE", checkDefault: (field) => {} },
"MEDIUMTEXT", BIT: { type: "BIT", checkDefault: (field) => {} },
"LONGTEXT", BOOLEAN: { type: "BOOLEAN", checkDefault: (field) => {} },
"ENUM", DATE: { type: "DATE", checkDefault: (field) => {} },
"SET", DATETIME: { type: "DATETIME", checkDefault: (field) => {} },
TIMESTAMP: { type: "TIMESTAMP", checkDefault: (field) => {} },
TIME: { type: "TIME", checkDefault: (field) => {} },
YEAR: { type: "YEAR", checkDefault: (field) => {} },
CHAR: { type: "CHAR", checkDefault: (field) => {} },
VARCHAR: { type: "VARCHAR", checkDefault: (field) => {} },
BINARY: { type: "BINARY", checkDefault: (field) => {} },
VARBINARY: { type: "VARBINARY", checkDefault: (field) => {} },
TINYBLOB: { type: "TINYBLOB", checkDefault: (field) => {} },
BLOB: { type: "BLOB", checkDefault: (field) => {} },
MEDIUMBLOB: { type: "MEDIUMBLOB", checkDefault: (field) => {} },
LONGBLOB: { type: "LONGBLOB", checkDefault: (field) => {} },
TINYTEXT: { type: "TINYTEXT", checkDefault: (field) => {} },
TEXT: { type: "TEXT", checkDefault: (field) => {} },
MEDIUMTEXT: { type: "MEDIUMTEXT", checkDefault: (field) => {} },
LONGTEXT: { type: "LONGTEXT", checkDefault: (field) => {} },
ENUM: { type: "ENUM", checkDefault: (field) => {} },
SET: { type: "SET", checkDefault: (field) => {} },
GEOMETRY: { type: "GEOMETRY", checkDefault: (field) => {} },
POINT: { type: "POINT", checkDefault: (field) => {} },
LINESTRING: { type: "LINESTRING", checkDefault: (field) => {} },
POLYGON: { type: "POLYGON", checkDefault: (field) => {} },
MULTIPOINT: { type: "MULTIPOINT", checkDefault: (field) => {} },
MULTILINESTRING: { type: "MULTILINESTRING", checkDefault: (field) => {} },
MULTIPOLYGON: { type: "MULTIPOLYGON", checkDefault: (field) => {} },
GEOMETRYCOLLECTION: {
type: "GEOMETRYCOLLECTION",
checkDefault: (field) => {},
},
JSON: { type: "JSON", checkDefault: (field) => {} },
};
// Spatial Data Types export const postgresTypes = {
"GEOMETRY", SMALLINT: { type: "SMALLINT", checkDefault: (field) => {} },
"POINT", INTEGER: { type: "INTEGER", checkDefault: (field) => {} },
"LINESTRING", BIGINT: { type: "BIGINT", checkDefault: (field) => {} },
"POLYGON", DECIMAL: { type: "DECIMAL", checkDefault: (field) => {} },
"MULTIPOINT", NUMERIC: { type: "NUMERIC", checkDefault: (field) => {} },
"MULTILINESTRING", REAL: { type: "REAL", checkDefault: (field) => {} },
"MULTIPOLYGON", "DOUBLE PRECISION": { type: "DOUBLE PRECISION", checkDefault: (field) => {} },
"GEOMETRYCOLLECTION", SMALLSERIAL: { type: "SMALLSERIAL", checkDefault: (field) => {} },
SERIAL: { type: "SERIAL", checkDefault: (field) => {} },
BIGSERIAL: { type: "BIGSERIAL", checkDefault: (field) => {} },
MONEY: { type: "MONEY", checkDefault: (field) => {} },
CHARACTER: { type: "CHARACTER", checkDefault: (field) => {} },
CHAR: { type: "CHAR", checkDefault: (field) => {} },
VARCHAR: { type: "VARCHAR", checkDefault: (field) => {} },
TEXT: { type: "TEXT", checkDefault: (field) => {} },
BYTEA: { type: "BYTEA", checkDefault: (field) => {} },
DATE: { type: "DATE", checkDefault: (field) => {} },
TIME: { type: "TIME", checkDefault: (field) => {} },
TIMESTAMP: { type: "TIMESTAMP", checkDefault: (field) => {} },
TIMESTAMPTZ: { type: "TIMESTAMPTZ", checkDefault: (field) => {} },
INTERVAL: { type: "INTERVAL", checkDefault: (field) => {} },
BOOLEAN: { type: "BOOLEAN", checkDefault: (field) => {} },
ENUM: { type: "ENUM", checkDefault: (field) => {} },
POINT: { type: "POINT", checkDefault: (field) => {} },
LINE: { type: "LINE", checkDefault: (field) => {} },
LSEG: { type: "LSEG", checkDefault: (field) => {} },
BOX: { type: "BOX", checkDefault: (field) => {} },
PATH: { type: "PATH", checkDefault: (field) => {} },
POLYGON: { type: "POLYGON", checkDefault: (field) => {} },
CIRCLE: { type: "CIRCLE", checkDefault: (field) => {} },
CIDR: { type: "CIDR", checkDefault: (field) => {} },
INET: { type: "INET", checkDefault: (field) => {} },
MACADDR: { type: "MACADDR", checkDefault: (field) => {} },
MACADDR8: { type: "", checkDefault: (field) => {} },
BIT: { type: "", checkDefault: (field) => {} },
VARBIT: { type: "", checkDefault: (field) => {} },
TSVECTOR: { type: "", checkDefault: (field) => {} },
TSQUERY: { type: "", checkDefault: (field) => {} },
JSON: { type: "", checkDefault: (field) => {} },
JSONB: { type: "", checkDefault: (field) => {} },
UUID: { type: "", checkDefault: (field) => {} },
XML: { type: "", checkDefault: (field) => {} },
ARRAY: { type: "", checkDefault: (field) => {} },
};
// JSON Data Type export const sqliteTypes = {
"JSON", INTEGER: { type: "INTEGER", checkDefault: (field) => {} },
]; REAL: { type: "REAL", checkDefault: (field) => {} },
TEXT: { type: "TEXT", checkDefault: (field) => {} },
BLOB: { type: "BLOB", checkDefault: (field) => {} },
NUMERIC: { type: "NUMERIC", checkDefault: (field) => {} },
BOOLEAN: { type: "BOOLEAN", checkDefault: (field) => {} },
DATE: { type: "DATE", checkDefault: (field) => {} },
DATETIME: { type: "DATETIME", checkDefault: (field) => {} },
TIME: { type: "TIME", checkDefault: (field) => {} },
TIMESTAMP: { type: "TIMESTAMP", checkDefault: (field) => {} },
};
export const postgresTypes = [ export const mariadbTypes = {
// Numeric Data Types TINYINT: { type: " ", checkDefault: (field) => {} },
"SMALLINT", SMALLINT: { type: "", checkDefault: (field) => {} },
"INTEGER", MEDIUMINT: { type: "", checkDefault: (field) => {} },
"BIGINT", INT: { type: "", checkDefault: (field) => {} },
"DECIMAL", INTEGER: { type: "", checkDefault: (field) => {} },
"NUMERIC", BIGINT: { type: "", checkDefault: (field) => {} },
"REAL", DECIMAL: { type: "", checkDefault: (field) => {} },
"DOUBLE PRECISION", NUMERIC: { type: "", checkDefault: (field) => {} },
"SMALLSERIAL", FLOAT: { type: "", checkDefault: (field) => {} },
"SERIAL", DOUBLE: { type: "", checkDefault: (field) => {} },
"BIGSERIAL", BIT: { type: "", checkDefault: (field) => {} },
"MONEY", BOOLEAN: { type: "", checkDefault: (field) => {} },
DATE: { type: "", checkDefault: (field) => {} },
DATETIME: { type: "", checkDefault: (field) => {} },
TIMESTAMP: { type: "", checkDefault: (field) => {} },
TIME: { type: "", checkDefault: (field) => {} },
YEAR: { type: "", checkDefault: (field) => {} },
CHAR: { type: "", checkDefault: (field) => {} },
VARCHAR: { type: "", checkDefault: (field) => {} },
BINARY: { type: "", checkDefault: (field) => {} },
VARBINARY: { type: "", checkDefault: (field) => {} },
TINYBLOB: { type: "", checkDefault: (field) => {} },
BLOB: { type: "", checkDefault: (field) => {} },
MEDIUMBLOB: { type: "", checkDefault: (field) => {} },
LONGBLOB: { type: "", checkDefault: (field) => {} },
TINYTEXT: { type: "", checkDefault: (field) => {} },
TEXT: { type: "", checkDefault: (field) => {} },
MEDIUMTEXT: { type: "", checkDefault: (field) => {} },
LONGTEXT: { type: "", checkDefault: (field) => {} },
ENUM: { type: "", checkDefault: (field) => {} },
SET: { type: "", checkDefault: (field) => {} },
GEOMETRY: { type: "", checkDefault: (field) => {} },
POINT: { type: "", checkDefault: (field) => {} },
LINESTRING: { type: "", checkDefault: (field) => {} },
POLYGON: { type: "", checkDefault: (field) => {} },
MULTIPOINT: { type: "", checkDefault: (field) => {} },
MULTILINESTRING: { type: "", checkDefault: (field) => {} },
MULTIPOLYGON: { type: "", checkDefault: (field) => {} },
GEOMETRYCOLLECTION: { type: "", checkDefault: (field) => {} },
JSON: { type: "", checkDefault: (field) => {} },
};
// Character Types export const mssqlTypes = {
"CHARACTER", BIGINT: { type: "", checkDefault: (field) => {} },
"CHAR", INT: { type: "", checkDefault: (field) => {} },
"VARCHAR", SMALLINT: { type: "", checkDefault: (field) => {} },
"TEXT", TINYINT: { type: "", checkDefault: (field) => {} },
BIT: { type: "", checkDefault: (field) => {} },
// Binary Data Types DECIMAL: { type: "", checkDefault: (field) => {} },
"BYTEA", NUMERIC: { type: "", checkDefault: (field) => {} },
MONEY: { type: "", checkDefault: (field) => {} },
// Date and Time Types SMALLMONEY: { type: "", checkDefault: (field) => {} },
"DATE", FLOAT: { type: "", checkDefault: (field) => {} },
"TIME", REAL: { type: "", checkDefault: (field) => {} },
"TIMESTAMP", DATE: { type: "", checkDefault: (field) => {} },
"TIMESTAMPTZ", TIME: { type: "", checkDefault: (field) => {} },
"INTERVAL", DATETIME: { type: "", checkDefault: (field) => {} },
DATETIME2: { type: "", checkDefault: (field) => {} },
// Boolean Type DATETIMEOFFSET: { type: "", checkDefault: (field) => {} },
"BOOLEAN", SMALLDATETIME: { type: "", checkDefault: (field) => {} },
TIMESTAMP: { type: "", checkDefault: (field) => {} },
// Enumerated Types CHAR: { type: "", checkDefault: (field) => {} },
"ENUM", VARCHAR: { type: "", checkDefault: (field) => {} },
TEXT: { type: "", checkDefault: (field) => {} },
// Geometric Types NCHAR: { type: "", checkDefault: (field) => {} },
"POINT", NVARCHAR: { type: "", checkDefault: (field) => {} },
"LINE", NTEXT: { type: "", checkDefault: (field) => {} },
"LSEG", BINARY: { type: "", checkDefault: (field) => {} },
"BOX", VARBINARY: { type: "", checkDefault: (field) => {} },
"PATH", IMAGE: { type: "", checkDefault: (field) => {} },
"POLYGON", UNIQUEIDENTIFIER: { type: "", checkDefault: (field) => {} },
"CIRCLE", XML: { type: "", checkDefault: (field) => {} },
CURSOR: { type: "", checkDefault: (field) => {} },
// Network Address Types TABLE: { type: "", checkDefault: (field) => {} },
"CIDR", SQL_VARIANT: { type: "", checkDefault: (field) => {} },
"INET", JSON: { type: "", checkDefault: (field) => {} },
"MACADDR", };
"MACADDR8",
// Bit String Types
"BIT",
"VARBIT",
// Text Search Types
"TSVECTOR",
"TSQUERY",
// JSON Types
"JSON",
"JSONB",
// UUID Type
"UUID",
// XML Type
"XML",
// Arrays
"ARRAY",
];
export const sqliteTypes = [
// Numeric Data Types
"INTEGER",
"REAL",
// Text Data Types
"TEXT",
// Blob Data Type
"BLOB",
// Affinity Types
"NUMERIC",
// Boolean Type (Alias of INTEGER)
"BOOLEAN",
// Date and Time Types (Recommended to store as TEXT)
"DATE",
"DATETIME",
"TIME",
"TIMESTAMP",
];
export const mariadbTypes = [
// Numeric Data Types
"TINYINT",
"SMALLINT",
"MEDIUMINT",
"INT",
"INTEGER",
"BIGINT",
"DECIMAL",
"NUMERIC",
"FLOAT",
"DOUBLE",
"BIT",
"BOOLEAN",
// Date and Time Data Types
"DATE",
"DATETIME",
"TIMESTAMP",
"TIME",
"YEAR",
// String Data Types
"CHAR",
"VARCHAR",
"BINARY",
"VARBINARY",
"TINYBLOB",
"BLOB",
"MEDIUMBLOB",
"LONGBLOB",
"TINYTEXT",
"TEXT",
"MEDIUMTEXT",
"LONGTEXT",
"ENUM",
"SET",
// Spatial Data Types
"GEOMETRY",
"POINT",
"LINESTRING",
"POLYGON",
"MULTIPOINT",
"MULTILINESTRING",
"MULTIPOLYGON",
"GEOMETRYCOLLECTION",
// JSON Data Type
"JSON",
];
export const mssqlTypes = [
// Exact Numeric Data Types
"BIGINT",
"INT",
"SMALLINT",
"TINYINT",
"BIT",
"DECIMAL",
"NUMERIC",
"MONEY",
"SMALLMONEY",
// Approximate Numeric Data Types
"FLOAT",
"REAL",
// Date and Time Data Types
"DATE",
"TIME",
"DATETIME",
"DATETIME2",
"DATETIMEOFFSET",
"SMALLDATETIME",
"TIMESTAMP",
// Character Strings
"CHAR",
"VARCHAR",
"TEXT",
// Unicode Character Strings
"NCHAR",
"NVARCHAR",
"NTEXT",
// Binary Data Types
"BINARY",
"VARBINARY",
"IMAGE",
// Other Data Types
"UNIQUEIDENTIFIER",
"XML",
"CURSOR",
"TABLE",
"SQL_VARIANT",
// JSON Data Type
"JSON", // Note: JSON is not a native type in MSSQL; it uses NVARCHAR to store JSON data
];
const dbToTypesBase = { const dbToTypesBase = {
generic: defaultTypes, generic: defaultTypes,

View File

@@ -1,86 +1,15 @@
import { dbToTypes } from "../data/datatypes";
import i18n from "../i18n/i18n"; import i18n from "../i18n/i18n";
import { isFunction, strHasQuotes } from "./utils"; import { isFunction } from "./utils";
function validateDateStr(str) { function checkDefault(field, database) {
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; if (field.default === "") return true;
if (isFunction(field.default)) return true; if (isFunction(field.default)) return true;
if (!field.notNull && field.default.toLowerCase() === "null") return true; if (!field.notNull && field.default.toLowerCase() === "null") return true;
switch (field.type) { return dbToTypes[database][field.type].checkDefault(field);
case "INT":
case "BIGINT":
case "SMALLINT":
return /^-?\d*$/.test(field.default);
case "SET": {
const defaultValues = field.default.split(",");
for (let i = 0; i < defaultValues.length; i++) {
if (!field.values.includes(defaultValues[i].trim())) return false;
}
return true;
}
case "ENUM":
return field.values.includes(field.default);
case "CHAR":
case "VARCHAR":
if (strHasQuotes(field.default)) {
return field.default.length - 2 <= field.size;
}
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().toLowerCase() === "false" ||
field.default.trim().toLowerCase() === "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 (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 c = field.default.split(" ");
const d = c[0].split("-");
return parseInt(d[0]) >= 1000 && parseInt(d[0]) <= 9999;
}
default:
return true;
}
} }
export function getIssues(diagram) { export function getIssues(diagram) {
@@ -123,7 +52,7 @@ export function getIssues(diagram) {
} }
} }
if (!checkDefault(field)) { if (!checkDefault(field, diagram.database)) {
issues.push( issues.push(
i18n.t("default_doesnt_match_type", { i18n.t("default_doesnt_match_type", {
tableName: table.name, tableName: table.name,

View File

@@ -1,8 +1,8 @@
import { defaultTypes } from "../data/datatypes"; import { dbToTypes, defaultTypes } from "../data/datatypes";
import { isFunction, isKeyword, strHasQuotes } from "./utils"; import { isFunction, isKeyword, strHasQuotes } from "./utils";
export function getJsonType(f) { export function getJsonType(f) {
if (!defaultTypes.includes(f.type)) { if (!Object.keys(defaultTypes).includes(f.type)) {
return '{ "type" : "object", additionalProperties : true }'; return '{ "type" : "object", additionalProperties : true }';
} }
switch (f.type) { switch (f.type) {
@@ -39,18 +39,26 @@ export 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}`;
} }
export function getTypeString(field, dbms = "mysql", baseType = false) { export function getTypeString(
field,
currentDb,
dbms = "mysql",
baseType = false,
) {
if (dbms === "mysql") { if (dbms === "mysql") {
if (field.type === "UUID") { if (field.type === "UUID") {
return `VARCHAR(36)`; return `VARCHAR(36)`;
} }
if (hasPrecision(field.type) || isSized(field.type)) { if (
dbToTypes[currentDb][field.type].isSized ||
dbToTypes[currentDb][field.type].hasPrecision
) {
return `${field.type}${field.size ? `(${field.size})` : ""}`; return `${field.type}${field.size ? `(${field.size})` : ""}`;
} }
if (field.type === "SET" || field.type === "ENUM") { if (field.type === "SET" || field.type === "ENUM") {
return `${field.type}(${field.values.map((v) => `"${v}"`).join(", ")})`; return `${field.type}(${field.values.map((v) => `"${v}"`).join(", ")})`;
} }
if (!defaultTypes.includes(field.type)) { if (!Object.keys(defaultTypes).includes(field.type)) {
return "JSON"; return "JSON";
} }
return field.type; return field.type;
@@ -76,7 +84,7 @@ export function getTypeString(field, dbms = "mysql", baseType = false) {
if (field.type === "DATETIME") { if (field.type === "DATETIME") {
return `timestamp`; return `timestamp`;
} }
if (isSized(field.type)) { if (dbToTypes[currentDb][field.type].isSized) {
const type = const type =
field.type === "BINARY" field.type === "BINARY"
? "bit" ? "bit"
@@ -85,7 +93,7 @@ export function getTypeString(field, dbms = "mysql", baseType = false) {
: field.type.toLowerCase(); : field.type.toLowerCase();
return `${type}(${field.size})`; return `${type}(${field.size})`;
} }
if (hasPrecision(field.type) && field.size !== "") { if (dbToTypes[currentDb][field.type].hasPrecision && field.size !== "") {
return `${field.type}${field.size}`; return `${field.type}${field.size}`;
} }
return field.type.toLowerCase(); return field.type.toLowerCase();
@@ -121,7 +129,7 @@ export function getTypeString(field, dbms = "mysql", baseType = false) {
type = field.type; type = field.type;
break; break;
} }
if (isSized(field.type)) { if (dbToTypes[currentDb][field.type].isSized) {
return `${type}(${field.size})`; return `${type}(${field.size})`;
} }
@@ -167,13 +175,14 @@ export function jsonToMySQL(obj) {
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${ `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${
field.name field.name
}\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${ }\` ${getTypeString(field, obj.database)}${field.notNull ? " NOT NULL" : ""}${
field.increment ? " AUTO_INCREMENT" : "" field.increment ? " AUTO_INCREMENT" : ""
}${field.unique ? " UNIQUE" : ""}${ }${field.unique ? " UNIQUE" : ""}${
field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : "" field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : ""
}${ }${
field.check === "" || !hasCheck(field.type) field.check === "" ||
? !defaultTypes.includes(field.type) !dbToTypes[obj.database][field.type].hasCheck
? !Object.keys(defaultTypes).includes(field.type)
? ` CHECK(\n\t\tJSON_SCHEMA_VALID("${generateSchema( ? ` CHECK(\n\t\tJSON_SCHEMA_VALID("${generateSchema(
obj.types.find( obj.types.find(
(t) => t.name === field.type.toLowerCase(), (t) => t.name === field.type.toLowerCase(),
@@ -181,7 +190,7 @@ export function jsonToMySQL(obj) {
)}", \`${field.name}\`))` )}", \`${field.name}\`))`
: "" : ""
: ` CHECK(${field.check})` : ` CHECK(${field.check})`
}${field.comment ? ` COMMENT '${field.comment}'` : ''}`, }${field.comment ? ` COMMENT '${field.comment}'` : ""}`,
) )
.join(",\n")}${ .join(",\n")}${
table.fields.filter((f) => f.primary).length > 0 table.fields.filter((f) => f.primary).length > 0
@@ -190,7 +199,7 @@ export function jsonToMySQL(obj) {
.map((f) => `\`${f.name}\``) .map((f) => `\`${f.name}\``)
.join(", ")})` .join(", ")})`
: "" : ""
}\n)${table.comment ? ` COMMENT='${table.comment}'` : ''};\n${ }\n)${table.comment ? ` COMMENT='${table.comment}'` : ""};\n${
table.indices.length > 0 table.indices.length > 0
? `\n${table.indices.map( ? `\n${table.indices.map(
(i) => (i) =>
@@ -233,14 +242,16 @@ export function jsonToPostgreSQL(obj) {
`${ `${
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, obj.database, "postgres")}`,
)
.join("\n")}\n);` .join("\n")}\n);`
); );
} else { } else {
return `${ return `${
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, obj.database, "postgres")}`)
.join("\n")}\n);`; .join("\n")}\n);`;
} }
})}\n${obj.tables })}\n${obj.tables
@@ -263,12 +274,13 @@ export function jsonToPostgreSQL(obj) {
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${ `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${
field.name field.name
}" ${getTypeString(field, "postgres")}${ }" ${getTypeString(field, obj.database, "postgres")}${
field.notNull ? " NOT NULL" : "" field.notNull ? " NOT NULL" : ""
}${ }${
field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : "" field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : ""
}${ }${
field.check === "" || !hasCheck(field.type) field.check === "" ||
!dbToTypes[obj.database][field.type].hasCheck
? "" ? ""
: ` CHECK(${field.check})` : ` CHECK(${field.check})`
}`, }`,
@@ -367,7 +379,8 @@ export function jsonToSQLite(obj) {
}" ${getSQLiteType(field)}${field.notNull ? " NOT NULL" : ""}${ }" ${getSQLiteType(field)}${field.notNull ? " NOT NULL" : ""}${
field.unique ? " UNIQUE" : "" field.unique ? " UNIQUE" : ""
}${field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : ""}${ }${field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : ""}${
field.check === "" || !hasCheck(field.type) field.check === "" ||
!dbToTypes[obj.database][field.type].hasCheck
? "" ? ""
: ` CHECK(${field.check})` : ` CHECK(${field.check})`
}`, }`,
@@ -408,13 +421,14 @@ export function jsonToMariaDB(obj) {
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${ `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${
field.name field.name
}\` ${getTypeString(field)}${field.notNull ? " NOT NULL" : ""}${ }\` ${getTypeString(field, obj.database)}${field.notNull ? " NOT NULL" : ""}${
field.increment ? " AUTO_INCREMENT" : "" field.increment ? " AUTO_INCREMENT" : ""
}${field.unique ? " UNIQUE" : ""}${ }${field.unique ? " UNIQUE" : ""}${
field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : "" field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : ""
}${ }${
field.check === "" || !hasCheck(field.type) field.check === "" ||
? !defaultTypes.includes(field.type) !dbToTypes[obj.database][field.type].hasCheck
? !Object.keys(defaultTypes).includes(field.type)
? ` CHECK(\n\t\tJSON_SCHEMA_VALID('${generateSchema( ? ` CHECK(\n\t\tJSON_SCHEMA_VALID('${generateSchema(
obj.types.find( obj.types.find(
(t) => t.name === field.type.toLowerCase(), (t) => t.name === field.type.toLowerCase(),
@@ -466,7 +480,7 @@ export function jsonToSQLServer(obj) {
}CREATE TYPE [${type.name}] FROM ${ }CREATE TYPE [${type.name}] FROM ${
type.fields.length < 0 type.fields.length < 0
? "" ? ""
: `${getTypeString(type.fields[0], "mssql", true)}` : `${getTypeString(type.fields[0], obj.database, "mssql", true)}`
};\nGO\n`; };\nGO\n`;
}) })
.join("\n")}\n${obj.tables .join("\n")}\n${obj.tables
@@ -479,14 +493,15 @@ export function jsonToSQLServer(obj) {
(field) => (field) =>
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t[${ `${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t[${
field.name field.name
}] ${getTypeString(field, "mssql")}${ }] ${getTypeString(field, obj.database, "mssql")}${
field.notNull ? " NOT NULL" : "" field.notNull ? " NOT NULL" : ""
}${field.increment ? " IDENTITY" : ""}${ }${field.increment ? " IDENTITY" : ""}${
field.unique ? " UNIQUE" : "" field.unique ? " UNIQUE" : ""
}${ }${
field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : "" field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : ""
}${ }${
field.check === "" || !hasCheck(field.type) field.check === "" ||
!dbToTypes[obj.database][field.type].hasCheck
? "" ? ""
: ` CHECK(${field.check})` : ` CHECK(${field.check})`
}`, }`,
@@ -522,41 +537,3 @@ export function jsonToSQLServer(obj) {
) )
.join("\n")}`; .join("\n")}`;
} }
export function isSized(type) {
return ["CHAR", "VARCHAR", "BINARY", "VARBINARY", "TEXT"].includes(type);
}
export function hasPrecision(type) {
return ["DOUBLE", "NUMERIC", "DECIMAL", "FLOAT"].includes(type);
}
export function hasCheck(type) {
return [
"INT",
"SMALLINT",
"BIGINT",
"CHAR",
"VARCHAR",
"FLOAT",
"DECIMAL",
"DOUBLE",
"NUMERIC",
"REAL",
].includes(type);
}
export function getSize(type) {
switch (type) {
case "CHAR":
case "BINARY":
return 1;
case "VARCHAR":
case "VARBINARY":
return 255;
case "TEXT":
return 65535;
default:
return "";
}
}