mirror of
https://github.com/Fabio286/antares.git
synced 2025-02-16 19:50:37 +01:00
feat(PostgreSQL): support of arrays in table settings
This commit is contained in:
parent
c20bff7bcb
commit
d0b3e1b1b8
@ -44,9 +44,12 @@ module.exports = {
|
||||
comment: false,
|
||||
collation: false,
|
||||
definer: false,
|
||||
arrays: false,
|
||||
onUpdate: false,
|
||||
tableArray: false,
|
||||
viewAlgorithm: false,
|
||||
viewSqlSecurity: false,
|
||||
viewUpdateOption: false
|
||||
viewUpdateOption: false,
|
||||
procedureDeterministic: false,
|
||||
procedureDataAccess: false,
|
||||
procedureSql: false
|
||||
};
|
||||
|
@ -14,22 +14,26 @@ module.exports = {
|
||||
tables: true,
|
||||
views: true,
|
||||
triggers: false,
|
||||
routines: false,
|
||||
routines: true,
|
||||
functions: false,
|
||||
schedulers: false,
|
||||
// Settings
|
||||
tableAdd: true,
|
||||
viewAdd: true,
|
||||
triggerAdd: false,
|
||||
routineAdd: true,
|
||||
functionAdd: true,
|
||||
databaseEdit: false,
|
||||
tableSettings: true,
|
||||
viewSettings: true,
|
||||
triggerSettings: false,
|
||||
routineSettings: false,
|
||||
routineSettings: true,
|
||||
functionSettings: false,
|
||||
schedulerSettings: false,
|
||||
indexes: true,
|
||||
foreigns: true,
|
||||
sortableFields: false,
|
||||
nullable: true,
|
||||
arrays: true
|
||||
tableArray: true,
|
||||
procedureSql: '$BODY$\r\n\r\n$BODY$'
|
||||
};
|
||||
|
@ -7,6 +7,8 @@ export class MySQLClient extends AntaresCore {
|
||||
constructor (args) {
|
||||
super(args);
|
||||
|
||||
this._schema = null;
|
||||
|
||||
this.types = {
|
||||
0: 'DECIMAL',
|
||||
1: 'TINYINT',
|
||||
@ -120,6 +122,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
use (schema) {
|
||||
this._schema = schema;
|
||||
return this.raw(`USE \`${schema}\``);
|
||||
}
|
||||
|
||||
@ -1049,7 +1052,7 @@ export class MySQLClient extends AntaresCore {
|
||||
options
|
||||
} = params;
|
||||
|
||||
let sql = `ALTER TABLE \`${table}\` `;
|
||||
let sql = `ALTER TABLE \`${this._schema}\`.\`${table}\` `;
|
||||
const alterColumns = [];
|
||||
|
||||
// OPTIONS
|
||||
|
@ -23,54 +23,16 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
this.types = {};
|
||||
for (const key in types.builtins)
|
||||
this.types[types.builtins[key]] = key;
|
||||
}
|
||||
|
||||
_getType (field) {
|
||||
let name = this.types[field.columnType];
|
||||
let length = field.columnLength;
|
||||
|
||||
if (['DATE', 'TIME', 'YEAR', 'DATETIME'].includes(name))
|
||||
length = field.decimals;
|
||||
|
||||
if (name === 'TIMESTAMP')
|
||||
length = 0;
|
||||
|
||||
if (field.charsetNr === 63) { // if binary
|
||||
if (name === 'CHAR')
|
||||
name = 'BINARY';
|
||||
else if (name === 'VARCHAR')
|
||||
name = 'VARBINARY';
|
||||
}
|
||||
|
||||
if (name === 'BLOB') {
|
||||
switch (length) {
|
||||
case 765:
|
||||
name = 'TYNITEXT';
|
||||
break;
|
||||
case 196605:
|
||||
name = 'TEXT';
|
||||
break;
|
||||
case 50331645:
|
||||
name = 'MEDIUMTEXT';
|
||||
break;
|
||||
case 4294967295:
|
||||
name = field.charsetNr === 63 ? 'LONGBLOB' : 'LONGTEXT';
|
||||
break;
|
||||
case 255:
|
||||
name = 'TINYBLOB';
|
||||
break;
|
||||
case 65535:
|
||||
name = 'BLOB';
|
||||
break;
|
||||
case 16777215:
|
||||
name = 'MEDIUMBLOB';
|
||||
break;
|
||||
default:
|
||||
name = field.charsetNr === 63 ? 'BLOB' : 'TEXT';
|
||||
}
|
||||
}
|
||||
|
||||
return { name, length };
|
||||
this._arrayTypes = {
|
||||
_int2: 'SMALLINT',
|
||||
_int4: 'INTEGER',
|
||||
_int8: 'BIGINT',
|
||||
_float4: 'REAL',
|
||||
_float8: 'DOUBLE PRECISION',
|
||||
_char: '"CHAR"',
|
||||
_varchar: 'CHARACTER VARYING'
|
||||
};
|
||||
}
|
||||
|
||||
_getTypeInfo (type) {
|
||||
@ -79,6 +41,12 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
.filter(_type => _type.name === type.toUpperCase())[0];
|
||||
}
|
||||
|
||||
_getArrayType (type) {
|
||||
if (Object.keys(this._arrayTypes).includes(type))
|
||||
return this._arrayTypes[type];
|
||||
return type.replace('_', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
@ -189,16 +157,11 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
});
|
||||
|
||||
// PROCEDURES
|
||||
const remappedProcedures = procedures.filter(procedure => procedure.Db === db.database).map(procedure => {
|
||||
const remappedProcedures = procedures.filter(procedure => procedure.routine_schema === db.database).map(procedure => {
|
||||
return {
|
||||
name: procedure.Name,
|
||||
type: procedure.Type,
|
||||
definer: procedure.Definer,
|
||||
created: procedure.Created,
|
||||
updated: procedure.Modified,
|
||||
comment: procedure.Comment,
|
||||
charset: procedure.character_set_client,
|
||||
security: procedure.Security_type
|
||||
name: procedure.routine_name,
|
||||
type: procedure.routine_type,
|
||||
security: procedure.security_type
|
||||
};
|
||||
});
|
||||
|
||||
@ -256,7 +219,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Object} table scructure
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async getTableColumns ({ schema, table }) {
|
||||
async getTableColumns ({ schema, table }, arrayRemap = true) {
|
||||
const { rows } = await this
|
||||
.select('*')
|
||||
.schema('information_schema')
|
||||
@ -266,10 +229,17 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
.run();
|
||||
|
||||
return rows.map(field => {
|
||||
let type = field.data_type;
|
||||
const isArray = type === 'ARRAY';
|
||||
|
||||
if (isArray && arrayRemap)
|
||||
type = this._getArrayType(field.udt_name);
|
||||
|
||||
return {
|
||||
name: field.column_name,
|
||||
key: null,
|
||||
type: field.data_type.toUpperCase(),
|
||||
type: type.toUpperCase(),
|
||||
isArray,
|
||||
schema: field.table_schema,
|
||||
table: field.table_name,
|
||||
numPrecision: field.numeric_precision,
|
||||
@ -583,16 +553,16 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async getRoutineInformations ({ schema, routine }) {
|
||||
const sql = `SHOW CREATE PROCEDURE \`${schema}\`.\`${routine}\``;
|
||||
const sql = `SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${routine}'));`;
|
||||
const results = await this.raw(sql);
|
||||
|
||||
return results.rows.map(row => {
|
||||
if (!row['Create Procedure']) {
|
||||
if (!row.pg_get_functiondef) {
|
||||
return {
|
||||
definer: null,
|
||||
sql: '',
|
||||
parameters: [],
|
||||
name: row.Procedure,
|
||||
name: routine,
|
||||
comment: '',
|
||||
security: 'DEFINER',
|
||||
deterministic: false,
|
||||
@ -600,7 +570,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
};
|
||||
}
|
||||
|
||||
const parameters = row['Create Procedure']
|
||||
const parameters = row.pg_get_functiondef
|
||||
.match(/(\([^()]*(?:(?:\([^()]*\))[^()]*)*\)\s*)/s)[0]
|
||||
.replaceAll('\r', '')
|
||||
.replaceAll('\t', '')
|
||||
@ -618,22 +588,23 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
}).filter(el => el.name);
|
||||
|
||||
let dataAccess = 'CONTAINS SQL';
|
||||
if (row['Create Procedure'].includes('NO SQL'))
|
||||
if (row.pg_get_functiondef.includes('NO SQL'))
|
||||
dataAccess = 'NO SQL';
|
||||
if (row['Create Procedure'].includes('READS SQL DATA'))
|
||||
if (row.pg_get_functiondef.includes('READS SQL DATA'))
|
||||
dataAccess = 'READS SQL DATA';
|
||||
if (row['Create Procedure'].includes('MODIFIES SQL DATA'))
|
||||
if (row.pg_get_functiondef.includes('MODIFIES SQL DATA'))
|
||||
dataAccess = 'MODIFIES SQL DATA';
|
||||
|
||||
return {
|
||||
definer: row['Create Procedure'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0],
|
||||
sql: row['Create Procedure'].match(/(BEGIN|begin)(.*)(END|end)/gs)[0],
|
||||
definer: '',
|
||||
sql: row.pg_get_functiondef.match(/(\$(.*)\$)(.*)(\$(.*)\$)/gs)[0],
|
||||
parameters: parameters || [],
|
||||
name: row.Procedure,
|
||||
comment: row['Create Procedure'].match(/(?<=COMMENT ').*?(?=')/gs) ? row['Create Procedure'].match(/(?<=COMMENT ').*?(?=')/gs)[0] : '',
|
||||
security: row['Create Procedure'].includes('SQL SECURITY INVOKER') ? 'INVOKER' : 'DEFINER',
|
||||
deterministic: row['Create Procedure'].includes('DETERMINISTIC'),
|
||||
dataAccess
|
||||
name: routine,
|
||||
comment: '',
|
||||
security: row.pg_get_functiondef.includes('SECURITY INVOKER') ? 'INVOKER' : 'DEFINER',
|
||||
deterministic: null,
|
||||
dataAccess,
|
||||
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0]
|
||||
};
|
||||
})[0];
|
||||
}
|
||||
@ -645,7 +616,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropRoutine (params) {
|
||||
const sql = `DROP PROCEDURE \`${params.routine}\``;
|
||||
const sql = `DROP PROCEDURE ${this._schema}.${params.routine}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@ -680,18 +651,15 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
async createRoutine (routine) {
|
||||
const parameters = 'parameters' in routine
|
||||
? routine.parameters.reduce((acc, curr) => {
|
||||
acc.push(`${curr.context} \`${curr.name}\` ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
acc.push(`${curr.context} ${curr.name} ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
return acc;
|
||||
}, []).join(',')
|
||||
: '';
|
||||
|
||||
const sql = `CREATE ${routine.definer ? `DEFINER=${routine.definer} ` : ''}PROCEDURE \`${routine.name}\`(${parameters})
|
||||
const sql = `CREATE PROCEDURE ${this._schema}.${routine.name}(${parameters})
|
||||
LANGUAGE SQL
|
||||
${routine.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
|
||||
${routine.dataAccess}
|
||||
SQL SECURITY ${routine.security}
|
||||
COMMENT '${routine.comment}'
|
||||
${routine.sql}`;
|
||||
SECURITY ${routine.security}
|
||||
AS ${routine.sql}`;
|
||||
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
@ -1043,7 +1011,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
const length = typeInfo.length ? addition.numLength || addition.charLength || addition.datePrecision : false;
|
||||
|
||||
alterColumns.push(`ADD COLUMN ${addition.name}
|
||||
${addition.type.toUpperCase()}${length ? `(${length})` : ''}
|
||||
${addition.type.toUpperCase()}${length ? `(${length})` : ''}${addition.isArray ? '[]' : ''}
|
||||
${addition.unsigned ? 'UNSIGNED' : ''}
|
||||
${addition.zerofill ? 'ZEROFILL' : ''}
|
||||
${addition.nullable ? 'NULL' : 'NOT NULL'}
|
||||
@ -1092,7 +1060,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
localType = change.type.toLowerCase();
|
||||
}
|
||||
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" TYPE ${localType}${length ? `(${length})` : ''} USING "${change.orgName}"::${localType}`);
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" TYPE ${localType}${length ? `(${length})` : ''}${change.isArray ? '[]' : ''} USING "${change.orgName}"::${localType}`);
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" ${change.nullable ? 'DROP NOT NULL' : 'SET NOT NULL'}`);
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" ${change.default ? `SET DEFAULT ${change.default}` : 'DROP DEFAULT'}`);
|
||||
if (['SERIAL', 'SMALLSERIAL', 'BIGSERIAL'].includes(change.type)) {
|
||||
@ -1345,7 +1313,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
if (!paramObj.table || !paramObj.schema) continue;
|
||||
|
||||
try { // Column details
|
||||
const columns = await this.getTableColumns(paramObj);
|
||||
const columns = await this.getTableColumns(paramObj, false);
|
||||
const indexes = await this.getTableIndexes(paramObj);
|
||||
|
||||
remappedFields = remappedFields.map(field => {
|
||||
|
@ -69,7 +69,7 @@ export default {
|
||||
this.editor = ace.edit(`editor-${this.id}`, {
|
||||
mode: `ace/mode/${this.mode}`,
|
||||
theme: `ace/theme/${this.editorTheme}`,
|
||||
value: this.value,
|
||||
value: this.value || '',
|
||||
fontSize: '14px',
|
||||
printMargin: false,
|
||||
readOnly: this.readOnly,
|
||||
|
@ -42,6 +42,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.tableArray" class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
{{ $t('word.array') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
|
@ -76,6 +76,16 @@
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
v-if="customizations.tableArray"
|
||||
class="td"
|
||||
tabindex="0"
|
||||
>
|
||||
<label class="form-checkbox">
|
||||
<input v-model="localRow.isArray" type="checkbox">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="td type-int" tabindex="0">
|
||||
<template v-if="fieldType.length">
|
||||
<span
|
||||
|
@ -102,7 +102,8 @@ module.exports = {
|
||||
variables: 'Variables',
|
||||
processes: 'Processes',
|
||||
database: 'Database',
|
||||
scratchpad: 'Scratchpad'
|
||||
scratchpad: 'Scratchpad',
|
||||
array: 'Array'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Welcome to Antares SQL Client!',
|
||||
|
@ -30,6 +30,7 @@
|
||||
"macaddr": $string-color,
|
||||
"macaddr8": $string-color,
|
||||
"uuid": $string-color,
|
||||
"regproc": $string-color,
|
||||
"int": $number-color,
|
||||
"tinyint": $number-color,
|
||||
"smallint": $number-color,
|
||||
@ -76,6 +77,7 @@
|
||||
"tsvector": $array-color,
|
||||
"tsquery": $array-color,
|
||||
"pg_node_tree": $array-color,
|
||||
"aclitem": $array-color,
|
||||
"unknown": $unknown-color,
|
||||
)
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user