LP1879335 Retrieve linked bibs on demand
authorBill Erickson <berickxx@gmail.com>
Thu, 3 Sep 2020 15:32:56 +0000 (11:32 -0400)
committerGalen Charlton <gmc@equinoxinitiative.org>
Fri, 11 Sep 2020 13:58:50 +0000 (09:58 -0400)
Avoid populating any lists of all linked bib IDs for an authority
record, since these lists can be very large.  Instead, report the linked
record count to the browse UI and teach the linked bibs UI to retrieve
paged linked bib data on demand.

Modifies the "abl" IDL class to be accessible via pcrud.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>

Open-ILS/examples/fm_IDL.xml
Open-ILS/src/eg2/src/app/staff/cat/authority/browse.service.ts
Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.html
Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.ts
Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.ts
Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Authority.pm

index 60e4bea..e5c945d 100644 (file)
@@ -2755,7 +2755,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="thesaurus" reltype="might_have" key="code" map="" class="at"/>
                </links>
        </class>
-       <class id="abl" controller="open-ils.cstore" oils_obj:fieldmapper="authority::bib_linking" oils_persist:tablename="authority.bib_linking" reporter:label="Authority-Bibliographic Record Link">
+       <class id="abl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="authority::bib_linking" oils_persist:tablename="authority.bib_linking" reporter:label="Authority-Bibliographic Record Link">
                <fields oils_persist:primary="id" oils_persist:sequence="authority.bib_linking_id_seq">
                        <field name="id" reporter:datatype="id" />
                        <field name="bib" reporter:datatype="link" />
@@ -2765,6 +2765,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="bib" reltype="has_a" key="id" map="" class="bre"/>
                        <link field="authority" reltype="has_a" key="id" map="" class="are"/>
                </links>
+               <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+                       <actions>
+                               <retrieve/>
+                       </actions>
+               </permacrud>
        </class>
        <class id="ash" controller="open-ils.cstore" oils_obj:fieldmapper="authority::simple_heading" oils_persist:tablename="authority.simple_heading" reporter:label="Authority Simple Heading">
                <fields oils_persist:primary="id" oils_persist:sequence="authority.simple_heading_id_seq">
index 83701c1..848fb51 100644 (file)
@@ -68,7 +68,7 @@ export class BrowseService {
 
             return {
                 authority: authMeta.authority,
-                link_count: authMeta.linked_bibs.length,
+                link_count: authMeta.linked_bib_count,
                 heading: authMeta.heading,
                 thesaurus: authMeta.thesaurus,
                 thesaurus_code: authMeta.thesaurus_code,
index 37bb7ec..c1951fe 100644 (file)
@@ -17,7 +17,7 @@
   <ngb-tab title="Linked Bibs" i18n-title id="bibs">
     <ng-template ngbTabContent>
       <div class="mt-3" *ngIf="authMeta">
-        <eg-bib-list #bibList [bibIds]="authMeta.linked_bibs"
+        <eg-bib-list #bibList [bibIdSource]="linkedBibIdSource"
           gridPersistKey="cat.authority.manage.bibs"></eg-bib-list>
       </div>
     </ng-template>
index 1234e76..d4bd0eb 100644 (file)
@@ -20,6 +20,7 @@ export class ManageAuthorityComponent implements OnInit {
     authId: number;
     authTab = 'bibs';
     authMeta: any;
+    linkedBibIdSource: (pager: Pager, sort: any) => Promise<number[]>;
 
     constructor(
         private router: Router,
@@ -44,6 +45,19 @@ export class ManageAuthorityComponent implements OnInit {
                 ).subscribe(meta => this.authMeta = meta);
             }
         });
+
+        this.linkedBibIdSource = (pager: Pager, sort: any) => {
+            return this.getLinkedBibIds(pager, sort);
+        };
+    }
+
+    getLinkedBibIds(pager: Pager, sort: any): Promise<number[]> {
+        return this.pcrud.search('abl',
+            {authority: this.authId},
+            {limit: pager.limit, offset: pager.offset},
+            {atomic: true}
+        ).pipe(map(links => links.map(l => l.bib()))
+        ).toPromise();
     }
 
     // Changing a tab in the UI means changing the route.
index 19faff3..5cacc8e 100644 (file)
@@ -1,6 +1,6 @@
 import {Component, Input, OnInit, ViewChild} from '@angular/core';
-import {Observable, empty} from 'rxjs';
-import {map, switchMap} from 'rxjs/operators';
+import {Observable, empty, from} from 'rxjs';
+import {map, tap, switchMap} from 'rxjs/operators';
 import {IdlObject} from '@eg/core/idl.service';
 import {Pager} from '@eg/share/util/pager';
 import {NetService} from '@eg/core/net.service';
@@ -19,8 +19,10 @@ import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
 })
 export class BibListComponent implements OnInit {
 
-    // Display bibs linked to this authority record.
+    // Static source of bib record IDs
     @Input() bibIds: number[];
+    // Dynamic source of bib record IDs
+    @Input() bibIdSource: (pager: Pager, sort: any) => Promise<number[]>;
     @Input() gridPersistKey: string;
 
     dataSource: GridDataSource;
@@ -40,7 +42,7 @@ export class BibListComponent implements OnInit {
 
         this.dataSource.getRows = (pager: Pager, sort: any): Observable<any> => {
 
-            if (this.bibIds) {
+            if (this.bibIds || this.bibIdSource) {
                 return this.loadIds(pager, sort);
             }
 
@@ -53,25 +55,33 @@ export class BibListComponent implements OnInit {
     }
 
     loadIds(pager: Pager, sort: any): Observable<any> {
-        if (this.bibIds.length === 0) {
+
+        let promise: Promise<number[]>;
+
+        if (this.bibIdSource) {
+            promise = this.bibIdSource(pager, sort);
+
+        } else if (this.bibIds && this.bibIds.length > 0) {
+            promise = Promise.resolve(
+              this.bibIds.slice(pager.offset, pager.offset + pager.limit));
+
+        } else {
             return empty();
         }
 
-        const orderBy: any = {rmsr: 'title'};
-        if (sort.length) {
-            orderBy.rmsr = sort[0].name + ' ' + sort[0].dir;
-        }
+        return from(promise).pipe(switchMap(bibIds => {
 
-        return this.pcrud.search('rmsr', {id: this.bibIds}, {
-            order_by: orderBy,
-            limit: pager.limit,
-            offset: pager.offset,
-            flesh: 2,
-            flesh_fields: {
-                rmsr: ['biblio_record'],
-                bre: ['creator', 'editor']
-            }
-        });
+            if (bibIds.length === 0) { return empty(); }
+
+            return this.pcrud.search('rmsr', {id: bibIds}, {
+                order_by: {rmsr: 'id'},
+                flesh: 2,
+                flesh_fields: {
+                    rmsr: ['biblio_record'],
+                    bre: ['creator', 'editor']
+                }
+            });
+        }));
     }
 }
 
index 57ec61d..47c52b4 100644 (file)
@@ -361,7 +361,7 @@ __PACKAGE__->register_method(
                     thesaurus: short_code,
                     thesaurus_code: code,
                     control_set: control_set_object,
-                    linked_bibs: [id1, id2, ...]
+                    linked_bib_count: number
                 }
             /,
             type => 'object'
@@ -381,16 +381,23 @@ sub authority_main_entry {
         my $rec = $e->retrieve_authority_record_entry([
             $auth_id, {
                 flesh => 1,
-                flesh_fields => {are => [qw/control_set bib_links creator/]}
+                flesh_fields => {are => [qw/control_set creator/]}
             }
         ]) or return $e->event;
 
         my $response = {
             authority => $rec,
-            control_set => $rec->control_set,
-            linked_bibs => [ map {$_->bib} @{$rec->bib_links} ]
+            control_set => $rec->control_set
         };
 
+        $response->{linked_bib_count} = $e->json_query({
+            select => {abl => [
+                {column => 'bib', transform => 'count', aggregate => 1}
+            ]},
+            from => 'abl',
+            where => {authority => $auth_id}
+        })->[0]->{bib};
+
         # Extract the heading and thesaurus.
         # In theory this data has already been extracted in the DB, but
         # using authority.simple_heading results in data that varies