From 95566ed5e13b66b47c672b8c60fb425d7bff06a7 Mon Sep 17 00:00:00 2001 From: Sanket Mehta Date: Thu, 7 Apr 2016 15:01:56 +0100 Subject: [PATCH] FTS Template support. --- .../schemas/fts_templates/__init__.py | 719 ++++++++++++++++++ .../static/img/coll-fts_template.png | Bin 0 -> 601 bytes .../fts_templates/static/img/fts_template.png | Bin 0 -> 696 bytes .../fts_template/js/fts_templates.js | 133 ++++ .../fts_template/sql/9.1_plus/create.sql | 11 + .../fts_template/sql/9.1_plus/delete.sql | 23 + .../fts_template/sql/9.1_plus/functions.sql | 23 + .../fts_template/sql/9.1_plus/nodes.sql | 12 + .../fts_template/sql/9.1_plus/properties.sql | 27 + .../fts_template/sql/9.1_plus/schema.sql | 19 + .../fts_template/sql/9.1_plus/sql.sql | 41 + .../fts_template/sql/9.1_plus/update.sql | 22 + 12 files changed, 1030 insertions(+) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/static/img/coll-fts_template.png create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/static/img/fts_template.png create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/js/fts_templates.js create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/functions.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/nodes.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/sql.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/update.sql diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py new file mode 100644 index 000000000..bc8044016 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py @@ -0,0 +1,719 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Defines views for management of Fts Template node""" + +import json +from flask import render_template, make_response, current_app, request, jsonify +from flask.ext.babel import gettext +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.server_groups.servers.databases.schemas.utils import SchemaChildModule +from pgadmin.browser.server_groups.servers.databases import DatabaseModule +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from config import PG_DEFAULT_DRIVER +from functools import wraps + + +class FtsTemplateModule(SchemaChildModule): + """ + class FtsTemplateModule(SchemaChildModule) + + A module class for FTS Template node derived from SchemaChildModule. + + Methods: + ------- + * __init__(*args, **kwargs) + - Method is used to initialize the FtsTemplateModule and it's base module. + + * get_nodes(gid, sid, did, scid) + - Method is used to generate the browser collection node. + + * node_inode() + - Method is overridden from its base class to make the node as leaf node. + + * script_load() + - Load the module script for FTS Template, when any of the schema node is + initialized. + """ + NODE_TYPE = 'fts_template' + COLLECTION_LABEL = gettext('FTS Templates') + + def __init__(self, *args, **kwargs): + self.min_ver = None + self.max_ver = None + super(FtsTemplateModule, self).__init__(*args, **kwargs) + + def get_nodes(self, gid, sid, did, scid): + """ + Generate the collection node + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Override the property to make the node as leaf node + """ + return False + + @property + def script_load(self): + """ + Load the module script for fts template, when any of the schema node is + initialized. + """ + return DatabaseModule.NODE_TYPE + + +blueprint = FtsTemplateModule(__name__) + + +class FtsTemplateView(PGChildNodeView): + """ + class FtsTemplateView(PGChildNodeView) + + A view class for FTS Tempalte node derived from PGChildNodeView. This class is + responsible for all the stuff related to view like create/update/delete + responsible for all the stuff related to view like create/update/delete + FTS template, showing properties of node, showing sql in sql pane. + + Methods: + ------- + * __init__(**kwargs) + - Method is used to initialize the FtsTemplateView and it's base view. + + * module_js() + - This property defines (if javascript) exists for this node. + Override this property for your own logic + + * check_precondition() + - This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to self + + * list() + - This function is used to list all the nodes within that collection. + + * nodes() + - This function will used to create all the child node within that collection. + Here it will create all the FTS Template nodes. + + * properties(gid, sid, did, scid, tid) + - This function will show the properties of the selected FTS Template node + + * create(gid, sid, did, scid) + - This function will create the new FTS Template object + + * update(gid, sid, did, scid, tid) + - This function will update the data for the selected FTS Template node + + * delete(self, gid, sid, did, scid, tid): + - This function will drop the FTS Template object + + * msql(gid, sid, did, scid, tid) + - This function is used to return modified SQL for the selected FTS Template node + + * get_sql(data, tid) + - This function will generate sql from model data + + * sql(gid, sid, did, scid, tid): + - This function will generate sql to show it in sql pane for the selected FTS Template node. + + * get_type(): + - This function will fetch all the types for source and target types select control. + + * dependents(gid, sid, did, scid, tid): + - This function get the dependents and return ajax response for the Fts Tempalte node. + + * dependencies(self, gid, sid, did, scid, tid): + - This function get the dependencies and return ajax response for the FTS Tempalte node. + + """ + + node_type = blueprint.node_type + + parent_ids = [ + {'type': 'int', 'id': 'gid'}, + {'type': 'int', 'id': 'sid'}, + {'type': 'int', 'id': 'did'}, + {'type': 'int', 'id': 'scid'} + ] + ids = [ + {'type': 'int', 'id': 'tid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'children': [{ + 'get': 'children' + }], + 'delete': [{'delete': 'delete'}], + 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'sql': [{'get': 'sql'}], + 'msql': [{'get': 'msql'}, {'get': 'msql'}], + 'stats': [{'get': 'statistics'}], + 'dependency': [{'get': 'dependencies'}], + 'dependent': [{'get': 'dependents'}], + 'module.js': [{}, {}, {'get': 'module_js'}], + 'get_lexize': [{'get': 'get_lexize'}, {'get': 'get_lexize'}], + 'get_init': [{'get': 'get_init'}, {'get': 'get_init'}], + }) + + def _init_(self, **kwargs): + self.conn = None + self.template_path = None + self.manager = None + super(FtsTemplateView, self).__init__(**kwargs) + + def module_js(self): + """ + This property defines whether javascript exists for this node. + """ + return make_response( + render_template( + "fts_template/js/fts_templates.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to self + """ + + @wraps(f) + def wrap(*args, **kwargs): + # Here args[0] will hold self & kwargs will hold gid,sid,did + self = args[0] + self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( + kwargs['sid']) + self.conn = self.manager.connection(did=kwargs['did']) + # If DB not connected then return error to browser + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + # we will set template path for sql scripts depending upon server version + ver = self.manager.version + if ver >= 90100: + self.template_path = 'fts_template/sql/9.1_plus' + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid): + sql = render_template( + "/".join([self.template_path, 'properties.sql']), + scid=scid + ) + status, res = self.conn.execute_dict(sql) + + if not status: + return internal_server_error(errormsg=res) + + return ajax_response( + response=res['rows'], + status=200 + ) + + @check_precondition + def nodes(self, gid, sid, did, scid): + res = [] + sql = render_template( + "/".join([self.template_path, 'nodes.sql']), + scid=scid + ) + status, rset = self.conn.execute_2darray(sql) + if not status: + return internal_server_error(errormsg=rset) + + for row in rset['rows']: + res.append( + self.blueprint.generate_browser_node( + row['oid'], + did, + row['name'], + icon="icon-fts_template" + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def node(self, gid, sid, did, scid, tid): + res = [] + sql = render_template( + "/".join([self.template_path, 'nodes.sql']), + tid=tid + ) + status, rset = self.conn.execute_2darray(sql) + if not status: + return internal_server_error(errormsg=rset) + + for row in rset['rows']: + return make_json_response( + data=self.blueprint.generate_browser_node( + row['oid'], + did, + row['name'], + icon="icon-fts_template" + ), + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, tid): + sql = render_template( + "/".join([self.template_path, 'properties.sql']), + scid=scid, + tid=tid + ) + status, res = self.conn.execute_dict(sql) + + if not status: + return internal_server_error(errormsg=res) + + return ajax_response( + response=res['rows'][0], + status=200 + ) + + @check_precondition + def create(self, gid, sid, did, scid): + """ + This function will creates new the fts_template object + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + """ + + # Mandatory fields to create a new fts template + required_args = [ + 'tmpllexize', + 'schema', + 'name' + ] + + data = request.form if request.form else json.loads( + request.data.decode()) + for arg in required_args: + if arg not in data: + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter (%s)." % arg + ) + ) + try: + # Fetch schema name from schema oid + sql = render_template("/".join([self.template_path, 'schema.sql']), + data=data, + conn=self.conn, + ) + + status, schema = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=schema) + + # replace schema oid with schema name before passing to create.sql + # to generate proper sql query + new_data = data.copy() + new_data['schema'] = schema + sql = render_template("/".join([self.template_path, 'create.sql']), + data=new_data, + conn=self.conn, + ) + status, res = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=res) + + # we need fts_template id to to add object in tree at browser, + # below sql will give the same + sql = render_template( + "/".join([self.template_path, 'properties.sql']), + name=data['name'] + ) + status, tid = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=tid) + + return jsonify( + node=self.blueprint.generate_browser_node( + tid, + did, + data['name'], + icon="icon-fts_template" + ) + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def update(self, gid, sid, did, scid, tid): + """ + This function will update text search template object + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + :param tid: fts tempate id + """ + data = request.form if request.form else json.loads( + request.data.decode()) + + # Fetch sql query to update fts template + sql = self.get_sql(gid, sid, did, scid, data, tid) + try: + if sql and sql.strip('\n') and sql.strip(' '): + status, res = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info="FTS Template updated", + data={ + 'id': tid, + 'sid': sid, + 'gid': gid, + 'did': did, + 'scid': scid + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update", + data={ + 'id': tid, + 'sid': sid, + 'gid': gid, + 'did': did, + 'scid': scid + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, scid, tid): + """ + This function will drop the fts_template object + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + :param tid: fts tempate id + """ + # Below will decide if it's simple drop or drop with cascade call + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + try: + # Get name for template from tid + sql = render_template("/".join([self.template_path, 'delete.sql']), + tid=tid) + status, res = self.conn.execute_dict(sql) + if not status: + return internal_server_error(errormsg=res) + + # Drop fts template + result = res['rows'][0] + sql = render_template("/".join([self.template_path, 'delete.sql']), + name=result['name'], + schema=result['schema'], + cascade=cascade + ) + + status, res = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info=gettext("FTS template dropped"), + data={ + 'id': tid, + 'sid': sid, + 'gid': gid, + 'did': did, + 'scid': scid + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def msql(self, gid, sid, did, scid, tid=None): + """ + This function returns modified SQL + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + :param tid: fts tempate id + """ + data = request.args + + # Fetch sql query for modified data + sql = self.get_sql(gid, sid, did, scid, data, tid) + + if isinstance(sql, str) and sql and sql.strip('\n') and sql.strip(' '): + return make_json_response( + data=sql, + status=200 + ) + else: + return make_json_response( + data="--modified SQL", + status=200 + ) + + def get_sql(self, gid, sid, did, scid, data, tid=None): + """ + This function will return SQL for model data + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + :param tid: fts tempate id + """ + try: + # Fetch sql for update + if tid is not None: + sql = render_template( + "/".join([self.template_path, 'properties.sql']), + tid=tid, + scid=scid + ) + + status, res = self.conn.execute_dict(sql) + if not status: + return internal_server_error(errormsg=res) + + old_data = res['rows'][0] + + # If user has changed the schema then fetch new schema directly + # using its oid otherwise fetch old schema name using fts template oid + sql = render_template( + "/".join([self.template_path, 'schema.sql']), + data=data) + + status, new_schema = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=new_schema) + + # Replace schema oid with schema name + new_data = data.copy() + if 'schema' in new_data: + new_data['schema'] = new_schema + + # Fetch old schema name using old schema oid + sql = render_template( + "/".join([self.template_path, 'schema.sql']), + data=old_data) + + status, old_schema = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=old_schema) + + # Replace old schema oid with old schema name + old_data['schema'] = old_schema + + sql = render_template( + "/".join([self.template_path, 'update.sql']), + data=new_data, o_data=old_data + ) + # Fetch sql query for modified data + else: + # Fetch schema name from schema oid + sql = render_template("/".join([self.template_path, 'schema.sql']), + data=data) + + status, schema = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=schema) + + # Replace schema oid with schema name + new_data = data.copy() + new_data['schema'] = schema + + if 'tmpllexize' in new_data and \ + 'name' in new_data and \ + 'schema' in new_data: + sql = render_template("/".join([self.template_path, + 'create.sql']), + data=new_data, + conn=self.conn + ) + else: + sql = "-- incomplete definition" + return str(sql.strip('\n')) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def get_lexize(self, gid, sid, did, scid, tid=None): + """ + This function will return lexize functions list for fts template + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + :param tid: fts tempate id + """ + data = request.args + sql = render_template("/".join([self.template_path, 'functions.sql']), + lexize=True) + status, rset = self.conn.execute_dict(sql) + + if not status: + return internal_server_error(errormsg=rset) + + # Empty set is added before actual list as initially it will be visible + # at lexize select control while creating a new fts template + res = [{'label': '', 'value': ''}] + for row in rset['rows']: + res.append({'label': row['proname'], + 'value': row['proname']}) + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def get_init(self, gid, sid, did, scid, tid=None): + """ + This function will return init functions list for fts template + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + :param tid: fts tempate id + """ + data = request.args + sql = render_template("/".join([self.template_path, 'functions.sql']), + init=True) + status, rset = self.conn.execute_dict(sql) + + if not status: + return internal_server_error(errormsg=rset) + + # We have added this to map against '-' which is coming from server + res = [{'label': '', 'value': '-'}] + for row in rset['rows']: + res.append({'label': row['proname'], + 'value': row['proname']}) + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def sql(self, gid, sid, did, scid, tid): + """ + This function will reverse generate sql for sql panel + :param gid: group id + :param sid: server id + :param did: database id + :param scid: schema id + :param tid: fts tempate id + """ + try: + sql = render_template( + "/".join([self.template_path, 'sql.sql']), + tid=tid, + scid=scid, + conn=self.conn + ) + status, res = self.conn.execute_scalar(sql) + if not status: + return internal_server_error( + _( + "ERROR: Couldn't generate reversed engineered Query for the FTS template!\n{0}").format( + res + ) + ) + + if res is None: + return gone( + _( + "ERROR: Couldn't generate reversed engineered Query for FTS template node!") + ) + + return ajax_response(response=res) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def dependents(self, gid, sid, did, scid, tid): + """ + This function get the dependents and return ajax response + for the FTS Template node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: FTS Template ID + """ + dependents_result = self.get_dependents(self.conn, tid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, tid): + """ + This function get the dependencies and return ajax response + for the FTS Template node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: FTS Tempalte ID + """ + dependencies_result = self.get_dependencies(self.conn, tid) + return ajax_response( + response=dependencies_result, + status=200 + ) + +FtsTemplateView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/static/img/coll-fts_template.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/static/img/coll-fts_template.png new file mode 100644 index 0000000000000000000000000000000000000000..fabd47da7ae27b04b0bfd38a7b1ee9f6c1a74d2c GIT binary patch literal 601 zcmY+9Ye-W86vyuj!!5?7zDS=7f?QnJEZv8iwXIEZ*mjEw%H7=uILpipL87b$mOaoY zG^59ICOS;*K|&8hv}qE{A&!ucGBAp8clWjXUN`;JhyVGV1Lp_lv{kzg=yjWQ008J+ zPMb$%;lC8DQ|mUP!K;F=J_y-WCa0Pc@5*zzR4zBCD6@+4NtUN2X;PBj=W_GWZkwVc zWch7eOret#)NwPdsRSoRLXw9|AOMO~(-3nbZ`$%Op=GMc^u!)A&)55r(46ZH9t z38IdoE|KIpl5EOk8VRDFAOh($o=&3+LQOz@UK8@Ty?}N33$6~@2IsM$O6O`EAM5t0 zO_$470Ts<5J~XUxtOtF59LHe{`S}eE>l)5RWAIXicVhB-Uu&D8O228Z^XA1!$H>+G zyJb#mUa!MbdE9ZteNwX}Qs9a94)(_j@6ozkcq>wQ5!GLk#CLzU3S)oQ!Yr$eFU<-t$cHKq-h(bd^Q2~h-MIjMo zBO)RJ1T=0%>WGXeVM%<^_+&IudiTD!Ug61y|NQ4q&iC@?)TAUG@by{m0|0<;qE2g& zJm8`;n6HC~D{V`Wn#u^!KY$1^XAv!XaHik}2wQV_;?{=MCv=JCwg z?M6|Yf}q2KFb+Y6lX;7qaaKO!Uvvz%k!fg_mbnDvg{+49p?FWJn!PT zR~+|@WgoNb1BSV8vuSC%o99P3?m5doVcCZaGsrM~G<}z*Z&Oq|NjBSTI+h(`n0}h> zq3JG)>Y%6=lDuiLs0iXJ!wfLYJ(|8lQMV|nl_VQU@;X6W!|}^Fei6f}Xu8vCjU&k> zl58M|I)b=@@6%eCr;WPOgta4;(&-EXUFOUO`XZ}&h~Uyt9KfZ6H!*@c!P-s3N06!6+37b}WYV{Rb2j+H&n>%K#X=1W4DBDlmE(m~2cNkN_Yt LK1n;MF;)Eq048yN literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/js/fts_templates.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/js/fts_templates.js new file mode 100644 index 000000000..407bc12dd --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/js/fts_templates.js @@ -0,0 +1,133 @@ +define( + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + // Extend the collection class for fts template + if (!pgBrowser.Nodes['coll-fts_template']) { + var fts_templates = pgAdmin.Browser.Nodes['coll-fts_template'] = + pgAdmin.Browser.Collection.extend({ + node: 'fts_template', + label: '{{ _('FTS Templates') }}', + type: 'coll-fts_template', + columns: ['name', 'description'] + }); + }; + + // Extend the node class for fts template + if (!pgBrowser.Nodes['fts_template']) { + pgAdmin.Browser.Nodes['fts_template'] = pgAdmin.Browser.Node.extend({ + parent_type: ['schema', 'catalog'], + type: 'fts_template', + canDrop: true, + canDropCascade: true, + label: '{{ _('FTS Templates') }}', + hasSQL: true, + hasDepends: true, + Init: function() { + + // Avoid multiple registration of menus + if (this.initialized) + return; + + this.initialized = true; + + // Add context menus for fts template + pgBrowser.add_menus([{ + name: 'create_fts_template_on_schema', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('FTS Template...') }}', + icon: 'wcTabIcon icon-fts_template', data: {action: 'create'} + },{ + name: 'create_fts_template_on_coll', node: 'coll-fts_template', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('FTS Template...') }}', + icon: 'wcTabIcon icon-fts_template', data: {action: 'create'} + },{ + name: 'create_fts_template', node: 'fts_template', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('FTS Template...') }}', + icon: 'wcTabIcon icon-fts_template', data: {action: 'create'} + }]); + + }, + + // Defining backform model for fts template node + model: pgAdmin.Browser.Node.Model.extend({ + defaults: { + name: undefined, // Fts template name + description: undefined, // Comment on template + schema: undefined, // Schema name to which template belongs + tmplinit: undefined, // Init function for fts template + tmpllexize: undefined // Lexize function for fts template + }, + initialize: function() { + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + if (_.isUndefined(this.get('schema'))) { + this.set('schema', this.node_info.schema._id); + } + }, + // Defining schema for fts template + schema: [{ + id: 'name', label: '{{ _('Name') }}', cell: 'string', + type: 'text', cellHeaderClasses: 'width_percent_50' + },{ + id: 'oid', label:'{{ _('OID') }}', cell: 'string', + editable: false, type: 'text', disabled: true, mode:['properties'] + },{ + id: 'schema', label: '{{ _('Schema')}}', cell: 'string', + type: 'text', mode: ['create','edit'], node: 'schema', + control: 'node-list-by-id' + },{ + id: 'description', label:'{{ _('Comment') }}', cell: 'string', + type: 'multiline', cellHeaderClasses: 'width_percent_50' + },{ + id: 'tmplinit', label: '{{ _('Init function')}}', group: '{{ _('Definition') }}', + type: 'text', disabled: function(m) { return !m.isNew(); }, + control: 'node-ajax-options', url: 'get_init' + },{ + id: 'tmpllexize', label: '{{ _('Lexize function')}}', group: '{{ _('Definition') }}', + type: 'text', disabled: function(m) { return !m.isNew(); }, + control: 'node-ajax-options', url: 'get_lexize' + }], + + /* + * Triggers control specific error messages for template name, + * lexize function and schema, if any one of them is not specified + * while creating new fts template + */ + validate: function(keys){ + var name = this.get('name'); + var lexize = this.get('tmpllexize'); + var schema = this.get('schema'); + + // Validate fts template name + if (_.isUndefined(name) || _.isNull(name) || String(name).replace(/^\s+|\s+$/g, '') == '') { + var msg = '{{ _('Name must be specified!') }}'; + this.errorModel.set('name', msg); + return msg; + } + + // Validate lexize function control + else if (_.isUndefined(lexize) || _.isNull(lexize) || String(lexize).replace(/^\s+|\s+$/g, '') == '') { + var msg = '{{ _('Lexize function must be selected!') }}'; + this.errorModel.set('tmpllexize', msg); + return msg; + } + + // Validate schema for fts template + else if (_.isUndefined(schema) || _.isNull(schema) || String(schema).replace(/^\s+|\s+$/g, '') == '') { + var msg = '{{ _('Schema must be selected!') }}'; + this.errorModel.set('schema', msg); + return msg; + } + else this.errorModel.clear(); + + this.trigger('on-status-clear'); + return null; + } + }) + }); + } + +return pgBrowser.Nodes['coll-fts_template']; +}); \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/create.sql new file mode 100644 index 000000000..3a290b382 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/create.sql @@ -0,0 +1,11 @@ +{# CREATE TEXT SEARCH TEMPLATE Statement #} +{% if data and data.schema and data.name and data.tmpllexize %} +CREATE TEXT SEARCH TEMPLATE {{ conn|qtIdent(data.schema, data.name) }} ( +{% if data.tmplinit and data.tmplinit != '-'%} INIT = {{data.tmplinit}},{% endif %} + LEXIZE = {{data.tmpllexize}} +); +{# Description for TEXT SEARCH TEMPLATE #} +{% if data.description %} +COMMENT ON TEXT SEARCH TEMPLATE {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.description|qtLiteral }}; +{% endif %}{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/delete.sql new file mode 100644 index 000000000..cca8dc448 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/delete.sql @@ -0,0 +1,23 @@ +{# FETCH TEXT SEARCH TEMPLATE NAME Statement #} +{% if tid %} +SELECT + t.tmplname AS name, + ( + SELECT + nspname + FROM + pg_namespace + WHERE + oid = t.tmplnamespace + ) as schema +FROM + pg_ts_template t LEFT JOIN pg_description d + ON d.objoid=t.oid AND d.classoid='pg_ts_template'::regclass +WHERE + t.oid = {{tid}}::OID; +{% endif %} + +{# DROP TEXT SEARCH TEMPLATE Statement #} +{% if schema and name %} +DROP TEXT SEARCH TEMPLATE {{conn|qtIdent(schema)}}.{{conn|qtIdent(name)}} {% if cascade %}CASCADE{%endif%}; +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/functions.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/functions.sql new file mode 100644 index 000000000..2fe9e0299 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/functions.sql @@ -0,0 +1,23 @@ +{# FETCH lexize functions for TEXT SEARCH TEMPLATE #} +{% if lexize %} +SELECT + proname, nspname +FROM + pg_proc JOIN pg_namespace n ON n.oid=pronamespace +WHERE + prorettype=2281 + AND proargtypes='2281 2281 2281 2281' +ORDER BY proname; +{% endif %} + +{# FETCH init functions for TEXT SEARCH TEMPLATE #} +{% if init %} +SELECT + proname, nspname +FROM + pg_proc JOIN pg_namespace n ON n.oid=pronamespace +WHERE + prorettype=2281 and proargtypes='2281' +ORDER BY + proname; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/nodes.sql new file mode 100644 index 000000000..850247e30 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/nodes.sql @@ -0,0 +1,12 @@ +SELECT + oid, tmplname as name +FROM + pg_ts_template tmpl +WHERE +{% if scid %} + tmpl.tmplnamespace = {{scid}}::OID +{% elif tid %} + tmpl.oid = {{tid}}::OID +{% endif %} + +ORDER BY name \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/properties.sql new file mode 100644 index 000000000..2b5a95fb1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/properties.sql @@ -0,0 +1,27 @@ +{# Get properties for FTS TEMPLATE #} +SELECT + tmpl.oid, + tmpl.tmplname as name, + tmpl.tmplinit, + tmpl.tmpllexize, + description, + tmpl.tmplnamespace AS schema +FROM + pg_ts_template tmpl + LEFT OUTER JOIN pg_description des +ON + ( + des.objoid=tmpl.oid + AND des.classoid='pg_ts_template'::regclass + ) +WHERE +{% if scid %} + tmpl.tmplnamespace = {{scid}}::OID +{% elif name %} + tmpl.tmplname = {{name|qtLiteral}} +{% endif %} +{% if tid %} + AND tmpl.oid = {{tid}}::OID +{% endif %} +ORDER BY + tmpl.tmplname \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/schema.sql new file mode 100644 index 000000000..bf7ddb3a8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/schema.sql @@ -0,0 +1,19 @@ +{# SCHEMA name FETCH statement #} +{% if data.schema %} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{data.schema}}::OID + +{% elif data.id %} +SELECT + nspname +FROM + pg_namespace nsp + LEFT JOIN pg_ts_template ts + ON ts.tmplnamespace = nsp.oid +WHERE + ts.oid = {{data.id}}::OID +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/sql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/sql.sql new file mode 100644 index 000000000..6661078b3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/sql.sql @@ -0,0 +1,41 @@ +{# Reverse engineered sql for FTS TEMPLATE #} +SELECT + array_to_string(array_agg(sql), E'\n\n') as sql +FROM + ( + SELECT + E'-- Text Search Template: ' || nspname || E'.' || tmpl.tmplname || + E'\n\n-- DROP TEXT SEARCH TEMPLATE ' || nspname || E'.' || tmpl.tmplname || + E'\n\nCREATE TEXT SEARCH TEMPLATE ' || nspname || E'.' || tmpl.tmplname || E' (\n' || + CASE + WHEN tmpl.tmplinit != '-'::regclass THEN E' INIT = ' || tmpl.tmplinit || E',\n' + ELSE '' END || + E' LEXIZE = ' || tmpl.tmpllexize || E'\n);' || + CASE + WHEN a.description IS NOT NULL THEN + E'\n\nCOMMENT ON TEXT SEARCH TEMPLATE ' || nspname || E'.' || tmpl.tmplname || + E' IS ' || pg_catalog.quote_literal(description) || E';' + ELSE '' END as sql +FROM + pg_ts_template tmpl + LEFT JOIN ( + SELECT + des.description as description, + des.objoid as descoid + FROM + pg_description des + WHERE + des.objoid={{tid}}::OID AND des.classoid='pg_ts_template'::regclass + ) a ON (a.descoid = tmpl.oid) + LEFT JOIN ( + SELECT + nspname, + nsp.oid as noid + FROM + pg_namespace nsp + WHERE + oid = {{scid}}::OID + ) b ON (b.noid = tmpl.tmplnamespace) +WHERE + tmpl.oid={{tid}}::OID +) as c; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/update.sql new file mode 100644 index 000000000..156defd7a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/templates/fts_template/sql/9.1_plus/update.sql @@ -0,0 +1,22 @@ +{# UPDATE statement for TEXT SEARCH TEMPLATE #} +{% if data %} +{% if data.name and data.name != o_data.name %} +ALTER TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(o_data.name)}} + RENAME TO {{data.name}}; +{% endif %} + +{#in case of rename, use new fts template name #} +{% if data.name and data.name != o_data.name %} +{% set name = data.name %} +{% else %} +{% set name = o_data.name %} +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +ALTER TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}} + SET SCHEMA {{data.schema}}; +{% endif %} +{% if 'description' in data and data.description != o_data.description %} +COMMENT ON TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}} + IS {{ data.description|qtLiteral }}; +{% endif %} +{% endif %} \ No newline at end of file