1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-04-26 15:58:42 +02:00

feat: database creation

This commit is contained in:
Fabio 2020-09-25 12:39:58 +02:00
parent c1cdd03938
commit 3d0a83f2cf
12 changed files with 311 additions and 73 deletions

View File

@ -66,36 +66,4 @@ export default connections => {
connections[uid].destroy(); connections[uid].destroy();
delete connections[uid]; delete connections[uid];
}); });
ipcMain.handle('get-structure', async (event, uid) => {
try {
const { rows: structure } = await connections[uid]
.select('*')
.schema('information_schema')
.from('TABLES')
.orderBy({ TABLE_SCHEMA: 'ASC', TABLE_NAME: 'ASC' })
.run();
return { status: 'success', response: structure };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('raw-query', async (event, { uid, query, schema }) => {
if (!query) return;
try {
if (schema)
await connections[uid].use(schema);
const result = await connections[uid].raw(query, true);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
}; };

View File

@ -0,0 +1,70 @@
import { ipcMain } from 'electron';
export default connections => {
ipcMain.handle('create-database', async (event, params) => {
try {
const query = `CREATE DATABASE \`${params.name}\` COLLATE ${params.collation}`;
const result = await connections[params.uid].raw(query, true);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-structure', async (event, uid) => {
try {
const { rows: structure } = await connections[uid]
.select('*')
.schema('information_schema')
.from('TABLES')
.orderBy({ TABLE_SCHEMA: 'ASC', TABLE_NAME: 'ASC' })
.run();
return { status: 'success', response: structure };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-collations', async (event, uid) => {
try {
const result = await connections[uid].getCollations();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-variables', async (event, uid) => {
try {
const result = await connections[uid].getVariables();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('raw-query', async (event, { uid, query, schema }) => {
if (!query) return;
try {
if (schema)
await connections[uid].use(schema);
const result = await connections[uid].raw(query, true);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
};

View File

@ -2,14 +2,14 @@ import connection from './connection';
import tables from './tables'; import tables from './tables';
import updates from './updates'; import updates from './updates';
import application from './application'; import application from './application';
import properties from './properties'; import database from './database';
const connections = {}; const connections = {};
export default () => { export default () => {
connection(connections); connection(connections);
tables(connections); tables(connections);
properties(connections); database(connections);
updates(); updates();
application(); application();
}; };

View File

@ -1,14 +0,0 @@
import { ipcMain } from 'electron';
export default (connections) => {
ipcMain.handle('get-collations', async (event, uid) => {
try {
const result = await connections[uid].getCollations();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
};

View File

@ -31,9 +31,44 @@ export class MySQLClient extends AntaresCore {
return this.raw(sql); return this.raw(sql);
} }
getCollations () { /**
* SHOW COLLATION
*
* @returns
* @memberof MySQLClient
*/
async getCollations () {
const sql = 'SHOW COLLATION'; const sql = 'SHOW COLLATION';
return this.raw(sql); const results = await this.raw(sql);
return results.rows.map(row => {
return {
charset: row.Charset,
collation: row.Collation,
compiled: row.Compiled.includes('Yes'),
default: row.Default.includes('Yes'),
id: row.Id,
sortLen: row.Sortlen
};
});
}
/**
* SHOW VARIABLES
*
* @returns
* @memberof MySQLClient
*/
async getVariables () {
const sql = 'SHOW VARIABLES';
const results = await this.raw(sql);
return results.rows.map(row => {
return {
name: row.Variable_name,
value: row.Value
};
});
} }
/** /**

View File

@ -0,0 +1,125 @@
<template>
<div class="modal active">
<a class="modal-overlay" @click.stop="closeModal" />
<div class="modal-container p-0">
<div class="modal-header pl-2">
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-database-plus mr-1" /> {{ $t('message.createNewDatabase') }}
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
</div>
<div class="modal-body pb-0">
<div class="content">
<form class="form-horizontal">
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.name') }}:</label>
</div>
<div class="col-9">
<input
v-model="database.name"
class="form-input"
type="text"
required
:placeholder="$t('message.databaseName')"
>
</div>
</div>
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.collation') }}:</label>
</div>
<div class="col-9">
<select v-model="database.collation" class="form-select">
<option
v-for="collation in collations"
:key="collation.id"
:value="collation.collation"
>
{{ collation.collation }}
</option>
</select>
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
</div>
</div>
</form>
</div>
</div>
<div class="modal-footer text-light">
<button class="btn btn-primary mr-2" @click.stop="createDatabase">
{{ $t('word.add') }}
</button>
<button class="btn btn-link" @click.stop="closeModal">
{{ $t('word.close') }}
</button>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import Database from '@/ipc-api/Database';
export default {
name: 'ModalNewDB',
data () {
return {
database: {
name: '',
collation: ''
}
};
},
computed: {
...mapGetters({
selectedWorkspace: 'workspaces/getSelected',
getWorkspace: 'workspaces/getWorkspace',
getDatabaseVariable: 'workspaces/getDatabaseVariable'
}),
collations () {
return this.getWorkspace(this.selectedWorkspace).collations;
},
defaultCollation () {
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value || '';
}
},
created () {
this.database = { ...this.database, collation: this.defaultCollation };
},
methods: {
...mapActions({
addNotification: 'notifications/addNotification'
}),
async createDatabase () {
try {
const { status, response } = await Database.createDatabase({
uid: this.selectedWorkspace,
...this.database
});
if (status === 'success') {
this.closeModal();
this.$emit('reload');
}
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
},
closeModal () {
this.$emit('close');
}
}
};
</script>
<style scoped>
.modal-container {
max-width: 360px;
}
</style>

View File

@ -10,13 +10,18 @@
<span class="workspace-explorebar-title">{{ connectionName }}</span> <span class="workspace-explorebar-title">{{ connectionName }}</span>
<span v-if="workspace.connected" class="workspace-explorebar-tools"> <span v-if="workspace.connected" class="workspace-explorebar-tools">
<i <i
class="mdi mdi-18px mdi-refresh c-hand" class="mdi mdi-18px mdi-database-plus c-hand mr-2"
:title="$t('message.createNewDatabase')"
@click="showNewDBModal"
/>
<i
class="mdi mdi-18px mdi-refresh c-hand mr-2"
:class="{'rotate':isRefreshing}" :class="{'rotate':isRefreshing}"
:title="$t('word.refresh')" :title="$t('word.refresh')"
@click="refresh" @click="refresh"
/> />
<i <i
class="mdi mdi-18px mdi-power-plug-off c-hand mr-1 ml-2" class="mdi mdi-18px mdi-power-plug-off c-hand"
:title="$t('word.disconnect')" :title="$t('word.disconnect')"
@click="disconnectWorkspace(connection.uid)" @click="disconnectWorkspace(connection.uid)"
/> />
@ -36,6 +41,11 @@
/> />
</div> </div>
</div> </div>
<ModalNewDB
v-if="isNewDBModal"
@close="hideNewDBModal"
@reload="refresh"
/>
</div> </div>
</template> </template>
@ -44,12 +54,14 @@ import { mapGetters, mapActions } from 'vuex';
import _ from 'lodash'; import _ from 'lodash';
import WorkspaceConnectPanel from '@/components/WorkspaceConnectPanel'; import WorkspaceConnectPanel from '@/components/WorkspaceConnectPanel';
import WorkspaceExploreBarDatabase from '@/components/WorkspaceExploreBarDatabase'; import WorkspaceExploreBarDatabase from '@/components/WorkspaceExploreBarDatabase';
import ModalNewDB from '@/components/ModalNewDB';
export default { export default {
name: 'WorkspaceExploreBar', name: 'WorkspaceExploreBar',
components: { components: {
WorkspaceConnectPanel, WorkspaceConnectPanel,
WorkspaceExploreBarDatabase WorkspaceExploreBarDatabase,
ModalNewDB
}, },
props: { props: {
connection: Object, connection: Object,
@ -58,6 +70,7 @@ export default {
data () { data () {
return { return {
isRefreshing: false, isRefreshing: false,
isNewDBModal: false,
localWidth: null localWidth: null
}; };
}, },
@ -117,6 +130,12 @@ export default {
}, },
stopResize () { stopResize () {
window.removeEventListener('mousemove', this.resize); window.removeEventListener('mousemove', this.resize);
},
showNewDBModal () {
this.isNewDBModal = true;
},
hideNewDBModal () {
this.isNewDBModal = false;
} }
} }
}; };

View File

@ -44,7 +44,7 @@
</template> </template>
<script> <script>
import Connection from '@/ipc-api/Connection'; import Database from '@/ipc-api/Database';
import Tables from '@/ipc-api/Tables'; import Tables from '@/ipc-api/Tables';
import QueryEditor from '@/components/QueryEditor'; import QueryEditor from '@/components/QueryEditor';
import WorkspaceQueryTable from '@/components/WorkspaceQueryTable'; import WorkspaceQueryTable from '@/components/WorkspaceQueryTable';
@ -114,7 +114,7 @@ export default {
query query
}; };
const { status, response } = await Connection.rawQuery(params); const { status, response } = await Database.rawQuery(params);
if (status === 'success') { if (status === 'success') {
this.results = Array.isArray(response) ? response : [response]; this.results = Array.isArray(response) ? response : [response];

View File

@ -75,7 +75,8 @@ module.exports = {
openNewTab: 'Open a new tab', openNewTab: 'Open a new tab',
affectedRows: 'Affected rows', affectedRows: 'Affected rows',
createNewDatabase: 'Create new Database', createNewDatabase: 'Create new Database',
databaseName: 'Database name' databaseName: 'Database name',
serverDefault: 'Server default'
}, },
// Date and Time // Date and Time
short: { short: {

View File

@ -17,16 +17,4 @@ export default class {
static disconnect (uid) { static disconnect (uid) {
return ipcRenderer.invoke('disconnect', uid); return ipcRenderer.invoke('disconnect', uid);
} }
static getStructure (uid) {
return ipcRenderer.invoke('get-structure', uid);
}
static getCollations (uid) {
return ipcRenderer.invoke('get-collations', uid);
}
static rawQuery (params) {
return ipcRenderer.invoke('raw-query', params);
}
} }

View File

@ -0,0 +1,24 @@
'use strict';
import { ipcRenderer } from 'electron';
export default class {
static createDatabase (params) {
return ipcRenderer.invoke('create-database', params);
}
static getStructure (uid) {
return ipcRenderer.invoke('get-structure', uid);
}
static getCollations (uid) {
return ipcRenderer.invoke('get-collations', uid);
}
static getVariables (uid) {
return ipcRenderer.invoke('get-variables', uid);
}
static rawQuery (params) {
return ipcRenderer.invoke('raw-query', params);
}
}

View File

@ -1,9 +1,10 @@
'use strict'; 'use strict';
import Connection from '@/ipc-api/Connection'; import Connection from '@/ipc-api/Connection';
import Database from '@/ipc-api/Database';
import { uidGen } from 'common/libs/uidGen'; import { uidGen } from 'common/libs/uidGen';
const tabIndex = []; const tabIndex = [];
function remapStructure (structure) { // TODO: move to main process and add fields (for autocomplete purpose) function remapStructure (structure) { // TODO: move to main process and add fields (for autocomplete purpose), also add empty database
const databases = structure.map(table => table.TABLE_SCHEMA) const databases = structure.map(table => table.TABLE_SCHEMA)
.filter((value, index, self) => self.indexOf(value) === index); .filter((value, index, self) => self.indexOf(value) === index);
@ -31,6 +32,9 @@ export default {
getWorkspace: state => uid => { getWorkspace: state => uid => {
return state.workspaces.find(workspace => workspace.uid === uid); return state.workspaces.find(workspace => workspace.uid === uid);
}, },
getDatabaseVariable: state => (uid, name) => {
return state.workspaces.find(workspace => workspace.uid === uid).variables.find(variable => variable.name === name);
},
getWorkspaceTab: (state, getters) => tUid => { getWorkspaceTab: (state, getters) => tUid => {
if (!getters.getSelected) return; if (!getters.getSelected) return;
const workspace = state.workspaces.find(workspace => workspace.uid === getters.getSelected); const workspace = state.workspaces.find(workspace => workspace.uid === getters.getSelected);
@ -57,8 +61,11 @@ export default {
REFRESH_STRUCTURE (state, { uid, structure }) { REFRESH_STRUCTURE (state, { uid, structure }) {
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, structure } : workspace); state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, structure } : workspace);
}, },
REFRESH_COLLATIONS (state, { uid, collations }) { // TODO: Save collations REFRESH_COLLATIONS (state, { uid, collations }) {
// state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, structure } : workspace); state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, collations } : workspace);
},
REFRESH_VARIABLES (state, { uid, variables }) {
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, variables } : workspace);
}, },
ADD_WORKSPACE (state, workspace) { ADD_WORKSPACE (state, workspace) {
state.workspaces.push(workspace); state.workspaces.push(workspace);
@ -150,6 +157,7 @@ export default {
else { else {
commit('ADD_CONNECTED', { uid: connection.uid, structure: remapStructure(response) }); commit('ADD_CONNECTED', { uid: connection.uid, structure: remapStructure(response) });
dispatch('refreshCollations', connection.uid); dispatch('refreshCollations', connection.uid);
dispatch('refreshVariables', connection.uid);
} }
} }
catch (err) { catch (err) {
@ -158,7 +166,7 @@ export default {
}, },
async refreshStructure ({ dispatch, commit }, uid) { async refreshStructure ({ dispatch, commit }, uid) {
try { try {
const { status, response } = await Connection.getStructure(uid); const { status, response } = await Database.getStructure(uid);
if (status === 'error') if (status === 'error')
dispatch('notifications/addNotification', { status, message: response }, { root: true }); dispatch('notifications/addNotification', { status, message: response }, { root: true });
else else
@ -170,7 +178,7 @@ export default {
}, },
async refreshCollations ({ dispatch, commit }, uid) { async refreshCollations ({ dispatch, commit }, uid) {
try { try {
const { status, response } = await Connection.getCollations(uid); const { status, response } = await Database.getCollations(uid);
if (status === 'error') if (status === 'error')
dispatch('notifications/addNotification', { status, message: response }, { root: true }); dispatch('notifications/addNotification', { status, message: response }, { root: true });
else else
@ -180,6 +188,18 @@ export default {
dispatch('notifications/addNotification', { status: 'error', message: err.stack }, { root: true }); dispatch('notifications/addNotification', { status: 'error', message: err.stack }, { root: true });
} }
}, },
async refreshVariables ({ dispatch, commit }, uid) {
try {
const { status, response } = await Database.getVariables(uid);
if (status === 'error')
dispatch('notifications/addNotification', { status, message: response }, { root: true });
else
commit('REFRESH_VARIABLES', { uid, variables: response });
}
catch (err) {
dispatch('notifications/addNotification', { status: 'error', message: err.stack }, { root: true });
}
},
removeConnected ({ commit }, uid) { removeConnected ({ commit }, uid) {
Connection.disconnect(uid); Connection.disconnect(uid);
commit('REMOVE_CONNECTED', uid); commit('REMOVE_CONNECTED', uid);
@ -203,6 +223,8 @@ export default {
keyUsage: [] keyUsage: []
}], }],
structure: {}, structure: {},
variables: [],
collations: [],
breadcrumbs: {} breadcrumbs: {}
}; };