diff --git a/.gitignore b/.gitignore index 2526b5df..66c6ef49 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ node_modules/ thumbs.db .idea/ .vscode -TODO.md \ No newline at end of file +TODO.md +*.txt \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b38cd110..016ded3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/src/main/ipc-handlers/connection.js b/src/main/ipc-handlers/connection.js index 61283e04..5cd23d3e 100644 --- a/src/main/ipc-handlers/connection.js +++ b/src/main/ipc-handlers/connection.js @@ -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) { diff --git a/src/main/ipc-handlers/index.js b/src/main/ipc-handlers/index.js index 179c7b58..154db989 100644 --- a/src/main/ipc-handlers/index.js +++ b/src/main/ipc-handlers/index.js @@ -1,5 +1,9 @@ import connection from './connection'; +import structure from './structure'; + +const connections = {}; export default () => { - connection(); + connection(connections); + structure(connections); }; diff --git a/src/main/ipc-handlers/structure.js b/src/main/ipc-handlers/structure.js new file mode 100644 index 00000000..50b704d9 --- /dev/null +++ b/src/main/ipc-handlers/structure.js @@ -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() }; + } + }); +}; diff --git a/src/main/libs/AntaresConnector.js b/src/main/libs/AntaresConnector.js index 2d522281..7fe3f304 100644 --- a/src/main/libs/AntaresConnector.js +++ b/src/main/libs/AntaresConnector.js @@ -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; } diff --git a/src/main/models/Generic.js b/src/main/models/Generic.js index 0747e2e2..eff5ca89 100644 --- a/src/main/models/Generic.js +++ b/src/main/models/Generic.js @@ -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(); + } } diff --git a/src/main/models/InformationSchema.js b/src/main/models/InformationSchema.js index 203291dd..8fa47e30 100644 --- a/src/main/models/InformationSchema.js +++ b/src/main/models/InformationSchema.js @@ -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(); + } } diff --git a/src/renderer/components/WorkspaceExploreBarDatabase.vue b/src/renderer/components/WorkspaceExploreBarDatabase.vue index c0f6f7f1..ed22dcd8 100644 --- a/src/renderer/components/WorkspaceExploreBarDatabase.vue +++ b/src/renderer/components/WorkspaceExploreBarDatabase.vue @@ -2,8 +2,8 @@
navigate_next view_agenda @@ -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})" > grid_on diff --git a/src/renderer/components/WorkspaceQueryTab.vue b/src/renderer/components/WorkspaceQueryTab.vue index de90563d..5858ff27 100644 --- a/src/renderer/components/WorkspaceQueryTab.vue +++ b/src/renderer/components/WorkspaceQueryTab.vue @@ -22,8 +22,8 @@
{{ $t('word.results') }}: {{ results.rows.length }}
-
- {{ $t('word.schema') }}: {{ workspace.breadcrumbs.database }} +
+ {{ $t('word.schema') }}: {{ workspace.breadcrumbs.schema }}
@@ -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 { diff --git a/src/renderer/components/WorkspaceTableTab.vue b/src/renderer/components/WorkspaceTableTab.vue index c848e85a..4af32391 100644 --- a/src/renderer/components/WorkspaceTableTab.vue +++ b/src/renderer/components/WorkspaceTableTab.vue @@ -6,7 +6,7 @@