diff --git a/src/assets/mariadb-icon.png b/src/assets/mariadb-icon.png new file mode 100644 index 0000000..a91ea73 Binary files /dev/null and b/src/assets/mariadb-icon.png differ diff --git a/src/assets/mssql-icon.png b/src/assets/mssql-icon.png new file mode 100644 index 0000000..8a450f8 Binary files /dev/null and b/src/assets/mssql-icon.png differ diff --git a/src/assets/mysql-icon.png b/src/assets/mysql-icon.png new file mode 100644 index 0000000..3b406cf Binary files /dev/null and b/src/assets/mysql-icon.png differ diff --git a/src/assets/postgres-icon.png b/src/assets/postgres-icon.png new file mode 100644 index 0000000..be7d437 Binary files /dev/null and b/src/assets/postgres-icon.png differ diff --git a/src/assets/sql-server.png b/src/assets/sql-server.png index 8c55a1a..2ceda69 100644 Binary files a/src/assets/sql-server.png and b/src/assets/sql-server.png differ diff --git a/src/assets/sqlite-icon.png b/src/assets/sqlite-icon.png new file mode 100644 index 0000000..f432730 Binary files /dev/null and b/src/assets/sqlite-icon.png differ diff --git a/src/components/EditorSidePanel/TablesTab/TableField.jsx b/src/components/EditorSidePanel/TablesTab/TableField.jsx index ef4f6de..9440118 100644 --- a/src/components/EditorSidePanel/TablesTab/TableField.jsx +++ b/src/components/EditorSidePanel/TablesTab/TableField.jsx @@ -1,4 +1,4 @@ -import { Action, ObjectType, sqlDataTypes } from "../../../data/constants"; +import { Action, ObjectType } from "../../../data/constants"; import { Row, Col, Input, Button, Popover, Select } from "@douyinfe/semi-ui"; import { IconMore, IconKeyStroked } from "@douyinfe/semi-icons"; import { getSize, hasCheck, hasPrecision, isSized } from "../../../utils/toSQL"; @@ -6,11 +6,12 @@ import { useTables, useTypes, useUndoRedo } from "../../../hooks"; import { useState } from "react"; import FieldDetails from "./FieldDetails"; import { useTranslation } from "react-i18next"; +import { dbToTypes } from "../../../data/datatypes"; export default function TableField({ data, tid, index }) { const { updateField } = useTables(); const { types } = useTypes(); - const { tables } = useTables(); + const { tables, database } = useTables(); const { t } = useTranslation(); const { setUndoStack, setRedoStack } = useUndoRedo(); const [editField, setEditField] = useState({}); @@ -50,7 +51,7 @@ export default function TableField({ data, tid, index }) { ({ + ...dbToTypes[database].map((value) => ({ label: value, value: value, })), diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index 9aa9447..62a8e8e 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -17,6 +17,9 @@ import { useSaveState, } from "../hooks"; import FloatingControls from "./FloatingControls"; +import { Modal } from "@douyinfe/semi-ui"; +import { useTranslation } from "react-i18next"; +import { databases } from "../data/databases"; export default function WorkSpace() { const [id, setId] = useState(0); @@ -24,6 +27,8 @@ export default function WorkSpace() { const [resize, setResize] = useState(false); const [width, setWidth] = useState(340); const [lastSaved, setLastSaved] = useState(""); + const [showSelectDbModal, setShowSelectDbModal] = useState(false); + const [selectedDb, setSelectedDb] = useState(""); const { layout } = useLayout(); const { settings } = useSettings(); const { types, setTypes } = useTypes(); @@ -32,8 +37,10 @@ export default function WorkSpace() { const { notes, setNotes } = useNotes(); const { saveState, setSaveState } = useSaveState(); const { transform, setTransform } = useTransform(); - const { tables, relationships, setTables, setRelationships } = useTables(); + const { tables, relationships, setTables, setRelationships, setDatabase } = + useTables(); const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo(); + const { t } = useTranslation(); const handleResize = (e) => { if (!resize) return; @@ -130,6 +137,9 @@ export default function WorkSpace() { .last() .then((d) => { if (d) { + if (!d.database) { + setShowSelectDbModal(true); + } setId(d.id); setTitle(d.name); setTables(d.tables); @@ -154,6 +164,9 @@ export default function WorkSpace() { .get(id) .then((diagram) => { if (diagram) { + if (!diagram.database) { + setShowSelectDbModal(true); + } setId(diagram.id); setTitle(diagram.name); setTables(diagram.tables); @@ -304,6 +317,46 @@ export default function WorkSpace() { )} + { + setDatabase(selectedDb); + setShowSelectDbModal(false); + }} + visible={showSelectDbModal} + > +
+ {databases.map((x) => ( +
setSelectedDb(x.label)} + className={`space-y-3 py-3 px-4 rounded-md border-2 ${ + settings.mode === "dark" + ? "bg-zinc-700 hover:bg-zinc-600" + : "bg-zinc-100 hover:bg-zinc-200" + } ${selectedDb === x.label ? "border-zinc-400" : "border-transparent"}`} + > +
{x.name}
+ {x.image && ( + + )} +
{x.description}
+
+ ))} +
+
); } diff --git a/src/context/TablesContext.jsx b/src/context/TablesContext.jsx index 564745e..bba9344 100644 --- a/src/context/TablesContext.jsx +++ b/src/context/TablesContext.jsx @@ -10,6 +10,7 @@ export const TablesContext = createContext(null); export default function TablesContextProvider({ children }) { const { t } = useTranslation(); + const [database, setDatabase] = useState(""); const [tables, setTables] = useState([]); const [relationships, setRelationships] = useState([]); const { transform } = useTransform(); @@ -261,6 +262,8 @@ export default function TablesContextProvider({ children }) { setRelationships, addRelationship, deleteRelationship, + database, + setDatabase, }} > {children} diff --git a/src/data/constants.js b/src/data/constants.js index 480b1ba..71ef058 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -1,31 +1,5 @@ import i18n from "../i18n/i18n"; -export const sqlDataTypes = [ - "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 tableThemes = [ "#f03c3c", "#ff4f81", diff --git a/src/data/databases.js b/src/data/databases.js new file mode 100644 index 0000000..f4e66b9 --- /dev/null +++ b/src/data/databases.js @@ -0,0 +1,40 @@ +import mysqlImage from "../assets/mysql-icon.png"; +import postgresImage from "../assets/postgres-icon.png"; +import sqliteImage from "../assets/sqlite-icon.png"; +import mariadbImage from "../assets/mariadb-icon.png"; +import mssqlImage from "../assets/mssql-icon.png"; + +export const databases = [ + { + name: "MySQL", + label: "mysql", + image: mysqlImage, + }, + { + name: "PostgreSQL", + label: "postgresql", + image: postgresImage, + }, + { + name: "SQLite", + label: "sqlite", + image: sqliteImage, + }, + { + name: "MariaDB", + label: "mariadb", + image: mariadbImage, + }, + { + name: "MSSQL", + label: "mssql", + image: mssqlImage, + }, + { + name: "Generic", + label: "generic", + image: null, + description: + "Generic diagrams can be exported to any SQL flavor but support few data types.", + }, +]; diff --git a/src/data/datatypes.js b/src/data/datatypes.js new file mode 100644 index 0000000..5596902 --- /dev/null +++ b/src/data/datatypes.js @@ -0,0 +1,290 @@ +export const defaultTypes = [ + "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 = [ + // 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 postgresTypes = [ + // Numeric Data Types + "SMALLINT", + "INTEGER", + "BIGINT", + "DECIMAL", + "NUMERIC", + "REAL", + "DOUBLE PRECISION", + "SMALLSERIAL", + "SERIAL", + "BIGSERIAL", + "MONEY", + + // Character Types + "CHARACTER", + "CHAR", + "VARCHAR", + "TEXT", + + // Binary Data Types + "BYTEA", + + // Date and Time Types + "DATE", + "TIME", + "TIMESTAMP", + "TIMESTAMPTZ", + "INTERVAL", + + // Boolean Type + "BOOLEAN", + + // Enumerated Types + "ENUM", + + // Geometric Types + "POINT", + "LINE", + "LSEG", + "BOX", + "PATH", + "POLYGON", + "CIRCLE", + + // Network Address Types + "CIDR", + "INET", + "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 = { + generic: defaultTypes, + mysql: mysqlTypes, + postgresql: postgresTypes, + sqlite: sqliteTypes, + mssql: mssqlTypes, + mariadb: mariadbTypes, +}; + +export const dbToTypes = new Proxy(dbToTypesBase, { + get: (target, prop) => (prop in target ? target[prop] : []), +}); diff --git a/src/pages/LandingPage.jsx b/src/pages/LandingPage.jsx index 1d7cd2e..6ad3ab6 100644 --- a/src/pages/LandingPage.jsx +++ b/src/pages/LandingPage.jsx @@ -197,7 +197,7 @@ export default function LandingPage() { />
diff --git a/src/utils/toSQL.js b/src/utils/toSQL.js index 2ad4961..5369488 100644 --- a/src/utils/toSQL.js +++ b/src/utils/toSQL.js @@ -1,8 +1,8 @@ -import { sqlDataTypes } from "../data/constants"; +import { defaultTypes } from "../data/datatypes"; import { isFunction, isKeyword, strHasQuotes } from "./utils"; export function getJsonType(f) { - if (!sqlDataTypes.includes(f.type)) { + if (!defaultTypes.includes(f.type)) { return '{ "type" : "object", additionalProperties : true }'; } switch (f.type) { @@ -50,7 +50,7 @@ export function getTypeString(field, dbms = "mysql", baseType = false) { if (field.type === "SET" || field.type === "ENUM") { return `${field.type}(${field.values.map((v) => `"${v}"`).join(", ")})`; } - if (!sqlDataTypes.includes(field.type)) { + if (!defaultTypes.includes(field.type)) { return "JSON"; } return field.type; @@ -173,7 +173,7 @@ export function jsonToMySQL(obj) { field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : "" }${ field.check === "" || !hasCheck(field.type) - ? !sqlDataTypes.includes(field.type) + ? !defaultTypes.includes(field.type) ? ` CHECK(\n\t\tJSON_SCHEMA_VALID("${generateSchema( obj.types.find( (t) => t.name === field.type.toLowerCase(), @@ -414,7 +414,7 @@ export function jsonToMariaDB(obj) { field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : "" }${ field.check === "" || !hasCheck(field.type) - ? !sqlDataTypes.includes(field.type) + ? !defaultTypes.includes(field.type) ? ` CHECK(\n\t\tJSON_SCHEMA_VALID('${generateSchema( obj.types.find( (t) => t.name === field.type.toLowerCase(),