Hi Dave,
All comments are resolved.
PFA the revised patch.
Regards,
Sanket Mehta
Sr Software engineer
Enterprisedb
On Thu, Feb 25, 2016 at 7:37 PM, Dave Page <[email protected]> wrote:
> Hi
>
> On Tue, Feb 23, 2016 at 1:44 PM, Sanket Mehta <
> [email protected]> wrote:
>
>> Hi,
>>
>> PFA the revised patch for fts template node which includes dependency and
>> dependent route handling code.
>> Please do review it and if found proper please do commit it.
>>
>
> - When creating a new template, errors in the dialogue are not cleared -
> e.g. the "Name must not be empty" doesn't clear, and save is not enabled,
> even when a name is entered.
>
> - "Fts Templates" should be "FTS Templates" on the treeview.
>
> - The "Init" field should be labelled "Init Function"
>
> - The "Lexize" field should be labelled "Lexize Function"
>
> - Selecting a schema should be optional, with the default being the
> current schema.
>
> - 4 character indents are not consistently used in SQL templates
>
> Thanks.
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
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 0000000..7091c93
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py
@@ -0,0 +1,700 @@
+##########################################################################
+#
+# 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.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases.schemas as schemas
+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(CollectionNodeModule):
+ """
+ class FtsTemplateModule(CollectionNodeModule)
+
+ A module class for FTS Template node derived from CollectionNodeModule.
+
+ 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 schemas.SchemaModule.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
+ 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, rg_id)
+ - This function will show the properties of the selected FTS Template node
+
+ * create(gid, sid, did, rg_id)
+ - This function will create the new FTS Template object
+
+ * update(gid, sid, did, rg_id)
+ - This function will update the data for the selected FTS Template node
+
+ * delete(self, gid, sid, rg_id):
+ - This function will drop the FTS Template object
+
+ * msql(gid, sid, did, rg_id)
+ - This function is used to return modified SQL for the selected FTS Template node
+
+ * get_sql(data, rg_id)
+ - This function will generate sql from model data
+
+ * sql(gid, sid, did, rg_id):
+ - 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.
+
+ * get_functions():
+ - This function will fetch associated functions list depending on selected source
+ and target types while creating a new FTS Template node.
+
+ * dependents(gid, sid, did, lid):
+ - This function get the dependents and return ajax response for the Fts Tempalte node.
+
+ * dependencies(self, gid, sid, did, lid):
+ - 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, 'properties.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['tmplname'],
+ icon="icon-fts_template"
+ ))
+
+ return make_json_response(
+ data=res,
+ 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',
+ 'tmplname'
+ ]
+
+ 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['tmplname']
+ )
+ 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['tmplname'],
+ 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 \
+ 'tmplname' 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 sql
+
+ 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
zWch<AzUKL-I1VYwXB<By%TpNUmZUKhtrUb892b%08Ci}?(zqzT6~$3Oc+T^K9M{LP
zw=t|r6yJ#AD?u3H`54DNK@cm;cGGmLAiNZWVV)o0xM()}fMvTF<`%=;K+*ji*OSfO
zXW34M>7eOret#)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)(<Qh8}A-&gKmyQ_1<c-Jm&72b|DB$SHpSuZL^%
zpB44T7vibJ;&@V940wM0S^B-a^8HtSaIAB*efUv})mI1s6I0UwKrb31UlSXe)DyRc
z>_<Z=9KtL}Bc=i{fhC}^#AF0ZAQNaY@3fdpw}Yh?5PZ0@Ble$g`V3l&H?Ij``Kq99
Yn=Rn3HDRXf@SrLHF1y<{w9gm*3#c75djJ3c
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/static/img/fts_template.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/static/img/fts_template.png
new file mode 100644
index 0000000000000000000000000000000000000000..eb780bf0bb0f5d777e8a72720b5ed0e2ad48bc45
GIT binary patch
literal 696
zcmY+CS4>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<?E2J5s@HYa0>`;n6HC~D{V`Wn#u^!KY$1^XAv!XaHik}2wQV_;?{=MCv=JCwg
z?M6|Yf}q2KFb+Y<JpTrQ^c?p>6lX;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=@<Ck#!0)|zX%}Nw4CCM8EQBM%HIPS#pY7DEyu(K#yhN2}1Qj8#lI9_A1
zM4{+uvl%p*6fj(1GKIqMaSS_;qGu4qfgq<4<OB@o!EmnIZFjqEZnt$+xwl3tROT=w
z83FZ=FLo(-pVVa*ORif|!bD!2v~(qE_oW8TSxqjWRxfwS*P1M=z1F2im-r=x?Q{Y$
z{<}AiR&>@6%eCr;WPOgta4;(&-EXUFOUO`XZ}&h~Uyt9KfZ6H!*@c<Ub1`7Gd^|9y
zwW*~!J0mM||H}OQKfgC_Xm2}`^EKFOaZ|_9Z*i~BiL%Oo%Fgfg)5EZHy!U6IQ=Q+I
ztuEI%EQTT<ZE%zV+`BCzbkDAsI`95tav4ziD`;WBxc%P;?Qq0rIBaGIq_P%4k^xFE
z98`oW6<~O(5>!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 0000000..e46ffc3
--- /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: ['tmplname', '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',
+ 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: {
+ tmplname: 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: 'tmplname', label: '{{ _('Name') }}', cell: 'string', group: 'Definition',
+ type: 'text', cellHeaderClasses: 'width_percent_50'
+ },{
+ id: 'oid', label:'{{ _('Oid') }}', cell: 'string', group: 'Definition',
+ editable: false, type: 'text', disabled: true
+ },{
+ id: 'description', label:'{{ _('Comment') }}', cell: 'string', group: 'Definition',
+ 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'
+ },{
+ id: 'schema', label: '{{ _('Schema')}}', cell: 'string', group: 'Definition',
+ type: 'text', mode: ['create','edit'], node: 'schema',
+ control: 'node-list-by-id'
+ }],
+
+ /*
+ * 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('tmplname');
+ 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 0000000..de76132
--- /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,12 @@
+{# CREATE TEXT SEARCH TEMPLATE Statement #}
+{% if data and data.schema and data.tmplname and data.tmpllexize %}
+
+CREATE TEXT SEARCH TEMPLATE {{ conn|qtIdent(data.schema, data.tmplname) }} (
+{% 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.tmplname) }}
+ 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 0000000..cca8dc4
--- /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 0000000..2fe9e02
--- /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/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 0000000..8b2a70c
--- /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,
+ 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 0000000..bf7ddb3
--- /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 0000000..103c7bf
--- /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\n CREATE TEXT SEARCH TEMPLATE ' || nspname || E'.' || tmpl.tmplname || E'(\n' ||
+ CASE
+ WHEN tmpl.tmplinit != '-'::regclass THEN E'\tINIT = ' || tmpl.tmplinit || E',\n'
+ ELSE '' END ||
+ E'\tLEXIZE = ' || 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 0000000..1faf08f
--- /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,15 @@
+{# UPDATE statement for TEXT SEARCH TEMPLATE #}
+{% if data %}
+{% if data.tmplname and data.tmplname != o_data.tmplname %}
+ALTER TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(o_data.tmplname)}}
+ RENAME TO {{data.tmplname}};
+{% endif %}
+{% if data.schema and data.schema != o_data.schema %}
+ALTER TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(o_data.tmplname)}}
+ SET SCHEMA {{data.schema}};
+{% endif %}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(o_data.tmplname)}}
+ IS {{ data.description|qtLiteral }};
+{% endif %}
+{% endif %}
\ No newline at end of file
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers