mirror of
https://github.com/Fabio286/antares.git
synced 2025-03-29 01:30:10 +01:00
Improvements to query builder
This commit is contained in:
parent
aa7618ec8d
commit
6f03e66ef2
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,4 +4,5 @@ node_modules/
|
||||
thumbs.db
|
||||
.idea/
|
||||
.vscode
|
||||
TODO.md
|
||||
TODO.md
|
||||
*.txt
|
30
package-lock.json
generated
30
package-lock.json
generated
@ -1164,9 +1164,9 @@
|
||||
"integrity": "sha512-4mXKoDptrXAwZErQHrLzpe0FN/0Wmf5JRniSVIdwUrtDf9wnmEV1teCNLBo/TwuXhkK/bVegoEn/wmb+x0AuPg=="
|
||||
},
|
||||
"@types/readable-stream": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.5.tgz",
|
||||
"integrity": "sha512-Mq2eLkGYamlcolW603FY2ROBvcl90jPF+3jLkjpBV6qS+2aVeJqlgRG0TVAa1oWbmPdb5yOWlOPVvQle76nUNw==",
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-oAbOdOKhx5nu1+pBPiwEHh6gqA3ojgwwNwNIjNd67TqwEjvVePqe21mnYc6RrnGZ8aVPFBe6sci3cU2pKKwuug==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"safe-buffer": "*"
|
||||
@ -1522,9 +1522,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "8.10.60",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.60.tgz",
|
||||
"integrity": "sha512-YjPbypHFuiOV0bTgeF07HpEEqhmHaZqYNSdCKeBJa+yFoQ/7BC+FpJcwmi34xUIIRVFktnUyP1dPU8U0612GOg=="
|
||||
"version": "8.10.61",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.61.tgz",
|
||||
"integrity": "sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -7715,9 +7715,9 @@
|
||||
}
|
||||
},
|
||||
"jsbi": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.2.tgz",
|
||||
"integrity": "sha512-5nDXo1X9QVaXK/Cpb5VECV9ss1QPbjUuk1qSruHB1PK/g39Sd414K4nci99ElFDZv0vzxDEnKn3o49/Tn9Yagw=="
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.3.tgz",
|
||||
"integrity": "sha512-nBJqA0C6Qns+ZxurbEoIR56wyjiUszpNy70FHvxO5ervMoCbZVE3z3kxr5nKGhlxr/9MhKTSUBs7cAwwuf3g9w=="
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
@ -8538,13 +8538,6 @@
|
||||
"debug": "^4",
|
||||
"tarn": "^1.1.5",
|
||||
"tedious": "^6.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"tarn": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz",
|
||||
"integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"multicast-dns": {
|
||||
@ -11973,6 +11966,11 @@
|
||||
"inherits": "2"
|
||||
}
|
||||
},
|
||||
"tarn": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz",
|
||||
"integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g=="
|
||||
},
|
||||
"tedious": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/tedious/-/tedious-6.7.0.tgz",
|
||||
|
@ -4,9 +4,7 @@ import { AntaresConnector } from '../libs/AntaresConnector';
|
||||
import InformationSchema from '../models/InformationSchema';
|
||||
import Generic from '../models/Generic';
|
||||
|
||||
const connections = {};
|
||||
|
||||
export default () => {
|
||||
export default (connections) => {
|
||||
ipcMain.handle('testConnection', async (event, conn) => {
|
||||
const Connection = new AntaresConnector({
|
||||
client: conn.client,
|
||||
@ -46,9 +44,9 @@ export default () => {
|
||||
poolSize: 3
|
||||
});
|
||||
|
||||
Connection.connect();
|
||||
|
||||
try {
|
||||
await Connection.connect();
|
||||
|
||||
const { rows: structure } = await InformationSchema.getStructure(Connection);
|
||||
connections[conn.uid] = Connection;
|
||||
return { status: 'success', response: structure };
|
||||
@ -73,10 +71,10 @@ export default () => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('rawQuery', async (event, { uid, query, database }) => {
|
||||
ipcMain.handle('rawQuery', async (event, { uid, query, schema }) => {
|
||||
if (!query) return;
|
||||
try {
|
||||
const result = await Generic.raw(connections[uid], query, database);
|
||||
const result = await Generic.raw(connections[uid], query, schema);
|
||||
return { status: 'success', response: result };
|
||||
}
|
||||
catch (err) {
|
||||
|
@ -1,5 +1,9 @@
|
||||
import connection from './connection';
|
||||
import structure from './structure';
|
||||
|
||||
const connections = {};
|
||||
|
||||
export default () => {
|
||||
connection();
|
||||
connection(connections);
|
||||
structure(connections);
|
||||
};
|
||||
|
25
src/main/ipc-handlers/structure.js
Normal file
25
src/main/ipc-handlers/structure.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { ipcMain } from 'electron';
|
||||
import InformationSchema from '../models/InformationSchema';
|
||||
import Generic from '../models/Generic';
|
||||
|
||||
export default (connections) => {
|
||||
ipcMain.handle('getTableColumns', async (event, { uid, schema, table }) => {
|
||||
try {
|
||||
const result = await InformationSchema.getTableColumns(connections[uid], schema, table);
|
||||
return { status: 'success', response: result };
|
||||
}
|
||||
catch (err) {
|
||||
return { status: 'error', response: err.toString() };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('getTableData', async (event, { uid, schema, table }) => {
|
||||
try {
|
||||
const result = await Generic.getTableData(connections[uid], schema, table);
|
||||
return { status: 'success', response: result };
|
||||
}
|
||||
catch (err) {
|
||||
return { status: 'error', response: err.toString() };
|
||||
}
|
||||
});
|
||||
};
|
@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
import mysql from 'mysql2';
|
||||
import mssql from 'mssql';
|
||||
|
||||
/**
|
||||
* As Simple As Possible Query Builder
|
||||
@ -26,7 +27,7 @@ export class AntaresConnector {
|
||||
where: [],
|
||||
groupBy: [],
|
||||
orderBy: [],
|
||||
limit: '',
|
||||
limit: [],
|
||||
join: [],
|
||||
update: [],
|
||||
insert: [],
|
||||
@ -62,7 +63,7 @@ export class AntaresConnector {
|
||||
/**
|
||||
* @memberof AntaresConnector
|
||||
*/
|
||||
connect () {
|
||||
async connect () {
|
||||
switch (this._client) {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
@ -75,7 +76,15 @@ export class AntaresConnector {
|
||||
this._connection = pool.promise();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mssql': {
|
||||
const mssqlParams = {
|
||||
user: this._params.user,
|
||||
password: this._params.password,
|
||||
server: this._params.host
|
||||
};
|
||||
this._connection = await mssql.connect(mssqlParams);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -111,28 +120,81 @@ export class AntaresConnector {
|
||||
return this;
|
||||
}
|
||||
|
||||
getQueryString () {
|
||||
const selectArray = this._query.select.reduce(this._reducer, []);
|
||||
const selectRaw = selectArray.length ? `SELECT ${selectArray.join(', ')}` : 'SELECT *';
|
||||
const fromRaw = this._query.from ? `FROM ${this._query.schema ? `\`${this._query.schema}\`.` : ''} \`${this._query.from}\`` : '';
|
||||
const whereArray = this._query.where.reduce(this._reducer, []);
|
||||
const whereRaw = whereArray.length ? `WHERE ${whereArray.join(', AND ')}` : '';
|
||||
const groupByArray = this._query.groupBy.reduce(this._reducer, []);
|
||||
const groupByRaw = groupByArray.length ? `GROUP BY ${groupByArray.join(', ')}` : '';
|
||||
const orderByArray = this._query.orderBy.reduce(this._reducer, []);
|
||||
const orderByRaw = orderByArray.length ? `ORDER BY ${orderByArray.join(', ')}` : '';
|
||||
|
||||
return `${selectRaw} ${fromRaw} ${whereRaw} ${groupByRaw} ${orderByRaw}`;
|
||||
limit (...args) {
|
||||
this._query.limit = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
run () {
|
||||
const rawQuery = this.getQueryString();
|
||||
/**
|
||||
* @returns {string} SQL string
|
||||
* @memberof AntaresConnector
|
||||
*/
|
||||
getSQL () {
|
||||
const selectArray = this._query.select.reduce(this._reducer, []);
|
||||
let selectRaw;
|
||||
switch (this._client) {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
selectRaw = selectArray.length ? `SELECT ${selectArray.join(', ')} ` : 'SELECT * ';
|
||||
break;
|
||||
case 'mssql': {
|
||||
const topRaw = this._query.limit.length ? ` TOP (${this._query.limit[0]}) ` : '';
|
||||
selectRaw = selectArray.length ? `SELECT${topRaw} ${selectArray.join(', ')} ` : 'SELECT * ';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
let fromRaw;
|
||||
switch (this._client) {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
fromRaw = this._query.from ? `FROM ${this._query.schema ? `\`${this._query.schema}\`.` : ''}\`${this._query.from}\` ` : '';
|
||||
break;
|
||||
case 'mssql':
|
||||
fromRaw = this._query.from ? `FROM ${this._query.schema ? `${this._query.schema}.` : ''}${this._query.from} ` : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const whereArray = this._query.where.reduce(this._reducer, []);
|
||||
const whereRaw = whereArray.length ? `WHERE ${whereArray.join(' AND ')} ` : '';
|
||||
const groupByArray = this._query.groupBy.reduce(this._reducer, []);
|
||||
const groupByRaw = groupByArray.length ? `GROUP BY ${groupByArray.join(', ')} ` : '';
|
||||
const orderByArray = this._query.orderBy.reduce(this._reducer, []);
|
||||
const orderByRaw = orderByArray.length ? `ORDER BY ${orderByArray.join(', ')} ` : '';
|
||||
|
||||
let limitRaw;
|
||||
switch (this._client) {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
limitRaw = this._query.limit.length ? `LIMIT ${this._query.limit.join(', ')} ` : '';
|
||||
break;
|
||||
case 'mssql':
|
||||
limitRaw = '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return `${selectRaw}${fromRaw}${whereRaw}${groupByRaw}${orderByRaw}${limitRaw}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise}
|
||||
* @memberof AntaresConnector
|
||||
*/
|
||||
async run () {
|
||||
const rawQuery = this.getSQL();
|
||||
if (process.env.NODE_ENV === 'development') console.log(rawQuery);
|
||||
this._resetQuery();
|
||||
return this.raw(rawQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} sql raw SQL query
|
||||
* @param {string} sql raw SQL query
|
||||
* @returns {Promise}
|
||||
* @memberof AntaresConnector
|
||||
*/
|
||||
@ -143,6 +205,10 @@ export class AntaresConnector {
|
||||
const [rows, fields] = await this._connection.query(sql);
|
||||
return { rows, fields };
|
||||
}
|
||||
case 'mssql': {
|
||||
const results = await this._connection.request().query(sql);
|
||||
return { rows: results.recordsets[0] };
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -154,10 +220,12 @@ export class AntaresConnector {
|
||||
destroy () {
|
||||
switch (this._client) {
|
||||
case 'maria':
|
||||
case 'mysql': {
|
||||
case 'mysql':
|
||||
this._connection.end();
|
||||
break;
|
||||
}
|
||||
case 'mssql':
|
||||
this._connection.close();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,7 +1,16 @@
|
||||
'use strict';
|
||||
export default class {
|
||||
static async raw (connection, query, database) {
|
||||
if (database) await connection.raw(`USE \`${database}\``);
|
||||
static async raw (connection, query, schema) {
|
||||
if (schema) await connection.raw(`USE \`${schema}\``);
|
||||
return connection.raw(query);
|
||||
}
|
||||
|
||||
static async getTableData (connection, schema, table) {
|
||||
return connection
|
||||
.select('*')
|
||||
.schema(schema)
|
||||
.from(table)
|
||||
.limit(1000)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ export default class {
|
||||
}
|
||||
|
||||
static getStructure (connection) {
|
||||
// return connection.raw('SELECT * FROM information_schema.TABLES ORDER BY TABLE_SCHEMA ASC, TABLE_NAME ASC');
|
||||
return connection
|
||||
.select('*')
|
||||
.schema('information_schema')
|
||||
@ -14,5 +13,13 @@ export default class {
|
||||
.run();
|
||||
}
|
||||
|
||||
// TODO: SELECT * FROM `information_schema`.`COLUMNS` WHERE TABLE_SCHEMA='fepcomdb' AND TABLE_NAME='macchine' ORDER BY ORDINAL_POSITION;
|
||||
static getTableColumns (connection, schema, table) {
|
||||
return connection
|
||||
.select('*')
|
||||
.schema('information_schema')
|
||||
.from('COLUMNS')
|
||||
.where({ TABLE_SCHEMA: `= '${schema}'`, TABLE_NAME: `= '${table}'` })
|
||||
.orderBy({ ORDINAL_POSITION: 'ASC' })
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
<details class="accordion workspace-explorebar-database">
|
||||
<summary
|
||||
class="accordion-header database-name pb-0"
|
||||
:class="{'text-bold': breadcrumbs.database === database.name}"
|
||||
@click="changeBreadcrumbs({database: database.name, table:null})"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name}"
|
||||
@click="changeBreadcrumbs({schema: database.name, table:null})"
|
||||
>
|
||||
<i class="icon material-icons md-18 mr-1">navigate_next</i>
|
||||
<i class="material-icons md-18 mr-1">view_agenda</i>
|
||||
@ -16,8 +16,8 @@
|
||||
v-for="table of database.tables"
|
||||
:key="table.TABLE_NAME"
|
||||
class="menu-item"
|
||||
:class="{'text-bold': breadcrumbs.database === database.name && breadcrumbs.table === table.TABLE_NAME}"
|
||||
@click="changeBreadcrumbs({database: database.name, table: table.TABLE_NAME})"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.table === table.TABLE_NAME}"
|
||||
@click="changeBreadcrumbs({schema: database.name, table: table.TABLE_NAME})"
|
||||
>
|
||||
<a class="table-name">
|
||||
<i class="material-icons md-18 mr-1">grid_on</i>
|
||||
|
@ -22,8 +22,8 @@
|
||||
<div v-if="results.rows">
|
||||
{{ $t('word.results') }}: <b>{{ results.rows.length }}</b>
|
||||
</div>
|
||||
<div v-if="workspace.breadcrumbs.database">
|
||||
{{ $t('word.schema') }}: <b>{{ workspace.breadcrumbs.database }}</b>
|
||||
<div v-if="workspace.breadcrumbs.schema">
|
||||
{{ $t('word.schema') }}: <b>{{ workspace.breadcrumbs.schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -76,7 +76,7 @@ export default {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
query: this.query,
|
||||
database: this.workspace.breadcrumbs.database
|
||||
schema: this.workspace.breadcrumbs.schema
|
||||
};
|
||||
|
||||
try {
|
||||
|
@ -6,7 +6,7 @@
|
||||
<button
|
||||
class="btn btn-link btn-sm"
|
||||
:class="{'loading':isQuering}"
|
||||
@click="runQuery"
|
||||
@click="getTableData"
|
||||
>
|
||||
<span>{{ $t('word.refresh') }}</span>
|
||||
<i class="material-icons ml-1">refresh</i>
|
||||
@ -33,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import Structure from '@/ipc-api/Structure';
|
||||
import WorkspaceQueryTable from '@/components/WorkspaceQueryTable';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
|
||||
@ -50,6 +50,7 @@ export default {
|
||||
return {
|
||||
isQuering: false,
|
||||
results: {},
|
||||
fields: {},
|
||||
lastTable: null
|
||||
};
|
||||
},
|
||||
@ -62,45 +63,54 @@ export default {
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 1;
|
||||
},
|
||||
query () {
|
||||
return `SELECT * FROM \`${this.table}\` LIMIT 1000`;// TODO: use query builder
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
table: function () {
|
||||
if (this.isSelected) {
|
||||
this.runQuery();
|
||||
this.getTableData();
|
||||
this.lastTable = this.table;
|
||||
}
|
||||
},
|
||||
isSelected: function (val) {
|
||||
if (val && this.lastTable !== this.table) {
|
||||
this.runQuery();
|
||||
this.getTableData();
|
||||
this.lastTable = this.table;
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.runQuery();
|
||||
this.getTableData();
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
async runQuery () {
|
||||
async getTableData () {
|
||||
if (!this.table) return;
|
||||
this.isQuering = true;
|
||||
this.results = {};
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
query: this.query,
|
||||
database: this.workspace.breadcrumbs.database
|
||||
schema: this.workspace.breadcrumbs.schema,
|
||||
table: this.workspace.breadcrumbs.table
|
||||
};
|
||||
|
||||
try {
|
||||
const { status, response } = await Connection.rawQuery(params);
|
||||
const { status, response } = await Structure.getTableColumns(params);
|
||||
if (status === 'success')
|
||||
this.fields = response.rows;
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
try {
|
||||
const { status, response } = await Structure.getTableData(params);
|
||||
console.log(status, response);
|
||||
if (status === 'success')
|
||||
this.results = response;
|
||||
else
|
||||
|
12
src/renderer/ipc-api/Structure.js
Normal file
12
src/renderer/ipc-api/Structure.js
Normal file
@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
export default class {
|
||||
static getTableColumns (params) {
|
||||
return ipcRenderer.invoke('getTableColumns', params);
|
||||
}
|
||||
|
||||
static getTableData (params) {
|
||||
return ipcRenderer.invoke('getTableData', params);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user