Add helper to extract collection elements as well as collections

In some cases, we need to access the individual collection pages
as they have things embedded (such as work package schemas).
pull/10358/head
Oliver Günther 3 years ago
parent db973ebdf9
commit 9bd471035a
No known key found for this signature in database
GPG Key ID: 88872239EB414F99
  1. 6
      frontend/src/app/core/apiv3/endpoints/work_packages/api-v3-work-packages-paths.ts
  2. 55
      frontend/src/app/core/apiv3/helpers/get-paginated-results.ts
  3. 8
      frontend/src/app/features/hal/services/hal-resource.service.ts

@ -64,6 +64,10 @@ export class ApiV3WorkPackagesPaths extends ApiV3Collection<WorkPackageResource,
* @param ids
*/
public requireAll(ids:string[]):Promise<unknown> {
if (ids.length === 0) {
return Promise.resolve();
}
return new Promise<undefined>((resolve, reject) => {
this
.loadCollectionsFor(_.uniq(ids))
@ -157,7 +161,7 @@ export class ApiV3WorkPackagesPaths extends ApiV3Collection<WorkPackageResource,
protected loadCollectionsFor(ids:string[]):Promise<WorkPackageCollectionResource[]> {
return this
.halResourceService
.getAllPaginated<WorkPackageCollectionResource>(
.getAllPaginated<WorkPackageCollectionResource>(
this.path,
{
filters: ApiV3Filter('id', '=', ids).toJson(),

@ -27,26 +27,29 @@ type ApiV3CollectionType<T> = CollectionResource<T>|IHALCollection<T>;
* Extract the elements of either a HAL class or an interface
*/
function extractCollectionElements<T>(collection:ApiV3CollectionType<T>):T[] {
// Some API endpoints return an undefined _embedded.elements
// so we ensure we return an array at all times.
if (collection instanceof HalResource) {
return collection.elements;
return collection.elements || [];
}
return collection._embedded.elements;
return collection._embedded?.elements || [];
}
/**
* Get ALL pages of a potentially paginated APIv3 request.
* Get ALL pages of a potentially paginated APIv3 request, returning an array of collections
*
* @param request The requesting callback to request specific pages
* @param pageSize The pageSize parameter to request, defaults to -1 (the maximum magic page number)
* @return an array of HAL collections
*/
export function getPaginatedResults<T>(
request:(params:ApiV3PaginationParameters) => Observable<ApiV3CollectionType<T>>,
export function getPaginatedCollections<T, C extends ApiV3CollectionType<T>>(
request:(params:ApiV3PaginationParameters) => Observable<C>,
pageSize = MAGIC_PAGE_NUMBER,
):Observable<T[]> {
):Observable<ApiV3CollectionType<T>[]> {
return request({ pageSize, offset: 1 })
.pipe(
mergeMap((collection:ApiV3CollectionType<T>) => {
mergeMap((collection:C) => {
const resolvedSize = collection.pageSize;
if (collection.total > collection.count) {
@ -58,20 +61,36 @@ export function getPaginatedResults<T>(
// Branch out and fetch all remaining pages in parallel.
// Afterwards, merge the resulting list
return forkJoin(...calls).pipe(
map(
(results:ApiV3CollectionType<T>[]) => results.reduce(
(acc, next) => acc.concat(extractCollectionElements(next)),
extractCollectionElements(collection),
),
),
);
return forkJoin(...calls)
.pipe(
map((results:C[]) => [collection, ...results]),
);
}
// The current page is the only page, return the results.
return of(extractCollectionElements(collection));
return of([collection]);
}),
// Elements may incorrectly be undefined here due to the way the representer works
map((elements) => elements || []),
);
}
/**
* Get ALL pages of a potentially paginated APIv3 request, returning all concatenated elements.
*
* @param request The requesting callback to request specific pages
* @param pageSize The pageSize parameter to request, defaults to -1 (the maximum magic page number)
* @return an array of plain HAL resources
*/
export function getPaginatedResults<T>(
request:(params:ApiV3PaginationParameters) => Observable<ApiV3CollectionType<T>>,
pageSize = MAGIC_PAGE_NUMBER,
):Observable<T[]> {
return getPaginatedCollections(request, pageSize)
.pipe(
map(
(results:ApiV3CollectionType<T>[]) => results.reduce(
(acc, next) => acc.concat(extractCollectionElements(next)),
[] as T[],
),
),
);
}

@ -65,7 +65,7 @@ import {
} from 'core-app/features/hal/resources/hal-resource';
import { initializeHalProperties } from '../helpers/hal-resource-builder';
import { HalError } from 'core-app/features/hal/services/hal-error';
import { getPaginatedResults } from 'core-app/core/apiv3/helpers/get-paginated-results';
import { getPaginatedCollections } from 'core-app/core/apiv3/helpers/get-paginated-results';
export interface HalResourceFactoryConfigInterface {
cls?:any;
@ -153,13 +153,13 @@ export class HalResourceService {
params:Record<string, string|number> = {},
headers:HTTPClientHeaders = {},
):Observable<T[]> {
return getPaginatedResults(
return getPaginatedCollections(
(pageParams) => {
const requestParams = { ...params, pageParams };
const requestParams = { ...params, ...pageParams };
return this.request<CollectionResource<T>>('get', href, this.toEprops(requestParams), headers);
},
(params.pageSize as number|undefined) || -1,
);
) as Observable<T[]>;
}
/**

Loading…
Cancel
Save