FTS Parser support

This commit is contained in:
Dave Page
2016-04-07 20:59:09 +01:00
parent d6d6361de5
commit 34a803fc68
11 changed files with 419 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

View File

@@ -0,0 +1,193 @@
define(
['jquery', 'underscore', 'underscore.string', 'pgadmin',
'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
function($, _, S, pgAdmin, pgBrowser, alertify) {
// Extend the collection class for fts parser
if (!pgBrowser.Nodes['coll-fts_parser']) {
var fts_parsers = pgAdmin.Browser.Nodes['coll-fts_parser'] =
pgAdmin.Browser.Collection.extend({
node: 'fts_parser',
label: '{{ _('FTS Parsers') }}',
type: 'coll-fts_parser',
columns: ['name', 'description']
});
};
// Extend the node class for fts parser
if (!pgBrowser.Nodes['fts_parser']) {
pgAdmin.Browser.Nodes['fts_parser'] = pgAdmin.Browser.Node.extend({
parent_type: ['schema', 'catalog'],
type: 'fts_parser',
canDrop: true,
canDropCascade: true,
label: '{{ _('FTS Parser') }}',
hasSQL: true,
hasDepends: true,
Init: function() {
// Avoid multiple registration of menus
if (this.initialized)
return;
this.initialized = true;
// Add context menus for fts parser
pgBrowser.add_menus([{
name: 'create_fts_parser_on_schema', node: 'schema', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('FTS Parser...') }}',
icon: 'wcTabIcon icon-fts_parser', data: {action: 'create'}
},{
name: 'create_fts_parser_on_coll', node: 'coll-fts_parser',
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('FTS Parser...') }}',
icon: 'wcTabIcon icon-fts_parser', data: {action: 'create'},
module: this
},{
name: 'create_fts_parser', node: 'fts_parser', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('FTS Parser...') }}',
icon: 'wcTabIcon icon-fts_parser', data: {action: 'create'}
}]);
},
// Defining backform model for fts parser node
model: pgAdmin.Browser.Node.Model.extend({
defaults: {
name: undefined, // Fts parser name
description: undefined, // Comment on parser
schema: undefined, // Schema name to which parser belongs
prsstart: undefined, // Start function for fts parser
prstoken: undefined, // Token function for fts parser
prsend: undefined, // End function for fts parser
prslextype: undefined, // Lextype function for fts parser
prsheadline: undefined // Headline function for fts parse
},
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 parser
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: 'prsstart', label: '{{ _('Start function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'start_functions',
group: '{{ _('Definition') }}'
},{
id: 'prstoken', label: '{{ _('Get next token function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'token_functions',
group: '{{ _('Definition') }}'
},{
id: 'prsend', label: '{{ _('End function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'end_functions',
group: '{{ _('Definition') }}'
},{
id: 'prslextype', label: '{{ _('Lextypes function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'lextype_functions',
group: '{{ _('Definition') }}'
},{
id: 'prsheadline', label: '{{ _('Headline function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'headline_functions',
group: '{{ _('Definition') }}'
}],
/*
* Triggers control specific error messages for parser name,
* start, token, end, lextype functions and schema, if any one of them is not specified
* while creating new fts parser
*/
validate: function(keys){
var name = this.get('name');
var start = this.get('prsstart');
var token = this.get('prstoken');
var end = this.get('prsend');
var lextype = this.get('prslextype');
var schema = this.get('schema');
// Validate fts parser 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 start function control
else if (_.isUndefined(start) ||
_.isNull(start) ||
String(start).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Start function must be selected!') }}';
this.errorModel.set('prsstart', msg);
return msg;
}
// Validate gettoken function control
else if (_.isUndefined(token) ||
_.isNull(token) ||
String(token).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Get next token function must be selected!') }}';
this.errorModel.set('prstoken', msg);
return msg;
}
// Validate end function control
else if (_.isUndefined(end) ||
_.isNull(end) ||
String(end).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('End function must be selected!') }}';
this.errorModel.set('prsend', msg);
return msg;
}
// Validate lextype function control
else if (_.isUndefined(lextype) ||
_.isNull(lextype) ||
String(lextype).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Lextype function must be selected!') }}';
this.errorModel.set('prslextype', msg);
return msg;
}
// Validate schema for fts parser
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_parser'];
});

View File

@@ -0,0 +1,15 @@
{# CREATE FTS PARSER Statement #}
{% if data and data.schema and data.name and data.prsstart and data.prstoken and data.prsend and data.prslextype %}
CREATE TEXT SEARCH PARSER {{ conn|qtIdent(data.schema, data.name) }} (
START = {{data.prsstart}},
GETTOKEN = {{data.prstoken}},
END = {{data.prsend}},
LEXTYPES = {{data.prslextype}}{% if data.prsheadline and data.prsheadline != '-'%},
HEADLINE = {{data.prsheadline}}{% endif %}
);
{# Description for FTS_PARSER #}
{% if data.description %}
COMMENT ON TEXT SEARCH PARSER {{ conn|qtIdent(data.schema, data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}{% endif %}

View File

@@ -0,0 +1,23 @@
{# FETCH FTS PARSER NAME Statement #}
{% if pid %}
SELECT
p.prsname AS name,
(
SELECT
nspname
FROM
pg_namespace
WHERE
oid = p.prsnamespace
) as schema
FROM
pg_ts_parser p LEFT JOIN pg_description d
ON d.objoid=p.oid AND d.classoid='pg_ts_parser'::regclass
WHERE
p.oid = {{pid}}::OID;
{% endif %}
{# DROP FTS PARSER Statement #}
{% if schema and name %}
DROP TEXT SEARCH PARSER {{conn|qtIdent(schema)}}.{{conn|qtIdent(name)}} {% if cascade %}CASCADE{%endif%};
{% endif %}

View File

@@ -0,0 +1,58 @@
{# FETCH start functions for FTS_PARSER #}
{% if start %}
SELECT
proname, nspname
FROM
pg_proc JOIN pg_namespace n ON n.oid=pronamespace
WHERE
proargtypes='2281 23'
ORDER BY proname;
{% endif %}
{# FETCH token functions for FTS_PARSER #}
{% if token %}
SELECT
proname, nspname
FROM
pg_proc JOIN pg_namespace n ON n.oid=pronamespace
WHERE
proargtypes='2281 2281 2281'
ORDER BY
proname;
{% endif %}
{# FETCH end functions for FTS_PARSER #}
{% if end %}
SELECT
proname, nspname
FROM
pg_proc JOIN pg_namespace n ON n.oid=pronamespace
WHERE
prorettype=2278 and proargtypes='2281'
ORDER BY
proname;
{% endif %}
{# FETCH lextype functions for FTS_PARSER #}
{% if lextype %}
SELECT
proname, nspname
FROM
pg_proc JOIN pg_namespace n ON n.oid=pronamespace
WHERE
prorettype=2281 and proargtypes='2281'
ORDER BY
proname;
{% endif %}
{# FETCH headline functions for FTS_PARSER #}
{% if headline %}
SELECT
proname, nspname
FROM
pg_proc JOIN pg_namespace n ON n.oid=pronamespace
WHERE
proargtypes='2281 2281 3615'
ORDER BY
proname;
{% endif %}

View File

@@ -0,0 +1,13 @@
{# FETCH FTS PARSER name statement #}
SELECT
oid, prsname as name
FROM
pg_ts_parser prs
WHERE
{% if scid %}
prs.prsnamespace = {{scid}}::OID
{% elif pid %}
prs.oid = {{pid}}::OID
{% endif %}
ORDER BY name

View File

@@ -0,0 +1,30 @@
{# FETCH properties for FTS PARSER #}
SELECT
prs.oid,
prs.prsname as name,
prs.prsstart,
prs.prstoken,
prs.prsend,
prs.prslextype,
prs.prsheadline,
description,
prs.prsnamespace AS schema
FROM
pg_ts_parser prs
LEFT OUTER JOIN pg_description des
ON
(
des.objoid=prs.oid
AND des.classoid='pg_ts_parser'::regclass
)
WHERE
{% if scid %}
prs.prsnamespace = {{scid}}::OID
{% elif name %}
prs.prsname = {{name|qtLiteral}}
{% endif %}
{% if pid %}
AND prs.oid = {{pid}}::OID
{% endif %}
ORDER BY
prs.prsname

View File

@@ -0,0 +1,19 @@
{# FETCH statement for SCHEMA name #}
{% 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_parser prs
ON prs.prsnamespace = nsp.oid
WHERE
prs.oid = {{data.id}}::OID
{% endif %}

View File

@@ -0,0 +1,46 @@
{# Reverse engineered sql for FTS PARSER #}
{% if pid and scid %}
SELECT
array_to_string(array_agg(sql), E'\n\n') as sql
FROM
(
SELECT
E'-- Text Search Parser: ' || nspname || E'.' || prs.prsname ||
E'\n\n-- DROP TEXT SEARCH PARSER ' || nspname || E'.' || prs.prsname ||
E'\n\nCREATE TEXT SEARCH PARSER ' || nspname || E'.' || prs.prsname || E' (\n' ||
E' START = ' || prs.prsstart || E',\n' ||
E' GETTOKEN = ' || prs.prstoken || E',\n' ||
E' END = ' || prs.prsend || E',\n' ||
E' LEXTYPES = ' || prs.prslextype ||
CASE
WHEN prs.prsheadline != '-'::regclass THEN E',\n HEADLINE = ' || prs.prsheadline
ELSE '' END || E'\n);' ||
CASE
WHEN description IS NOT NULL THEN
E'\n\nCOMMENT ON TEXT SEARCH PARSER ' || nspname || E'.' || prs.prsname ||
E' IS ' || pg_catalog.quote_literal(description) || E';'
ELSE '' END as sql
FROM
pg_ts_parser prs
LEFT JOIN (
SELECT
des.description as description,
des.objoid as descoid
FROM
pg_description des
WHERE
des.objoid={{pid}}::OID AND des.classoid='pg_ts_parser'::regclass
) a ON (a.descoid = prs.oid)
LEFT JOIN (
SELECT
nspname,
nsp.oid as noid
FROM
pg_namespace nsp
WHERE
oid = {{scid}}::OID
) b ON (b.noid = prs.prsnamespace)
WHERE
prs.oid={{pid}}::OID
) as c;
{% endif %}

View File

@@ -0,0 +1,22 @@
{# UPDATE statement for FTS PARSER #}
{% if data %}
{% if data.name and data.name != o_data.name %}
ALTER TEXT SEARCH PARSER {{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 PARSER {{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 PARSER {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}}
IS {{ data.description|qtLiteral }};
{% endif %}
{% endif %}