diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js index d465922..bd8824c 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js @@ -4,6 +4,247 @@ define( 'pgadmin.browser.collection', 'pgadmin.browser.server.privilege'], function($, _, S, pgAdmin, pgBrowser, Backform, alertify) { + + // VaccumSettings Collection to display all settings parameters as Grid + var VacuumCollectionControl = Backform.VacuumCollectionControl = + Backform.Control.extend({ + + grid_columns:undefined, + + initialize: function() { + Backform.Control.prototype.initialize.apply(this, arguments); + var self = this, + m = this.model; + url = self.field.get('url'); + + if (url && m.isNew()) { + var node = self.field.get('node'), + node_data = self.field.get('node_data'), + node_info = self.field.get('node_info'), + full_url = node.generate_url.apply( + node, [ + null, url, node_data, false, node_info + ]), + data; + m.trigger('pgadmin-view:fetching', m, self.field); + + // fetch default values for autovacuum fields + $.ajax({ + async: false, + url: full_url, + success: function (res) { + data = res; + }, + error: function() { + m.trigger('pgadmin-view:fetch:error', m, self.field); + } + }); + m.trigger('pgadmin-view:fetched', m, self.field); + + // Add fetched models into collection + if (data && _.isArray(data)) { + m.get(self.field.get('name')).reset(data, {silent: true}); + } + } + }, + + render: function() { + var self = this, + m = this.model, + attributes = self.field.attributes; + + // remove grid + if(self.grid) { + self.grid.remove(); + delete self.grid; + self.grid = undefined; + } + + self.$el.empty(); + + var gridHeader = _.template([ + '
', + ' ', + '
'].join("\n")), + gridBody = $('
').append( + gridHeader(attributes) + ); + + // Initialize a new Grid instance + var grid = self.grid = new Backgrid.Grid({ + columns: self.grid_columns, + collection: self.model.get(self.field.get('name')), + className: "backgrid table-bordered" + }); + + // render grid + self.$el.append($(gridBody).append(grid.render().$el)); + + return self; + } + }); + + // We will use this function in VacuumSettings Control + // to convert data type on the fly + var cellFunction = Backform.cellFunction = function(model) { + var self = this, + m = model, + vartype = model.get('column_type'); + + switch(vartype) { + case "integer": + return Backgrid.IntegerCell; + break; + case "number": + return Backgrid.NumberCell; + break; + case "string": + return Backgrid.StringCell; + break; + default: + return Backgrid.Cell; + break; + } + }; + + // Define Security Model with fields and validation for VacuumSettings Control + var VacuumTableModel = Backform.VacuumTableModel = pgAdmin.Browser.Node.Model.extend({ + defaults: { + name: undefined, + setting: undefined, + label:undefined, + value: undefined, + column_type: undefined + }, + + toJSON: function(){ + var d = pgAdmin.Browser.Node.Model.prototype.toJSON.apply(this); + delete d.label; + delete d.setting; + delete d.column_type; + return d; + } + }); + + // Extend the browser's collection class for VacuumSettingsModel + var VacuumSettingsSchema = Backform.VacuumSettingsSchema = + [{ + id: 'autovacuum_custom', label: '{{ _("Custom auto-vacuum?") }}', + group: '{{ _("Table") }}', mode: ['edit', 'create'], + type: 'switch', + disabled: function(m) { + if(!m.top.inSchema.apply(this, [m])) { + return false; + } + return true; + } + },{ + id: 'autovacuum_enabled', label: '{{ _("Enabled?") }}', + group: '{{ _("Table") }}', mode: ['edit', 'create'], + type: 'switch', + deps: ['autovacuum_custom'], + disabled: function(m) { + if(!m.top.inSchema.apply(this, [m]) && + m.get('autovacuum_custom') == true) { + return false; + } + + // We also need to unset rest of all + setTimeout(function() { + m.set('autovacuum_enabled', false); + return true; + }, 10); + return true; + } + },{ + id: 'vacuum_table', label: '{{ _("Vacuum Table") }}', + model: Backform.VacuumTableModel, editable: false, type: 'collection', + canEdit: true, group: '{{ _("Table") }}', + mode: ['edit', 'create'], url: 'get_table_vacumum', + control: Backform.VacuumCollectionControl.extend({ + grid_columns :[ + { + name: 'label', label: '{{ _("Label") }}', + cell: 'string', editable: false + }, + { + name: 'value', label: '{{ _("Value") }}', + cellFunction: Backform.cellFunction, editable: function(m) { + return m.handler.get('autovacuum_enabled'); + } + }, + { + name: 'setting', label: '{{ _("Default value") }}', + cellFunction: Backform.cellFunction, editable: false + } + ] + }), + deps: ['autovacuum_enabled'] + },{ + id: 'toast_autovaccum', label: '{{ _("Custom auto-vaccum?") }}', + group: '{{ _("Toast Table") }}', mode: ['edit', 'create'], + type: 'switch', + disabled: function(m) { + // We need to check additional condition to toggle enable/disable + // for table auto-vacuum + if(!m.top.inSchema.apply(this, [m]) && m.isNew()) { + return false; + } else if(!m.top.inSchema.apply(this, [m]) && + m.get('toast_autovacuum_enabled') === true) { + return false; + } + return true; + } + },{ + id: 'toast_autovacuum_enabled', label: '{{ _("Enabled?") }}', + group: '{{ _("Toast Table") }}', mode: ['edit', 'create'], + type: 'switch', + deps:['toast_autovaccum'], + disabled: function(m) { + // If in schema & in create mode then enable it + if(!m.top.inSchema.apply(this, [m]) && + m.get('toast_autovaccum') === true && + m.top.get('hastoasttable') === true ) { + return false; + } + + // we also need to unset rest of all + setTimeout(function() { + m.set('toast_autovacuum_enabled', false); + return true; + }, 10); + + return true; + + } + },{ + id: 'vacuum_toast', label: '{{ _("Vacuum Toast Table") }}', + model: Backform.VacuumTableModel, type: 'collection', editable: function(m) { + return m.isNew(); + }, + canEdit: true, group: '{{ _("Toast Table") }}', + mode: ['edit', 'create'], url: 'get_toast_table_vacumum', + control: Backform.VacuumCollectionControl.extend({ + grid_columns :[ + { + name: 'label', label: '{{ _("Label") }}', + cell: 'string', editable: false + }, + { + name: 'value', label: '{{ _("Value") }}', + cellFunction: Backform.cellFunction, editable: function(m) { + return m.handler.get('toast_autovacuum_enabled'); + } + }, + { + name: 'setting', label: '{{ _("Default value") }}', + cellFunction: Backform.cellFunction, editable: false + } + ] + }), + deps: ['toast_autovacuum_enabled'] + }]; + // Extend the browser's collection class for SecurityLabel control var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({ defaults: { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py index 129c19e..3672e10 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py @@ -247,3 +247,143 @@ def parse_rule_definition(res): except Exception as e: return internal_server_error(errormsg=str(e)) return res_data + +class VacuumSettings: + """ + VacuumSettings Class. + + This class includes common utilities to fetch and parse + vacuum defaults settings. + + Methods: + ------- + * get_vacuum_table_settings(conn): + - Returns vacuum table defaults settings. + + * get_vacuum_toast_settings(conn): + - Returns vacuum toast defaults settings. + + * parse_vacuum_data(conn, result, type): + - Returns result of an associated array + of fields name, label, value and column_type. + It adds name, label, column_type properties of table/toast + vacuum into the array and returns it. + args: + * conn - It is db connection object + * result - Resultset of vacuum data + * type - table/toast vacuum type + + """ + def get_vacuum_table_settings(self, conn): + """ + Fetch the default values for autovacuum + fields, return an array of + - label + - name + - setting + values + """ + + # returns an array of name & label values + vacuum_fields = render_template("vacuum_settings/vacuum_fields.json") + + vacuum_fields = json.loads(vacuum_fields) + + # returns an array of setting & name values + vacuum_fields_keys = "'"+"','".join( + vacuum_fields['table'].keys())+"'" + SQL = render_template('vacuum_settings/sql/vacuum_defaults.sql', + columns=vacuum_fields_keys) + status, res = conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + + for row in res['rows']: + row_name = row['name'] + row['name'] = vacuum_fields['table'][row_name][0] + row['label'] = vacuum_fields['table'][row_name][1] + row['column_type'] = vacuum_fields['table'][row_name][2] + + return res + + def get_vacuum_toast_settings(self, conn): + """ + Fetch the default values for autovacuum + fields, return an array of + - label + - name + - setting + values + """ + + # returns an array of name & label values + vacuum_fields = render_template("vacuum_settings/vacuum_fields.json") + + vacuum_fields = json.loads(vacuum_fields) + + # returns an array of setting & name values + vacuum_fields_keys = "'"+"','".join( + vacuum_fields['toast'].keys())+"'" + SQL = render_template('vacuum_settings/sql/vacuum_defaults.sql', + columns=vacuum_fields_keys) + status, res = conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + + for row in res['rows']: + row_name = row['name'] + row['name'] = vacuum_fields['toast'][row_name][0] + row['label'] = vacuum_fields['toast'][row_name][1] + row['column_type'] = vacuum_fields['table'][row_name][2] + + return res + + def parse_vacuum_data(self, conn, result, type): + """ + This function returns result of an associated array + of fields name, label, value and column_type. + It adds name, label, column_type properties of table/toast + vacuum into the array and returns it. + args: + * conn - It is db connection object + * result - Resultset of vacuum data + * type - table/toast vacuum type + """ + + # returns an array of name & label values + vacuum_fields = render_template("vacuum_settings/vacuum_fields.json") + + vacuum_fields = json.loads(vacuum_fields) + + # returns an array of setting & name values + vacuum_fields_keys = "'"+"','".join( + vacuum_fields[type].keys()) + "'" + SQL = render_template('vacuum_settings/sql/vacuum_defaults.sql', + columns=vacuum_fields_keys) + status, res = conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + + if type is 'table': + for row in res['rows']: + row_name = row['name'] + row['name'] = vacuum_fields[type][row_name][0] + row['label'] = vacuum_fields[type][row_name][1] + row['column_type'] = vacuum_fields[type][row_name][2] + if result[row['name']] is not None: + row['value'] = row['setting'] = float(result[row['name']]) + + elif type is 'toast': + for row in res['rows']: + row_old_name = row['name'] + row_name = 'toast_{0}'.format(vacuum_fields[type][row_old_name][0]) + row['name'] = vacuum_fields[type][row_old_name][0] + row['label'] = vacuum_fields[type][row_old_name][1] + row['column_type'] = vacuum_fields[type][row_old_name][2] + if result[row_name] and result[row_name] is not None: + row['value'] = row['setting'] = float(result[row_name]) + + return res['rows']