Search Filter Groups and Generic Queries : DB / IDL
authorBill Erickson <berick@esilibrary.com>
Thu, 23 Feb 2012 19:28:50 +0000 (14:28 -0500)
committerMike Rylander <mrylander@gmail.com>
Tue, 22 May 2012 19:03:16 +0000 (15:03 -0400)
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@esilibrary.com>
Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/sql/Pg/005.schema.actors.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_query_groups.sql [new file with mode: 0644]

index 2ff2904..79b8738 100644 (file)
@@ -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">
index 21363b9..8695852 100644 (file)
@@ -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 (file)
index 0000000..1ce760d
--- /dev/null
@@ -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;
+*/