[open-ils-commits] [GIT] Evergreen ILS branch master updated. aaa3b6c77d54f59fcb2cb7d709797a80aeac908a

Evergreen Git git at git.evergreen-ils.org
Tue May 22 15:03:01 EDT 2012


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  aaa3b6c77d54f59fcb2cb7d709797a80aeac908a (commit)
       via  36592af1e51f4534fcf2207de19706c19daf9efe (commit)
       via  4c61706238fe44ee4c5afe41366a760583d3e797 (commit)
       via  e808d718a1104217a884ea2f353b9c1fec8ca101 (commit)
       via  712720c419d6f42576426cff43feac773da65b09 (commit)
       via  497430ca0a24713c6885fbd26324707baf616d5e (commit)
      from  287a3e2052f5699daacddb7c536b6a15631fcf16 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit aaa3b6c77d54f59fcb2cb7d709797a80aeac908a
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Feb 23 17:01:28 2012 -0500

    TPAC: Search Filter Groups
    
    Adds support for a new CGI param:
    
    fg:<filter_group_code>=filter_group_entry
    
    Each filter group entry will be mapped to a filter_group_entry()
    filter and appended to the current search query.
    
    This includes a new filter selector builder at
    parts/filter_group_selector.tt2.
    
    Usage, assuming a filter_group with code "audience":
    
    <span>[% ctx.filter_groups.audience.label %]<span>
    <span>
    [%
        INCLUDE 'opac/parts/filter_group_selector.tt2'
        filter_group=audience
        none_ok=1
    %]
    <span>
    
    The set of filter groups available to the TPAC are those defined at the
    search org unit and its ancestors.  If multiple filters have the same
    code name, the filter owned closest to the context org unit is used.
    This allows for global filters with local overrides.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
index 7791cf8..63f919a 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
@@ -270,6 +270,7 @@ sub load_common {
     $self->load_eg_cache_hash;
     $self->load_copy_location_groups;
     $self->staff_saved_searches_set_expansion_state if $ctx->{is_staff};
+    $self->load_search_filter_groups($ctx->{search_ou});
 
     return Apache2::Const::OK;
 }
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
index 1bf8b61..e4e23e5 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
@@ -65,6 +65,15 @@ sub _prepare_biblio_search {
         $query .= " $1($term)" if length $term;
     }
 
+    # filter group entries.  Entries from like filters are grouped into a single 
+    # filter_group_entry() filter (ORed).  Each collection is ANDed together.
+    # fg:foo_group=foo_entry_id
+    foreach (grep /^fg:/, $cgi->param) {
+        /:(-?\w+)$/ or next;
+        my $term = join(",", $cgi->param($_));
+        $query .= " filter_group_entry($term)" if length $term;
+    }
+
     if ($cgi->param("bookbag")) {
         $query .= " container(bre,bookbag," . int($cgi->param("bookbag")) . ")";
     }
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
index d973947..db660fe 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
@@ -15,7 +15,8 @@ our %cache = ( # cached data
     list => {},
     search => {},
     org_settings => {},
-    eg_cache_hash => undef
+    eg_cache_hash => undef,
+    search_filter_groups => {}
 );
 
 sub init_ro_object_cache {
@@ -513,4 +514,35 @@ sub apache_log_if_event {
     return;
 }
 
+sub load_search_filter_groups {
+    my $self = shift;
+    my $ctx_org = shift;
+    my $org_list = $U->get_org_ancestors($ctx_org, 1);
+
+    my %seen;
+    for my $org_id (@$org_list) {
+
+        my $grps;
+        if (!$cache{search_filter_groups}{$org_id}) {
+            $grps = $self->editor->search_actor_search_filter_group([
+                {owner => $org_id},
+                {   flesh => 2, 
+                    flesh_fields => {
+                        asfg => ['entries'],
+                        asfge => ['query']
+                    }
+                }
+            ]);
+            $cache{search_filter_groups}{$org_id} = $grps;
+        }
+            
+        # for the current context, if a descendant org has a group 
+        # with a matching code replace the group from the parent.
+        $seen{$_->code} = $_ for @$grps;
+    }
+
+    return $self->ctx->{search_filter_groups} = \%seen;
+}
+
+
 1;
diff --git a/Open-ILS/src/templates/opac/parts/filter_group_selector.tt2 b/Open-ILS/src/templates/opac/parts/filter_group_selector.tt2
new file mode 100644
index 0000000..3b8f730
--- /dev/null
+++ b/Open-ILS/src/templates/opac/parts/filter_group_selector.tt2
@@ -0,0 +1,31 @@
+[%- 
+    # If caller passes a list of possible filter_groups
+    # search all until we find some values
+    IF !filter_group.size; filter_group = [filter_group]; END;
+    group = '';
+    FOR code IN filter_group;
+        group = ctx.search_filter_groups.$code;
+        LAST IF group AND group.entries.size;
+    END;
+    name = name || "fg:" _ group.code;
+    id = id || group.code _ "_selector";
+    values = values || CGI.param(name); 
+-%]
+
+<select id='[% id %]' name='[% name %]'[%
+    multiple ? ' multiple="multiple"' : '';
+    size ? (' size="' _ size _ '"') : ''; %]>
+[% IF none_ok %]
+    <option value=''>[% none_label ? none_label : l('-- Any --') %]</option>
+[% END;
+# turn the list of objects into a list of hashes to 
+# leverage TT's array.sort('<hashkey>') behavior
+sorter = [];
+FOR o IN group.entries;
+    sorter.push({id => o.id, label => o.query.label}); 
+END;
+FOR o IN sorter.sort('label') %]
+    <option value='[% o.id %]'[% values.grep(o.id).size ? ' selected="selected"' : '' %]>[% o.label | html %]</option>
+[%  END -%]
+</select>
+

commit 36592af1e51f4534fcf2207de19706c19daf9efe
Author: Bill Erickson <berick at esilibrary.com>
Date:   Wed Apr 18 16:15:46 2012 -0400

    tpac : search_HINT cache fixes
    
    When searching for multiple values like a list of IDs, generate the
    cache key from the sorted JSON form of the search value instead of the
    bare ARRAY ref.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
index 57b8407..d973947 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
@@ -73,6 +73,11 @@ sub init_ro_object_cache {
             my ($field, $val, $filterfield, $filterval) = @_;
             my $method = "search_$eclass";
             my $cacheval = $val;
+            if (ref $val) {
+                $val = [sort(@$val)] if ref $val eq 'ARRAY';
+                $cacheval = OpenSRF::Utils::JSON->perl2JSON($val); 
+                #$self->apache->log->info("cacheval : $cacheval");
+            }
             my $search_obj = {$field => $val};
             if($filterfield) {
                 $search_obj->{$filterfield} = $filterval;

commit 4c61706238fe44ee4c5afe41366a760583d3e797
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Apr 19 13:54:34 2012 -0400

    New QueryParser filter_group_entry filter
    
    filter_group_entry() takes one or more filter_group_entry IDs as
    parameters and applies the included sub-searches as filters on the
    current search.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
index 1bdbec7..a3ea1ac 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
@@ -25,6 +25,23 @@ sub subquery_callback {
     );
 }
 
+sub filter_group_entry_callback {
+    my ($invocant, $self, $struct, $filter, $params, $negate) = @_;
+
+    return sprintf(' saved_query(%s)', 
+        join(
+            ',', 
+            map {
+                $_->query
+            } @{
+                OpenILS::Utils::CStoreEditor
+                    ->new
+                    ->search_actor_search_filter_group_entry({ id => $params })
+            }
+        )
+    );
+}
+
 sub quote_value {
     my $self = shift;
     my $value = shift;
@@ -429,6 +446,7 @@ __PACKAGE__->default_search_class( 'keyword' );
 
 # implements EG-specific stored subqueries
 __PACKAGE__->add_search_filter( 'saved_query', sub { return __PACKAGE__->subquery_callback(@_) } );
+__PACKAGE__->add_search_filter( 'filter_group_entry', sub { return __PACKAGE__->filter_group_entry_callback(@_) } );
 
 # will be retained simply for back-compat
 __PACKAGE__->add_search_filter( 'format' );

commit e808d718a1104217a884ea2f353b9c1fec8ca101
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Apr 18 13:25:06 2012 -0400

    Give the PG QP driver a subquery callback for the new saved_query() filter
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
index 89e3c12..1bdbec7 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
@@ -6,9 +6,24 @@ use OpenILS::Application::Storage::QueryParser;
 use base 'QueryParser';
 use OpenSRF::Utils::JSON;
 use OpenILS::Application::AppUtils;
+use OpenILS::Utils::CStoreEditor;
 my $U = 'OpenILS::Application::AppUtils';
 
 my ${spc} = ' ' x 2;
+sub subquery_callback {
+    my ($invocant, $self, $struct, $filter, $params, $negate) = @_;
+
+    return join(
+        ' ',
+        map {
+            $_->query_text
+        } @{
+            OpenILS::Utils::CStoreEditor
+                ->new
+                ->search_actor_search_query({ id => $params })
+        }
+    );
+}
 
 sub quote_value {
     my $self = shift;
@@ -412,6 +427,9 @@ sub TEST_SETUP {
 
 __PACKAGE__->default_search_class( 'keyword' );
 
+# implements EG-specific stored subqueries
+__PACKAGE__->add_search_filter( 'saved_query', sub { return __PACKAGE__->subquery_callback(@_) } );
+
 # will be retained simply for back-compat
 __PACKAGE__->add_search_filter( 'format' );
 

commit 712720c419d6f42576426cff43feac773da65b09
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Apr 18 13:24:24 2012 -0400

    Teach QueryParser about search filter callbacks, and if a callback returns a value, parse it at the current recursion level
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
index 4cb51ed..7ee0402 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
@@ -63,6 +63,14 @@ sub filters {
     return $parser_config{$class}{filters};
 }
 
+sub filter_callbacks {
+    my $class = shift;
+    $class = ref($class) || $class;
+
+    $parser_config{$class}{filter_callbacks} ||= {};
+    return $parser_config{$class}{filter_callbacks};
+}
+
 sub modifiers {
     my $class = shift;
     $class = ref($class) || $class;
@@ -100,9 +108,11 @@ sub add_search_filter {
     my $pkg = shift;
     $pkg = ref($pkg) || $pkg;
     my $filter = shift;
+    my $callback = shift;
 
     return $filter if (grep { $_ eq $filter } @{$pkg->filters});
     push @{$pkg->filters}, $filter;
+    $pkg->filter_callbacks->{$filter} = $callback if ($callback);
     return $filter;
 }
 
@@ -568,7 +578,17 @@ sub decompose {
 
             my $negate = ($1 eq $pkg->operator('disallowed')) ? 1 : 0;
             $_ = $';
-            $struct->new_filter( $2 => [ split '[,]+', $3 ], $negate );
+
+            my $filter = $2;
+            my $params = [ split '[,]+', $3 ];
+
+            if ($pkg->filter_callbacks->{$filter}) {
+                my $replacement = $pkg->filter_callbacks->{$filter}->($self, $struct, $filter, $params, $negate);
+                $_ = "$replacement $_" if ($replacement);
+            } else {
+                $struct->new_filter( $filter => $params, $negate );
+            }
+
 
             $last_type = '';
         } elsif ($self->filter_count && /$filter_as_class_re/) { # found a filter
@@ -576,7 +596,16 @@ sub decompose {
 
             my $negate = ($1 eq $pkg->operator('disallowed')) ? 1 : 0;
             $_ = $';
-            $struct->new_filter( $2 => [ split '[,]+', $3 ], $negate );
+
+            my $filter = $2;
+            my $params = [ split '[,]+', $3 ];
+
+            if ($pkg->filter_callbacks->{$filter}) {
+                my $replacement = $pkg->filter_callbacks->{$filter}->($self, $struct, $filter, $params, $negate);
+                $_ = "$replacement $_" if ($replacement);
+            } else {
+                $struct->new_filter( $filter => $params, $negate );
+            }
 
             $last_type = '';
         } elsif ($self->modifier_count && /$modifier_re/) { # found a modifier

commit 497430ca0a24713c6885fbd26324707baf616d5e
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Feb 23 14:28:50 2012 -0500

    Search Filter Groups and Generic Queries : DB / IDL
    
    Adds 3 new tables.  The first is a general purpose container for
    query-parser queries.  These can be used by other entities for storing
    saved searches, saved search filters, etc.  Each contains a query string
    and a label.
    
    The two other tables are for creating org unit saved search filter
    groups.  A filter group is a named set of search queries, treated as
    filters, collected to create a high-level search filter.  Filter group
    entries use search_query's under the covers, so the content of the
    filter can be any valid query string, including other filters or even
    other filter groups.
    
    For example, you could create an "Audience" filter group with entries
    like, "Children" => "audience(a, b) locations(3,4,5)" to filter on copy
    location in addition to the MARC audience data.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 2ff2904..79b8738 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -4771,6 +4771,68 @@ SELECT  usr,
             </actions>
         </permacrud>
 	</class>
+	<class id="asq" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::search_query" oils_persist:tablename="actor.search_query" reporter:label="Search Query" oils_persist:field_safe="true">
+		<fields oils_persist:primary="id" oils_persist:sequence="actor.search_query_id_seq">
+			<field name="id" reporter:datatype="id" reporter:selector="label"/>
+			<field name="label" reporter:datatype="text" oils_persist:i18n="true"/>
+			<field name="query_text" reporter:datatype="text"/>
+		</fields>
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+            <actions>
+                <retrieve/>
+            </actions>
+        </permacrud>
+	</class>
+
+	<class id="asfg" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::search_filter_group" oils_persist:tablename="actor.search_filter_group" reporter:label="Search Filter Group" oils_persist:field_safe="true">
+		<fields oils_persist:primary="id" oils_persist:sequence="actor.search_filter_group_id_seq">
+			<field name="id" reporter:datatype="id" reporter:selector="label"/>
+			<field name="owner" reporter:datatype="org_unit"/>
+			<field name="code" reporter:datatype="text"/>
+			<field name="label" reporter:datatype="text" oils_persist:i18n="true"/>
+			<field name="create_date" reporter:datatype="timestamp"/>
+			<field name="entries" oils_persist:virtual="true" reporter:datatype="link"/>
+		</fields>
+		<links>
+			<link field="owner" reltype="has_a" key="id" map="" class="aou"/>
+			<link field="entries" reltype="has_many" key="grp" map="" class="asfge"/>
+		</links>
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+            <actions>
+                <create permission="ADMIN_SEARCH_FILTER_GROUP" context_field="owner"/>
+                <retrieve/>
+                <update permission="ADMIN_SEARCH_FILTER_GROUP" context_field="owner"/>
+                <delete permission="ADMIN_SEARCH_FILTER_GROUP" context_field="owner"/>
+            </actions>
+        </permacrud>
+	</class>
+	<class id="asfge" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::search_filter_group_entry" oils_persist:tablename="actor.search_filter_group_entry" reporter:label="Search Filter Group Entry" oils_persist:field_safe="true">
+		<fields oils_persist:primary="id" oils_persist:sequence="actor.search_filter_group_entry_id_seq">
+			<field name="id" reporter:datatype="id" reporter:selector="label"/>
+			<field name="grp" reporter:datatype="link"/>
+			<field name="pos" reporter:datatype="int"/>
+			<field name="query" reporter:datatype="link"/>
+		</fields>
+		<links>
+			<link field="grp" reltype="has_a" key="id" map="" class="asfge"/>
+			<link field="query" reltype="has_a" key="id" map="" class="asq"/>
+		</links>
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+            <actions>
+                <create permission="ADMIN_SEARCH_FILTER_GROUP">
+                    <context link="grp" field="owner"/>
+                </create>
+                <retrieve/>
+                <update permission="ADMIN_SEARCH_FILTER_GROUP">
+                    <context link="grp" field="owner"/>
+                </update>
+                <delete permission="ADMIN_SEARCH_FILTER_GROUP">
+                    <context link="grp" field="owner"/>
+                </delete>
+            </actions>
+        </permacrud>
+	</class>
+
 	<!-- A note: Please update alhr when updating ahr -->
 	<class id="ahr" controller="open-ils.cstore" oils_obj:fieldmapper="action::hold_request" oils_persist:tablename="action.hold_request" reporter:core="true" reporter:label="Hold Request">
 		<fields oils_persist:primary="id" oils_persist:sequence="action.hold_request_id_seq">
diff --git a/Open-ILS/src/sql/Pg/005.schema.actors.sql b/Open-ILS/src/sql/Pg/005.schema.actors.sql
index 21363b9..8695852 100644
--- a/Open-ILS/src/sql/Pg/005.schema.actors.sql
+++ b/Open-ILS/src/sql/Pg/005.schema.actors.sql
@@ -681,4 +681,31 @@ CREATE TABLE actor.org_unit_custom_tree_node (
     CONSTRAINT aouctn_once_per_org UNIQUE (tree, org_unit)
 );
 
+CREATE TABLE actor.search_query (
+    id          SERIAL PRIMARY KEY, 
+    label       TEXT NOT NULL, -- i18n
+    query_text  TEXT NOT NULL -- QP text
+);
+
+CREATE TABLE actor.search_filter_group (
+    id          SERIAL      PRIMARY KEY,
+    owner       INT         NOT NULL REFERENCES actor.org_unit (id) 
+                            ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+    code        TEXT        NOT NULL, -- for CGI, etc.
+    label       TEXT        NOT NULL, -- i18n
+    create_date TIMESTAMPTZ NOT NULL DEFAULT now(),
+    CONSTRAINT  asfg_label_once_per_org UNIQUE (owner, label),
+    CONSTRAINT  asfg_code_once_per_org UNIQUE (owner, code)
+);
+
+CREATE TABLE actor.search_filter_group_entry (
+    id          SERIAL  PRIMARY KEY,
+    grp         INT     NOT NULL REFERENCES actor.search_filter_group(id) 
+                        ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+    pos         INT     NOT NULL DEFAULT 0,
+    query       INT     NOT NULL REFERENCES actor.search_query(id) 
+                        ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+    CONSTRAINT asfge_query_once_per_group UNIQUE (grp, query)
+);
+
 COMMIT;
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_query_groups.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_query_groups.sql
new file mode 100644
index 0000000..1ce760d
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_query_groups.sql
@@ -0,0 +1,78 @@
+
+BEGIN;
+
+-- General purpose query container.  Any table the needs to store
+-- a QueryParser query should store it here.  This will be the 
+-- source for top-level and QP sub-search inclusion queries.
+CREATE TABLE actor.search_query (
+    id          SERIAL PRIMARY KEY, 
+    label       TEXT NOT NULL, -- i18n
+    query_text  TEXT NOT NULL -- QP text
+);
+
+-- e.g. "Reading Level"
+CREATE TABLE actor.search_filter_group (
+    id          SERIAL      PRIMARY KEY,
+    owner       INT         NOT NULL REFERENCES actor.org_unit (id) 
+                            ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+    code        TEXT        NOT NULL, -- for CGI, etc.
+    label       TEXT        NOT NULL, -- i18n
+    create_date TIMESTAMPTZ NOT NULL DEFAULT now(),
+    CONSTRAINT  asfg_label_once_per_org UNIQUE (owner, label),
+    CONSTRAINT  asfg_code_once_per_org UNIQUE (owner, code)
+);
+
+-- e.g. "Adult", "Teen", etc.
+CREATE TABLE actor.search_filter_group_entry (
+    id          SERIAL  PRIMARY KEY,
+    grp         INT     NOT NULL REFERENCES actor.search_filter_group(id) 
+                        ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+    pos         INT     NOT NULL DEFAULT 0,
+    query       INT     NOT NULL REFERENCES actor.search_query(id) 
+                        ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+    CONSTRAINT asfge_query_once_per_group UNIQUE (grp, query)
+);
+
+COMMIT;
+
+/*
+-- Fictional Example
+BEGIN;
+
+INSERT INTO actor.search_filter_group (owner, code, label) 
+    VALUES (4, 'reading_level', 'Reading Level');
+
+INSERT INTO actor.search_query (label, query_text) 
+    VALUES ('Children', 'audience(a,b,c) locations(3,4,5,6)');
+INSERT INTO actor.search_query (label, query_text) 
+    VALUES ('Juvenile', 'audience(j,d) locations(1,2,7,8)');
+INSERT INTO actor.search_query (label, query_text) 
+    VALUES ('General',  'audience(e,f,g)');
+
+INSERT INTO actor.search_filter_group_entry (grp, query)
+    VALUES (
+        (SELECT id FROM actor.search_filter_group WHERE code = 'reading_level'),
+        (SELECT id FROM actor.search_query WHERE label = 'Children')
+    );
+INSERT INTO actor.search_filter_group_entry (grp, query) 
+    VALUES (
+        (SELECT id FROM actor.search_filter_group WHERE code = 'reading_level'),
+        (SELECT id FROM actor.search_query WHERE label = 'Juvenile')
+    );
+INSERT INTO actor.search_filter_group_entry (grp, query) 
+    VALUES (
+        (SELECT id FROM actor.search_filter_group WHERE code = 'reading_level'),
+        (SELECT id FROM actor.search_query WHERE label = 'General')
+    );
+
+COMMIT;
+*/
+
+/* 
+-- UNDO
+BEGIN;
+DROP TABLE actor.search_filter_group_entry;
+DROP TABLE actor.search_filter_group;
+DROP TABLE actor.search_query;
+COMMIT;
+*/

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/examples/fm_IDL.xml                       |   62 ++++++++++++++++
 .../Application/Storage/Driver/Pg/QueryParser.pm   |   36 +++++++++
 .../lib/OpenILS/Application/Storage/QueryParser.pm |   33 ++++++++-
 .../src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm    |    1 +
 .../perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm |    9 ++
 .../perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm   |   39 ++++++++++-
 Open-ILS/src/sql/Pg/005.schema.actors.sql          |   27 +++++++
 .../Pg/upgrade/XXXX.schema.search_query_groups.sql |   78 ++++++++++++++++++++
 .../templates/opac/parts/filter_group_selector.tt2 |   31 ++++++++
 9 files changed, 313 insertions(+), 3 deletions(-)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_query_groups.sql
 create mode 100644 Open-ILS/src/templates/opac/parts/filter_group_selector.tt2


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list