WIP: complex, cross-table searches
authorMike Rylander <mrylander@gmail.com>
Tue, 10 Mar 2020 13:34:51 +0000 (09:34 -0400)
committerGalen Charlton <gmc@equinoxinitiative.org>
Wed, 11 Mar 2020 18:39:50 +0000 (14:39 -0400)
Signed-off-by: Mike Rylander <mrylander@gmail.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider-search-form.component.ts
Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider-search.service.ts

index 79f9822..afd33bf 100644 (file)
@@ -68,37 +68,38 @@ export class AcqProviderSearchFormComponent implements OnInit, AfterViewInit {
 
         const searchTerms: AcqProviderSearchTerm[] = [];
         if (this.providerName) {
-            searchTerms.push({ field: 'name', op: 'ilike', value: this.providerName });
+            searchTerms.push({ fields: ['name'], op: 'ilike', value: this.providerName });
         }
         if (this.providerCode) {
-            searchTerms.push({ field: 'code', op: 'ilike', value: this.providerCode });
+            searchTerms.push({ fields: ['code'], op: 'ilike', value: this.providerCode });
         }
         if (this.providerOwners) {
-            searchTerms.push({ field: 'owner', op: 'in', value: this.providerOwners.orgIds });
+            searchTerms.push({ fields: ['owner'], op: 'in', value: this.providerOwners.orgIds });
         }
         if (this.contactName) {
-            // TODO
+            searchTerms.push({ classes: ['acqpc'], fields: ['name'], op: 'ilike', value: this.contactName });
         }
         if (this.providerEmail) {
-            searchTerms.push({ field: 'email', op: 'ilike', value: this.providerEmail });
+            searchTerms.push({ classes: ['acqpro','acqpc'], fields: ['email','email'], op: 'ilike', value: this.providerEmail });
         }
         if (this.providerPhone) {
-            searchTerms.push({ field: 'phone', op: 'ilike', value: this.providerPhone });
+            // this requires the flesh hash to contain: { ... join: { acqpc: { type: 'left' } } ... }
+            searchTerms.push({ classes: ['acqpc','acqpro','acqpro'], fields: ['phone','phone','fax_phone'], op: 'ilike', value: this.providerPhone });
         }
         if (this.providerCurrencyType) {
-            searchTerms.push({ field: 'currency_type', op: 'ilike', value: this.providerCurrencyType });
+            searchTerms.push({ fields: ['currency_type'], op: 'ilike', value: this.providerCurrencyType });
         }
         if (this.providerSAN) {
-            searchTerms.push({ field: 'san', op: 'ilike', value: this.providerSAN });
+            searchTerms.push({ fields: ['san'], op: 'ilike', value: this.providerSAN });
         }
         if (this.providerEDIDefault) {
-            searchTerms.push({ field: 'edi_default', op: '=', value: this.providerEDIDefault });
+            searchTerms.push({ fields: ['edi_default'], op: '=', value: this.providerEDIDefault });
         }
         if (this.providerURL) {
-            searchTerms.push({ field: 'url', op: 'ilike', value: this.providerURL });
+            searchTerms.push({ fields: ['url'], op: 'ilike', value: this.providerURL });
         }
         if (this.providerIsActive) {
-            searchTerms.push({ field: 'active', op: '=', value: (this.providerIsActive ? 't' : 'f') });
+            searchTerms.push({ fields: ['active'], op: '=', value: (this.providerIsActive ? 't' : 'f') });
         }
 
         // tossing setTimeout here to ensure that the
index 295f2c1..501ce59 100644 (file)
@@ -8,7 +8,8 @@ import {Pager} from '@eg/share/util/pager';
 import {EventService} from '@eg/core/event.service';
 
 export interface AcqProviderSearchTerm {
-    field: string;
+    classes?: string[];
+    fields: string[];
     op: string;
     value: any;
 }
@@ -36,6 +37,23 @@ export class AcqProviderSearchService {
         this.firstRun = false;
     }
 
+    generateSearchJoins(): any {
+        let joinPart = new Object();
+        let class_list = new Array();
+
+        // get all the classes used
+        this._terms.forEach(term => {class_list = class_list.concat(term.classes)})
+
+        // filter out acqpro, empty names, and make unique
+        class_list = class_list.filter((x, i, a) => x && x !== 'acqpro' && a.indexOf(x) == i);
+
+        // build a join clause for use in the "opts" part of a pcrud query
+        class_list.forEach(cls => { joinPart[cls].type = 'left' })
+
+        if (Object.keys(joinPart).length == 0) return null;
+        return joinPart;
+    }
+
     generateSearch(filters): any {
         // base query to grab all providers
         const base = { id: { '!=': null } };
@@ -48,16 +66,58 @@ export class AcqProviderSearchService {
                 return;
             }
 
-            const query_part = new Object();
+            // not const because we may want an array
+            let query_part = new Object();
 
-            query_part[term.field] = {};
             let op = term.op;
             if (!op) { op = '=' }; // just in case
+
             let val = term.value;
             if (op === 'ilike') {
                 val = '%' + val + '%';
             }
-            query_part[term.field][op] = val;
+
+            let isOR = false;
+            term.fields.forEach( (field,ind) => {
+                const curr_cls = term.classes[ind];
+
+                if (ind == 1) {
+                    // we're OR'ing in other classes/fields
+                    // and this is the first so restructure
+                    const first_cls = term.classes[0];
+                    isOR = true;
+                    let tmp = new Object();
+                    if (first_cls) {
+                        tmp['+'+first_cls] = query_part;
+                    } else {
+                        tmp = query_part;
+                    }
+
+                    query_part = new Array();
+                    query_part.push(tmp);
+                }
+
+                if (curr_cls) {
+                    if (isOR) {
+                        let tmp = new Object();
+                        tmp['+'+curr_cls][field][op] = val;
+                        query_part.push(tmp);
+                    } else {
+                        query_part['+'+curr_cls][field][op] = val;
+                    }
+                } else {
+                    if (isOR) {
+                        let tmp = new Object();
+                        tmp[field][op] = val;
+                        query_part.push(tmp);
+                    } else {
+                        query_part[field][op] = val;
+                    }
+                }
+
+            });
+
+            if (isOR) { query_part = {'-or':query_part} }
             query.push(query_part);
         });
 
@@ -88,9 +148,11 @@ export class AcqProviderSearchService {
                 return empty();
             }
 
+            const joins = this.generateSearchJoins();
             const query = this.generateSearch(gridSource.filters);
 
             const opts = {};
+            if (joins) opts['join'] = joins;
             opts['offset'] = pager.offset;
             opts['limit'] = pager.limit;
             opts['au_by_id'] = true;