Port Procedure and Function node to react. Fixes #6632 #6677

pull/58/head
Pradip Parkale 2021-08-24 12:06:07 +05:30 committed by Akshay Joshi
parent 27e446a0b0
commit 2074534b72
8 changed files with 1172 additions and 376 deletions

View File

@ -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;
},
}),
});

View File

@ -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);
}
}
}
}

View File

@ -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,

View File

@ -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', ()=>{

View File

@ -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);
});
});

View File

@ -85,7 +85,7 @@ describe('LanguageSchema', ()=>{
schema={schemaObj}
getInitData={getInitData}
viewHelperProps={{
mode: 'create',
mode: 'edit',
}}
onSave={()=>{}}
onClose={()=>{}}

View File

@ -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);
});
});

View File

@ -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();
});
});