Acq: General Search refactor user/senator/acq-unified-search-refactor-rel_2_1
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 14 Feb 2012 22:49:54 +0000 (17:49 -0500)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 17 Apr 2012 14:39:05 +0000 (10:39 -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>
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Search.pm
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 602ee6b..d0942dc 100644 (file)
@@ -8811,6 +8811,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 92cb0bf..7c03d84 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;