Improvements

This commit is contained in:
Fabio 2020-06-06 16:27:42 +02:00
parent cd42b65b9e
commit 268688cdb8
7 changed files with 193 additions and 14 deletions

View File

@ -2,6 +2,7 @@
import { ipcMain } from 'electron';
import knex from 'knex';
import InformationSchema from '../models/InformationSchema';
import { RawQuery } from '../models/RawQuery';
const connections = {};
@ -74,4 +75,19 @@ export default () => {
return { status: 'error', response: err.toString() };
}
});
ipcMain.on('runQuery', async (event, { connection, query, database }) => {
const knexIstance = connections[connection.uid];
const Query = new RawQuery({ knexIstance, database });
try {
Query.runQuery(query);
Query.on('row', row => {
event.sender.send('row', row);
});
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
};

View File

@ -0,0 +1,22 @@
'use strict';
import { EventEmitter } from 'events';
export class RawQuery extends EventEmitter {
constructor ({ knexIstance, database }) {
super();
this.conn = knexIstance;
this.database = database;
}
async runQuery (query) {
if (this.database) await this.conn.raw(`USE \`${this.database}\``);
const stream = this.conn.raw(query).stream();
stream.on('data', row => {
this.emit('row', row);
});
stream.on('error', err => {
this.emit('error', err);
});
}
}

View File

@ -89,6 +89,7 @@ export default {
padding: 0;
justify-content: flex-start;
height: calc(100vh - #{$excluding-size});
width: calc(100% - #{$settingbar-width});
> .columns{
height: calc(100vh - #{$footer-height});

View File

@ -85,7 +85,7 @@ export default {
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
max-width: 25rem;
max-width: 30rem;
user-select: none;
}

View File

@ -1,18 +1,18 @@
<template>
<div v-show="isSelected" class="workspace column columns">
<div v-show="isSelected" class="workspace column columns col-gapless">
<WorkspaceExploreBar :connection="connection" :is-selected="isSelected" />
<div class="workspace-tabs column p-0">
<ul class="tab tab-block">
<div v-if="workspace.connected" class="workspace-tabs column columns col-gapless">
<ul class="tab tab-block column col-12">
<li
v-for="(tab, key) of workspace.tabs"
:key="tab.uid"
class="tab-item"
:class="{'active': selectedTab === tab.uid}"
>
<a href="#">Query #{{ key }} <span class="btn btn-clear" /></a>
<a href="#">Query #{{ key }} <span v-if="workspace.tabs.length > 1" class="btn btn-clear" /></a>
</li>
</ul>
<QueryEditor v-model="query" />
<WorkspaceQueryTab :connection="connection" />
</div>
</div>
</template>
@ -21,22 +21,17 @@
import { mapGetters, mapActions } from 'vuex';
import Connection from '@/ipc-api/Connection';
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar';
import QueryEditor from '@/components/QueryEditor';
import WorkspaceQueryTab from '@/components/WorkspaceQueryTab';
export default {
name: 'Workspace',
components: {
WorkspaceExploreBar,
QueryEditor
WorkspaceQueryTab
},
props: {
connection: Object
},
data () {
return {
query: ''
};
},
computed: {
...mapGetters({
selectedWorkspace: 'workspaces/getSelected',

View File

@ -1,5 +1,5 @@
<template>
<div class="p-relative">
<div class="column col-auto p-relative">
<div ref="resizer" class="workspace-explorebar-resizer" />
<div
ref="explorebar"

View File

@ -0,0 +1,145 @@
<template>
<div class="workspace-query-tab column col-12 columns col-gapless">
<div class="workspace-query-runner column col-12">
<QueryEditor v-model="query" />
<div class="workspace-query-runner-footer">
<div class="workspace-query-buttons">
<i class="material-icons text-success" @click="runQuery">play_arrow</i>
</div>
<div>
Schema: <b>{{ workspace.breadcrumbs.database }}</b>
</div>
</div>
</div>
<div ref="resultTable" class="workspace-query-results column col-12">
<table v-if="results.length" class="table table-hover">
<thead>
<tr>
<th v-for="field in fields" :key="field">
{{ field }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rKey) in results" :key="rKey">
<td v-for="(col, cKey) in row" :key="cKey">
{{ col }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import { ipcRenderer } from 'electron';
import QueryEditor from '@/components/QueryEditor';
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'WorkspaceQueryTab',
components: {
QueryEditor
},
props: {
connection: Object
},
data () {
return {
query: '',
results: []
};
},
computed: {
...mapGetters({
getWorkspace: 'workspaces/getWorkspace'
}),
workspace () {
return this.getWorkspace(this.connection.uid);
},
fields () {
return Object.keys(this.results[0]);
}
},
mounted () {
window.addEventListener('resize', this.resizeResults);
},
destroyed () {
window.removeEventListener('resize', this.resizeResults);
},
methods: {
...mapActions({
addNotification: 'notifications/addNotification'
}),
async runQuery () {
this.results = [];
this.resizeResults();
const params = {
connection: this.connection,
query: this.query,
database: this.workspace.breadcrumbs.database
};
try {
ipcRenderer.send('runQuery', params);
ipcRenderer.on('row', (event, row) => {
this.results.push(row);
});
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
},
resizeResults (e) {
const el = this.$refs.resultTable;
const footer = document.getElementById('footer');
if (el) {
const size = window.innerHeight - el.getBoundingClientRect().top - footer.offsetHeight;
el.style.height = size + 'px';
}
}
}
};
</script>
<style lang="scss">
.workspace-tabs{
align-content: baseline;
.workspace-query-runner{
.workspace-query-runner-footer{
display: flex;
justify-content: space-between;
padding: .2rem .6rem;
align-items: center;
.workspace-query-buttons{
display: flex;
}
}
}
.workspace-query-results{
overflow: auto;
white-space: nowrap;
th{
position: sticky;
top: 0;
background: $bg-color;
border-color: $bg-color-light;
}
td{
border-color: $bg-color-light;
padding: 0 .4rem;
}
}
}
</style>