feat:Added support for exporting SQL as OracleDB SQL

This commit is contained in:
Aditya 2024-07-30 17:13:02 +05:30
parent 06f7284ea8
commit f6920e7165
10 changed files with 405 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
src/assets/oraclesql.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -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: () => {

View File

@ -112,5 +112,6 @@ export const DB = {
MSSQL: "transactsql",
SQLITE: "sqlite",
MARIADB: "mariadb",
ORACLESQL: "oraclesql",
GENERIC: "generic",
};

View File

@ -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,

View File

@ -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, {

View File

@ -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

View File

@ -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")}`;
}

View File

@ -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 "";
}

View 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")}`;
}