diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 9d064b68..2cc5c5f1 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -30,6 +30,7 @@ import { jsonToSQLite, jsonToMariaDB, jsonToSQLServer, + jsonToDjangoModels } from "../../utils/toSQL"; import { ObjectType, @@ -933,6 +934,21 @@ export default function ControlPanel({ })); }, }, + { + "Django Models": () => { + setModal(MODAL.CODE); + const src = jsonToDjangoModels({ + tables: tables, + references: relationships, + types: types, + }); + setExportData((prev) => ({ + ...prev, + data: src, + extension: "py", + })); + }, + } ], function: () => {}, }, diff --git a/src/data/constants.js b/src/data/constants.js index 8d8d1e1a..415bbb2e 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -125,4 +125,43 @@ export const SIDESHEET = { NONE: 0, TODO: 1, TIMELINE: 2, -}; \ No newline at end of file +}; + +export const SQL_TO_DJANGO_TYPE_MAPPING = { + 'INT': 'IntegerField', + 'TINYINT': 'SmallIntegerField', + 'SMALLINT': 'SmallIntegerField', + 'MEDIUMINT': 'IntegerField', + 'BIGINT': 'BigIntegerField', + 'FLOAT': 'FloatField', + 'DOUBLE': 'FloatField', + 'DECIMAL': 'DecimalField', + 'DATE': 'DateField', + 'TIME': 'TimeField', + 'DATETIME': 'DateTimeField', + 'TIMESTAMP': 'DateTimeField', + 'YEAR': 'IntegerField', + 'CHAR': 'CharField', + 'VARCHAR': 'CharField', + 'TEXT': 'TextField', + 'BLOB': 'BinaryField', + 'MEDIUMBLOB': 'BinaryField', + 'LONGBLOB': 'BinaryField', + 'TINYBLOB': 'BinaryField', +}; + +export const SQL_TO_DJANGO_DELETE_CONSTRAINT_MAPPING = { + 'NO ACTION': 'DO_NOTHING', + 'RESTRICT': 'PROTECT', + 'CASCADE': 'CASCADE', + 'SET NULL': 'SET_NULL', + 'SET DEFAULT': 'SET_DEFAULT', +}; + +export const SQL_TO_DJANGO_UPDATE_CONSTRAINT_MAPPING = { + 'NO ACTION': 'DO_NOTHING', + 'RESTRICT': 'PROTECT', + 'CASCADE': 'CASCADE', + 'SET NULL': 'SET_NULL', + 'SET DEFAULT': 'SET_DEFAULT', +}; diff --git a/src/utils/toSQL.js b/src/utils/toSQL.js index 4720a6ef..5a1db760 100644 --- a/src/utils/toSQL.js +++ b/src/utils/toSQL.js @@ -1,6 +1,8 @@ -import { sqlDataTypes } from "../data/constants"; +import { sqlDataTypes, SQL_TO_DJANGO_TYPE_MAPPING, + SQL_TO_DJANGO_DELETE_CONSTRAINT_MAPPING, + SQL_TO_DJANGO_UPDATE_CONSTRAINT_MAPPING } + from "../data/constants"; import { strHasQuotes } from "./utils"; - export function getJsonType(f) { if (!sqlDataTypes.includes(f.type)) { return '{ "type" : "object", additionalProperties : true }'; @@ -397,6 +399,77 @@ export function jsonToSQLite(obj) { .join("\n"); } +export function jsonToDjangoModels(obj) { + let djangoCode = ""; + + djangoCode += "from django.db import models\n"; + djangoCode += "from django.db.models import DO_NOTHING, CASCADE, PROTECT, SET_NULL, SET_DEFAULT\n\n"; + + obj.types.forEach(type => { + let typeStatements = []; + + type.fields.forEach(field => { + if (field.type === "ENUM" || field.type === "SET") { + typeStatements.push(` ${field.name}_t = models.TextChoices(\n${field.values.map(value => ` ('${value}', '${value}')`).join(',\n')}\n )`); + } + }); + + djangoCode += `class ${type.name}(models.Model) {\n`; + type.fields.forEach(field => { + const djangoType = SQL_TO_DJANGO_TYPE_MAPPING[field.type] || 'CharField'; + djangoCode += ` ${field.name} = models.${djangoType}(`; + if (field.primary) { + djangoCode += "primary_key=True, "; + } + if (field.unique) { + djangoCode += "unique=True, "; + } + if (!field.notNull) { + djangoCode += "null=True, "; + } + if (field.default !== "") { + djangoCode += `default=${parseDefault(field)}, `; + } + djangoCode += ")\n"; + }); + djangoCode += `}\n\n`; + }); + + obj.tables.forEach(table => { + djangoCode += `class ${table.name}(models.Model) {\n`; + table.fields.forEach(field => { + const djangoType = SQL_TO_DJANGO_TYPE_MAPPING[field.type] || 'CharField'; // Convert SQL type to Django type + djangoCode += ` ${field.name} = models.${djangoType}(`; + if (field.primary) { + djangoCode += "primary_key=True, "; + } + if (field.unique) { + djangoCode += "unique=True, "; + } + if (!field.notNull) { + djangoCode += "null=True, "; + } + if (field.default !== "") { + djangoCode += `default=${parseDefault(field)}, `; + } + djangoCode += ")\n"; + }); + djangoCode += `}\n\n`; + }); + + obj.references.forEach(reference => { + const startTable = obj.tables[reference.startTableId]; + const endTable = obj.tables[reference.endTableId]; + const deleteConstraint = SQL_TO_DJANGO_DELETE_CONSTRAINT_MAPPING[reference.deleteConstraint.toUpperCase()] || 'CASCADE'; + const updateConstraint = SQL_TO_DJANGO_UPDATE_CONSTRAINT_MAPPING[reference.updateConstraint.toUpperCase()] || 'CASCADE'; + djangoCode += `class ${startTable.name}(models.Model) {\n`; + djangoCode += ` ${endTable.name} = models.ForeignKey('${endTable.name}', on_delete=models.${deleteConstraint}, related_name='${startTable.name.toLowerCase()}_${endTable.name.toLowerCase()}', db_column='${endTable.name.toLowerCase()}', on_update=models.${updateConstraint})\n`; + djangoCode += `\n`; + }); + + return djangoCode; +} + export function jsonToMariaDB(obj) { return `${obj.tables .map(