From 1e7d4ca347f4b9337ff266ec78bb4bbc6dd20d4d Mon Sep 17 00:00:00 2001 From: Fabio Di Stasio Date: Thu, 14 Jan 2021 18:11:36 +0100 Subject: [PATCH] feat: schedulers delete --- README.md | 4 + package.json | 4 + src/main/ipc-handlers/index.js | 2 + src/main/ipc-handlers/schedulers.js | 43 +++ src/main/libs/clients/MySQLClient.js | 90 ++++++ src/renderer/components/Workspace.vue | 10 +- .../WorkspaceExploreBarMiscContext.vue | 15 +- .../components/WorkspacePropsTabScheduler.vue | 301 ++++++++++++++++++ .../components/WorkspaceQueryTable.vue | 2 +- src/renderer/i18n/en-US.js | 10 +- src/renderer/ipc-api/Schedulers.js | 20 ++ src/renderer/libs/arrayToFile.js | 1 - 12 files changed, 491 insertions(+), 11 deletions(-) create mode 100644 src/main/ipc-handlers/schedulers.js create mode 100644 src/renderer/components/WorkspacePropsTabScheduler.vue create mode 100644 src/renderer/ipc-api/Schedulers.js diff --git a/README.md b/README.md index 5d701e67..cb538694 100644 --- a/README.md +++ b/README.md @@ -88,3 +88,7 @@ This is a roadmap with major features will come in near future. [Giuseppe Gigliotti](https://github.com/ReverbOD) / [Italian Translation](https://github.com/Fabio286/antares/pull/20) [Mohd-PH](https://github.com/Mohd-PH) / [Arabic Translation](https://github.com/Fabio286/antares/pull/29) [hongkfui](https://github.com/hongkfui) / [Spanish Translation](https://github.com/Fabio286/antares/pull/32) + +## Reviews + +Antares SQL Client review diff --git a/package.json b/package.json index 9259f3b3..b6d9b2a3 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,10 @@ "AppImage" ], "category": "Development" + }, + "appImage": { + "license": "./LICENSE", + "category": "Development" } }, "electronWebpack": { diff --git a/src/main/ipc-handlers/index.js b/src/main/ipc-handlers/index.js index d9753da4..a3f0cf71 100644 --- a/src/main/ipc-handlers/index.js +++ b/src/main/ipc-handlers/index.js @@ -4,6 +4,7 @@ import views from './views'; import triggers from './triggers'; import routines from './routines'; import functions from './functions'; +import schedulers from './schedulers'; import updates from './updates'; import application from './application'; import database from './database'; @@ -18,6 +19,7 @@ export default () => { triggers(connections); routines(connections); functions(connections); + schedulers(connections); database(connections); users(connections); updates(); diff --git a/src/main/ipc-handlers/schedulers.js b/src/main/ipc-handlers/schedulers.js new file mode 100644 index 00000000..4133fbed --- /dev/null +++ b/src/main/ipc-handlers/schedulers.js @@ -0,0 +1,43 @@ +import { ipcMain } from 'electron'; + +export default (connections) => { + ipcMain.handle('get-scheduler-informations', async (event, params) => { + try { + const result = await connections[params.uid].getEventInformations(params); + return { status: 'success', response: result }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); + + ipcMain.handle('drop-scheduler', async (event, params) => { + try { + await connections[params.uid].dropEvent(params); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); + + ipcMain.handle('alter-scheduler', async (event, params) => { + try { + await connections[params.uid].alterEvent(params); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); + + ipcMain.handle('create-scheduler', async (event, params) => { + try { + await connections[params.uid].createEvent(params); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); +}; diff --git a/src/main/libs/clients/MySQLClient.js b/src/main/libs/clients/MySQLClient.js index 9c5a110d..db300e1a 100644 --- a/src/main/libs/clients/MySQLClient.js +++ b/src/main/libs/clients/MySQLClient.js @@ -663,6 +663,96 @@ export class MySQLClient extends AntaresCore { return await this.raw(sql, { split: false }); } + /** + * SHOW CREATE EVENT + * + * @returns {Array.} view informations + * @memberof MySQLClient + */ + async getEventInformations ({ schema, scheduler }) { + const sql = `SHOW CREATE EVENT \`${schema}\`.\`${scheduler}\``; + const results = await this.raw(sql); + + return results.rows.map(row => { + const schedule = row['Create Event'].match(/(?<=ON SCHEDULE\n*?\s*?).*?(?=\n)/gs)[0]; + const execution = schedule.includes('EVERY') ? 'EVERY' : 'ONCE'; + const every = execution === 'EVERY' ? row['Create Event'].match(/(?<=EVERY )(\s*(\w+)){0,2}/gs)[0].split(' ') : []; + const starts = execution === 'EVERY' && schedule.includes('STARTS') ? schedule.match(/(?<=STARTS ').*?(?='\s)/gs)[0] : ''; + const ends = execution === 'EVERY' && schedule.includes('ENDS') ? schedule.match(/(?<=ENDS ').*?(?='\s)/gs)[0] : ''; + const at = execution === 'ONCE' && schedule.includes('AT') ? schedule.match(/(?<=AT ').*?(?='\s)/gs)[0] : ''; + + return { + definer: row['Create Event'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0], + sql: row['Create Event'].match(/(BEGIN|begin)(.*)(END|end)/gs)[0], + name: row.Event, + comment: row['Create Event'].match(/(?<=COMMENT ').*?(?=')/gs) ? row['Create Event'].match(/(?<=COMMENT ').*?(?=')/gs)[0] : '', + state: row['Create Event'].includes('ENABLE') ? 'ENABLE' : row['Create Event'].includes('DISABLE ON SLAVE') ? 'DISABLE ON SLAVE' : 'DISABLE', + preserve: row['Create Event'].includes('ON COMPLETION PRESERVE'), + execution, + every, + starts, + ends, + at + }; + })[0]; + } + + /** + * DROP EVENT + * + * @returns {Array.} parameters + * @memberof MySQLClient + */ + async dropEvent (params) { + const sql = `DROP EVENT \`${params.scheduler}\``; + return await this.raw(sql); + } + + /** + * ALTER EVENT + * + * @returns {Array.} parameters + * @memberof MySQLClient + */ + async alterEvent (params) { + const { scheduler } = params; + const tempProcedure = Object.assign({}, scheduler); + tempProcedure.name = `Antares_${tempProcedure.name}_tmp`; + + try { + await this.createEvent(tempProcedure); + await this.dropEvent({ scheduler: tempProcedure.name }); + await this.dropEvent({ scheduler: scheduler.oldName }); + await this.createEvent(scheduler); + } + catch (err) { + return Promise.reject(err); + } + } + + /** + * CREATE EVENT + * + * @returns {Array.} parameters + * @memberof MySQLClient + */ + async createEvent (scheduler) { + const parameters = scheduler.parameters.reduce((acc, curr) => { + acc.push(`\`${curr.name}\` ${curr.type}${curr.length ? `(${curr.length})` : ''}`); + return acc; + }, []).join(','); + + const sql = `CREATE ${scheduler.definer ? `DEFINER=${scheduler.definer} ` : ''}FUNCTION \`${scheduler.name}\`(${parameters}) RETURNS ${scheduler.returns}${scheduler.returnsLength ? `(${scheduler.returnsLength})` : ''} + LANGUAGE SQL + ${scheduler.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'} + ${scheduler.dataAccess} + SQL SECURITY ${scheduler.security} + COMMENT '${scheduler.comment}' + ${scheduler.sql}`; + + return await this.raw(sql, { split: false }); + } + /** * SHOW COLLATION * diff --git a/src/renderer/components/Workspace.vue b/src/renderer/components/Workspace.vue index ec5f6dae..c23b7d9f 100644 --- a/src/renderer/components/Workspace.vue +++ b/src/renderer/components/Workspace.vue @@ -95,6 +95,12 @@ :connection="connection" :function="workspace.breadcrumbs.function" /> + +
+
+ +
+
+
+
+ + +
+
+
+
+ + + +
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+ + +
+
+ + + diff --git a/src/renderer/components/WorkspaceQueryTable.vue b/src/renderer/components/WorkspaceQueryTable.vue index e6334623..c3a8d1db 100644 --- a/src/renderer/components/WorkspaceQueryTable.vue +++ b/src/renderer/components/WorkspaceQueryTable.vue @@ -359,7 +359,7 @@ export default { downloadTable (format, filename) { if (!this.sortedResults) return; - const rows = this.sortedResults.map(row => { + const rows = [...this.sortedResults].map(row => { delete row._id; return row; }); diff --git a/src/renderer/i18n/en-US.js b/src/renderer/i18n/en-US.js index e41df398..0c2b3829 100644 --- a/src/renderer/i18n/en-US.js +++ b/src/renderer/i18n/en-US.js @@ -80,7 +80,9 @@ module.exports = { deterministic: 'Deterministic', context: 'Context', export: 'Export', - returns: 'Returns' + returns: 'Returns', + timing: 'Timing', + state: 'State' }, message: { appWelcome: 'Welcome to Antares SQL Client!', @@ -163,7 +165,11 @@ module.exports = { deleteRoutine: 'Delete stored routine', functionBody: 'Function body', createNewFunction: 'Create new function', - deleteFunction: 'Delete function' + deleteFunction: 'Delete function', + schedulerBody: 'Scheduler body', + createNewScheduler: 'Create new scheduler', + deleteScheduler: 'Delete scheduler', + preserveOnCompletion: 'Preserve on completion' }, // Date and Time short: { diff --git a/src/renderer/ipc-api/Schedulers.js b/src/renderer/ipc-api/Schedulers.js new file mode 100644 index 00000000..7ff8bcf4 --- /dev/null +++ b/src/renderer/ipc-api/Schedulers.js @@ -0,0 +1,20 @@ +'use strict'; +import { ipcRenderer } from 'electron'; + +export default class { + static getSchedulerInformations (params) { + return ipcRenderer.invoke('get-scheduler-informations', params); + } + + static dropScheduler (params) { + return ipcRenderer.invoke('drop-scheduler', params); + } + + static alterScheduler (params) { + return ipcRenderer.invoke('alter-scheduler', params); + } + + static createScheduler (params) { + return ipcRenderer.invoke('create-scheduler', params); + } +} diff --git a/src/renderer/libs/arrayToFile.js b/src/renderer/libs/arrayToFile.js index 57d27122..7f4cd54c 100644 --- a/src/renderer/libs/arrayToFile.js +++ b/src/renderer/libs/arrayToFile.js @@ -20,7 +20,6 @@ const arrayToFile = args => { mime = 'application/json'; content = JSON.stringify(args.content, null, 3); break; - default: break; }