Skip to content

Commit

Permalink
feat: import sql and export dbml
Browse files Browse the repository at this point in the history
commit 8215aa4
Author: Jingchao Di <[email protected]>
Date:   Mon May 13 01:55:46 2024 +0800

    feat: export current dbml to sql

commit e01b005
Author: Jingchao Di <[email protected]>
Date:   Mon May 13 01:17:23 2024 +0800

    feat: support import sql
  • Loading branch information
alswl committed May 12, 2024
1 parent cbce7cc commit 2c58aa5
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 14 deletions.
1 change: 0 additions & 1 deletion src/components/viewer/viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Snapline } from '@antv/x6-plugin-snapline';
import React, { useEffect, useRef, useState } from 'react';

interface Props {
code: string;
database: any;
}

Expand Down
171 changes: 158 additions & 13 deletions src/pages/Home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,53 @@
import { CompilerDiagnostic, Parser } from '@dbml/core';
import { Col, Row, message } from 'antd';
import { CompilerDiagnostic, exporter, importer, Parser } from '@dbml/core';
import { Col, FloatButton, message, Modal, Row, Select, Space } from 'antd';
import { debounce } from 'lodash-es';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import MonacoEditor from 'react-monaco-editor';

import { InitCode } from '@/components/editor';
import Viewer from '@/components/viewer/viewer';
import { ExportOutlined, ImportOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { CompilerError } from '@dbml/core/types/parse/error';
import TextArea from 'antd/es/input/TextArea';
import './index.less';

type ImportFormat =
| 'dbml'
| 'mysql'
| 'postgres'
| 'json'
| 'mssql'
| 'postgresLegacy';

type ExportFormat = 'dbml' | 'mysql' | 'postgres' | 'json' | 'mssql' | 'oracle';

export default () => {
const [messageApi, contextHolder] = message.useMessage();
const parser = new Parser();
const initialDatabase = parser.parse(InitCode, 'dbmlv2');

const [code] = useState(InitCode);
let initialDatabase = parser.parse(code, 'dbmlv2');
const [code, setCode] = useState(InitCode);
const [database, setDatabase] = useState(initialDatabase);

const [importText, setImportText] = useState('');
const [importFormat, setImportFormat] = useState<ImportFormat>('mysql');
const [isImportModalOpen, setIsImportModalOpen] = useState(false);

const [isExportModalOpen, setIsExportModalOpen] = useState(false);
const [exportFormat, setExportFormat] = useState<ExportFormat>('mysql');
const [exportText, setExportText] = useState('');
const [regen, setRegen] = useState(0);

// editorDidMount
const editorDidMount = () => {
setDatabase(initialDatabase);
};

// onchange
const onChange = (newValue: any) => {
// code change
useEffect(() => {
try {
const newDB = parser.parse(newValue, 'dbmlv2');
console.log(newDB);
const newDB = parser.parse(code, 'dbmlv2');
setDatabase(newDB);
} catch (e) {
if (e as CompilerError) {
Expand All @@ -38,20 +58,146 @@ export default () => {
.join('\n');

messageApi.error(diags);
console.error(e);
// TODO hl to editor
} else if (e instanceof Error) {
messageApi.error(`${e.message}`);
} else {
throw e;
}
}
}, [code]);

// editor change
const editorOnChange = (newValue: any) => {
setCode(newValue);
};
const debouncedOnChange = debounce(editorOnChange, 500);

const handleImport = () => {
try {
const s = importer.import(importText, importFormat);
setCode(s);
setIsImportModalOpen(false);
} catch (e) {
if (e as CompilerError) {
const diags = (e as CompilerError).diags
.map((d: CompilerDiagnostic) => {
return `${d.location.start.line}:${d.location.start.column} ${d.message}`;
})
.join('\n');

messageApi.error(diags);
} else if (e instanceof Error) {
messageApi.error(`${e.message}`);
return;
} else {
throw e;
}
}
};
const debouncedOnChange = debounce(onChange, 500);

useEffect(() => {
if (!isExportModalOpen) return;

try {
const s = exporter.export(code, exportFormat);
setExportText(s);
} catch (e) {
if (e as CompilerError) {
const diags = (e as CompilerError).diags
.map((d: CompilerDiagnostic) => {
return `${d.location.start.line}:${d.location.start.column} ${d.message}`;
})
.join('\n');

messageApi.error(diags);
} else if (e instanceof Error) {
messageApi.error(`${e.message}`);
} else {
throw e;
}
}
}, [exportFormat, regen]);

return (
<>
{contextHolder}
<FloatButton
tooltip={<div>Import SQL</div>}
icon={<ImportOutlined />}
style={{ left: 24 }}
onClick={function () {
setIsImportModalOpen(true);
}}
/>
<FloatButton
tooltip={<div>Export SQL</div>}
icon={<ExportOutlined />}
style={{ left: 72 }}
onClick={function () {
setRegen(regen + 1);
setIsExportModalOpen(true);
}}
/>

<Modal
title="Import SQL"
open={isImportModalOpen}
onOk={handleImport}
onCancel={() => {
setIsImportModalOpen(false);
}}
>
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
<Select
defaultValue={importFormat}
style={{ width: 120 }}
onChange={(v) => setImportFormat(v)}
options={[
{ value: 'mysql', label: 'MySQL' },
{ value: 'postgres', label: 'Postgres' },
{ value: 'postgresLegacy', label: 'Postgres Legacy' },
{ value: 'dbml', label: 'DBML' },
{ value: 'mssql', label: 'MSSQL' },
{ value: 'json', label: 'JSON' },
]}
/>
<TextArea
rows={24}
placeholder="Import your schema"
onChange={(e) => setImportText(e.target.value)}
/>
</Space>
</Modal>

<Modal
title="Export SQL"
open={isExportModalOpen}
onOk={() => {
setIsExportModalOpen(false);
}}
onCancel={() => {
setIsExportModalOpen(false);
}}
>
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
<Select
defaultValue={exportFormat}
style={{ width: 120 }}
onChange={(v) => setExportFormat(v)}
options={[
{ value: 'mysql', label: 'MySQL' },
{ value: 'postgres', label: 'Postgres' },
{ value: 'dbml', label: 'DBML' },
{ value: 'mssql', label: 'MSSQL' },
{ value: 'oracle', label: 'Oracle' },
{ value: 'json', label: 'JSON' },
]}
/>
<TextArea rows={24} value={exportText} readOnly />
</Space>
</Modal>

<PageContainer ghost header={{ title: '' }}>
<Row gutter={[8, 8]}>
<Col xxl={12} xl={12} lg={12} md={24} sm={24} xs={24}>
Expand All @@ -71,12 +217,11 @@ export default () => {
}}
onChange={debouncedOnChange}
editorDidMount={editorDidMount}
// handle resize TODO
/>
</div>
</Col>
<Col xxl={12} xl={12} lg={12} md={24} sm={24} xs={24}>
<Viewer code={code} database={database} />
<Viewer database={database} />
</Col>
</Row>
</PageContainer>
Expand Down

0 comments on commit 2c58aa5

Please sign in to comment.