1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-06-05 21:59:22 +02:00

feat(PostgreSQL): trigger rename and delete

This commit is contained in:
2021-06-08 09:12:43 +02:00
parent e6d67fcb0c
commit cce5adbac7
7 changed files with 115 additions and 42 deletions

View File

@ -115,7 +115,7 @@
"electron-devtools-installer": "^3.2.0", "electron-devtools-installer": "^3.2.0",
"electron-webpack": "^2.8.2", "electron-webpack": "^2.8.2",
"electron-webpack-vue": "^2.4.0", "electron-webpack-vue": "^2.4.0",
"eslint": "^7.27.0", "eslint": "^7.28.0",
"eslint-config-standard": "^16.0.3", "eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
@ -127,8 +127,8 @@
"stylelint": "^13.13.1", "stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0", "stylelint-config-standard": "^22.0.0",
"stylelint-scss": "^3.19.0", "stylelint-scss": "^3.19.0",
"vue": "^2.6.13", "vue": "^2.6.14",
"vue-template-compiler": "^2.6.13", "vue-template-compiler": "^2.6.14",
"webpack": "^4.46.0" "webpack": "^4.46.0"
} }
} }

View File

@ -63,7 +63,9 @@ module.exports = {
functionContext: false, functionContext: false,
functionLanguage: false, functionLanguage: false,
triggerMiltipleEvents: false, triggerMiltipleEvents: false,
triggerTableInName: false,
triggerUpdateColumns: false, triggerUpdateColumns: false,
triggerOnlyRename: false,
parametersLength: false, parametersLength: false,
languages: false languages: false
}; };

View File

@ -13,7 +13,7 @@ module.exports = {
// Structure // Structure
tables: true, tables: true,
views: true, views: true,
triggers: false, triggers: true,
routines: true, routines: true,
functions: true, functions: true,
// Settings // Settings
@ -25,7 +25,7 @@ module.exports = {
databaseEdit: false, databaseEdit: false,
tableSettings: true, tableSettings: true,
viewSettings: true, viewSettings: true,
triggerSettings: false, triggerSettings: true,
routineSettings: true, routineSettings: true,
functionSettings: true, functionSettings: true,
indexes: true, indexes: true,
@ -38,5 +38,8 @@ module.exports = {
functionSql: '$BODY$\r\n\r\n$BODY$', functionSql: '$BODY$\r\n\r\n$BODY$',
functionContext: true, functionContext: true,
functionLanguage: true, functionLanguage: true,
triggerMultipleEvents: true,
triggerTableInName: true,
triggerOnlyRename: true,
languages: ['sql', 'plpgsql', 'c', 'internal'] languages: ['sql', 'plpgsql', 'c', 'internal']
}; };

View File

@ -584,8 +584,8 @@ export class MySQLClient extends AntaresCore {
sql: row['SQL Original Statement'].match(/(BEGIN|begin)(.*)(END|end)/gs)[0], sql: row['SQL Original Statement'].match(/(BEGIN|begin)(.*)(END|end)/gs)[0],
name: row.Trigger, name: row.Trigger,
table: row['SQL Original Statement'].match(/(?<=ON `).*?(?=`)/gs)[0], table: row['SQL Original Statement'].match(/(?<=ON `).*?(?=`)/gs)[0],
event1: row['SQL Original Statement'].match(/(BEFORE|AFTER)/gs)[0], activation: row['SQL Original Statement'].match(/(BEFORE|AFTER)/gs)[0],
event2: row['SQL Original Statement'].match(/(INSERT|UPDATE|DELETE)/gs)[0] event: row['SQL Original Statement'].match(/(INSERT|UPDATE|DELETE)/gs)[0]
}; };
})[0]; })[0];
} }
@ -630,7 +630,7 @@ export class MySQLClient extends AntaresCore {
* @memberof MySQLClient * @memberof MySQLClient
*/ */
async createTrigger (trigger) { async createTrigger (trigger) {
const sql = `CREATE ${trigger.definer ? `DEFINER=${trigger.definer} ` : ''}TRIGGER \`${this._schema}\`.\`${trigger.name}\` ${trigger.event1} ${trigger.event2} ON \`${trigger.table}\` FOR EACH ROW ${trigger.sql}`; const sql = `CREATE ${trigger.definer ? `DEFINER=${trigger.definer} ` : ''}TRIGGER \`${this._schema}\`.\`${trigger.name}\` ${trigger.activation} ${trigger.event} ON \`${trigger.table}\` FOR EACH ROW ${trigger.sql}`;
return await this.raw(sql, { split: false }); return await this.raw(sql, { split: false });
} }

View File

@ -496,17 +496,33 @@ export class PostgreSQLClient extends AntaresCore {
* @memberof PostgreSQLClient * @memberof PostgreSQLClient
*/ */
async getTriggerInformations ({ schema, trigger }) { async getTriggerInformations ({ schema, trigger }) {
const sql = `SHOW CREATE TRIGGER \`${schema}\`.\`${trigger}\``; const [table, triggerName] = trigger.split('.');
const results = await this.raw(sql);
const results = await this.raw(`
SELECT event_object_schema AS table_schema,
event_object_table AS table_name,
trigger_schema,
trigger_name,
string_agg(event_manipulation, ',') AS event,
action_timing AS activation,
action_condition AS condition,
action_statement AS definition
FROM information_schema.triggers
WHERE trigger_schema = '${schema}'
AND trigger_name = '${triggerName}'
AND event_object_table = '${table}'
GROUP BY 1,2,3,4,6,7,8
ORDER BY table_schema,
table_name
`);
return results.rows.map(row => { return results.rows.map(row => {
return { return {
definer: row['SQL Original Statement'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0], sql: row.definition,
sql: row['SQL Original Statement'].match(/(BEGIN|begin)(.*)(END|end)/gs)[0], name: row.trigger_name,
name: row.Trigger, table: row.table_name,
table: row['SQL Original Statement'].match(/(?<=ON `).*?(?=`)/gs)[0], event: row.event.split(','),
event1: row['SQL Original Statement'].match(/(BEFORE|AFTER)/gs)[0], activation: row.activation
event2: row['SQL Original Statement'].match(/(INSERT|UPDATE|DELETE)/gs)[0]
}; };
})[0]; })[0];
} }
@ -531,18 +547,21 @@ export class PostgreSQLClient extends AntaresCore {
*/ */
async alterTrigger (params) { async alterTrigger (params) {
const { trigger } = params; const { trigger } = params;
const tempTrigger = Object.assign({}, trigger); // const tempTrigger = Object.assign({}, trigger);
tempTrigger.name = `Antares_${tempTrigger.name}_tmp`; // tempTrigger.name = `Antares_${tempTrigger.name}_tmp`;
try { // try {
await this.createTrigger(tempTrigger); // await this.createTrigger(tempTrigger);
await this.dropTrigger({ trigger: tempTrigger.name }); // await this.dropTrigger({ trigger: tempTrigger.name });
await this.dropTrigger({ trigger: trigger.oldName }); // await this.dropTrigger({ trigger: trigger.oldName });
await this.createTrigger(trigger); // await this.createTrigger(trigger);
} // }
catch (err) { // catch (err) {
return Promise.reject(err); // return Promise.reject(err);
} // }
const sql = `ALTER TRIGGER ${trigger.oldName} ON ${trigger.table} RENAME TO ${trigger.name}`;
return await this.raw(sql);
} }
/** /**
@ -552,7 +571,7 @@ export class PostgreSQLClient extends AntaresCore {
* @memberof PostgreSQLClient * @memberof PostgreSQLClient
*/ */
async createTrigger (trigger) { async createTrigger (trigger) {
const sql = `CREATE ${trigger.definer ? `DEFINER=${trigger.definer} ` : ''}TRIGGER \`${trigger.name}\` ${trigger.event1} ${trigger.event2} ON \`${trigger.table}\` FOR EACH ROW ${trigger.sql}`; const sql = `CREATE ${trigger.definer ? `DEFINER=${trigger.definer} ` : ''}TRIGGER \`${trigger.name}\` ${trigger.event} ${trigger.activation} ON \`${trigger.table}\` FOR EACH ROW ${trigger.sql}`;
return await this.raw(sql, { split: false }); return await this.raw(sql, { split: false });
} }

View File

@ -71,11 +71,11 @@
</label> </label>
<div class="column"> <div class="column">
<div class="input-group"> <div class="input-group">
<select v-model="localTrigger.event1" class="form-select"> <select v-model="localTrigger.activation" class="form-select">
<option>BEFORE</option> <option>BEFORE</option>
<option>AFTER</option> <option>AFTER</option>
</select> </select>
<select v-model="localTrigger.event2" class="form-select"> <select v-model="localTrigger.event" class="form-select">
<option>INSERT</option> <option>INSERT</option>
<option>UPDATE</option> <option>UPDATE</option>
<option>DELETE</option> <option>DELETE</option>
@ -106,8 +106,8 @@ export default {
sql: 'BEGIN\r\n\r\nEND', sql: 'BEGIN\r\n\r\nEND',
name: '', name: '',
table: '', table: '',
event1: 'BEFORE', activation: 'BEFORE',
event2: 'INSERT' event: 'INSERT'
}, },
isOptionsChanging: false isOptionsChanging: false
}; };

View File

@ -37,7 +37,7 @@
> >
</div> </div>
</div> </div>
<div class="column col-auto"> <div v-if="customizations.definer" class="column col-auto">
<div class="form-group"> <div class="form-group">
<label class="form-label">{{ $t('word.definer') }}</label> <label class="form-label">{{ $t('word.definer') }}</label>
<select <select
@ -67,7 +67,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="columns"> <fieldset class="columns" :disabled="customizations.triggerOnlyRename">
<div class="column col-auto"> <div class="column col-auto">
<div class="form-group"> <div class="form-group">
<label class="form-label">{{ $t('word.table') }}</label> <label class="form-label">{{ $t('word.table') }}</label>
@ -82,19 +82,33 @@
<div class="form-group"> <div class="form-group">
<label class="form-label">{{ $t('word.event') }}</label> <label class="form-label">{{ $t('word.event') }}</label>
<div class="input-group"> <div class="input-group">
<select v-model="localTrigger.event1" class="form-select"> <select v-model="localTrigger.activation" class="form-select">
<option>BEFORE</option> <option>BEFORE</option>
<option>AFTER</option> <option>AFTER</option>
</select> </select>
<select v-model="localTrigger.event2" class="form-select"> <select
<option>INSERT</option> v-if="!customizations.triggerMultipleEvents"
<option>UPDATE</option> v-model="localTrigger.event"
<option>DELETE</option> class="form-select"
>
<option v-for="event in Object.keys(localEvents)" :key="event">
{{ event }}
</option>
</select> </select>
<div v-if="customizations.triggerMultipleEvents" class="px-4">
<label
v-for="event in Object.keys(localEvents)"
:key="event"
class="form-checkbox form-inline"
@change.prevent="changeEvents(event)"
>
<input :checked="localEvents[event]" type="checkbox"><i class="form-icon" /> {{ event }}
</label>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </fieldset>
</div> </div>
<div class="workspace-query-results column col-12 mt-2 p-relative"> <div class="workspace-query-results column col-12 mt-2 p-relative">
<BaseLoader v-if="isLoading" /> <BaseLoader v-if="isLoading" />
@ -136,7 +150,8 @@ export default {
localTrigger: { sql: '' }, localTrigger: { sql: '' },
lastTrigger: null, lastTrigger: null,
sqlProxy: '', sqlProxy: '',
editorHeight: 300 editorHeight: 300,
localEvents: { INSERT: false, UPDATE: false, DELETE: false }
}; };
}, },
computed: { computed: {
@ -147,6 +162,9 @@ export default {
workspace () { workspace () {
return this.getWorkspace(this.connection.uid); return this.getWorkspace(this.connection.uid);
}, },
customizations () {
return this.workspace.customizations;
},
isSelected () { isSelected () {
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.trigger; return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.trigger;
}, },
@ -209,6 +227,10 @@ export default {
async getTriggerData () { async getTriggerData () {
if (!this.trigger) return; if (!this.trigger) return;
Object.keys(this.localEvents).forEach(event => {
this.localEvents[event] = false;
});
this.localTrigger = { sql: '' }; this.localTrigger = { sql: '' };
this.isLoading = true; this.isLoading = true;
@ -224,6 +246,12 @@ export default {
this.originalTrigger = response; this.originalTrigger = response;
this.localTrigger = JSON.parse(JSON.stringify(this.originalTrigger)); this.localTrigger = JSON.parse(JSON.stringify(this.originalTrigger));
this.sqlProxy = this.localTrigger.sql; this.sqlProxy = this.localTrigger.sql;
if (this.customizations.triggerMultipleEvents) {
this.originalTrigger.event.forEach(e => {
this.localEvents[e] = true;
});
}
} }
else else
this.addNotification({ status: 'error', message: response }); this.addNotification({ status: 'error', message: response });
@ -235,6 +263,16 @@ export default {
this.resizeQueryEditor(); this.resizeQueryEditor();
this.isLoading = false; this.isLoading = false;
}, },
changeEvents (event) {
if (this.customizations.triggerMultipleEvents) {
this.localEvents[event] = !this.localEvents[event];
this.localTrigger.event = [];
for (const key in this.localEvents) {
if (this.localEvents[key])
this.localTrigger.event.push(key);
}
}
},
async saveChanges () { async saveChanges () {
if (this.isSaving) return; if (this.isSaving) return;
this.isSaving = true; this.isSaving = true;
@ -257,7 +295,8 @@ export default {
if (oldName !== this.localTrigger.name) { if (oldName !== this.localTrigger.name) {
this.setUnsavedChanges(false); this.setUnsavedChanges(false);
this.changeBreadcrumbs({ schema: this.schema, trigger: this.localTrigger.name }); const triggerName = this.customizations.triggerTableInName ? `${this.localTrigger.table}.${this.localTrigger.name}` : this.localTrigger.name;
this.changeBreadcrumbs({ schema: this.schema, trigger: triggerName });
} }
this.getTriggerData(); this.getTriggerData();
@ -274,6 +313,16 @@ export default {
clearChanges () { clearChanges () {
this.localTrigger = JSON.parse(JSON.stringify(this.originalTrigger)); this.localTrigger = JSON.parse(JSON.stringify(this.originalTrigger));
this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql); this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql);
Object.keys(this.localEvents).forEach(event => {
this.localEvents[event] = false;
});
if (this.customizations.triggerMultipleEvents) {
this.originalTrigger.event.forEach(e => {
this.localEvents[e] = true;
});
}
}, },
resizeQueryEditor () { resizeQueryEditor () {
if (this.$refs.queryEditor) { if (this.$refs.queryEditor) {