Skip to content

Commit

Permalink
feat: DDL query in table settings for MySQL and PostgreSQL, closes #581
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabio286 committed May 25, 2023
1 parent 5669872 commit f454b4b
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 6 deletions.
3 changes: 2 additions & 1 deletion src/common/customizations/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ export const defaults: Customizations = {
routines: false,
functions: false,
schedulers: false,
// Settings
// Misc
elementsWrapper: '',
stringsWrapper: '"',
tableAdd: false,
tableTruncateDisableFKCheck: false,
tableDdl: false,
viewAdd: false,
triggerAdd: false,
triggerFunctionAdd: false,
Expand Down
1 change: 1 addition & 0 deletions src/common/customizations/mysql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const customizations: Customizations = {
tableAdd: true,
tableTruncateDisableFKCheck: true,
tableDuplicate: true,
tableDdl: true,
viewAdd: true,
triggerAdd: true,
routineAdd: true,
Expand Down
3 changes: 2 additions & 1 deletion src/common/customizations/postgresql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ export const customizations: Customizations = {
triggerFunctions: true,
routines: true,
functions: true,
// Settings
// Misc
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableDuplicate: true,
tableDdl: true,
viewAdd: true,
triggerAdd: true,
triggerFunctionAdd: true,
Expand Down
3 changes: 2 additions & 1 deletion src/common/interfaces/customizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface Customizations {
routines?: boolean;
functions?: boolean;
schedulers?: boolean;
// Settings
// Misc
elementsWrapper: string;
stringsWrapper: string;
tableAdd?: boolean;
Expand All @@ -39,6 +39,7 @@ export interface Customizations {
tableArray?: boolean;
tableRealCount?: boolean;
tableTruncateDisableFKCheck?: boolean;
tableDdl?: boolean;
viewAdd?: boolean;
viewSettings?: boolean;
triggerAdd?: boolean;
Expand Down
11 changes: 11 additions & 0 deletions src/main/ipc-handlers/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ export default (connections: {[key: string]: antares.Client}) => {
}
});

ipcMain.handle('get-table-ddl', async (event, params) => {
try {
const result = await connections[params.uid].getTableDll(params);

return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});

ipcMain.handle('get-key-usage', async (event, params) => {
try {
const result = await connections[params.uid].getKeyUsage(params);
Expand Down
4 changes: 4 additions & 0 deletions src/main/libs/AntaresCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ export abstract class AntaresCore {
throw new Error('Method "dropSchema" not implemented');
}

getTableDll (...args: any) {
throw new Error('Method "getTableDll" not implemented');
}

getDatabaseCollation (...args: any) {
throw new Error('Method "getDatabaseCollation" not implemented');
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/libs/clients/MySQLClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,17 @@ export class MySQLClient extends AntaresCore {
});
}

async getTableDll ({ schema, table }: { schema: string; table: string }) {
const { rows } = await this.raw<antares.QueryResult<{
'Create Table'?: string;
Table: string;
}>>(`SHOW CREATE TABLE \`${schema}\`.\`${table}\``);

if (rows.length)
return rows[0]['Create Table'];
else return '';
}

async getKeyUsage ({ schema, table }: { schema: string; table: string }) {
interface KeyResult {
TABLE_SCHEMA: string;
Expand Down
140 changes: 140 additions & 0 deletions src/main/libs/clients/PostgreSQLClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,146 @@ export class PostgreSQLClient extends AntaresCore {
}, {} as {table: string; schema: string}[]);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async getTableDll ({ schema, table }: { schema: string; table: string }) {
// const { rows } = await this.raw<antares.QueryResult<{'ddl'?: string}>>(`
// SELECT
// 'CREATE TABLE ' || relname || E'\n(\n' ||
// array_to_string(
// array_agg(' ' || column_name || ' ' || type || ' '|| not_null)
// , E',\n'
// ) || E'\n);\n' AS ddl
// FROM (
// SELECT
// a.attname AS column_name
// , pg_catalog.format_type(a.atttypid, a.atttypmod) AS type
// , CASE WHEN a.attnotnull THEN 'NOT NULL' ELSE 'NULL' END AS not_null
// , c.relname
// FROM pg_attribute a, pg_class c, pg_type t
// WHERE a.attnum > 0
// AND a.attrelid = c.oid
// AND a.atttypid = t.oid
// AND c.relname = '${table}'
// ORDER BY a.attnum
// ) AS tabledefinition
// GROUP BY relname
// `);

// if (rows.length)
// return rows[0].ddl;
// else return '';

/* eslint-disable camelcase */
interface SequenceRecord {
sequence_catalog: string;
sequence_schema: string;
sequence_name: string;
data_type: string;
numeric_precision: number;
numeric_precision_radix: number;
numeric_scale: number;
start_value: string;
minimum_value: string;
maximum_value: string;
increment: string;
cycle_option: string;
}
/* eslint-enable camelcase */

let createSql = '';
const sequences = [];
const columnsSql = [];
const arrayTypes: {[key: string]: string} = {
_int2: 'smallint',
_int4: 'integer',
_int8: 'bigint',
_float4: 'real',
_float8: 'double precision',
_char: '"char"',
_varchar: 'character varying'
};

// Table columns
const { rows } = await this.raw(`
SELECT *
FROM "information_schema"."columns"
WHERE "table_schema" = '${schema}'
AND "table_name" = '${table}'
ORDER BY "ordinal_position" ASC
`, { schema: 'information_schema' });

if (!rows.length) return '';

for (const column of rows) {
let fieldType = column.data_type;
if (fieldType === 'USER-DEFINED') fieldType = `"${schema}".${column.udt_name}`;
else if (fieldType === 'ARRAY') {
if (Object.keys(arrayTypes).includes(fieldType))
fieldType = arrayTypes[column.udt_name] + '[]';
else
fieldType = column.udt_name.replaceAll('_', '') + '[]';
}

const columnArr = [
`"${column.column_name}"`,
`${fieldType}${column.character_maximum_length ? `(${column.character_maximum_length})` : ''}`
];

if (column.column_default) {
columnArr.push(`DEFAULT ${column.column_default}`);
if (column.column_default.includes('nextval')) {
const sequenceName = column.column_default.split('\'')[1];
sequences.push(sequenceName);
}
}
if (column.is_nullable === 'NO') columnArr.push('NOT NULL');

columnsSql.push(columnArr.join(' '));
}

// Table sequences
for (let sequence of sequences) {
if (sequence.includes('.')) sequence = sequence.split('.')[1];

const { rows } = await this.select('*')
.schema('information_schema')
.from('sequences')
.where({ sequence_schema: `= '${schema}'`, sequence_name: `= '${sequence}'` })
.run<SequenceRecord>();

if (rows.length) {
createSql += `CREATE SEQUENCE "${schema}"."${sequence}"
START WITH ${rows[0].start_value}
INCREMENT BY ${rows[0].increment}
MINVALUE ${rows[0].minimum_value}
MAXVALUE ${rows[0].maximum_value}
CACHE 1;\n`;

// createSql += `\nALTER TABLE "${sequence}" OWNER TO ${this._client._params.user};\n\n`;
}
}

// Table create
createSql += `\nCREATE TABLE "${schema}"."${table}"(
${columnsSql.join(',\n ')}
);\n`;

// createSql += `\nALTER TABLE "${tableName}" OWNER TO ${this._client._params.user};\n\n`;

// Table indexes
createSql += '\n';
const { rows: indexes } = await this.select('*')
.schema('pg_catalog')
.from('pg_indexes')
.where({ schemaname: `= '${schema}'`, tablename: `= '${table}'` })
.run<{indexdef: string}>();

for (const index of indexes)
createSql += `${index.indexdef};\n`;

return createSql;
}

async getKeyUsage ({ schema, table }: { schema: string; table: string }) {
/* eslint-disable camelcase */
interface KeyResult {
Expand Down
2 changes: 1 addition & 1 deletion src/main/workers/exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import MysqlExporter from '../libs/exporters/sql/MysqlExporter';
import PostgreSQLExporter from '../libs/exporters/sql/PostgreSQLExporter';
let exporter: antares.Exporter;

process.on('message', async ({ type, client, tables, options }) => {
process.on('message', async ({ type, client, tables, options }: any) => {
if (type === 'init') {
const connection = await ClientsFactory.getClient({
client: client.name,
Expand Down
5 changes: 5 additions & 0 deletions src/renderer/components/BaseTextEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ watch(() => props.mode, () => {
editor.session.setMode(`ace/mode/${props.mode}`);
});
watch(() => props.modelValue, () => {
if (editor)
editor.session.setValue(props.modelValue);
});
watch(editorTheme, () => {
if (editor)
editor.setTheme(`ace/theme/${editorTheme.value}`);
Expand Down
31 changes: 30 additions & 1 deletion src/renderer/components/WorkspaceTabPropsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,25 @@
<span>{{ t('word.indexes') }}</span>
</button>
<button
class="btn btn-dark btn-sm"
class="btn btn-dark btn-sm mr-0"
:disabled="isSaving"
@click="showForeignModal"
>
<i class="mdi mdi-24px mdi-key-link mr-1" />
<span>{{ t('word.foreignKeys') }}</span>
</button>

<div class="divider-vert py-3" />

<button
v-if="workspace.customizations.tableDdl"
class="btn btn-dark btn-sm"
:disabled="isSaving"
@click="showDdlModal"
>
<i class="mdi mdi-24px mdi-code-tags mr-1" />
<span>{{ t('word.ddl') }}</span>
</button>
</div>
<div class="workspace-query-info">
<div class="d-flex" :title="t('word.schema')">
Expand Down Expand Up @@ -169,6 +181,13 @@
@hide="hideForeignModal"
@foreigns-update="foreignsUpdate"
/>
<WorkspaceTabPropsTableDdlModal
v-if="isDdlModal"
:table="table"
:schema="schema"
:workspace="workspace"
@hide="hideDdlModal"
/>
</div>
</template>

Expand All @@ -186,6 +205,7 @@ import BaseSelect from '@/components/BaseSelect.vue';
import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue';
import WorkspaceTabPropsTableIndexesModal from '@/components/WorkspaceTabPropsTableIndexesModal.vue';
import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue';
import WorkspaceTabPropsTableDdlModal from '@/components/WorkspaceTabPropsTableDdlModal.vue';
import { ipcRenderer } from 'electron';
import { useSettingsStore } from '@/stores/settings';
Expand Down Expand Up @@ -221,6 +241,7 @@ const isLoading = ref(false);
const isSaving = ref(false);
const isIndexesModal = ref(false);
const isForeignModal = ref(false);
const isDdlModal = ref(false);
const originalFields: Ref<TableField[]> = ref([]);
const localFields: Ref<TableField[]> = ref([]);
const originalKeyUsage: Ref<TableForeign[]> = ref([]);
Expand Down Expand Up @@ -649,6 +670,14 @@ const hideForeignModal = () => {
isForeignModal.value = false;
};
const showDdlModal = () => {
isDdlModal.value = true;
};
const hideDdlModal = () => {
isDdlModal.value = false;
};
const foreignsUpdate = (foreigns: TableForeign[]) => {
localKeyUsage.value = foreigns;
};
Expand Down
Loading

0 comments on commit f454b4b

Please sign in to comment.