mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-05-23 17:59:19 +00:00
feat:Added support for exporting SQL as OracleDB SQL (#192)
* feat:Added support for exporting SQL as OracleDB SQL * Add parser * Import from sql * Add beta tag * Export from generic * Fix export * Add import affinity --------- Co-authored-by: 1ilit <1ilit@proton.me>
This commit is contained in:
parent
fcc16bbe85
commit
16ea2ee23c
7
package-lock.json
generated
7
package-lock.json
generated
@ -32,6 +32,7 @@
|
||||
"lexical": "^0.12.5",
|
||||
"node-sql-parser": "^5.3.8",
|
||||
"octokit": "^4.0.2",
|
||||
"oracle-sql-parser": "^0.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hotkeys-hook": "^4.4.1",
|
||||
@ -5373,6 +5374,12 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/oracle-sql-parser": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/oracle-sql-parser/-/oracle-sql-parser-0.1.0.tgz",
|
||||
"integrity": "sha512-8MLYOJIKaOY1cWvnMFuYPxWcDH5GfmJMh/f1Tyow0bydC31heO+eSoexZW+NJBSdK87lNJl8nsQ/SY//ZGOwcQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
|
@ -34,6 +34,7 @@
|
||||
"lexical": "^0.12.5",
|
||||
"node-sql-parser": "^5.3.8",
|
||||
"octokit": "^4.0.2",
|
||||
"oracle-sql-parser": "^0.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hotkeys-hook": "^4.4.1",
|
||||
|
BIN
src/assets/oraclesql-icon.png
Normal file
BIN
src/assets/oraclesql-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/oraclesql.png
Normal file
BIN
src/assets/oraclesql.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -20,6 +20,7 @@ import {
|
||||
InputNumber,
|
||||
Tooltip,
|
||||
Spin,
|
||||
Tag,
|
||||
Toast,
|
||||
Popconfirm,
|
||||
} from "@douyinfe/semi-ui";
|
||||
@ -30,6 +31,7 @@ import {
|
||||
jsonToSQLite,
|
||||
jsonToMariaDB,
|
||||
jsonToSQLServer,
|
||||
jsonToOracleSQL,
|
||||
} from "../../utils/exportSQL/generic";
|
||||
import {
|
||||
ObjectType,
|
||||
@ -793,13 +795,15 @@ export default function ControlPanel({
|
||||
import_from: {
|
||||
children: [
|
||||
{
|
||||
JSON: fileImport,
|
||||
function: fileImport,
|
||||
name: "JSON",
|
||||
},
|
||||
{
|
||||
DBML: () => {
|
||||
function: () => {
|
||||
setModal(MODAL.IMPORT);
|
||||
setImportFrom(IMPORT_FROM.DBML);
|
||||
},
|
||||
name: "DBML",
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -807,34 +811,47 @@ export default function ControlPanel({
|
||||
...(database === DB.GENERIC && {
|
||||
children: [
|
||||
{
|
||||
MySQL: () => {
|
||||
function: () => {
|
||||
setModal(MODAL.IMPORT_SRC);
|
||||
setImportDb(DB.MYSQL);
|
||||
},
|
||||
name: "MySQL",
|
||||
},
|
||||
{
|
||||
PostgreSQL: () => {
|
||||
function: () => {
|
||||
setModal(MODAL.IMPORT_SRC);
|
||||
setImportDb(DB.POSTGRES);
|
||||
},
|
||||
name: "PostgreSQL",
|
||||
},
|
||||
{
|
||||
SQLite: () => {
|
||||
function: () => {
|
||||
setModal(MODAL.IMPORT_SRC);
|
||||
setImportDb(DB.SQLITE);
|
||||
},
|
||||
name: "SQLite",
|
||||
},
|
||||
{
|
||||
MariaDB: () => {
|
||||
function: () => {
|
||||
setModal(MODAL.IMPORT_SRC);
|
||||
setImportDb(DB.MARIADB);
|
||||
},
|
||||
name: "MariaDB",
|
||||
},
|
||||
{
|
||||
MSSQL: () => {
|
||||
function: () => {
|
||||
setModal(MODAL.IMPORT_SRC);
|
||||
setImportDb(DB.MSSQL);
|
||||
},
|
||||
name: "MSSQL",
|
||||
},
|
||||
{
|
||||
function: () => {
|
||||
setModal(MODAL.IMPORT_SRC);
|
||||
setImportDb(DB.ORACLESQL);
|
||||
},
|
||||
name: "Oracle",
|
||||
label: "Beta",
|
||||
},
|
||||
],
|
||||
}),
|
||||
@ -848,7 +865,8 @@ export default function ControlPanel({
|
||||
...(database === DB.GENERIC && {
|
||||
children: [
|
||||
{
|
||||
MySQL: () => {
|
||||
name: "MySQL",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const src = jsonToMySQL({
|
||||
tables: tables,
|
||||
@ -864,7 +882,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
PostgreSQL: () => {
|
||||
name: "PostgreSQL",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const src = jsonToPostgreSQL({
|
||||
tables: tables,
|
||||
@ -880,7 +899,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
SQLite: () => {
|
||||
name: "SQLite",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const src = jsonToSQLite({
|
||||
tables: tables,
|
||||
@ -896,7 +916,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
MariaDB: () => {
|
||||
name: "MariaDB",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const src = jsonToMariaDB({
|
||||
tables: tables,
|
||||
@ -912,7 +933,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
MSSQL: () => {
|
||||
name: "MSSQL",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const src = jsonToSQLServer({
|
||||
tables: tables,
|
||||
@ -927,6 +949,24 @@ export default function ControlPanel({
|
||||
}));
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Beta",
|
||||
name: "Oracle",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const src = jsonToOracleSQL({
|
||||
tables: tables,
|
||||
references: relationships,
|
||||
types: types,
|
||||
database: database,
|
||||
});
|
||||
setExportData((prev) => ({
|
||||
...prev,
|
||||
data: src,
|
||||
extension: "sql",
|
||||
}));
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
function: () => {
|
||||
@ -949,7 +989,8 @@ export default function ControlPanel({
|
||||
export_as: {
|
||||
children: [
|
||||
{
|
||||
PNG: () => {
|
||||
name: "PNG",
|
||||
function: () => {
|
||||
toPng(document.getElementById("canvas")).then(function (dataUrl) {
|
||||
setExportData((prev) => ({
|
||||
...prev,
|
||||
@ -961,7 +1002,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
JPEG: () => {
|
||||
name: "JPEG",
|
||||
function: () => {
|
||||
toJpeg(document.getElementById("canvas"), { quality: 0.95 }).then(
|
||||
function (dataUrl) {
|
||||
setExportData((prev) => ({
|
||||
@ -975,7 +1017,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
SVG: () => {
|
||||
name: "SVG",
|
||||
function: () => {
|
||||
const filter = (node) => node.tagName !== "i";
|
||||
toSvg(document.getElementById("canvas"), { filter: filter }).then(
|
||||
function (dataUrl) {
|
||||
@ -990,7 +1033,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
JSON: () => {
|
||||
name: "JSON",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const result = JSON.stringify(
|
||||
{
|
||||
@ -1014,7 +1058,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
DBML: () => {
|
||||
name: "DBML",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const result = toDBML({
|
||||
tables,
|
||||
@ -1029,7 +1074,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
PDF: () => {
|
||||
name: "PDF",
|
||||
function: () => {
|
||||
const canvas = document.getElementById("canvas");
|
||||
toJpeg(canvas).then(function (dataUrl) {
|
||||
const doc = new jsPDF("l", "px", [
|
||||
@ -1049,7 +1095,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
MERMAID: () => {
|
||||
name: "Mermaid",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const result = jsonToMermaid({
|
||||
tables: tables,
|
||||
@ -1067,7 +1114,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
readme: () => {
|
||||
name: "Markdown",
|
||||
function: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const result = jsonToDocumentation({
|
||||
tables: tables,
|
||||
@ -1271,7 +1319,8 @@ export default function ControlPanel({
|
||||
theme: {
|
||||
children: [
|
||||
{
|
||||
light: () => {
|
||||
name: t("light"),
|
||||
function: () => {
|
||||
const body = document.body;
|
||||
if (body.hasAttribute("theme-mode")) {
|
||||
body.setAttribute("theme-mode", "light");
|
||||
@ -1281,7 +1330,8 @@ export default function ControlPanel({
|
||||
},
|
||||
},
|
||||
{
|
||||
dark: () => {
|
||||
name: t("dark"),
|
||||
function: () => {
|
||||
const body = document.body;
|
||||
if (body.hasAttribute("theme-mode")) {
|
||||
body.setAttribute("theme-mode", "dark");
|
||||
@ -1602,9 +1652,9 @@ export default function ControlPanel({
|
||||
const body = document.body;
|
||||
if (body.hasAttribute("theme-mode")) {
|
||||
if (body.getAttribute("theme-mode") === "light") {
|
||||
menu["view"]["theme"].children[1]["dark"]();
|
||||
menu["view"]["theme"].children[1].function();
|
||||
} else {
|
||||
menu["view"]["theme"].children[0]["light"]();
|
||||
menu["view"]["theme"].children[0].function();
|
||||
}
|
||||
}
|
||||
}}
|
||||
@ -1703,7 +1753,7 @@ export default function ControlPanel({
|
||||
if (menu[category][item].children) {
|
||||
return (
|
||||
<Dropdown
|
||||
style={{ width: "120px" }}
|
||||
style={{ width: "150px" }}
|
||||
key={item}
|
||||
position="rightTop"
|
||||
render={
|
||||
@ -1712,9 +1762,18 @@ export default function ControlPanel({
|
||||
(e, i) => (
|
||||
<Dropdown.Item
|
||||
key={i}
|
||||
onClick={Object.values(e)[0]}
|
||||
onClick={e.function}
|
||||
className="flex justify-between"
|
||||
>
|
||||
{t(Object.keys(e)[0])}
|
||||
<span>{e.name}</span>
|
||||
{e.label && (
|
||||
<Tag
|
||||
size="small"
|
||||
color="light-blue"
|
||||
>
|
||||
{e.label}
|
||||
</Tag>
|
||||
)}
|
||||
</Dropdown.Item>
|
||||
),
|
||||
)}
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
} from "../../../hooks";
|
||||
import { saveAs } from "file-saver";
|
||||
import { Parser } from "node-sql-parser";
|
||||
import { Parser as OracleParser } from "oracle-sql-parser";
|
||||
import {
|
||||
getModalTitle,
|
||||
getModalWidth,
|
||||
@ -131,12 +132,21 @@ export default function Modal({
|
||||
};
|
||||
|
||||
const parseSQLAndLoadDiagram = () => {
|
||||
const parser = new Parser();
|
||||
const targetDatabase = database === DB.GENERIC ? importDb : database;
|
||||
|
||||
let ast = null;
|
||||
try {
|
||||
ast = parser.astify(importSource.src, {
|
||||
database: database === DB.GENERIC ? importDb : database,
|
||||
});
|
||||
if (targetDatabase === DB.ORACLESQL) {
|
||||
const oracleParser = new OracleParser();
|
||||
|
||||
ast = oracleParser.parse(importSource.src);
|
||||
} else {
|
||||
const parser = new Parser();
|
||||
|
||||
ast = parser.astify(importSource.src, {
|
||||
database: targetDatabase,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error.location
|
||||
? `${error.name} [Ln ${error.location.start.line}, Col ${error.location.start.column}]: ${error.message}`
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
useEnums,
|
||||
} from "../hooks";
|
||||
import FloatingControls from "./FloatingControls";
|
||||
import { Modal } from "@douyinfe/semi-ui";
|
||||
import { Modal, Tag } from "@douyinfe/semi-ui";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { databases } from "../data/databases";
|
||||
import { isRtl } from "../i18n/utils/rtl";
|
||||
@ -161,7 +161,7 @@ export default function WorkSpace() {
|
||||
enums,
|
||||
gistId,
|
||||
loadedFromGistId,
|
||||
saveState
|
||||
saveState,
|
||||
]);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
@ -467,17 +467,24 @@ export default function WorkSpace() {
|
||||
<div
|
||||
key={x.name}
|
||||
onClick={() => setSelectedDb(x.label)}
|
||||
className={`space-y-3 py-3 px-4 rounded-md border-2 select-none ${
|
||||
className={`space-y-3 p-3 rounded-md border-2 select-none ${
|
||||
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"}`}
|
||||
>
|
||||
<div className="font-semibold">{x.name}</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="font-semibold">{x.name}</div>
|
||||
{x.beta && (
|
||||
<Tag size="small" color="light-blue">
|
||||
Beta
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
{x.image && (
|
||||
<img
|
||||
src={x.image}
|
||||
className="h-10"
|
||||
className="h-8"
|
||||
style={{
|
||||
filter:
|
||||
"opacity(0.4) drop-shadow(0 0 0 white) drop-shadow(0 0 0 white)",
|
||||
|
@ -113,6 +113,7 @@ export const DB = {
|
||||
MSSQL: "transactsql",
|
||||
SQLITE: "sqlite",
|
||||
MARIADB: "mariadb",
|
||||
ORACLESQL: "oraclesql",
|
||||
GENERIC: "generic",
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@ 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";
|
||||
import oraclesqlImage from "../assets/oraclesql-icon.png";
|
||||
import i18n from "../i18n/i18n";
|
||||
import { DB } from "./constants";
|
||||
|
||||
@ -42,6 +43,15 @@ export const databases = new Proxy(
|
||||
image: mssqlImage,
|
||||
hasTypes: false,
|
||||
},
|
||||
[DB.ORACLESQL]: {
|
||||
name: "Oracle SQL",
|
||||
label: DB.ORACLESQL,
|
||||
image: oraclesqlImage,
|
||||
hasTypes: false,
|
||||
hasEnums: false,
|
||||
hasArrays: false,
|
||||
beta: true,
|
||||
},
|
||||
[DB.GENERIC]: {
|
||||
name: i18n.t("generic"),
|
||||
label: DB.GENERIC,
|
||||
|
@ -55,6 +55,16 @@ const defaultTypesBase = {
|
||||
isSized: false,
|
||||
hasPrecision: true,
|
||||
},
|
||||
NUMBER: {
|
||||
type: "NUMBER",
|
||||
checkDefault: (field) => {
|
||||
return /^-?\d+(\.\d+)?$/.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: true,
|
||||
canIncrement: false,
|
||||
},
|
||||
FLOAT: {
|
||||
type: "FLOAT",
|
||||
checkDefault: (field) => {
|
||||
@ -110,6 +120,20 @@ const defaultTypesBase = {
|
||||
defaultSize: 255,
|
||||
hasQuotes: true,
|
||||
},
|
||||
VARCHAR2: {
|
||||
type: "VARCHAR2",
|
||||
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: 225,
|
||||
hasQuotes: true,
|
||||
},
|
||||
TEXT: {
|
||||
type: "TEXT",
|
||||
checkDefault: (field) => true,
|
||||
@ -140,7 +164,9 @@ const defaultTypesBase = {
|
||||
}
|
||||
const content = field.default.split(" ");
|
||||
const date = content[0].split("-");
|
||||
return Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038;
|
||||
return (
|
||||
Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
@ -223,6 +249,22 @@ const defaultTypesBase = {
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
CLOB: {
|
||||
type: "CLOB",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
NCLOB: {
|
||||
type: "NCLOB",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
JSON: {
|
||||
type: "JSON",
|
||||
checkDefault: (field) => true,
|
||||
@ -405,7 +447,9 @@ const mysqlTypesBase = {
|
||||
}
|
||||
const content = field.default.split(" ");
|
||||
const date = content[0].split("-");
|
||||
return Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038;
|
||||
return (
|
||||
Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
@ -913,8 +957,9 @@ const postgresTypesBase = {
|
||||
checkDefault: (field) => {
|
||||
const specialValues = ["now", "allballs"];
|
||||
return (
|
||||
/^(?:[01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d([+-]\d{2}:\d{2})?$/.test(field.default) ||
|
||||
specialValues.includes(field.default.toLowerCase())
|
||||
/^(?:[01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d([+-]\d{2}:\d{2})?$/.test(
|
||||
field.default,
|
||||
) || specialValues.includes(field.default.toLowerCase())
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
@ -939,7 +984,8 @@ const postgresTypesBase = {
|
||||
];
|
||||
return (
|
||||
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(field.default) ||
|
||||
(Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038) ||
|
||||
(Number.parseInt(date[0]) >= 1970 &&
|
||||
Number.parseInt(date[0]) <= 2038) ||
|
||||
specialValues.includes(field.default.toLowerCase())
|
||||
);
|
||||
},
|
||||
@ -1118,7 +1164,11 @@ const postgresTypesBase = {
|
||||
elementsStr = field.default.slice(1, -1);
|
||||
}
|
||||
elements = JSON.parse(elementsStr);
|
||||
return Array.isArray(elements) && elements.length === field.size && elements.every(Number.isFinite);
|
||||
return (
|
||||
Array.isArray(elements) &&
|
||||
elements.length === field.size &&
|
||||
elements.every(Number.isFinite)
|
||||
);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
@ -1128,7 +1178,7 @@ const postgresTypesBase = {
|
||||
hasPrecision: false,
|
||||
hasQuotes: true,
|
||||
},
|
||||
HALFVEC:{
|
||||
HALFVEC: {
|
||||
type: "HALFVEC",
|
||||
checkDefault: (field) => {
|
||||
let elements;
|
||||
@ -1138,7 +1188,11 @@ const postgresTypesBase = {
|
||||
elementsStr = field.default.slice(1, -1);
|
||||
}
|
||||
elements = JSON.parse(elementsStr);
|
||||
return Array.isArray(elements) && elements.length === field.size && elements.every(Number.isFinite);
|
||||
return (
|
||||
Array.isArray(elements) &&
|
||||
elements.length === field.size &&
|
||||
elements.every(Number.isFinite)
|
||||
);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
@ -1155,9 +1209,9 @@ const postgresTypesBase = {
|
||||
if (strHasQuotes(field.default)) {
|
||||
elementsStr = field.default.slice(1, -1);
|
||||
}
|
||||
const lengthStr = elementsStr.split('/')[1]
|
||||
const length = Number.parseInt(lengthStr)
|
||||
return length === field.size
|
||||
const lengthStr = elementsStr.split("/")[1];
|
||||
const length = Number.parseInt(lengthStr);
|
||||
return length === field.size;
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: true,
|
||||
@ -1320,7 +1374,9 @@ const sqliteTypesBase = {
|
||||
}
|
||||
const content = field.default.split(" ");
|
||||
const date = content[0].split("-");
|
||||
return Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038;
|
||||
return (
|
||||
Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
@ -1581,7 +1637,9 @@ const mssqlTypesBase = {
|
||||
}
|
||||
const content = field.default.split(" ");
|
||||
const date = content[0].split("-");
|
||||
return Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038;
|
||||
return (
|
||||
Number.parseInt(date[0]) >= 1970 && Number.parseInt(date[0]) <= 2038
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
@ -1747,6 +1805,218 @@ export const mssqlTypes = new Proxy(mssqlTypesBase, {
|
||||
get: (target, prop) => (prop in target ? target[prop] : false),
|
||||
});
|
||||
|
||||
const oraclesqlTypesBase = {
|
||||
INTEGER: {
|
||||
type: "INTEGER",
|
||||
checkDefault: (field) => {
|
||||
return intRegex.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: false,
|
||||
canIncrement: true,
|
||||
},
|
||||
NUMBER: {
|
||||
type: "NUMBER",
|
||||
checkDefault: (field) => {
|
||||
return /^-?\d+(\.\d+)?$/.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: true,
|
||||
canIncrement: false,
|
||||
},
|
||||
FLOAT: {
|
||||
type: "FLOAT",
|
||||
checkDefault: (field) => {
|
||||
return /^-?\d+(\.\d+)?$/.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: true,
|
||||
},
|
||||
LONG: {
|
||||
type: "LONG",
|
||||
checkDefault: (field) => {
|
||||
return intRegex.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: false,
|
||||
canIncrement: true,
|
||||
},
|
||||
VARCHAR2: {
|
||||
type: "VARCHAR2",
|
||||
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: 4000,
|
||||
hasQuotes: true,
|
||||
},
|
||||
NVARCHAR2: {
|
||||
type: "VARCHAR2",
|
||||
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: 4000,
|
||||
hasQuotes: true,
|
||||
},
|
||||
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,
|
||||
hasQuotes: true,
|
||||
},
|
||||
NCHAR: {
|
||||
type: "NCHAR",
|
||||
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,
|
||||
hasQuotes: true,
|
||||
},
|
||||
CLOB: {
|
||||
type: "CLOB",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
NCLOB: {
|
||||
type: "NCLOB",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
BLOB: {
|
||||
type: "BLOB",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
BFILE: {
|
||||
type: "BFILE",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
JSON: {
|
||||
type: "JSON",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
VECTOR: {
|
||||
type: "VECTOR",
|
||||
checkDefault: (field) => true,
|
||||
isSized: false,
|
||||
hasCheck: false,
|
||||
hasPrecision: false,
|
||||
noDefault: true,
|
||||
},
|
||||
DATE: {
|
||||
type: "DATE",
|
||||
checkDefault: (field) => {
|
||||
return /^\d{4}-\d{2}-\d{2}$/.test(field.default);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
hasPrecision: false,
|
||||
hasQuotes: true,
|
||||
},
|
||||
TIMESTAMP: {
|
||||
type: "TIMESTAMP",
|
||||
checkDefault: (field) => {
|
||||
if (field.default.toUpperCase() === "CURRENT_TIMESTAMP") {
|
||||
return true;
|
||||
}
|
||||
return /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(
|
||||
field.default,
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
hasPrecision: true,
|
||||
hasQuotes: true,
|
||||
},
|
||||
INTERVAL: {
|
||||
type: "INTERVAL",
|
||||
checkDefault: (field) => {
|
||||
return /^INTERVAL\s'\d+'(\s+DAY|HOUR|MINUTE|SECOND)?$/.test(
|
||||
field.default,
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
hasPrecision: false,
|
||||
hasQuotes: true,
|
||||
},
|
||||
BOOLEAN: {
|
||||
type: "BOOLEAN",
|
||||
checkDefault: (field) => {
|
||||
return (
|
||||
field.default === "0" ||
|
||||
field.default === "1" ||
|
||||
field.default.toUpperCase() === "TRUE" ||
|
||||
field.default.toUpperCase() === "FALSE"
|
||||
);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: false,
|
||||
hasPrecision: false,
|
||||
},
|
||||
RAW: {
|
||||
type: "RAW",
|
||||
checkDefault: (field) => {
|
||||
return /^[0-9A-Fa-f]+$/.test(field.default);
|
||||
},
|
||||
hasCheck: false,
|
||||
isSized: true,
|
||||
hasPrecision: false,
|
||||
defaultSize: 2000,
|
||||
hasQuotes: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const oraclesqlTypes = new Proxy(oraclesqlTypesBase, {
|
||||
get: (target, prop) => (prop in target ? target[prop] : false),
|
||||
});
|
||||
|
||||
const dbToTypesBase = {
|
||||
[DB.GENERIC]: defaultTypes,
|
||||
[DB.MYSQL]: mysqlTypes,
|
||||
@ -1754,6 +2024,7 @@ const dbToTypesBase = {
|
||||
[DB.SQLITE]: sqliteTypes,
|
||||
[DB.MSSQL]: mssqlTypes,
|
||||
[DB.MARIADB]: mysqlTypes,
|
||||
[DB.ORACLESQL]: oraclesqlTypes,
|
||||
};
|
||||
|
||||
export const dbToTypes = new Proxy(dbToTypesBase, {
|
||||
|
@ -8,6 +8,7 @@ import mysql_icon from "../assets/mysql.png";
|
||||
import postgres_icon from "../assets/postgres.png";
|
||||
import sqlite_icon from "../assets/sqlite.png";
|
||||
import mariadb_icon from "../assets/mariadb.png";
|
||||
import oraclesql_icon from "../assets/oraclesql.png";
|
||||
import sql_server_icon from "../assets/sql-server.png";
|
||||
import discord from "../assets/discord.png";
|
||||
import github from "../assets/github.png";
|
||||
@ -150,7 +151,7 @@ export default function LandingPage() {
|
||||
<div className="text-lg font-medium text-center mt-12 mb-6">
|
||||
Design for your database
|
||||
</div>
|
||||
<div className="flex justify-center items-center gap-8 md:block">
|
||||
<div className="grid grid-cols-3 place-items-center sm:grid-cols-1 sm:gap-10">
|
||||
{dbs.map((s, i) => (
|
||||
<img
|
||||
key={"icon-" + i}
|
||||
@ -300,6 +301,7 @@ const dbs = [
|
||||
{ icon: sqlite_icon, height: 64 },
|
||||
{ icon: mariadb_icon, height: 64 },
|
||||
{ icon: sql_server_icon, height: 64 },
|
||||
{ icon: oraclesql_icon, height: 172 },
|
||||
];
|
||||
|
||||
const features = [
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { DB } from "../../data/constants";
|
||||
import { dbToTypes, defaultTypes } from "../../data/datatypes";
|
||||
import { getInlineFK, parseDefault } from "./shared";
|
||||
|
||||
@ -42,10 +43,10 @@ export function generateSchema(type) {
|
||||
export function getTypeString(
|
||||
field,
|
||||
currentDb,
|
||||
dbms = "mysql",
|
||||
dbms = DB.MYSQL,
|
||||
baseType = false,
|
||||
) {
|
||||
if (dbms === "mysql") {
|
||||
if (dbms === DB.MYSQL) {
|
||||
if (field.type === "UUID") {
|
||||
return `VARCHAR(36)`;
|
||||
}
|
||||
@ -62,7 +63,7 @@ export function getTypeString(
|
||||
return "JSON";
|
||||
}
|
||||
return field.type;
|
||||
} else if (dbms === "postgres") {
|
||||
} else if (dbms === DB.POSTGRES) {
|
||||
if (field.type === "SMALLINT" && field.increment) {
|
||||
return "smallserial";
|
||||
}
|
||||
@ -97,7 +98,7 @@ export function getTypeString(
|
||||
return `${field.type.toLowerCase()}${field.size ? `(${field.size})` : ""}`;
|
||||
}
|
||||
return field.type.toLowerCase();
|
||||
} else if (dbms === "mssql") {
|
||||
} else if (dbms === DB.MSSQL) {
|
||||
let type = field.type;
|
||||
switch (field.type) {
|
||||
case "ENUM":
|
||||
@ -134,6 +135,47 @@ export function getTypeString(
|
||||
}
|
||||
|
||||
return type;
|
||||
} else if (dbms === DB.ORACLESQL) {
|
||||
let oracleType;
|
||||
switch (field.type) {
|
||||
case "BIGINT":
|
||||
oracleType = "NUMBER";
|
||||
break;
|
||||
case "VARCHAR":
|
||||
oracleType = "VARCHAR2";
|
||||
break;
|
||||
case "TEXT":
|
||||
oracleType = "CLOB";
|
||||
break;
|
||||
case "TIME":
|
||||
case "DATETIME":
|
||||
oracleType = "TIMESTAMP";
|
||||
break;
|
||||
case "BINARY":
|
||||
case "VARBINARY":
|
||||
oracleType = "RAW";
|
||||
break;
|
||||
case "UUID":
|
||||
oracleType = "RAW(16)";
|
||||
break;
|
||||
case "SET":
|
||||
case "ENUM":
|
||||
oracleType = field.name + "_t";
|
||||
break;
|
||||
default:
|
||||
oracleType = field.type;
|
||||
break;
|
||||
}
|
||||
const typeInfo = dbToTypes[currentDb][oracleType];
|
||||
if (typeInfo.isSized || typeInfo.hasPrecision) {
|
||||
if (oracleType === "NUMBER") {
|
||||
return `${oracleType}${field.size ? `(${field.size})` : "(38,0)"}`;
|
||||
} else {
|
||||
return `${oracleType}${field.size ? `(${field.size})` : ""}`;
|
||||
}
|
||||
}
|
||||
|
||||
return oracleType;
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,13 +255,15 @@ export function jsonToPostgreSQL(obj) {
|
||||
type.comment === "" ? "" : `/**\n${type.comment}\n*/\n`
|
||||
}CREATE TYPE ${type.name} AS (\n${type.fields
|
||||
.map(
|
||||
(f) => `\t${f.name} ${getTypeString(f, obj.database, "postgres")}`,
|
||||
(f) => `\t${f.name} ${getTypeString(f, obj.database, DB.POSTGRES)}`,
|
||||
)
|
||||
.join("\n")}\n);`
|
||||
);
|
||||
} else {
|
||||
return `CREATE TYPE ${type.name} AS (\n${type.fields
|
||||
.map((f) => `\t${f.name} ${getTypeString(f, obj.database, "postgres")}`)
|
||||
.map(
|
||||
(f) => `\t${f.name} ${getTypeString(f, obj.database, DB.POSTGRES)}`,
|
||||
)
|
||||
.join(",\n")}\n);\n${
|
||||
type.comment && type.comment.trim() != ""
|
||||
? `\nCOMMENT ON TYPE ${type.name} IS '${type.comment}';\n`
|
||||
@ -247,7 +291,7 @@ export function jsonToPostgreSQL(obj) {
|
||||
(field) =>
|
||||
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${
|
||||
field.name
|
||||
}" ${getTypeString(field, obj.database, "postgres")}${
|
||||
}" ${getTypeString(field, obj.database, DB.POSTGRES)}${
|
||||
field.notNull ? " NOT NULL" : ""
|
||||
}${field.unique ? " UNIQUE" : ""}${
|
||||
field.default !== "" ? ` DEFAULT ${parseDefault(field)}` : ""
|
||||
@ -377,7 +421,7 @@ export function jsonToMariaDB(obj) {
|
||||
(field) =>
|
||||
`\t\`${
|
||||
field.name
|
||||
}\` ${getTypeString(field, obj.database)}${field.notNull ? " NOT NULL" : ""}${
|
||||
}\` ${getTypeString(field, obj.database, DB.MYSQL)}${field.notNull ? " NOT NULL" : ""}${
|
||||
field.increment ? " AUTO_INCREMENT" : ""
|
||||
}${field.unique ? " UNIQUE" : ""}${
|
||||
field.default !== ""
|
||||
@ -436,7 +480,7 @@ export function jsonToSQLServer(obj) {
|
||||
}CREATE TYPE [${type.name}] FROM ${
|
||||
type.fields.length < 0
|
||||
? ""
|
||||
: `${getTypeString(type.fields[0], obj.database, "mssql", true)}`
|
||||
: `${getTypeString(type.fields[0], obj.database, DB.MSSQL, true)}`
|
||||
};\nGO\n`;
|
||||
})
|
||||
.join("\n")}\n${obj.tables
|
||||
@ -449,7 +493,7 @@ export function jsonToSQLServer(obj) {
|
||||
(field) =>
|
||||
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t[${
|
||||
field.name
|
||||
}] ${getTypeString(field, obj.database, "mssql")}${
|
||||
}] ${getTypeString(field, obj.database, DB.MSSQL)}${
|
||||
field.notNull ? " NOT NULL" : ""
|
||||
}${field.increment ? " IDENTITY" : ""}${
|
||||
field.unique ? " UNIQUE" : ""
|
||||
@ -493,3 +537,70 @@ export function jsonToSQLServer(obj) {
|
||||
)
|
||||
.join("\n")}`;
|
||||
}
|
||||
|
||||
export function jsonToOracleSQL(obj) {
|
||||
return `${obj.tables
|
||||
.map(
|
||||
(table) =>
|
||||
`${
|
||||
table.fields.filter((f) => f.type === "ENUM" || f.type === "SET")
|
||||
.length > 0
|
||||
? `${table.fields
|
||||
.filter((f) => f.type === "ENUM" || f.type === "SET")
|
||||
.map(
|
||||
(f) =>
|
||||
`CREATE DOMAIN "${f.name}_t" AS ENUM (${f.values
|
||||
.map((v) => `'${v}'`)
|
||||
.join(", ")});\n`,
|
||||
)
|
||||
.join("\n")}\n`
|
||||
: ""
|
||||
}${
|
||||
table.comment === "" ? "" : `/* ${table.comment} */\n`
|
||||
}CREATE TABLE "${table.name}" (\n${table.fields
|
||||
.map(
|
||||
(field) =>
|
||||
`${field.comment === "" ? "" : ` -- ${field.comment}\n`} "${
|
||||
field.name
|
||||
}" ${getTypeString(field, obj.database, DB.ORACLESQL)}${
|
||||
field.notNull ? " NOT NULL" : ""
|
||||
}${field.increment ? " GENERATED ALWAYS AS IDENTITY" : ""}${
|
||||
field.unique ? " UNIQUE" : ""
|
||||
}${
|
||||
field.default !== ""
|
||||
? ` DEFAULT ${parseDefault(field, obj.database)}`
|
||||
: ""
|
||||
}${
|
||||
field.check === "" ||
|
||||
!dbToTypes[obj.database][field.type].hasCheck
|
||||
? ""
|
||||
: ` CHECK (${field.check})`
|
||||
}`,
|
||||
)
|
||||
.join(",\n")}${
|
||||
table.fields.filter((f) => f.primary).length > 0
|
||||
? `,\n PRIMARY KEY (${table.fields
|
||||
.filter((f) => f.primary)
|
||||
.map((f) => `"${f.name}"`)
|
||||
.join(", ")})`
|
||||
: ""
|
||||
}\n);\n${table.indices
|
||||
.map(
|
||||
(i) =>
|
||||
`\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX "${i.name}"\n ON "${
|
||||
table.name
|
||||
}" (${i.fields.map((f) => `"${f}"`).join(", ")});`,
|
||||
)
|
||||
.join("\n")}`,
|
||||
)
|
||||
.join("\n\n")}\n${obj.references
|
||||
.map(
|
||||
(r) =>
|
||||
`ALTER TABLE "${obj.tables[r.startTableId].name}"\nADD CONSTRAINT "${r.name}" FOREIGN KEY ("${
|
||||
obj.tables[r.startTableId].fields[r.startFieldId].name
|
||||
}") REFERENCES "${obj.tables[r.endTableId].name}"("${
|
||||
obj.tables[r.endTableId].fields[r.endFieldId].name
|
||||
}");`,
|
||||
)
|
||||
.join("\n")}`;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { DB } from "../../data/constants";
|
||||
import { toMariaDB } from "./mariadb";
|
||||
import { toMSSQL } from "./mssql";
|
||||
import { toMySQL } from "./mysql";
|
||||
import { toOracleSQL } from "./oraclesql";
|
||||
import { toPostgres } from "./postgres";
|
||||
import { toSqlite } from "./sqlite";
|
||||
|
||||
@ -17,6 +18,8 @@ export function exportSQL(diagram) {
|
||||
return toMariaDB(diagram);
|
||||
case DB.MSSQL:
|
||||
return toMSSQL(diagram);
|
||||
case DB.ORACLESQL:
|
||||
return toOracleSQL(diagram);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
56
src/utils/exportSQL/oraclesql.js
Normal file
56
src/utils/exportSQL/oraclesql.js
Normal file
@ -0,0 +1,56 @@
|
||||
import { dbToTypes } from "../../data/datatypes";
|
||||
import { parseDefault } from "./shared";
|
||||
|
||||
export function toOracleSQL(diagram) {
|
||||
return `${diagram.tables
|
||||
.map(
|
||||
(table) =>
|
||||
`${
|
||||
table.comment === "" ? "" : `/* ${table.comment} */\n`
|
||||
}CREATE TABLE "${table.name}" (\n${table.fields
|
||||
.map(
|
||||
(field) =>
|
||||
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t"${
|
||||
field.name
|
||||
}" ${field.type}${field.size && Boolean(field.size.trim()) ? "(" + field.size + ")" : ""}${
|
||||
field.notNull ? " NOT NULL" : ""
|
||||
}${
|
||||
field.increment ? " GENERATED ALWAYS AS IDENTITY" : ""
|
||||
}${field.unique ? " UNIQUE" : ""}${
|
||||
field.default !== ""
|
||||
? ` DEFAULT ${parseDefault(field, diagram.database)}`
|
||||
: ""
|
||||
}${
|
||||
field.check === "" ||
|
||||
!dbToTypes[diagram.database][field.type].hasCheck
|
||||
? ""
|
||||
: ` CHECK(${field.check})`
|
||||
}${field.comment ? ` -- ${field.comment}` : ""}`,
|
||||
)
|
||||
.join(",\n")}${
|
||||
table.fields.filter((f) => f.primary).length > 0
|
||||
? `,\n\tPRIMARY KEY(${table.fields
|
||||
.filter((f) => f.primary)
|
||||
.map((f) => `"${f.name}"`)
|
||||
.join(", ")})`
|
||||
: ""
|
||||
}\n)${table.comment ? ` -- ${table.comment}` : ""};\n${`\n${table.indices
|
||||
.map(
|
||||
(i) =>
|
||||
`\nCREATE ${i.unique ? "UNIQUE " : ""}INDEX "${i.name}"\nON "${table.name}" (${i.fields
|
||||
.map((f) => `"${f}"`)
|
||||
.join(", ")});`,
|
||||
)
|
||||
.join("")}`}`,
|
||||
)
|
||||
.join("\n")}\n${diagram.references
|
||||
.map(
|
||||
(r) =>
|
||||
`ALTER TABLE "${diagram.tables[r.startTableId].name}"\nADD CONSTRAINT "${r.name}" FOREIGN KEY ("${
|
||||
diagram.tables[r.startTableId].fields[r.startFieldId].name
|
||||
}") REFERENCES "${diagram.tables[r.endTableId].name}" ("${
|
||||
diagram.tables[r.endTableId].fields[r.endFieldId].name
|
||||
}")\nON UPDATE ${r.updateConstraint.toUpperCase()} ON DELETE ${r.deleteConstraint.toUpperCase()};`,
|
||||
)
|
||||
.join("\n")}`;
|
||||
}
|
@ -3,6 +3,7 @@ import { arrangeTables } from "../arrangeTables";
|
||||
import { fromMariaDB } from "./mariadb";
|
||||
import { fromMSSQL } from "./mssql";
|
||||
import { fromMySQL } from "./mysql";
|
||||
import { fromOracleSQL } from "./oraclesql";
|
||||
import { fromPostgres } from "./postgres";
|
||||
import { fromSQLite } from "./sqlite";
|
||||
|
||||
@ -24,6 +25,9 @@ export function importSQL(ast, toDb = DB.MYSQL, diagramDb = DB.GENERIC) {
|
||||
case DB.MSSQL:
|
||||
diagram = fromMSSQL(ast, diagramDb);
|
||||
break;
|
||||
case DB.ORACLESQL:
|
||||
diagram = fromOracleSQL(ast, diagramDb);
|
||||
break;
|
||||
default:
|
||||
diagram = { tables: [], relationships: [] };
|
||||
break;
|
||||
|
137
src/utils/importSQL/oraclesql.js
Normal file
137
src/utils/importSQL/oraclesql.js
Normal file
@ -0,0 +1,137 @@
|
||||
import { Cardinality, Constraint, DB } from "../../data/constants";
|
||||
import { dbToTypes } from "../../data/datatypes";
|
||||
|
||||
const affinity = {
|
||||
[DB.ORACLESQL]: new Proxy(
|
||||
{ INT: "INTEGER" },
|
||||
{ NUMERIC: "NUMBER" },
|
||||
{ DECIMAL: "NUMBER" },
|
||||
{ CHARACTER: "CHAR" },
|
||||
{ get: (target, prop) => (prop in target ? target[prop] : "BLOB") },
|
||||
),
|
||||
[DB.GENERIC]: new Proxy(
|
||||
{
|
||||
INTEGER: "INT",
|
||||
MEDIUMINT: "INTEGER",
|
||||
},
|
||||
{ get: (target, prop) => (prop in target ? target[prop] : "BLOB") },
|
||||
),
|
||||
};
|
||||
|
||||
export function fromOracleSQL(ast, diagramDb = DB.GENERIC) {
|
||||
const tables = [];
|
||||
const relationships = [];
|
||||
const enums = [];
|
||||
|
||||
const parseSingleStatement = (e) => {
|
||||
console.log(e);
|
||||
if (e.operation === "create") {
|
||||
if (e.object === "table") {
|
||||
const table = {};
|
||||
table.name = e.name.name;
|
||||
table.comment = "";
|
||||
table.color = "#175e7a";
|
||||
table.fields = [];
|
||||
table.indices = [];
|
||||
table.id = tables.length;
|
||||
e.table.relational_properties.forEach((d) => {
|
||||
if (d.resource === "column") {
|
||||
const field = {};
|
||||
field.name = d.name;
|
||||
|
||||
let type = d.type.type.toUpperCase();
|
||||
if (!dbToTypes[diagramDb][type]) {
|
||||
type = affinity[diagramDb][type];
|
||||
}
|
||||
field.type = type;
|
||||
|
||||
if (d.type.scale && d.type.precision) {
|
||||
field.size = d.type.precision + "," + d.type.scale;
|
||||
} else if (d.type.size || d.type.precision) {
|
||||
field.size = d.type.size || d.type.precision;
|
||||
}
|
||||
|
||||
field.comment = "";
|
||||
field.check = "";
|
||||
field.default = "";
|
||||
field.unique = false;
|
||||
field.increment = false;
|
||||
field.notNull = false;
|
||||
field.primary = false;
|
||||
|
||||
for (const c of d.constraints) {
|
||||
if (c.constraint.primary_key === "primary key")
|
||||
field.primary = true;
|
||||
if (c.constraint.not_null === "not null") field.notNull = true;
|
||||
if (c.constraint.unique === "unique") field.unique = true;
|
||||
}
|
||||
|
||||
if (d.identity) {
|
||||
field.increment = true;
|
||||
}
|
||||
|
||||
// TODO: reconstruct default when implemented in parser
|
||||
if (d.default) {
|
||||
field.default = JSON.stringify(d.default.expr);
|
||||
}
|
||||
|
||||
table.fields.push(field);
|
||||
} else if (d.resource === "constraint") {
|
||||
const relationship = {};
|
||||
const startTableId = table.id;
|
||||
const startField = d.constraint.columns[0];
|
||||
const endField = d.constraint.reference.columns[0];
|
||||
const endTable = d.constraint.reference.object.name;
|
||||
|
||||
const endTableId = tables.findIndex((t) => t.name === endTable);
|
||||
if (endTableId === -1) return;
|
||||
|
||||
const endFieldId = tables[endTableId].fields.findIndex(
|
||||
(f) => f.name === endField,
|
||||
);
|
||||
if (endFieldId === -1) return;
|
||||
|
||||
const startFieldId = table.fields.findIndex(
|
||||
(f) => f.name === startField,
|
||||
);
|
||||
if (startFieldId === -1) return;
|
||||
|
||||
relationship.startTableId = startTableId;
|
||||
relationship.startFieldId = startFieldId;
|
||||
relationship.endTableId = endTableId;
|
||||
relationship.endFieldId = endFieldId;
|
||||
relationship.updateConstraint = Constraint.NONE;
|
||||
relationship.name =
|
||||
d.name && Boolean(d.name.trim())
|
||||
? d.name
|
||||
: "fk_" + table.name + "_" + startField + "_" + endTable;
|
||||
relationship.deleteConstraint =
|
||||
d.constraint.reference.on_delete &&
|
||||
Boolean(d.constraint.reference.on_delete.trim())
|
||||
? d.constraint.reference.on_delete[0].toUpperCase() +
|
||||
d.constraint.reference.on_delete.substring(1)
|
||||
: Constraint.NONE;
|
||||
|
||||
if (table.fields[startFieldId].unique) {
|
||||
relationship.cardinality = Cardinality.ONE_TO_ONE;
|
||||
} else {
|
||||
relationship.cardinality = Cardinality.MANY_TO_ONE;
|
||||
}
|
||||
|
||||
relationships.push(relationship);
|
||||
}
|
||||
});
|
||||
table.fields.forEach((f, j) => {
|
||||
f.id = j;
|
||||
});
|
||||
tables.push(table);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ast.forEach((e) => parseSingleStatement(e));
|
||||
|
||||
relationships.forEach((r, i) => (r.id = i));
|
||||
|
||||
return { tables, relationships, enums };
|
||||
}
|
Loading…
Reference in New Issue
Block a user