mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-05-24 18:39:12 +00:00
feat:Added support for exporting SQL as OracleDB SQL
This commit is contained in:
parent
06f7284ea8
commit
f6920e7165
BIN
src/assets/oraclesql-icon.png
Normal file
BIN
src/assets/oraclesql-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 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 |
@ -29,6 +29,7 @@ import {
|
||||
jsonToSQLite,
|
||||
jsonToMariaDB,
|
||||
jsonToSQLServer,
|
||||
jsonToOracleSQL,
|
||||
} from "../../utils/exportSQL/generic";
|
||||
import {
|
||||
ObjectType,
|
||||
@ -882,6 +883,22 @@ export default function ControlPanel({
|
||||
}));
|
||||
},
|
||||
},
|
||||
{
|
||||
OracleSQL: () => {
|
||||
setModal(MODAL.CODE);
|
||||
const src = jsonToOracleSQL({
|
||||
tables: tables,
|
||||
references: relationships,
|
||||
types: types,
|
||||
database: database,
|
||||
});
|
||||
setExportData((prev) => ({
|
||||
...prev,
|
||||
data: src,
|
||||
extension: "sql",
|
||||
}));
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
function: () => {
|
||||
|
@ -112,5 +112,6 @@ 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";
|
||||
|
||||
@ -40,6 +41,14 @@ 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,
|
||||
},
|
||||
[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,
|
||||
@ -223,6 +247,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,
|
||||
@ -1616,6 +1656,155 @@ export const mssqlTypes = new Proxy(mssqlTypesBase, {
|
||||
get: (target, prop) => (prop in target ? target[prop] : false),
|
||||
});
|
||||
|
||||
const oraclesqlTypesBase = {
|
||||
NUMBER: {
|
||||
type: "NUMBER",
|
||||
checkDefault: (field) => {
|
||||
return /^-?\d+(\.\d+)?$/.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: true,
|
||||
canIncrement: false,
|
||||
},
|
||||
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,
|
||||
},
|
||||
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,
|
||||
},
|
||||
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,
|
||||
},
|
||||
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,
|
||||
},
|
||||
FLOAT: {
|
||||
type: "FLOAT",
|
||||
checkDefault: (field) => {
|
||||
return /^-?\d+(\.\d+)?$/.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: true,
|
||||
},
|
||||
DOUBLE: {
|
||||
type: "DOUBLE",
|
||||
checkDefault: (field) => {
|
||||
return /^-?\d+(\.\d+)?$/.test(field.default);
|
||||
},
|
||||
hasCheck: true,
|
||||
isSized: false,
|
||||
hasPrecision: 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,
|
||||
@ -1623,6 +1812,7 @@ const dbToTypesBase = {
|
||||
[DB.SQLITE]: sqliteTypes,
|
||||
[DB.MSSQL]: mssqlTypes,
|
||||
[DB.MARIADB]: mysqlTypes,
|
||||
[DB.ORACLESQL]: oraclesqlTypes,
|
||||
};
|
||||
|
||||
export const dbToTypes = new Proxy(dbToTypesBase, {
|
||||
|
@ -9,6 +9,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";
|
||||
@ -178,7 +179,7 @@ export default function LandingPage() {
|
||||
<div className="text-center text-2xl font-bold mb-4">
|
||||
We support these DBMS
|
||||
</div>
|
||||
<div className="grid grid-cols-5 place-items-center items-baseline sm:grid-cols-1 sm:gap-4">
|
||||
<div className="grid grid-cols-3 grid-rows-2 gap-y-[4rem] place-items-center items-baseline sm:grid-cols-1 sm:grid-rows-1 sm:gap-10">
|
||||
<img
|
||||
src={mysql_icon}
|
||||
className="opacity-70 hover:opacity-100 transition-all duration-300 h-20"
|
||||
@ -199,6 +200,10 @@ export default function LandingPage() {
|
||||
src={sql_server_icon}
|
||||
className="opacity-70 hover:opacity-100 transition-all duration-300 h-16"
|
||||
/>
|
||||
<img
|
||||
src={oraclesql_icon}
|
||||
className="opacity-70 hover:opacity-100 transition-all duration-300 h-16 scale-[300%]"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-16 mb-2 text-2xl font-bold text-center">
|
||||
Reach out to us
|
||||
|
@ -134,6 +134,76 @@ export function getTypeString(
|
||||
}
|
||||
|
||||
return type;
|
||||
} else if (dbms === "oraclesql") {
|
||||
let oracleType;
|
||||
switch (field.type) {
|
||||
case "INT":
|
||||
case "INTEGER":
|
||||
case "SMALLINT":
|
||||
case "BIGINT":
|
||||
case "DECIMAL":
|
||||
case "NUMERIC":
|
||||
case "REAL":
|
||||
case "FLOAT":
|
||||
case "DOUBLE":
|
||||
oracleType = "NUMBER";
|
||||
break;
|
||||
case "CHAR":
|
||||
oracleType = "CHAR";
|
||||
break;
|
||||
case "VARCHAR":
|
||||
oracleType = "VARCHAR2";
|
||||
break;
|
||||
case "TEXT":
|
||||
oracleType = "CLOB";
|
||||
break;
|
||||
case "TIME":
|
||||
oracleType = "TIMESTAMP";
|
||||
break;
|
||||
case "TIMESTAMP":
|
||||
case "DATE":
|
||||
case "DATETIME":
|
||||
oracleType = field.type;
|
||||
break;
|
||||
case "BOOLEAN":
|
||||
oracleType = "NUMBER(1)";
|
||||
break;
|
||||
case "BINARY":
|
||||
case "VARBINARY":
|
||||
oracleType = "RAW";
|
||||
break;
|
||||
case "BLOB":
|
||||
oracleType = "BLOB";
|
||||
break;
|
||||
case "JSON":
|
||||
oracleType = "JSON";
|
||||
break;
|
||||
case "UUID":
|
||||
oracleType = "RAW(16)";
|
||||
break;
|
||||
case "ENUM":
|
||||
case "SET":
|
||||
oracleType = "VARCHAR2";
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported type for Oracle: ${field.type}`);
|
||||
}
|
||||
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})` : ""}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (field.type === "ENUM" || field.type === "SET") {
|
||||
oracleType += ` CHECK (${field.name} IN (${field.values
|
||||
.map((v) => `'${v}'`)
|
||||
.join(", ")}))`;
|
||||
}
|
||||
|
||||
return oracleType;
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,7 +456,7 @@ export function jsonToMariaDB(obj) {
|
||||
(field) =>
|
||||
`${field.comment === "" ? "" : `\t-- ${field.comment}\n`}\t\`${
|
||||
field.name
|
||||
}\` ${getTypeString(field, obj.database)}${field.notNull ? " NOT NULL" : ""}${
|
||||
}\` ${getTypeString(field, obj.database, "oraclesql")}${field.notNull ? " NOT NULL" : ""}${
|
||||
field.increment ? " AUTO_INCREMENT" : ""
|
||||
}${field.unique ? " UNIQUE" : ""}${
|
||||
field.default !== ""
|
||||
@ -502,3 +572,55 @@ export function jsonToSQLServer(obj) {
|
||||
)
|
||||
.join("\n")}`;
|
||||
}
|
||||
|
||||
export function jsonToOracleSQL(obj) {
|
||||
return `${obj.tables
|
||||
.map(
|
||||
(table) =>
|
||||
`${
|
||||
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, "oraclesql")}${field.primary ? "" : field.notNull ? (table.indices.some((index) => index.fields.some((f) => f === field.name)) ? " NOT NULL" : field.unique ? " NOT NULL 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 fk_${
|
||||
r.startTableId
|
||||
}_${r.endTableId} 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.ORACLE:
|
||||
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 !== undefined && field.size !== "" ? "(" + 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")}`;
|
||||
}
|
Loading…
Reference in New Issue
Block a user