Acq: General Search refactor collab/dyrcona/rel_2_0
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 14 Feb 2012 22:49:54 +0000 (17:49 -0500)
committerJason Stephenson <jstephenson@mvlc.org>
Fri, 4 May 2012 18:42:25 +0000 (14:42 -0400)
This is a combination of the following three commits from master:

3149433d354889fb
56121886c72b2d41
35fe5b9cbe10b132

The first two were meant for backport to rel_2_0 and rel_2_1 at the
time, but the backport wasn't done.  They were buggy anyway, and now it
makes the most sense (I hope) to backport them together with the
corrective commit all at once.

Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Signed-off-by: Jason Stephenson <jason@sigio.com>
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/OpenILS/Application/Acq/Search.pm
Open-ILS/src/sql/Pg/002.schema.config.sql
Open-ILS/src/sql/Pg/200.schema.acq.sql
Open-ILS/src/sql/Pg/upgrade/0691.schema.acq_fk_indices.sql [new file with mode: 0644]

index 8088e35..c91bbd7 100644 (file)
@@ -8454,6 +8454,142 @@ SELECT  usr,
                        </actions>
                </permacrud>
        </class>
+       <class id="acqmapinv" controller="open-ils.cstore" oils_obj:fieldmapper="acq::map_to_invoice" reporter:label="Acq Map to Invoice View" oils_persist:readonly="true">
+               <oils_persist:source_definition><![CDATA[
+               SELECT
+                       poi.purchase_order AS purchase_order,
+                       ii.invoice AS invoice,
+                       NULL AS lineitem,
+                       poi.id AS po_item,
+                       NULL AS picklist
+               FROM
+                       acq.po_item poi
+                       JOIN acq.invoice_item ii ON (ii.po_item = poi.id)
+               UNION SELECT
+                       jub.purchase_order AS purchase_order,
+                       ie.invoice AS invoice,
+                       jub.id AS lineitem,
+                       NULL AS po_item,
+                       jub.picklist AS picklist
+               FROM
+                       acq.lineitem jub
+                       JOIN acq.invoice_entry ie ON (ie.lineitem = jub.id)
+               UNION SELECT
+                       ii.purchase_order AS purchase_order,
+                       ii.invoice AS invoice,
+                       NULL AS lineitem,
+                       NULL AS po_item,
+                       NULL AS picklist
+               FROM
+                       acq.invoice_item ii
+               WHERE ii.po_item IS NULL
+               UNION SELECT
+                       ie.purchase_order AS purchase_order,
+                       ie.invoice AS invoice,
+                       NULL AS lineitem,
+                       NULL AS po_item,
+                       NULL AS picklist
+               FROM
+                       acq.invoice_entry ie
+               WHERE ie.lineitem IS NULL
+               UNION SELECT
+                       NULL AS purchase_order,
+                       NULL AS invoice,
+                       jub.id AS lineitem,
+                       NULL AS po_item,
+                       jub.picklist AS picklist
+               FROM
+                       acq.lineitem jub
+               WHERE jub.purchase_order IS NULL
+               ]]></oils_persist:source_definition>
+               <fields>
+                       <field reporter:label="Purchase Order ID" name="purchase_order" reporter:datatype="link"/>
+                       <field reporter:label="Lineitem ID" name="lineitem" reporter:datatype="link"/>
+                       <field reporter:label="Invoice ID" name="invoice" reporter:datatype="link"/>
+                       <field reporter:label="Purchase Order Item ID" name="po_item" reporter:datatype="link"/>
+                       <field reporter:label="Picklist ID" name="picklist" reporter:datatype="link"/>
+               </fields>
+               <links>
+                       <link field="purchase_order" reltype="has_a" key="id" map="" class="acqpo" />
+                       <link field="lineitem" reltype="has_a" key="id" map="" class="jub" />
+                       <link field="invoice" reltype="has_a" key="id" map="" class="acqinv" />
+                       <link field="po_item" reltype="has_a" key="id" map="" class="acqpoi" />
+                       <link field="picklist" reltype="has_a" key="id" map="" class="acqpl" />
+               </links>
+       </class>
+       <class id="cbc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::barcode_completion" oils_persist:tablename="config.barcode_completion" reporter:label="Barcode Completions">
+               <fields oils_persist:primary="id" oils_persist:sequence="config.barcode_completion_id_seq">
+                       <field reporter:label="ID" name="id" reporter:datatype="id"/>
+                       <field reporter:label="Active" name="active" reporter:datatype="bool"/>
+                       <field reporter:label="Owner" name="org_unit" reporter:datatype="org_unit"/>
+                       <field reporter:label="Prefix" name="prefix" reporter:datatype="text"/>
+                       <field reporter:label="Suffix" name="suffix" reporter:datatype="text"/>
+                       <field reporter:label="Length" name="length" reporter:datatype="int"/>
+                       <field reporter:label="Padding" name="padding" reporter:datatype="text"/>
+                       <field reporter:label="Padding At End" name="padding_end" reporter:datatype="bool"/>
+                       <field reporter:label="Applies to Items" name="asset" reporter:datatype="bool"/>
+                       <field reporter:label="Applies to Users" name="actor" reporter:datatype="bool"/>
+               </fields>
+               <links>
+                       <link field="org_unit" reltype="has_a" key="id" map="" class="aou"/>
+               </links>
+               <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+                       <actions>
+                               <create permission="UPDATE_ORG_UNIT_SETTING_ALL" context_field="org_unit"/>
+                               <retrieve/>
+                               <update permission="UPDATE_ORG_UNIT_SETTING_ALL" context_field="org_unit"/>
+                               <delete permission="UPDATE_ORG_UNIT_SETTING_ALL" context_field="org_unit"/>
+                       </actions>
+               </permacrud>
+       </class>
+
+       <class id="coustl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::org_unit_setting_type_log" oils_persist:tablename="config.org_unit_setting_type_log" reporter:label="Organizational Unit Setting Type Log">
+               <fields oils_persist:primary="date_applied" oils_persist:sequence="config.org_unit_setting_type_log_id_seq">
+                       <field reporter:label="ID" name="id" reporter:datatype="id"/>
+                       <field name="date_applied" reporter:datatype="timestamp"/>
+                       <field name="org" reporter:datatype="org_unit"/>
+                       <field name="original_value" reporter:datatype="text"/>
+                       <field name="new_value" reporter:datatype="text"/>
+                       <field name="field_name" reporter:datatype="link"/>
+               </fields>
+               <links>
+                       <link field="field_name" reltype="has_a" key="name" map="" class="coust"/>
+                       <link field="org" reltype="has_a" key="id" map="" class="aou"/>
+               </links>
+               <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+                       <actions>
+                               <create permission="ADMIN_ORG_UNIT_SETTING_TYPE" context_field="org"/>
+                               <retrieve/>
+                               <update permission="ADMIN_ORG_UNIT_SETTING_TYPE_LOG" context_field="org"/>
+                               <delete permission="ADMIN_ORG_UNIT_SETTING_TYPE_LOG" context_field="org"/>
+                       </actions>
+               </permacrud>
+       </class>
+       <class id="aaactsc" controller="open-ils.reporter-store" oils_obj:fieldmapper="action::archive_actor_stat_cat" oils_persist:tablename="action.archive_actor_stat_cat" reporter:label="Circ-Archived Patron Statistical Category Entries">
+               <fields oils_persist:primary="id" oils_persist:sequence="action.archive_actor_stat_cat_id_seq">
+                       <field reporter:label="ID" name="id" reporter:datatype="id"/>
+                       <field reporter:label="Circ" name="xact" reporter:datatype="link"/>
+                       <field reporter:label="Statistical Category" name="stat_cat" reporter:datatype="link"/>
+                       <field reporter:label="Entry Value" name="value" reporter:datatype="text"/>
+               </fields>
+               <links>
+                       <link field="xact" reltype="has_a" key="id" map="" class="combcirc"/>
+                       <link field="stat_cat" reltype="has_a" key="id" map="" class="actsc"/>
+               </links>
+       </class>
+       <class id="aaasc" controller="open-ils.reporter-store" oils_obj:fieldmapper="action::archive_asset_stat_cat" oils_persist:tablename="action.archive_asset_stat_cat" reporter:label="Circ-Archived Copy Statistical Category Entries">
+               <fields oils_persist:primary="id" oils_persist:sequence="action.archive_actor_stat_cat_id_seq">
+                       <field reporter:label="ID" name="id" reporter:datatype="id"/>
+                       <field reporter:label="Circ" name="xact" reporter:datatype="link"/>
+                       <field reporter:label="Statistical Category" name="stat_cat" reporter:datatype="link"/>
+                       <field reporter:label="Entry Value" name="value" reporter:datatype="text"/>
+               </fields>
+               <links>
+                       <link field="xact" reltype="has_a" key="id" map="" class="combcirc"/>
+                       <link field="stat_cat" reltype="has_a" key="id" map="" class="asc"/>
+               </links>
+       </class>
+
 
        <!-- ********************************************************************************************************************* -->
 
index 6e2d854..cbf4c73 100644 (file)
@@ -156,12 +156,16 @@ sub get_fm_links_by_hint {
 
 sub gen_au_term {
     my ($value, $n) = @_;
+    my $lc_value = {
+        "=" => { transform => "lowercase", value => lc($value) }
+    };
+
     +{
         "-or" => [
             {"+au$n" => {"usrname" => $value}},
-            {"+au$n" => {"first_given_name" => $value}},
-            {"+au$n" => {"second_given_name" => $value}},
-            {"+au$n" => {"family_name" => $value}},
+            {"+au$n" => {"first_given_name" => $lc_value}},
+            {"+au$n" => {"second_given_name" => $lc_value}},
+            {"+au$n" => {"family_name" => $lc_value}},
             {"+ac$n" => {"barcode" => $value}}
         ]
     };
@@ -262,19 +266,13 @@ sub prepare_terms {
 }
 
 sub add_au_joins {
-    my ($from) = shift;
+    my $graft_map = shift;
+    my $core_hint = shift;
 
     my $n = 0;
     foreach my $join (@_) {
         my ($hint, $attr, $num) = @$join;
-        my $start;
-        if ($hint eq "jub") {
-            $start = $from->{$hint};
-        } elsif ($hint eq "acqinv") {
-            $start = $from->{"jub"}->{"acqie"}->{"join"}->{$hint};
-        } else {
-            $start = $from->{"jub"}->{$hint};
-        }
+        my $start = $graft_map->{$hint};
         my $clause = {
             "class" => "au",
             "type" => "left",
@@ -289,17 +287,64 @@ sub add_au_joins {
                 }
             }
         };
-        if ($hint eq "jub") {
+
+        if ($hint eq $core_hint) {
             $start->{"au$num"} = $clause;
         } else {
             $start->{"join"} ||= {};
             $start->{"join"}->{"au$num"} = $clause;
         }
+
         $n++;
     }
     $n;
 }
 
+sub build_from_clause_and_joins {
+    my ($query, $core, $and_terms, $or_terms) = @_;
+
+    my %graft_map = ();
+
+    $graft_map{$core} = $query->{from}{$core} = {};
+
+    my $join_type = keys(%$or_terms) ? "left" : "inner";
+
+    my @classes = grep { $core ne $_ } (keys(%$and_terms), keys(%$or_terms));
+    my %classes_uniq = map { $_ => 1 } @classes;
+    @classes = keys(%classes_uniq);
+
+    my $acqlia_join = sub {
+        return {"type" => "left", "field" => "lineitem", "fkey" => "id"};
+    };
+
+    foreach my $class (@classes) {
+        if ($class eq 'acqlia') {
+            if ($core eq 'acqinv') {
+                $graft_map{acqlia} =
+                    $query->{from}{$core}{acqmapinv}{join}{jub}{join}{acqlia} =
+                    $acqlia_join->();
+            } elsif ($core eq 'jub') {
+                $graft_map{acqlia} = 
+                    $query->{from}{$core}{acqlia} =
+                    $acqlia_join->();
+            } else {
+                $graft_map{acqlia} = 
+                    $query->{from}{$core}{jub}{join}{acqlia} =
+                    $acqlia_join->();
+            }
+        } elsif ($class eq 'acqinv' or $core eq 'acqinv') {
+            $graft_map{$class} =
+                $query->{from}{$core}{acqmapinv}{join}{$class} ||= {};
+            $graft_map{$class}{type} = $join_type;
+        } else {
+            $graft_map{$class} = $query->{from}{$core}{$class} ||= {};
+            $graft_map{$class}{type} = $join_type;
+        }
+    }
+
+    return \%graft_map;
+}
+
 __PACKAGE__->register_method(
     method    => "unified_search",
     api_name  => "open-ils.acq.lineitem.unified_search",
@@ -394,54 +439,22 @@ q/order_by clause must be of the long form, like:
     }
 
     my $query = {
-        "select" => $select_clause,
-        "from" => {
-            "jub" => {
-                "acqpo" => {
-                    "type" => "full",
-                    "field" => "id",
-                    "fkey" => "purchase_order"
-                },
-                "acqpl" => {
-                    "type" => "full",
-                    "field" => "id",
-                    "fkey" => "picklist"
-                },
-                "acqie" => {
-                    "type" => "full",
-                    "field" => "lineitem",
-                    "fkey" => "id",
-                    "join" => {
-                        "acqinv" => {
-                            "type" => "full",
-                            "fkey" => "invoice",
-                            "field" => "id"
-                        }
-                    }
-                }
-            }
-        },
-        "order_by" => ($options->{"order_by"} || {$hint => {"id" => {}}}),
-        "offset" => ($options->{"offset"} || 0)
+        select => $select_clause,
+        order_by => ($options->{order_by} || {$hint => {id => {}}}),
+        offset => ($options->{offset} || 0)
     };
 
     $query->{"limit"} = $options->{"limit"} if $options->{"limit"};
 
-    # XXX for the future? but it doesn't quite work as is.
-#    # Remove anything in temporary picklists from search results.
-#    $and_terms ||= {};
-#    $and_terms->{"acqpl"} ||= [];
-#    push @{$and_terms->{"acqpl"}}, {"name" => "", "__not" => 1};
+    my $graft_map = build_from_clause_and_joins(
+        $query, $hint, $and_terms, $or_terms
+    );
 
     $and_terms = prepare_terms($and_terms, 1);
-    $or_terms = prepare_terms($or_terms, 0) and do {
-        $query->{"from"}->{"jub"}->{"acqlia"} = {
-            "type" => "left", "field" => "lineitem", "fkey" => "id",
-        };
-    };
+    $or_terms = prepare_terms($or_terms, 0);
 
-    my $offset = add_au_joins($query->{"from"}, prepare_au_terms($and_terms));
-    add_au_joins($query->{"from"}, prepare_au_terms($or_terms, $offset));
+    my $offset = add_au_joins($graft_map, $hint, prepare_au_terms($and_terms));
+    add_au_joins($graft_map, $hint, prepare_au_terms($or_terms, $offset));
 
     if ($and_terms and $or_terms) {
         $query->{"where"} = {
index 9aa25b7..371f0cb 100644 (file)
@@ -57,7 +57,7 @@ CREATE TABLE config.upgrade_log (
     install_date    TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
 );
 
-INSERT INTO config.upgrade_log (version) VALUES ('0665'); -- phasefx/miker
+INSERT INTO config.upgrade_log (version) VALUES ('0691'); -- senator/miker
 
 CREATE TABLE config.bib_source (
        id              SERIAL  PRIMARY KEY,
index e8869a3..a00c1d3 100644 (file)
@@ -839,6 +839,10 @@ CREATE TABLE acq.invoice_entry (
        amount_paid     NUMERIC (8,2)
 );
 
+CREATE INDEX ie_inv_idx on acq.invoice_entry (invoice);
+CREATE INDEX ie_po_idx on acq.invoice_entry (purchase_order);
+CREATE INDEX ie_li_idx on acq.invoice_entry (lineitem);
+
 CREATE TABLE acq.invoice_item_type (
     code    TEXT    PRIMARY KEY,
     name    TEXT    NOT NULL,  -- i18n-ize
@@ -864,6 +868,8 @@ CREATE TABLE acq.po_item (
     target          BIGINT
 );
 
+CREATE INDEX poi_po_idx ON acq.po_item (purchase_order);
+
 CREATE TABLE acq.invoice_item ( -- for invoice-only debits: taxes/fees/non-bib items/etc
     id              SERIAL      PRIMARY KEY,
     invoice         INT         NOT NULL REFERENCES acq.invoice (id) ON UPDATE CASCADE ON DELETE CASCADE,
@@ -883,6 +889,10 @@ CREATE TABLE acq.invoice_item ( -- for invoice-only debits: taxes/fees/non-bib i
     target          BIGINT
 );
 
+CREATE INDEX ii_inv_idx on acq.invoice_item (invoice);
+CREATE INDEX ii_po_idx on acq.invoice_item (purchase_order);
+CREATE INDEX ii_poi_idx on acq.invoice_item (po_item);
+
 -- Patron requests
 CREATE TABLE acq.user_request_type (
     id      SERIAL  PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/0691.schema.acq_fk_indices.sql b/Open-ILS/src/sql/Pg/upgrade/0691.schema.acq_fk_indices.sql
new file mode 100644 (file)
index 0000000..6a04874
--- /dev/null
@@ -0,0 +1,15 @@
+BEGIN;
+
+INSERT INTO config.upgrade_log (version) VALUES ('0691');
+
+CREATE INDEX poi_po_idx ON acq.po_item (purchase_order);
+
+CREATE INDEX ie_inv_idx on acq.invoice_entry (invoice);
+CREATE INDEX ie_po_idx on acq.invoice_entry (purchase_order);
+CREATE INDEX ie_li_idx on acq.invoice_entry (lineitem);
+
+CREATE INDEX ii_inv_idx on acq.invoice_item (invoice);
+CREATE INDEX ii_po_idx on acq.invoice_item (purchase_order);
+CREATE INDEX ii_poi_idx on acq.invoice_item (po_item);
+
+COMMIT;