parent
27e446a0b0
commit
2074534b72
|
@ -7,14 +7,20 @@
|
|||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { getNodeAjaxOptions, getNodeListByName, getNodeListById} from '../../../../../../../static/js/node_ajax';
|
||||
import FunctionSchema from './function.ui';
|
||||
import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui';
|
||||
import { getNodeVariableSchema } from '../../../../../static/js/variable.ui';
|
||||
import _ from 'lodash';
|
||||
|
||||
/* Create and Register Function Collection and Node. */
|
||||
define('pgadmin.node.function', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'backbone',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||
'pgadmin.browser.collection', 'pgadmin.browser.server.privilege',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, schemaChild,
|
||||
gettext, url_for, $, Backbone, pgAdmin, pgBrowser, Backform, schemaChild,
|
||||
schemaChildTreeNode
|
||||
) {
|
||||
|
||||
|
@ -30,69 +36,6 @@ define('pgadmin.node.function', [
|
|||
canDropCascade: schemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
});
|
||||
}
|
||||
|
||||
// Argument Model
|
||||
var ArgumentModel = pgBrowser.Node.Model.extend({
|
||||
idAttribute: 'argid',
|
||||
defaults: {
|
||||
argid: undefined,
|
||||
argtype: undefined,
|
||||
argmode: undefined,
|
||||
argname: undefined,
|
||||
argdefval: undefined,
|
||||
},
|
||||
schema: [{
|
||||
id: 'argid', visible: false, type: 'text',
|
||||
mode: ['properties', 'edit','create'],
|
||||
},{
|
||||
id: 'argtype', label: gettext('Data type'), cell:
|
||||
'node-ajax-options', cellHeaderClasses: 'width_percent_30',
|
||||
control: 'node-ajax-options', type: 'text', url: 'get_types',
|
||||
editable: 'isEditable', first_empty: true,
|
||||
},{
|
||||
id: 'argmode', label: gettext('Mode'), type: 'options',
|
||||
control: 'node-ajax-options', cellHeaderClasses:'width_percent_20',
|
||||
cell: 'node-ajax-options', select2: {
|
||||
allowClear: false,
|
||||
},
|
||||
options:[
|
||||
{'label': 'IN', 'value': 'IN'},
|
||||
{'label': 'OUT', 'value': 'OUT'},
|
||||
{'label': 'INOUT', 'value': 'INOUT'},
|
||||
{'label': 'VARIADIC', 'value': 'VARIADIC'},
|
||||
], editable: 'isEditable',
|
||||
},{
|
||||
id: 'argname', label: gettext('Argument name'), type: 'text',
|
||||
cell: 'string', editable: 'isInCatalog', cellHeaderClasses:'width_percent_30',
|
||||
},{
|
||||
id: 'argdefval', label: gettext('Default'), type: 'text',
|
||||
cell: 'string', editable: 'isInCatalog', cellHeaderClasses:'width_percent_20',
|
||||
},
|
||||
],
|
||||
toJSON: Backbone.Model.prototype.toJSON,
|
||||
isEditable: function(m) {
|
||||
var node_info = this.get('node_info');
|
||||
if(node_info && 'catalog' in node_info) {
|
||||
return false;
|
||||
}
|
||||
return _.isUndefined(m.isNew) ? true : m.isNew();
|
||||
},
|
||||
isInCatalog: function(m){
|
||||
var node_info = this.get('node_info');
|
||||
if(node_info && 'catalog' in node_info) {
|
||||
return false;
|
||||
}
|
||||
// Below will disable default value cell if argument mode is 'INOUT' or 'OUT' as
|
||||
// user cannot set default value for out parameters.
|
||||
if(!_.isUndefined(m.get('argmode')) && !_.isUndefined(this.get('name')) &&
|
||||
this.get('name') == 'argdefval' &&
|
||||
(m.get('argmode') == 'INOUT' || m.get('argmode') == 'OUT')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
if (!pgBrowser.Nodes['function']) {
|
||||
|
||||
pgBrowser.Nodes['function'] = schemaChild.SchemaChildNode.extend({
|
||||
|
@ -138,6 +81,36 @@ define('pgadmin.node.function', [
|
|||
]);
|
||||
|
||||
},
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
return new FunctionSchema(
|
||||
(privileges)=>getNodePrivilegeRoleSchema(this, treeNodeInfo, itemNodeData, privileges),
|
||||
()=>getNodeVariableSchema(this, treeNodeInfo, itemNodeData, false, false),
|
||||
{
|
||||
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
|
||||
schema: ()=>getNodeListById(pgBrowser.Nodes['schema'], treeNodeInfo, itemNodeData, {
|
||||
cacheLevel: 'database'
|
||||
}
|
||||
),
|
||||
getTypes: ()=>getNodeAjaxOptions('get_types', this, treeNodeInfo, itemNodeData),
|
||||
getLanguage: ()=>getNodeAjaxOptions('get_languages', this, treeNodeInfo, itemNodeData),
|
||||
getSupportFunctions: ()=>getNodeAjaxOptions('get_support_functions', this, treeNodeInfo, itemNodeData, {
|
||||
cacheNode: 'function'
|
||||
}),
|
||||
|
||||
},
|
||||
{
|
||||
node_info: treeNodeInfo,
|
||||
},
|
||||
{
|
||||
type: pgBrowser.Nodes['function'].type,
|
||||
},
|
||||
{
|
||||
funcowner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
|
||||
pronamespace: treeNodeInfo.schema ? treeNodeInfo.schema._id : null,
|
||||
lanname: 'sql',
|
||||
}
|
||||
);
|
||||
},
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
idAttribute: 'oid',
|
||||
initialize: function(attrs, args) {
|
||||
|
@ -153,40 +126,6 @@ define('pgadmin.node.function', [
|
|||
}
|
||||
pgBrowser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
defaults: {
|
||||
name: undefined,
|
||||
oid: undefined,
|
||||
xmin: undefined,
|
||||
funcowner: undefined,
|
||||
pronamespace: undefined,
|
||||
description: undefined,
|
||||
pronargs: undefined, /* Argument Count */
|
||||
proargs: undefined, /* Arguments */
|
||||
proargtypenames: undefined, /* Argument Signature */
|
||||
prorettypename: undefined, /* Return Type */
|
||||
lanname: 'sql', /* Language Name in which function is being written */
|
||||
provolatile: undefined, /* Volatility */
|
||||
proretset: undefined, /* Return Set */
|
||||
proisstrict: undefined,
|
||||
prosecdef: undefined, /* Security of definer */
|
||||
proiswindow: undefined, /* Window Function ? */
|
||||
proparallel: undefined, /* Parallel mode */
|
||||
procost: undefined, /* Estimated execution Cost */
|
||||
prorows: 0, /* Estimated number of rows */
|
||||
proleakproof: undefined,
|
||||
prosupportfunc: undefined, /* Support function */
|
||||
arguments: [],
|
||||
prosrc: undefined,
|
||||
prosrc_c: undefined,
|
||||
probin: '$libdir/',
|
||||
options: [],
|
||||
variables: [],
|
||||
proacl: undefined,
|
||||
seclabels: [],
|
||||
acl: [],
|
||||
sysfunc: undefined,
|
||||
sysproc: undefined,
|
||||
},
|
||||
schema: [{
|
||||
id: 'name', label: gettext('Name'), cell: 'string',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
|
@ -202,270 +141,8 @@ define('pgadmin.node.function', [
|
|||
id: 'pronamespace', label: gettext('Schema'), cell: 'string',
|
||||
control: 'node-list-by-id', type: 'text', cache_level: 'database',
|
||||
node: 'schema', disabled: 'isDisabled', mode: ['create', 'edit'],
|
||||
},{
|
||||
id: 'sysfunc', label: gettext('System function?'),
|
||||
cell:'boolean', type: 'switch',
|
||||
mode: ['properties'], visible: 'isVisible',
|
||||
},{
|
||||
id: 'sysproc', label: gettext('System procedure?'),
|
||||
cell:'boolean', type: 'switch',
|
||||
mode: ['properties'], visible: 'isVisible',
|
||||
},{
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline', disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'pronargs', label: gettext('Argument count'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), mode: ['properties'],
|
||||
},{
|
||||
id: 'proargs', label: gettext('Arguments'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), mode: ['properties'],
|
||||
},{
|
||||
id: 'proargtypenames', label: gettext('Signature arguments'), cell:
|
||||
'string', type: 'text', group: gettext('Definition'), mode: ['properties'],
|
||||
},{
|
||||
id: 'prorettypename', label: gettext('Return type'), cell: 'string',
|
||||
control: 'node-ajax-options', type: 'text', group: gettext('Definition'),
|
||||
url: 'get_types', readonly: 'isReadonly', first_empty: true,
|
||||
mode: ['create'], visible: 'isVisible',
|
||||
},{
|
||||
id: 'prorettypename', label: gettext('Return type'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'),
|
||||
mode: ['properties', 'edit'], readonly: 'isReadonly', visible: 'isVisible',
|
||||
}, {
|
||||
id: 'lanname', label: gettext('Language'), cell: 'string',
|
||||
control: 'node-ajax-options', type: 'text', group: gettext('Definition'),
|
||||
url: 'get_languages', disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'prosrc', label: gettext('Code'), cell: 'string',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
group: gettext('Code'), deps: ['lanname'],
|
||||
tabPanelCodeClass: 'sql-code-control',
|
||||
control: Backform.SqlCodeControl,
|
||||
extraClasses:['custom_height_css_class'],
|
||||
visible: function(m) {
|
||||
if (m.get('lanname') == 'c') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'probin', label: gettext('Object file'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), deps: ['lanname'], visible:
|
||||
function(m) {
|
||||
if (m.get('lanname') == 'c') { return true; }
|
||||
return false;
|
||||
}, disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'prosrc_c', label: gettext('Link symbol'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), deps: ['lanname'], visible:
|
||||
function(m) {
|
||||
if (m.get('lanname') == 'c') { return true; }
|
||||
return false;
|
||||
}, disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'provolatile', label: gettext('Volatility'), cell: 'string',
|
||||
control: 'node-ajax-options', type: 'text', group: gettext('Options'),
|
||||
deps: ['lanname'],
|
||||
options:[
|
||||
{'label': 'VOLATILE', 'value': 'v'},
|
||||
{'label': 'STABLE', 'value': 's'},
|
||||
{'label': 'IMMUTABLE', 'value': 'i'},
|
||||
], disabled: 'isDisabled', select2: {allowClear: false},
|
||||
},{
|
||||
id: 'proretset', label: gettext('Returns a set?'), type: 'switch',
|
||||
disabled: 'isDisabled', group: gettext('Options'),
|
||||
visible: 'isVisible',
|
||||
},{
|
||||
id: 'proisstrict', label: gettext('Strict?'), type: 'switch',
|
||||
group: gettext('Options'), disabled: 'isDisabled',
|
||||
deps: ['lanname'],
|
||||
},{
|
||||
id: 'prosecdef', label: gettext('Security of definer?'),
|
||||
group: gettext('Options'), type: 'switch',
|
||||
disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'proiswindow', label: gettext('Window?'),
|
||||
group: gettext('Options'), cell:'boolean', type: 'switch',
|
||||
disabled: 'isDisabled', visible: 'isVisible',
|
||||
},{
|
||||
id: 'proparallel', label: gettext('Parallel'), cell: 'string',
|
||||
control: 'node-ajax-options', type: 'text', group: gettext('Options'),
|
||||
deps: ['lanname'],
|
||||
options:[
|
||||
{'label': 'UNSAFE', 'value': 'u'},
|
||||
{'label': 'RESTRICTED', 'value': 'r'},
|
||||
{'label': 'SAFE', 'value': 's'},
|
||||
], disabled: 'isDisabled', min_version: 90600,
|
||||
select2: {allowClear: false},
|
||||
},{
|
||||
id: 'procost', label: gettext('Estimated cost'), group: gettext('Options'),
|
||||
cell:'string', type: 'text', readonly: 'isReadonly', deps: ['lanname'], disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'prorows', label: gettext('Estimated rows'), type: 'text',
|
||||
deps: ['proretset'], visible: 'isVisible', readonly: 'isReadonly',
|
||||
group: gettext('Options'),disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'proleakproof', label: gettext('Leak proof?'),
|
||||
group: gettext('Options'), cell:'boolean', type: 'switch', min_version: 90200,
|
||||
disabled: 'isDisabled', deps: ['lanname'],
|
||||
},{
|
||||
id: 'prosupportfunc', label: gettext('Support function'),
|
||||
type: 'text', disabled: 'isDisabled',
|
||||
group: gettext('Options'), visible: 'isVisible',
|
||||
control: 'node-ajax-options', url: 'get_support_functions',
|
||||
cache_node: 'function', min_version: 120000,
|
||||
},{
|
||||
id: 'proacl', label: gettext('Privileges'), type: 'text',
|
||||
mode: ['properties'], group: gettext('Security'),
|
||||
},{
|
||||
id: 'arguments', label: gettext('Arguments'), cell: 'string',
|
||||
group: gettext('Definition'), type: 'collection', canAdd: function(m){
|
||||
return m.isNew();
|
||||
},
|
||||
canDelete: true, model: ArgumentModel, mode: ['create', 'edit'],
|
||||
columns: ['argtype', 'argmode', 'argname', 'argdefval'],
|
||||
disabled: 'isDisabled', canDeleteRow: function(m) {
|
||||
return m.isNew();
|
||||
},
|
||||
},{
|
||||
id: 'variables', label: '', type: 'collection',
|
||||
group: gettext('Parameters'), control: 'variable-collection',
|
||||
model: pgBrowser.Node.VariableModel,
|
||||
mode: ['edit', 'create'], canAdd: 'canVarAdd', canEdit: false,
|
||||
canDelete: true, disabled: 'isDisabled',
|
||||
}, pgBrowser.SecurityGroupSchema, {
|
||||
id: 'acl', label: gettext('Privileges'), editable: false,
|
||||
model: pgBrowser.Node.PrivilegeRoleModel.extend({
|
||||
privileges: ['X'],
|
||||
}), uniqueCol : ['grantee', 'grantor'], type: 'collection',
|
||||
group: 'security', mode: ['edit', 'create'], canAdd: true,
|
||||
canDelete: true, control: 'unique-col-collection',
|
||||
disabled: 'isDisabled',
|
||||
},{
|
||||
id: 'seclabels', label: gettext('Security labels'), canAdd: true,
|
||||
model: pgBrowser.SecLabelModel, type: 'collection',
|
||||
min_version: 90100, group: 'security', mode: ['edit', 'create'],
|
||||
canEdit: false, canDelete: true, uniqueCol : ['provider'],
|
||||
disabled: 'isDisabled', control: 'unique-col-collection',
|
||||
visible: function() {
|
||||
return this.node && this.node.type != 'procedure';
|
||||
},
|
||||
},
|
||||
],
|
||||
validate: function()
|
||||
{
|
||||
var err = {},
|
||||
errmsg,
|
||||
seclabels = this.get('seclabels');
|
||||
|
||||
if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['name'] = gettext('Name cannot be empty.');
|
||||
errmsg = err['name'];
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.get('funcowner')) || String(this.get('funcowner')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['funcowner'] = gettext('Owner cannot be empty.');
|
||||
errmsg = errmsg || err['funcowner'];
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['pronamespace'] = gettext('Schema cannot be empty.');
|
||||
errmsg = errmsg || err['pronamespace'];
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.get('prorettypename')) || String(this.get('prorettypename')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['prorettypename'] = gettext('Return type cannot be empty.');
|
||||
errmsg = errmsg || err['prorettypename'];
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['lanname'] = gettext('Language cannot be empty.');
|
||||
errmsg = errmsg || err['lanname'];
|
||||
}
|
||||
|
||||
if (String(this.get('lanname')) == 'c') {
|
||||
if (_.isUndefined(this.get('probin')) || String(this.get('probin'))
|
||||
.replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['probin'] = gettext('Object File cannot be empty.');
|
||||
errmsg = errmsg || err['probin'];
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.get('prosrc_c')) || String(this.get('prosrc_c')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['prosrc_c'] = gettext('Link Symbol cannot be empty.');
|
||||
errmsg = errmsg || err['prosrc_c'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['prosrc'] = gettext('Code cannot be empty.');
|
||||
errmsg = errmsg || err['prosrc'];
|
||||
}
|
||||
}
|
||||
|
||||
if (seclabels) {
|
||||
var secLabelsErr;
|
||||
for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) {
|
||||
secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]);
|
||||
if (secLabelsErr) {
|
||||
err['seclabels'] = secLabelsErr;
|
||||
errmsg = errmsg || secLabelsErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.errorModel.clear().set(err);
|
||||
|
||||
if (_.size(err)) {
|
||||
this.trigger('on-status', {msg: errmsg});
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
isVisible: function() {
|
||||
if (this.name == 'sysproc') { return false; }
|
||||
return true;
|
||||
},
|
||||
isDisabled: function(m) {
|
||||
//Disable the returns a set and window in edit mode.
|
||||
if((this.name == 'proretset' || this.name == 'proiswindow') && !m.isNew()){
|
||||
return true;
|
||||
}
|
||||
if(this.node_info && 'catalog' in this.node_info) {
|
||||
return true;
|
||||
}
|
||||
if(this.name === 'prosupportfunc'){
|
||||
var item = pgAdmin.Browser.tree.selected();
|
||||
if(pgAdmin.Browser.Nodes['function'].getTreeNodeHierarchy(item).server.user.is_superuser)
|
||||
return false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
isReadonly: function(m) {
|
||||
switch(this.name){
|
||||
case 'proargs':
|
||||
case 'proargtypenames':
|
||||
case 'proretset':
|
||||
case 'proiswindow':
|
||||
case 'prorettypename':
|
||||
return !m.isNew();
|
||||
case 'prorows':
|
||||
if(m.get('proretset') == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
canVarAdd: function() {
|
||||
if(this.node_info && 'catalog' in this.node_info) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import SecLabelSchema from '../../../../../static/js/sec_label.ui';
|
||||
import { isEmptyString } from 'sources/validators';
|
||||
import _ from 'lodash';
|
||||
|
||||
export class DefaultArgumentSchema extends BaseUISchema {
|
||||
constructor(node_info, getTypes) {
|
||||
super();
|
||||
this.node_info = node_info;
|
||||
this.getTypes = getTypes;
|
||||
this.type_options = {};
|
||||
}
|
||||
setTypeOptions(options) {
|
||||
options.forEach((option)=>{
|
||||
this.type_options[option.value] = {
|
||||
...option,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
return[{
|
||||
id: 'argid', visible: false, type: 'text',
|
||||
mode: ['properties', 'edit','create'],
|
||||
},{
|
||||
id: 'argtype', label: gettext('Data type'),
|
||||
options: this.getTypes,
|
||||
type: 'text',
|
||||
cell: ()=>({
|
||||
cell: 'select', options: this.getTypes,
|
||||
optionsLoaded: (options)=>{this.setTypeOptions(options);},
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
}
|
||||
}),
|
||||
editable: this.isEditable, first_empty: true,
|
||||
},{
|
||||
id: 'argmode', label: gettext('Mode'),
|
||||
type: 'text',
|
||||
cell: ()=>({
|
||||
cell: 'select',
|
||||
options:[
|
||||
{'label': 'IN', 'value': 'IN'},
|
||||
{'label': 'OUT', 'value': 'OUT'},
|
||||
{'label': 'INOUT', 'value': 'INOUT'},
|
||||
{'label': 'VARIADIC', 'value': 'VARIADIC'},
|
||||
],
|
||||
optionsLoaded: (options)=>{this.setTypeOptions(options);},
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
}
|
||||
}),
|
||||
editable: this.isEditable,
|
||||
},{
|
||||
id: 'argname', label: gettext('Argument name'), type: 'text',
|
||||
editable: this.isInCatalog, cell: ()=>({cell: 'text'})
|
||||
},{
|
||||
id: 'argdefval', label: gettext('Default'), type: 'text',
|
||||
cell: ()=>({cell: 'text'}), editable: this.isInCatalog,
|
||||
}];
|
||||
}
|
||||
|
||||
isEditable() {
|
||||
var node_info = this.node_info;
|
||||
if(node_info && 'catalog' in node_info) {
|
||||
return false;
|
||||
}
|
||||
return _.isUndefined(this.isNew) ? true : this.isNew();
|
||||
}
|
||||
isInCatalog(state){
|
||||
var node_info = this.node_info;
|
||||
if(node_info && 'catalog' in node_info) {
|
||||
return false;
|
||||
}
|
||||
// Below will disable default value cell if argument mode is 'INOUT' or 'OUT' as
|
||||
// user cannot set default value for out parameters.
|
||||
if(!_.isUndefined(state.argmode) && !_.isUndefined(state.name) &&
|
||||
state.name == 'argdefval' &&
|
||||
(state.argmode == 'INOUT' || state.argmode == 'OUT')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default class FunctionSchema extends BaseUISchema {
|
||||
constructor(getPrivilegeRoleSchema, getNodeVariableSchema, fieldOptions={}, node_info, type, initValues) {
|
||||
super({
|
||||
name: undefined,
|
||||
oid: undefined,
|
||||
xmin: undefined,
|
||||
funcowner: undefined,
|
||||
pronamespace: undefined,
|
||||
description: undefined,
|
||||
pronargs: undefined, /* Argument Count */
|
||||
proargs: undefined, /* Arguments */
|
||||
proargtypenames: undefined, /* Argument Signature */
|
||||
prorettypename: undefined, /* Return Type */
|
||||
lanname: undefined, /* Language Name in which function is being written */
|
||||
provolatile: undefined, /* Volatility */
|
||||
proretset: undefined, /* Return Set */
|
||||
proisstrict: undefined,
|
||||
prosecdef: undefined, /* Security of definer */
|
||||
proiswindow: undefined, /* Window Function ? */
|
||||
proparallel: undefined, /* Parallel mode */
|
||||
procost: undefined, /* Estimated execution Cost */
|
||||
prorows: 0, /* Estimated number of rows */
|
||||
proleakproof: undefined,
|
||||
prosupportfunc: undefined, /* Support function */
|
||||
arguments: [],
|
||||
prosrc: undefined,
|
||||
prosrc_c: undefined,
|
||||
probin: '$libdir/',
|
||||
options: [],
|
||||
variables: [],
|
||||
proacl: undefined,
|
||||
seclabels: [],
|
||||
acl: [],
|
||||
sysfunc: undefined,
|
||||
sysproc: undefined,
|
||||
...initValues
|
||||
});
|
||||
|
||||
this.getPrivilegeRoleSchema = getPrivilegeRoleSchema;
|
||||
this.getNodeVariableSchema = getNodeVariableSchema;
|
||||
this.node_info = node_info;
|
||||
this.type = type.type;
|
||||
this.fieldOptions = {
|
||||
role: [],
|
||||
schema: [],
|
||||
getTypes: [],
|
||||
...fieldOptions,
|
||||
};
|
||||
}
|
||||
|
||||
get idAttribute() {
|
||||
return 'oid';
|
||||
}
|
||||
|
||||
isVisible(state) {
|
||||
if(!(this.type === 'procedure')){
|
||||
if (state.sysproc) { return false; }
|
||||
return true;
|
||||
}else{
|
||||
if (state.sysfunc) {
|
||||
return false;
|
||||
} else if (state.sysproc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
isDisabled() {
|
||||
if (this.node_info && 'catalog' in this.node_info) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
isGreaterThan95(state){
|
||||
if (
|
||||
this.node_info['node_info'].server.version < 90500 ||
|
||||
this.node_info['node_info']['server'].server_type != 'ppas' ||
|
||||
state.lanname != 'edbspl'
|
||||
) {
|
||||
state.provolatile = null;
|
||||
state.proisstrict = false;
|
||||
state.procost = null;
|
||||
state.proleakproof = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isGreaterThan96(state){
|
||||
if (
|
||||
this.node_info['node_info'].server.version < 90600 ||
|
||||
this.node_info['node_info']['server'].server_type != 'ppas' ||
|
||||
state.lanname != 'edbspl'
|
||||
) {
|
||||
state.proparallel = null;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isProcedure(state) {
|
||||
|
||||
if (this.node_info && 'catalog' in this.node_info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state.prorows) {
|
||||
var server = this.node_info['node_info']['server'];
|
||||
return !(server.version >= 90500 && state.proretset == true);
|
||||
}
|
||||
}
|
||||
|
||||
isReadonly() {
|
||||
return !this.isNew();
|
||||
}
|
||||
|
||||
canVarAdd(){
|
||||
if(this.node_info && 'catalog' in this.node_info) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [{
|
||||
id: 'name', label: gettext('Name'), cell: 'string',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
noEmpty: true,
|
||||
},{
|
||||
id: 'oid', label: gettext('OID'), cell: 'string',
|
||||
type: 'text' , mode: ['properties'],
|
||||
},{
|
||||
id: 'funcowner', label: gettext('Owner'), cell: 'string',
|
||||
options: this.fieldOptions.role, type: 'select',
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled : obj.isGreaterThan95,
|
||||
noEmpty: true,
|
||||
},{
|
||||
id: 'pronamespace', label: gettext('Schema'), cell: 'string',
|
||||
type: 'select', disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
mode: ['create', 'edit'],
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
first_empty: false,
|
||||
},
|
||||
options: obj.fieldOptions.schema, noEmpty: true,
|
||||
},{
|
||||
id: 'sysfunc', label: gettext('System function?'),
|
||||
cell:'boolean', type: 'switch',
|
||||
mode: ['properties'], visible: obj.isVisible,
|
||||
},{
|
||||
id: 'sysproc', label: gettext('System procedure?'),
|
||||
cell:'boolean', type: 'switch',
|
||||
mode: ['properties'], visible: obj.isVisible,
|
||||
},{
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline', disabled: obj.isDisabled,
|
||||
},{
|
||||
id: 'pronargs', label: gettext('Argument count'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), mode: ['properties'],
|
||||
},{
|
||||
id: 'proargs', label: gettext('Arguments'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), mode: ['properties'],
|
||||
},{
|
||||
id: 'proargtypenames', label: gettext('Signature arguments'), cell:
|
||||
'string', type: 'text', group: gettext('Definition'), mode: ['properties'],
|
||||
},{
|
||||
id: 'prorettypename', label: gettext('Return type'), cell: 'string',
|
||||
type: 'select', group: gettext('Definition'),
|
||||
options: this.fieldOptions.getTypes,
|
||||
readonly: obj.isReadonly, first_empty: true,
|
||||
mode: ['create'], visible: obj.isVisible,
|
||||
},{
|
||||
id: 'prorettypename', label: gettext('Return type'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'),
|
||||
mode: ['properties', 'edit'], readonly: obj.isReadonly, visible: obj.isVisible,
|
||||
},{
|
||||
id: 'lanname', label: gettext('Language'), cell: 'string',
|
||||
options: this.fieldOptions.getLanguage, type: 'select', group: gettext('Definition'),
|
||||
disabled: function() {
|
||||
if (this.node_info && 'catalog' in this.node_info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.node_info['node_info'].server.version < 110000;
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'probin', label: gettext('Object file'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), deps: ['lanname'], visible:
|
||||
function(state) {
|
||||
if (state.lanname == 'c') { return true; }
|
||||
return false;
|
||||
}, disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
},{
|
||||
id: 'prosrc_c', label: gettext('Link symbol'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'), deps: ['lanname'], visible:
|
||||
function(state) {
|
||||
if (state.lanname == 'c') { return true; }
|
||||
return false;
|
||||
}, disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
},
|
||||
{
|
||||
id: 'arguments', label: gettext('Arguments'), cell: 'string',
|
||||
group: gettext('Definition'), type: 'collection', canAdd: function(){
|
||||
return obj.isNew();
|
||||
},
|
||||
canDelete: true, mode: ['create', 'edit'],
|
||||
columns: ['argtype', 'argmode', 'argname', 'argdefval'],
|
||||
schema : new DefaultArgumentSchema(this.node_info, this.fieldOptions.getTypes),
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
canDeleteRow: function() {
|
||||
return obj.isNew();
|
||||
},
|
||||
},{
|
||||
id: 'prosrc', label: gettext('Code'), cell: 'text',
|
||||
type: 'sql', mode: ['properties', 'create', 'edit'],
|
||||
group: gettext('Code'), deps: ['lanname'],
|
||||
isFullTab: true,
|
||||
visible: function(state) {
|
||||
if (state.lanname === 'c') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
},{
|
||||
id: 'provolatile', label: gettext('Volatility'), cell: 'text',
|
||||
type: 'select', group: gettext('Options'),
|
||||
deps: ['lanname'],
|
||||
options:[
|
||||
{'label': 'VOLATILE', 'value': 'v'},
|
||||
{'label': 'STABLE', 'value': 's'},
|
||||
{'label': 'IMMUTABLE', 'value': 'i'},
|
||||
], disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
controlProps: {allowClear: false},
|
||||
},{
|
||||
id: 'proretset', label: gettext('Returns a set?'), type: 'switch',
|
||||
disabled: ()=>{return !obj.isNew();}, group: gettext('Options'),
|
||||
visible: obj.isVisible, readonly: obj.isReadonly,
|
||||
},{
|
||||
id: 'proisstrict', label: gettext('Strict?'), type: 'switch',
|
||||
group: gettext('Options'), disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isGreaterThan95,
|
||||
deps: ['lanname'],
|
||||
},{
|
||||
id: 'prosecdef', label: gettext('Security of definer?'),
|
||||
group: gettext('Options'), type: 'switch',
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: ()=>{
|
||||
return obj.node_info['node_info'].server.version < 90500;
|
||||
},
|
||||
},{
|
||||
id: 'proiswindow', label: gettext('Window?'),
|
||||
group: gettext('Options'), cell:'boolean', type: 'switch',
|
||||
disabled: ()=>{return !obj.isNew();}, visible: obj.isVisible, readonly: obj.isReadonly,
|
||||
},{
|
||||
id: 'proparallel', label: gettext('Parallel'), cell: 'string',
|
||||
type: 'select', group: gettext('Options'),
|
||||
deps: ['lanname'],
|
||||
options:[
|
||||
{'label': 'UNSAFE', 'value': 'u'},
|
||||
{'label': 'RESTRICTED', 'value': 'r'},
|
||||
{'label': 'SAFE', 'value': 's'},
|
||||
],
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isGreaterThan96,
|
||||
min_version: 90600,
|
||||
controlProps: {allowClear: false},
|
||||
},{
|
||||
id: 'procost', label: gettext('Estimated cost'), group: gettext('Options'),
|
||||
cell:'string', type: 'text', deps: ['lanname'],
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isGreaterThan95,
|
||||
},{
|
||||
id: 'prorows', label: gettext('Estimated rows'), type: 'text',
|
||||
deps: ['proretset'], visible: obj.isVisible,
|
||||
readonly: (state) => {
|
||||
let isReadonly = true;
|
||||
if(state.proretset == true) {
|
||||
isReadonly = false;
|
||||
}
|
||||
return isReadonly;
|
||||
},
|
||||
group: gettext('Options'),
|
||||
},{
|
||||
id: 'proleakproof', label: gettext('Leak proof?'),
|
||||
group: gettext('Options'), cell:'boolean', type: 'switch', min_version: 90200,
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isGreaterThan95,
|
||||
deps: ['lanname'],
|
||||
},{
|
||||
id: 'prosupportfunc', label: gettext('Support function'),
|
||||
type: 'select',
|
||||
disabled: ()=>{
|
||||
if (obj.node_info && 'catalog' in obj.node_info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.node_info['node_info'].server.user.is_superuser)
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
group: gettext('Options'), visible: obj.isVisible,
|
||||
options: this.fieldOptions.getSupportFunctions, min_version: 120000,
|
||||
},{
|
||||
id: 'proacl', label: gettext('Privileges'), type: 'text',
|
||||
mode: ['properties'], group: gettext('Security'),
|
||||
},
|
||||
{
|
||||
id: 'variables', label: '', type: 'collection',
|
||||
group: gettext('Parameters'),
|
||||
schema: this.getNodeVariableSchema(),
|
||||
mode: ['edit', 'create'], canAdd: obj.canVarAdd, canEdit: false,
|
||||
canDelete: true,
|
||||
},
|
||||
{
|
||||
id: 'acl', label: gettext('Privileges'), editable: false,
|
||||
schema: this.getPrivilegeRoleSchema(['X']),
|
||||
uniqueCol : ['grantee', 'grantor'], type: 'collection',
|
||||
group: 'Security', mode: ['edit', 'create'], canAdd: true,
|
||||
canDelete: true,
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
},{
|
||||
id: 'seclabels', label: gettext('Security labels'), canAdd: true,
|
||||
schema: new SecLabelSchema(), type: 'collection',
|
||||
min_version: 90100, group: 'Security', mode: ['edit', 'create'],
|
||||
canEdit: false, canDelete: true, uniqueCol : ['provider'],
|
||||
disabled: (!(this.type === 'procedure')) ? obj.isDisabled: obj.isProcedure,
|
||||
visible: function() {
|
||||
return this.node_info && !(this.type === 'procedure');
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
validate(state, setError) {
|
||||
let errmsg = null;
|
||||
if (!(this.type === 'procedure') &&(isEmptyString(state.prorettypename))) {
|
||||
errmsg = gettext('Return type cannot be empty.');
|
||||
setError('prorettypename', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('prorettypename', errmsg);
|
||||
}
|
||||
|
||||
if ((String(state.lanname) == 'c')) {
|
||||
if (isEmptyString(state.probin)){
|
||||
errmsg = gettext('Object File cannot be empty.');
|
||||
setError('probin', errmsg);
|
||||
return true;
|
||||
}else {
|
||||
errmsg = null;
|
||||
setError('probin', errmsg);
|
||||
}
|
||||
|
||||
if (isEmptyString(state.prosrc_c)) {
|
||||
errmsg = gettext('Link Symbol cannot be empty.');
|
||||
setError('prosrc_c', errmsg);
|
||||
return true;
|
||||
}else {
|
||||
errmsg = null;
|
||||
setError('prosrc_c', errmsg);
|
||||
}
|
||||
|
||||
}else {
|
||||
/* code validation*/
|
||||
if (isEmptyString(state.prosrc)) {
|
||||
errmsg = gettext('Code cannot be empty.');
|
||||
setError('prosrc', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('prosrc', errmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,14 +7,20 @@
|
|||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { getNodeAjaxOptions, getNodeListByName, getNodeListById} from '../../../../../../../static/js/node_ajax';
|
||||
import FunctionSchema from './function.ui';
|
||||
import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui';
|
||||
import { getNodeVariableSchema } from '../../../../../static/js/variable.ui';
|
||||
import _ from 'lodash';
|
||||
|
||||
/* Create and Register Procedure Collection and Node. */
|
||||
define('pgadmin.node.procedure', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/gettext', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'alertify',
|
||||
'pgadmin.node.function', 'pgadmin.node.schema.dir/child',
|
||||
'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||
'pgadmin.browser.collection', 'pgadmin.browser.server.privilege',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, alertify, Function,
|
||||
], function(gettext, url_for, $, pgAdmin, pgBrowser, alertify, Function,
|
||||
schemaChild, schemaChildTreeNode) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-procedure']) {
|
||||
|
@ -89,6 +95,37 @@ define('pgadmin.node.procedure', [
|
|||
)
|
||||
);
|
||||
},
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
return new FunctionSchema(
|
||||
(privileges)=>getNodePrivilegeRoleSchema(this, treeNodeInfo, itemNodeData, privileges),
|
||||
()=>getNodeVariableSchema(this, treeNodeInfo, itemNodeData, false, false),
|
||||
{
|
||||
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
|
||||
schema: ()=>getNodeListById(pgBrowser.Nodes['schema'], treeNodeInfo, itemNodeData, {
|
||||
cacheLevel: 'database'
|
||||
}
|
||||
),
|
||||
getTypes: ()=>getNodeAjaxOptions('get_types', this, treeNodeInfo, itemNodeData),
|
||||
getLanguage: ()=>getNodeAjaxOptions('get_languages', this, treeNodeInfo, itemNodeData),
|
||||
getSupportFunctions: ()=>getNodeAjaxOptions('get_support_functions', this, treeNodeInfo, itemNodeData, {
|
||||
cacheNode: 'function'
|
||||
}),
|
||||
|
||||
},
|
||||
{
|
||||
node_info: treeNodeInfo,
|
||||
},
|
||||
{
|
||||
type: pgBrowser.Nodes['procedure'].type,
|
||||
},
|
||||
{
|
||||
funcowner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
|
||||
pronamespace: treeNodeInfo.schema ? treeNodeInfo.schema._id : null,
|
||||
lanname: 'edbspl',
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
model: Function.model.extend({
|
||||
defaults: _.extend({},
|
||||
Function.model.prototype.defaults,
|
||||
|
|
|
@ -70,7 +70,7 @@ describe('CastSchema', ()=>{
|
|||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
|
@ -99,12 +99,14 @@ describe('CastSchema', ()=>{
|
|||
|
||||
it('srctyp depChange', ()=>{
|
||||
let depChange = _.find(schemaObj.fields, (f)=>f.id=='srctyp').depChange;
|
||||
depChange({srctyp: 'abc', trgtyp: 'abc'});
|
||||
let status = depChange({srctyp: 'abc', trgtyp: 'abc'});
|
||||
expect(status).toEqual('abc->abc');
|
||||
});
|
||||
|
||||
it('trgtyp depChange', ()=>{
|
||||
let depChange = _.find(schemaObj.fields, (f)=>f.id=='trgtyp').depChange;
|
||||
depChange({srctyp: 'abc', trgtyp: 'abc'});
|
||||
let status = depChange({srctyp: 'abc', trgtyp: 'abc'});
|
||||
expect(status).toEqual('abc->abc');
|
||||
});
|
||||
|
||||
it('validate', ()=>{
|
||||
|
|
|
@ -0,0 +1,610 @@
|
|||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import jasmineEnzyme from 'jasmine-enzyme';
|
||||
import React from 'react';
|
||||
import '../helper/enzyme.helper';
|
||||
import { createMount } from '@material-ui/core/test-utils';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import {messages} from '../fake_messages';
|
||||
import SchemaView from '../../../pgadmin/static/js/SchemaView';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import FunctionSchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/functions/static/js/function.ui';
|
||||
|
||||
class MockSchema extends BaseUISchema {
|
||||
get baseFields() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
describe('FunctionSchema', ()=>{
|
||||
let mount;
|
||||
//Procedure schema
|
||||
let procedureSchemaObj = new FunctionSchema(
|
||||
()=>new MockSchema(),
|
||||
()=>new MockSchema(),
|
||||
{
|
||||
role: [],
|
||||
schema: [],
|
||||
getLanguage: [],
|
||||
getTypes: [],
|
||||
getSupportFunctions: [],
|
||||
},
|
||||
{
|
||||
node_info: {
|
||||
connected: true,
|
||||
user: {id: 10, name: 'postgres', is_superuser: true, can_create_role: true, can_create_db: true},
|
||||
user_id: 1,
|
||||
user_name: 'postgres',
|
||||
version: 130005,
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
server_type: 'postgres',
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
} },
|
||||
},
|
||||
{
|
||||
type: 'procedure',
|
||||
},
|
||||
{
|
||||
funcowner: 'postgres',
|
||||
pronamespace: 'public',
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let schemaObj = new FunctionSchema(
|
||||
() => new MockSchema(),
|
||||
() => new MockSchema(),
|
||||
{
|
||||
role: [],
|
||||
schema: [],
|
||||
getLanguage: [],
|
||||
getTypes: [],
|
||||
getSupportFunctions: [],
|
||||
},
|
||||
{
|
||||
node_info: {
|
||||
connected: true,
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
user_id: 1,
|
||||
user_name: 'postgres',
|
||||
version: 130005,
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
server_type: 'postgres',
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
funcowner: 'postgres',
|
||||
pronamespace: 'public',
|
||||
}
|
||||
);
|
||||
let getInitData = ()=>Promise.resolve({});
|
||||
|
||||
/* Use createMount so that material ui components gets the required context */
|
||||
/* https://material-ui.com/guides/testing/#api */
|
||||
beforeAll(()=>{
|
||||
mount = createMount();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
mount.cleanUp();
|
||||
});
|
||||
|
||||
beforeEach(()=>{
|
||||
jasmineEnzyme();
|
||||
/* messages used by validators */
|
||||
pgAdmin.Browser = pgAdmin.Browser || {};
|
||||
pgAdmin.Browser.messages = pgAdmin.Browser.messages || messages;
|
||||
pgAdmin.Browser.utils = pgAdmin.Browser.utils || {};
|
||||
});
|
||||
|
||||
it('create', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={schemaObj}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('create', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={procedureSchemaObj}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('edit', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('properties', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='tab'
|
||||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'properties',
|
||||
}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('proiswindow visible', ()=>{
|
||||
|
||||
|
||||
let editSchemaObj = new FunctionSchema(
|
||||
() => new MockSchema(),
|
||||
() => new MockSchema(),
|
||||
{
|
||||
role: [],
|
||||
schema: [],
|
||||
getLanguage: [],
|
||||
getTypes: [],
|
||||
getSupportFunctions: [],
|
||||
},
|
||||
{
|
||||
node_info: {
|
||||
catalog: {},
|
||||
connected: true,
|
||||
user_id: 1,
|
||||
user_name: 'postgres',
|
||||
version: 130005,
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
server_type: 'postgres',
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
funcowner: 'postgres',
|
||||
pronamespace: 'public',
|
||||
}
|
||||
);
|
||||
|
||||
let initData = ()=>Promise.resolve({
|
||||
sysfunc: true,
|
||||
type: 'function',
|
||||
});
|
||||
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={editSchemaObj}
|
||||
getInitData={initData}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
|
||||
});
|
||||
|
||||
it('proiswindow visible', ()=>{
|
||||
|
||||
|
||||
let editSchemaObj = new FunctionSchema(
|
||||
() => new MockSchema(),
|
||||
() => new MockSchema(),
|
||||
{
|
||||
role: [],
|
||||
schema: [],
|
||||
getLanguage: [],
|
||||
getTypes: [],
|
||||
getSupportFunctions: [],
|
||||
},
|
||||
{
|
||||
node_info: {
|
||||
catalog: {},
|
||||
connected: true,
|
||||
user_id: 1,
|
||||
user_name: 'postgres',
|
||||
version: 130005,
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
server_type: 'postgres',
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
funcowner: 'postgres',
|
||||
pronamespace: 'public',
|
||||
}
|
||||
);
|
||||
|
||||
let initData = ()=>Promise.resolve({
|
||||
sysproc: true,
|
||||
type: 'function',
|
||||
});
|
||||
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={editSchemaObj}
|
||||
getInitData={initData}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
|
||||
});
|
||||
|
||||
it('proiswindow visible', ()=>{
|
||||
|
||||
|
||||
let editSchemaObj = new FunctionSchema(
|
||||
() => new MockSchema(),
|
||||
() => new MockSchema(),
|
||||
{
|
||||
role: [],
|
||||
schema: [],
|
||||
getLanguage: [],
|
||||
getTypes: [],
|
||||
getSupportFunctions: [],
|
||||
},
|
||||
{
|
||||
node_info: {
|
||||
connected: true,
|
||||
user_id: 1,
|
||||
user_name: 'postgres',
|
||||
version: 130005,
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
server_type: 'postgres',
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'procedure',
|
||||
},
|
||||
{
|
||||
funcowner: 'postgres',
|
||||
pronamespace: 'public',
|
||||
}
|
||||
);
|
||||
|
||||
let initData = ()=>Promise.resolve({
|
||||
sysfunc: true,
|
||||
type: 'procedure',
|
||||
});
|
||||
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={editSchemaObj}
|
||||
getInitData={initData}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('proiswindow visible', ()=>{
|
||||
|
||||
|
||||
let editSchemaObj = new FunctionSchema(
|
||||
() => new MockSchema(),
|
||||
() => new MockSchema(),
|
||||
{
|
||||
role: [],
|
||||
schema: [],
|
||||
getLanguage: [],
|
||||
getTypes: [],
|
||||
getSupportFunctions: [],
|
||||
},
|
||||
{
|
||||
node_info: {
|
||||
connected: true,
|
||||
user_id: 1,
|
||||
user_name: 'postgres',
|
||||
version: 130005,
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
server_type: 'postgres',
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'procedure',
|
||||
},
|
||||
{
|
||||
funcowner: 'postgres',
|
||||
pronamespace: 'public',
|
||||
}
|
||||
);
|
||||
|
||||
let initData = ()=>Promise.resolve({
|
||||
sysproc: true,
|
||||
type: 'procedure',
|
||||
});
|
||||
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={editSchemaObj}
|
||||
getInitData={initData}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('pronamespace disabled', ()=>{
|
||||
|
||||
|
||||
let editSchemaObj = new FunctionSchema(
|
||||
() => new MockSchema(),
|
||||
() => new MockSchema(),
|
||||
{
|
||||
role: [],
|
||||
schema: [],
|
||||
getLanguage: [],
|
||||
getTypes: [],
|
||||
getSupportFunctions: [],
|
||||
},
|
||||
{
|
||||
node_info: {
|
||||
catalog: {},
|
||||
connected: true,
|
||||
user_id: 1,
|
||||
user_name: 'postgres',
|
||||
version: 130005,
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
server_type: 'postgres',
|
||||
user: {
|
||||
id: 10,
|
||||
name: 'postgres',
|
||||
is_superuser: true,
|
||||
can_create_role: true,
|
||||
can_create_db: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'procedure',
|
||||
},
|
||||
{
|
||||
funcowner: 'postgres',
|
||||
pronamespace: 'public',
|
||||
}
|
||||
);
|
||||
|
||||
let initData = ()=>Promise.resolve({
|
||||
sysfunc: true,
|
||||
type: 'procedure',
|
||||
});
|
||||
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={editSchemaObj}
|
||||
getInitData={initData}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
|
||||
});
|
||||
|
||||
it('probin visible', ()=>{
|
||||
let editable = _.find(schemaObj.fields, (f)=>f.id=='probin').visible;
|
||||
let status = editable({lanname: 'c'});
|
||||
expect(status).toBe(true);
|
||||
});
|
||||
|
||||
it('prosrc_c visible', ()=>{
|
||||
let visibleData = _.find(schemaObj.fields, (f)=>f.id=='prosrc_c').visible;
|
||||
let status = visibleData({lanname: 'c'});
|
||||
expect(status).toBe(true);
|
||||
});
|
||||
|
||||
it('prosrc visible', ()=>{
|
||||
let visibleData = _.find(schemaObj.fields, (f)=>f.id=='prosrc').visible;
|
||||
let status = visibleData({lanname: 'c'});
|
||||
expect(status).toBe(false);
|
||||
});
|
||||
|
||||
it('prorows readonly', ()=>{
|
||||
let readOnly = _.find(schemaObj.fields, (f)=>f.id=='prorows').readonly;
|
||||
let status = readOnly({proretset: true});
|
||||
expect(status).toBe(false);
|
||||
});
|
||||
|
||||
it('prorettypename validate', () => {
|
||||
let state = {lanname: 'c', prorettypename: null};
|
||||
let setError = jasmine.createSpy('setError');
|
||||
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('prorettypename', 'Return type cannot be empty.');
|
||||
});
|
||||
|
||||
it('probin validate', () => {
|
||||
let state = { lanname: 'c', prorettypename: 'char' };
|
||||
let setError = jasmine.createSpy('setError');
|
||||
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('probin', 'Object File cannot be empty.');
|
||||
});
|
||||
|
||||
it('probin validate', () => {
|
||||
let state = { lanname: 'c', probin: 'test1', prorettypename: 'char'};
|
||||
let setError = jasmine.createSpy('setError');
|
||||
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('probin', null);
|
||||
});
|
||||
|
||||
it('prosrc_c validate', () => {
|
||||
let state = { lanname: 'c', probin : '$libdir/', prorettypename: 'char'};
|
||||
let setError = jasmine.createSpy('setError');
|
||||
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('prosrc_c', 'Link Symbol cannot be empty.');
|
||||
});
|
||||
|
||||
it('prosrc_c validate', () => {
|
||||
let state = { lanname: 'c', probin : '$libdir/', prosrc_c: 'test1', prorettypename: 'char'};
|
||||
let setError = jasmine.createSpy('setError');
|
||||
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('prosrc_c', null);
|
||||
});
|
||||
|
||||
it('validate', ()=>{
|
||||
let state = {prorettypename: 'char'};
|
||||
let setError = jasmine.createSpy('setError');
|
||||
state.prosrc = null;
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('prosrc', 'Code cannot be empty.');
|
||||
|
||||
state.prosrc = 'SELECT 1';
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('prosrc', null);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -85,7 +85,7 @@ describe('LanguageSchema', ()=>{
|
|||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
|
|
|
@ -109,12 +109,14 @@ describe('PublicationSchema', ()=>{
|
|||
|
||||
it('pubtable disabled', ()=>{
|
||||
let disabled = _.find(schemaObj.fields, (f)=>f.id=='pubtable').disabled;
|
||||
disabled({all_table: true});
|
||||
let status = disabled({all_table: true});
|
||||
expect(status).toBe(true);
|
||||
});
|
||||
|
||||
it('only_table readonly', ()=>{
|
||||
let readonly = _.find(schemaObj.fields, (f)=>f.id=='only_table').readonly;
|
||||
readonly({all_table: true});
|
||||
let status = readonly({all_table: true});
|
||||
expect(status).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -81,7 +81,7 @@ describe('SubscriptionSchema', ()=>{
|
|||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
|
@ -110,12 +110,14 @@ describe('SubscriptionSchema', ()=>{
|
|||
|
||||
it('copy_data_after_refresh readonly', ()=>{
|
||||
let isReadonly = _.find(schemaObj.fields, (f)=>f.id=='copy_data_after_refresh').readonly;
|
||||
isReadonly({host: '127.0.0.1', port : 5432});
|
||||
let status = isReadonly({host: '127.0.0.1', port : 5432});
|
||||
expect(status).toBe(true);
|
||||
});
|
||||
|
||||
it('copy_data_after_refresh readonly', ()=>{
|
||||
let isReadonly = _.find(schemaObj.fields, (f)=>f.id=='copy_data_after_refresh').readonly;
|
||||
isReadonly({refresh_pub : true});
|
||||
let status = isReadonly({refresh_pub : true});
|
||||
expect(status).toBe(false);
|
||||
});
|
||||
|
||||
it('validate', ()=>{
|
||||
|
@ -159,9 +161,5 @@ describe('SubscriptionSchema', ()=>{
|
|||
state.tunnel_identity_file = '/file/path/xyz.pem';
|
||||
expect(schemaObj.validate(state, setError)).toBeFalse();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue