mirror of
https://github.com/Fabio286/antares.git
synced 2025-02-18 12:40:41 +01:00
feat(PostgreSQL): functions management
This commit is contained in:
parent
b33199ea59
commit
cd31413256
@ -727,7 +727,7 @@ export class PostgreSQLClient extends AntaresCore {
|
|||||||
|
|
||||||
const results = await this.raw(sql);
|
const results = await this.raw(sql);
|
||||||
|
|
||||||
const parameters = results.rows.map(row => {
|
const parameters = results.rows.filter(row => row.parameter_mode).map(row => {
|
||||||
return {
|
return {
|
||||||
name: row.parameter_name,
|
name: row.parameter_name,
|
||||||
type: row.data_type.toUpperCase(),
|
type: row.data_type.toUpperCase(),
|
||||||
@ -746,7 +746,7 @@ export class PostgreSQLClient extends AntaresCore {
|
|||||||
deterministic: null,
|
deterministic: null,
|
||||||
dataAccess: null,
|
dataAccess: null,
|
||||||
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0],
|
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0],
|
||||||
returns: row.pg_get_functiondef.match(/(?<=RETURNS SETOF )(.*)(?<=[\S+\n\r\s])/gm)[0].toUpperCase()
|
returns: row.pg_get_functiondef.match(/(?<=RETURNS )(.*)(?<=[\S+\n\r\s])/gm)[0].replace('SETOF ', '').toUpperCase()
|
||||||
};
|
};
|
||||||
})[0];
|
})[0];
|
||||||
}
|
}
|
||||||
@ -758,7 +758,7 @@ export class PostgreSQLClient extends AntaresCore {
|
|||||||
* @memberof PostgreSQLClient
|
* @memberof PostgreSQLClient
|
||||||
*/
|
*/
|
||||||
async dropFunction (params) {
|
async dropFunction (params) {
|
||||||
const sql = `DROP FUNCTION \`${params.func}\``;
|
const sql = `DROP FUNCTION ${this._schema}.${params.func}`;
|
||||||
return await this.raw(sql);
|
return await this.raw(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,18 +791,23 @@ export class PostgreSQLClient extends AntaresCore {
|
|||||||
* @memberof PostgreSQLClient
|
* @memberof PostgreSQLClient
|
||||||
*/
|
*/
|
||||||
async createFunction (func) {
|
async createFunction (func) {
|
||||||
const parameters = func.parameters.reduce((acc, curr) => {
|
const parameters = 'parameters' in func
|
||||||
acc.push(`\`${curr.name}\` ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
? func.parameters.reduce((acc, curr) => {
|
||||||
return acc;
|
acc.push(`${curr.context} ${curr.name} ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||||
}, []).join(',');
|
return acc;
|
||||||
|
}, []).join(',')
|
||||||
|
: '';
|
||||||
|
|
||||||
const sql = `CREATE ${func.definer ? `DEFINER=${func.definer} ` : ''}FUNCTION \`${func.name}\`(${parameters}) RETURNS ${func.returns}${func.returnsLength ? `(${func.returnsLength})` : ''}
|
if (this._schema !== 'public')
|
||||||
|
this.use(this._schema);
|
||||||
|
|
||||||
|
const body = func.returns ? func.sql : '$BODY$\n$BODY$';
|
||||||
|
|
||||||
|
const sql = `CREATE FUNCTION ${this._schema}.${func.name}(${parameters})
|
||||||
|
RETURNS ${func.returns || 'void'}
|
||||||
LANGUAGE ${func.language}
|
LANGUAGE ${func.language}
|
||||||
${func.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
|
SECURITY ${func.security}
|
||||||
${func.dataAccess}
|
AS ${body}`;
|
||||||
SQL SECURITY ${func.security}
|
|
||||||
COMMENT '${func.comment}'
|
|
||||||
${func.sql}`;
|
|
||||||
|
|
||||||
return await this.raw(sql, { split: false });
|
return await this.raw(sql, { split: false });
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
<div
|
<div
|
||||||
v-for="(parameter, i) in localRoutine.parameters"
|
v-for="(parameter, i) in inParameters"
|
||||||
:key="parameter._id"
|
:key="parameter._id"
|
||||||
class="form-group"
|
class="form-group"
|
||||||
>
|
>
|
||||||
@ -66,6 +66,11 @@ export default {
|
|||||||
values: {}
|
values: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
inParameters () {
|
||||||
|
return this.localRoutine.parameters.filter(param => param.context === 'IN');
|
||||||
|
}
|
||||||
|
},
|
||||||
created () {
|
created () {
|
||||||
window.addEventListener('keydown', this.onKey);
|
window.addEventListener('keydown', this.onKey);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
>
|
>
|
||||||
<template :slot="'header'">
|
<template :slot="'header'">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<i class="mdi mdi-24px mdi-plus mr-1" /> {{ $t('message.createNewRoutine') }}
|
<i class="mdi mdi-24px mdi-plus mr-1" /> {{ $t('message.createNewFunction') }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div :slot="'body'">
|
<div :slot="'body'">
|
||||||
@ -25,7 +25,19 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.languages" class="form-group">
|
||||||
|
<label class="form-label col-4">
|
||||||
|
{{ $t('word.language') }}
|
||||||
|
</label>
|
||||||
|
<div class="column">
|
||||||
|
<select v-model="localFunction.language" class="form-select">
|
||||||
|
<option v-for="language in customizations.languages" :key="language">
|
||||||
|
{{ language }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="customizations.definer" class="form-group">
|
||||||
<label class="form-label col-4">
|
<label class="form-label col-4">
|
||||||
{{ $t('word.definer') }}
|
{{ $t('word.definer') }}
|
||||||
</label>
|
</label>
|
||||||
@ -53,42 +65,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.comment" class="form-group">
|
||||||
<label class="form-label col-4">
|
|
||||||
{{ $t('word.returns') }}
|
|
||||||
</label>
|
|
||||||
<div class="column">
|
|
||||||
<div class="input-group">
|
|
||||||
<select
|
|
||||||
v-model="localFunction.returns"
|
|
||||||
class="form-select text-uppercase"
|
|
||||||
style="width: 0;"
|
|
||||||
>
|
|
||||||
<optgroup
|
|
||||||
v-for="group in workspace.dataTypes"
|
|
||||||
:key="group.group"
|
|
||||||
:label="group.group"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
v-for="type in group.types"
|
|
||||||
:key="type.name"
|
|
||||||
:selected="localFunction.returns === type.name"
|
|
||||||
:value="type.name"
|
|
||||||
>
|
|
||||||
{{ type.name }}
|
|
||||||
</option>
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
<input
|
|
||||||
v-model="localFunction.returnsLength"
|
|
||||||
class="form-input"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label col-4">
|
<label class="form-label col-4">
|
||||||
{{ $t('word.comment') }}
|
{{ $t('word.comment') }}
|
||||||
</label>
|
</label>
|
||||||
@ -111,7 +88,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.functionDataAccess" class="form-group">
|
||||||
<label class="form-label col-4">
|
<label class="form-label col-4">
|
||||||
{{ $t('message.dataAccess') }}
|
{{ $t('message.dataAccess') }}
|
||||||
</label>
|
</label>
|
||||||
@ -124,7 +101,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.functionDeterministic" class="form-group">
|
||||||
<div class="col-4" />
|
<div class="col-4" />
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<label class="form-checkbox form-inline">
|
<label class="form-checkbox form-inline">
|
||||||
@ -152,11 +129,12 @@ export default {
|
|||||||
return {
|
return {
|
||||||
localFunction: {
|
localFunction: {
|
||||||
definer: '',
|
definer: '',
|
||||||
sql: 'BEGIN\r\n RETURN NULL;\r\nEND',
|
sql: '',
|
||||||
parameters: [],
|
parameters: [],
|
||||||
name: '',
|
name: '',
|
||||||
comment: '',
|
comment: '',
|
||||||
returns: 'INT',
|
language: null,
|
||||||
|
returns: null,
|
||||||
returnsLength: 10,
|
returnsLength: 10,
|
||||||
security: 'DEFINER',
|
security: 'DEFINER',
|
||||||
deterministic: false,
|
deterministic: false,
|
||||||
@ -168,9 +146,17 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
schema () {
|
schema () {
|
||||||
return this.workspace.breadcrumbs.schema;
|
return this.workspace.breadcrumbs.schema;
|
||||||
|
},
|
||||||
|
customizations () {
|
||||||
|
return this.workspace.customizations;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
if (this.customizations.languages)
|
||||||
|
this.localFunction.language = this.customizations.languages[0];
|
||||||
|
|
||||||
|
if (this.customizations.procedureSql)
|
||||||
|
this.localFunction.sql = this.customizations.procedureSql;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$refs.firstInput.focus();
|
this.$refs.firstInput.focus();
|
||||||
}, 20);
|
}, 20);
|
||||||
|
@ -25,6 +25,18 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="customizations.languages" class="form-group">
|
||||||
|
<label class="form-label col-4">
|
||||||
|
{{ $t('word.language') }}
|
||||||
|
</label>
|
||||||
|
<div class="column">
|
||||||
|
<select v-model="localRoutine.language" class="form-select">
|
||||||
|
<option v-for="language in customizations.languages" :key="language">
|
||||||
|
{{ language }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-if="customizations.definer" class="form-group">
|
<div v-if="customizations.definer" class="form-group">
|
||||||
<label class="form-label col-4">
|
<label class="form-label col-4">
|
||||||
{{ $t('word.definer') }}
|
{{ $t('word.definer') }}
|
||||||
@ -121,6 +133,7 @@ export default {
|
|||||||
parameters: [],
|
parameters: [],
|
||||||
name: '',
|
name: '',
|
||||||
comment: '',
|
comment: '',
|
||||||
|
language: null,
|
||||||
security: 'DEFINER',
|
security: 'DEFINER',
|
||||||
deterministic: false,
|
deterministic: false,
|
||||||
dataAccess: 'CONTAINS SQL'
|
dataAccess: 'CONTAINS SQL'
|
||||||
@ -137,6 +150,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
if (this.customizations.languages)
|
||||||
|
this.localRoutine.language = this.customizations.languages[0];
|
||||||
|
|
||||||
if (this.customizations.procedureSql)
|
if (this.customizations.procedureSql)
|
||||||
this.localRoutine.sql = this.customizations.procedureSql;
|
this.localRoutine.sql = this.customizations.procedureSql;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -248,9 +248,11 @@ export default {
|
|||||||
switch (this.workspace.client) { // TODO: move in a better place
|
switch (this.workspace.client) { // TODO: move in a better place
|
||||||
case 'maria':
|
case 'maria':
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
case 'pg':
|
|
||||||
sql = `SELECT \`${this.localElement.name}\` (${params.join(',')})`;
|
sql = `SELECT \`${this.localElement.name}\` (${params.join(',')})`;
|
||||||
break;
|
break;
|
||||||
|
case 'pg':
|
||||||
|
sql = `SELECT ${this.localElement.name}(${params.join(',')})`;
|
||||||
|
break;
|
||||||
case 'mssql':
|
case 'mssql':
|
||||||
sql = `SELECT ${this.localElement.name} ${params.join(',')}`;
|
sql = `SELECT ${this.localElement.name} ${params.join(',')}`;
|
||||||
break;
|
break;
|
||||||
|
@ -26,7 +26,19 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.languages" class="form-group">
|
||||||
|
<label class="form-label col-4">
|
||||||
|
{{ $t('word.language') }}
|
||||||
|
</label>
|
||||||
|
<div class="column">
|
||||||
|
<select v-model="optionsProxy.language" class="form-select">
|
||||||
|
<option v-for="language in customizations.languages" :key="language">
|
||||||
|
{{ language }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="customizations.definer" class="form-group">
|
||||||
<label class="form-label col-4">
|
<label class="form-label col-4">
|
||||||
{{ $t('word.definer') }}
|
{{ $t('word.definer') }}
|
||||||
</label>
|
</label>
|
||||||
@ -81,6 +93,7 @@
|
|||||||
</optgroup>
|
</optgroup>
|
||||||
</select>
|
</select>
|
||||||
<input
|
<input
|
||||||
|
v-if="customizations.parametersLength"
|
||||||
v-model="optionsProxy.returnsLength"
|
v-model="optionsProxy.returnsLength"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
type="number"
|
type="number"
|
||||||
@ -89,7 +102,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.comment" class="form-group">
|
||||||
<label class="form-label col-4">
|
<label class="form-label col-4">
|
||||||
{{ $t('word.comment') }}
|
{{ $t('word.comment') }}
|
||||||
</label>
|
</label>
|
||||||
@ -112,7 +125,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.functionDataAccess" class="form-group">
|
||||||
<label class="form-label col-4">
|
<label class="form-label col-4">
|
||||||
{{ $t('message.dataAccess') }}
|
{{ $t('message.dataAccess') }}
|
||||||
</label>
|
</label>
|
||||||
@ -125,7 +138,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.functionDeterministic" class="form-group">
|
||||||
<div class="col-4" />
|
<div class="col-4" />
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<label class="form-checkbox form-inline">
|
<label class="form-checkbox form-inline">
|
||||||
@ -159,6 +172,9 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
isTableNameValid () {
|
isTableNameValid () {
|
||||||
return this.optionsProxy.name !== '';
|
return this.optionsProxy.name !== '';
|
||||||
|
},
|
||||||
|
customizations () {
|
||||||
|
return this.workspace.customizations;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
<div class="tile-title">
|
<div class="tile-title">
|
||||||
{{ param.name }}
|
{{ param.name }}
|
||||||
</div>
|
</div>
|
||||||
<small class="tile-subtitle text-gray">{{ param.type }}{{ param.length ? `(${param.length})` : '' }}</small>
|
<small class="tile-subtitle text-gray">{{ param.type }}{{ param.length ? `(${param.length})` : '' }} · {{ param.context }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="tile-action">
|
<div class="tile-action">
|
||||||
<button
|
<button
|
||||||
@ -106,7 +106,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div v-if="customizations.parametersLength" class="form-group">
|
||||||
<label class="form-label col-3">
|
<label class="form-label col-3">
|
||||||
{{ $t('word.length') }}
|
{{ $t('word.length') }}
|
||||||
</label>
|
</label>
|
||||||
@ -119,6 +119,37 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="customizations.functionContext" class="form-group">
|
||||||
|
<label class="form-label col-3">
|
||||||
|
{{ $t('word.context') }}
|
||||||
|
</label>
|
||||||
|
<div class="column">
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="selectedParamObj.context"
|
||||||
|
type="radio"
|
||||||
|
name="context"
|
||||||
|
value="IN"
|
||||||
|
> <i class="form-icon" /> IN
|
||||||
|
</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="selectedParamObj.context"
|
||||||
|
type="radio"
|
||||||
|
value="OUT"
|
||||||
|
name="context"
|
||||||
|
> <i class="form-icon" /> OUT
|
||||||
|
</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="selectedParamObj.context"
|
||||||
|
type="radio"
|
||||||
|
value="INOUT"
|
||||||
|
name="context"
|
||||||
|
> <i class="form-icon" /> INOUT
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div v-if="!parametersProxy.length" class="empty">
|
<div v-if="!parametersProxy.length" class="empty">
|
||||||
<div class="empty-icon">
|
<div class="empty-icon">
|
||||||
@ -168,6 +199,9 @@ export default {
|
|||||||
},
|
},
|
||||||
isChanged () {
|
isChanged () {
|
||||||
return JSON.stringify(this.localParameters) !== JSON.stringify(this.parametersProxy);
|
return JSON.stringify(this.localParameters) !== JSON.stringify(this.parametersProxy);
|
||||||
|
},
|
||||||
|
customizations () {
|
||||||
|
return this.workspace.customizations;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
@ -281,9 +281,11 @@ export default {
|
|||||||
switch (this.connection.client) { // TODO: move in a better place
|
switch (this.connection.client) { // TODO: move in a better place
|
||||||
case 'maria':
|
case 'maria':
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
case 'pg':
|
|
||||||
sql = `SELECT \`${this.originalFunction.name}\` (${params.join(',')})`;
|
sql = `SELECT \`${this.originalFunction.name}\` (${params.join(',')})`;
|
||||||
break;
|
break;
|
||||||
|
case 'pg':
|
||||||
|
sql = `SELECT ${this.originalFunction.name}(${params.join(',')})`;
|
||||||
|
break;
|
||||||
case 'mssql':
|
case 'mssql':
|
||||||
sql = `SELECT ${this.originalFunction.name} ${params.join(',')}`;
|
sql = `SELECT ${this.originalFunction.name} ${params.join(',')}`;
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user