From 02cf98c75912c2de0ec3f977bedba8643cb17581 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 26 Aug 2019 17:51:42 +0200 Subject: [PATCH] 64574: relationship-service's getRelatedItemsByLabel returns paginated list using new REST API search endpoint + test cases on publication pages --- .../edit-relationship-list.component.ts | 8 +-- .../publication/publication.component.html | 6 +-- .../publication/publication.component.ts | 22 +++----- .../shared/item-relationships-utils.ts | 29 +++++++++++ .../item-types/shared/item.component.ts | 4 +- src/app/core/data/relationship.service.ts | 52 ++++++++++++++----- .../item-pages/person/person.component.ts | 4 +- 7 files changed, 91 insertions(+), 34 deletions(-) diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts index 765d6484d4..3a145c99e0 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts @@ -4,8 +4,10 @@ import { Observable } from 'rxjs/internal/Observable'; import { FieldUpdate, FieldUpdates } from '../../../../core/data/object-updates/object-updates.reducer'; import { RelationshipService } from '../../../../core/data/relationship.service'; import { Item } from '../../../../core/shared/item.model'; -import { switchMap } from 'rxjs/operators'; +import { map, switchMap } from 'rxjs/operators'; import { hasValue } from '../../../../shared/empty.util'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../core/data/paginated-list'; @Component({ selector: 'ds-edit-relationship-list', @@ -63,7 +65,7 @@ export class EditRelationshipListComponent implements OnInit, OnChanges { * Transform the item's relationships of a specific type into related items * @param label The relationship type's label */ - public getRelatedItemsByLabel(label: string): Observable { + public getRelatedItemsByLabel(label: string): Observable>> { return this.relationshipService.getRelatedItemsByLabel(this.item, label); } @@ -73,7 +75,7 @@ export class EditRelationshipListComponent implements OnInit, OnChanges { */ public getUpdatesByLabel(label: string): Observable { return this.getRelatedItemsByLabel(label).pipe( - switchMap((items: Item[]) => this.objectUpdatesService.getFieldUpdatesExclusive(this.url, items)) + switchMap((itemsRD) => this.objectUpdatesService.getFieldUpdatesExclusive(this.url, itemsRD.payload.page)) ) } diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.html b/src/app/+item-page/simple/item-types/publication/publication.component.html index abf5225c27..aae269cdbe 100644 --- a/src/app/+item-page/simple/item-types/publication/publication.component.html +++ b/src/app/+item-page/simple/item-types/publication/publication.component.html @@ -32,15 +32,15 @@ [representations]="authors$ | async"> diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.ts b/src/app/+item-page/simple/item-types/publication/publication.component.ts index 81e2726e0c..1d5a942559 100644 --- a/src/app/+item-page/simple/item-types/publication/publication.component.ts +++ b/src/app/+item-page/simple/item-types/publication/publication.component.ts @@ -8,6 +8,8 @@ import { import { ItemComponent } from '../shared/item.component'; import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model'; import { getRelatedItemsByTypeLabel } from '../shared/item-relationships-utils'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../core/data/paginated-list'; @rendersItemType('Publication', ItemViewMode.Full) @rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Full) @@ -26,17 +28,17 @@ export class PublicationComponent extends ItemComponent implements OnInit { /** * The projects related to this publication */ - projects$: Observable; + projects$: Observable>>; /** * The organisation units related to this publication */ - orgUnits$: Observable; + orgUnits$: Observable>>; /** * The journal issues related to this publication */ - journalIssues$: Observable; + journalIssues$: Observable>>; ngOnInit(): void { super.ngOnInit(); @@ -45,17 +47,9 @@ export class PublicationComponent extends ItemComponent implements OnInit { this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author'); - this.projects$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isProjectOfPublication') - ); - - this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isOrgUnitOfPublication') - ); - - this.journalIssues$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isJournalIssueOfPublication') - ); + this.projects$ = this.relationshipService.getRelatedItemsByLabel(this.item, 'isProjectOfPublication'); + this.orgUnits$ = this.relationshipService.getRelatedItemsByLabel(this.item, 'isOrgUnitOfPublication'); + this.journalIssues$ = this.relationshipService.getRelatedItemsByLabel(this.item, 'isJournalIssueOfPublication'); } } diff --git a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts index b4eda2abfb..c63900663d 100644 --- a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts +++ b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts @@ -13,6 +13,7 @@ import { ItemDataService } from '../../../../core/data/item-data.service'; import { Item } from '../../../../core/shared/item.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { RelationshipService } from '../../../../core/data/relationship.service'; +import { PaginatedList } from '../../../../core/data/paginated-list'; /** * Operator for comparing arrays using a mapping function @@ -99,6 +100,34 @@ export const relationsToItems = (thisId: string) => distinctUntilChanged(compareArraysUsingIds()), ); +export const paginatedRelationsToItems = (thisId: string) => + (source: Observable>>): Observable>> => + source.pipe( + getSucceededRemoteData(), + switchMap((relationshipsRD: RemoteData>) => { + return observableZip( + ...relationshipsRD.payload.page.map((rel: Relationship) => observableCombineLatest(rel.leftItem, rel.rightItem)) + ).pipe( + map((arr) => + arr + .filter(([leftItem, rightItem]) => leftItem.hasSucceeded && rightItem.hasSucceeded) + .map(([leftItem, rightItem]) => { + if (leftItem.payload.id === thisId) { + return rightItem.payload; + } else if (rightItem.payload.id === thisId) { + return leftItem.payload; + } + }) + .filter((item: Item) => hasValue(item)) + ), + distinctUntilChanged(compareArraysUsingIds()), + map((relatedItems: Item[]) => + Object.assign(relationshipsRD, { payload: { page: relatedItems } }) + ) + ) + }) + ); + /** * Operator for turning a list of relationships and their relationship-types into a list of relevant items by relationship label * @param thisId The item's id of which the relations belong to diff --git a/src/app/+item-page/simple/item-types/shared/item.component.ts b/src/app/+item-page/simple/item-types/shared/item.component.ts index 556496fe49..e3b9ce59a8 100644 --- a/src/app/+item-page/simple/item-types/shared/item.component.ts +++ b/src/app/+item-page/simple/item-types/shared/item.component.ts @@ -15,6 +15,7 @@ import { MetadatumRepresentation } from '../../../../core/shared/metadata-repres import { of } from 'rxjs/internal/observable/of'; import { MetadataValue } from '../../../../core/shared/metadata.models'; import { compareArraysUsingIds } from './item-relationships-utils'; +import { RelationshipService } from '../../../../core/data/relationship.service'; /** * Operator for turning a list of relationships into a list of metadatarepresentations given the original metadata @@ -68,7 +69,8 @@ export class ItemComponent implements OnInit { resolvedRelsAndTypes$: Observable<[Relationship[], RelationshipType[]]>; constructor( - @Inject(ITEM) public item: Item + @Inject(ITEM) public item: Item, + public relationshipService: RelationshipService ) {} ngOnInit(): void { diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts index 1699b6a27d..5791ab2165 100644 --- a/src/app/core/data/relationship.service.ts +++ b/src/app/core/data/relationship.service.ts @@ -10,7 +10,7 @@ import { getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators'; -import { DeleteRequest, RestRequest } from './request.models'; +import { DeleteRequest, FindAllOptions, RestRequest } from './request.models'; import { Observable } from 'rxjs/internal/Observable'; import { RestResponse } from '../cache/response.models'; import { Item } from '../shared/item.model'; @@ -22,23 +22,42 @@ import { zip as observableZip } from 'rxjs'; import { PaginatedList } from './paginated-list'; import { ItemDataService } from './item-data.service'; import { - compareArraysUsingIds, filterRelationsByTypeLabel, + compareArraysUsingIds, filterRelationsByTypeLabel, paginatedRelationsToItems, relationsToItems } from '../../+item-page/simple/item-types/shared/item-relationships-utils'; import { ObjectCacheService } from '../cache/object-cache.service'; +import { DataService } from './data.service'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../core.reducers'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { HttpClient } from '@angular/common/http'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { SearchParam } from '../cache/models/search-param.model'; /** * The service handling all relationship requests */ @Injectable() -export class RelationshipService { +export class RelationshipService extends DataService { protected linkPath = 'relationships'; + protected forceBypassCache = false; - constructor(protected requestService: RequestService, - protected halService: HALEndpointService, + constructor(protected itemService: ItemDataService, + protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected itemService: ItemDataService, - protected objectCache: ObjectCacheService) { + protected dataBuildService: NormalizedObjectBuildService, + protected store: Store, + protected halService: HALEndpointService, + protected objectCache: ObjectCacheService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + super(); + } + + getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable { + return this.halService.getEndpoint(linkPath); } /** @@ -208,11 +227,20 @@ export class RelationshipService { * @param item * @param label */ - getRelatedItemsByLabel(item: Item, label: string): Observable { - return this.getItemResolvedRelsAndTypes(item).pipe( - filterRelationsByTypeLabel(label), - relationsToItems(item.uuid) - ); + getRelatedItemsByLabel(item: Item, label: string): Observable>> { + return this.getItemRelationshipsByLabel(item, label).pipe(paginatedRelationsToItems(item.uuid)); + } + + /** + * Resolve a given item's relationships into related items, filtered by a relationship label + * and return the items as an array + * @param item + * @param label + */ + getItemRelationshipsByLabel(item: Item, label: string): Observable>> { + const options = new FindAllOptions(); + options.searchParams = [ new SearchParam('label', label), new SearchParam('dso', item.id) ]; + return this.searchBy('byLabel', options); } /** diff --git a/src/app/entity-groups/research-entities/item-pages/person/person.component.ts b/src/app/entity-groups/research-entities/item-pages/person/person.component.ts index 8b36175b96..cd43c0b08b 100644 --- a/src/app/entity-groups/research-entities/item-pages/person/person.component.ts +++ b/src/app/entity-groups/research-entities/item-pages/person/person.component.ts @@ -7,6 +7,7 @@ import { SearchFixedFilterService } from '../../../../+search-page/search-filter import { isNotEmpty } from '../../../../shared/empty.util'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { RelationshipService } from '../../../../core/data/relationship.service'; @rendersItemType('Person', ItemViewMode.Full) @Component({ @@ -45,9 +46,10 @@ export class PersonComponent extends ItemComponent { constructor( @Inject(ITEM) public item: Item, + public relationshipService: RelationshipService, private fixedFilterService: SearchFixedFilterService ) { - super(item); + super(item, relationshipService); } ngOnInit(): void { super.ngOnInit();