diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts index f197773387..6cf09353a8 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -26,6 +26,7 @@ export class RemoteDataBuildService { ) { } + //TODO refactor, nearly identical to buildList, only payload differs buildSingle( href: string, normalizedType: GenericConstructor @@ -50,6 +51,12 @@ export class RemoteDataBuildService { .map((entry: ResponseCacheEntry) => entry.response.statusCode) .distinctUntilChanged(); + const pageInfo = responseCacheObs + .filter((entry: ResponseCacheEntry) => hasValue(entry) + && hasValue(entry.response) && hasValue(entry.response['pageInfo'])) + .map((entry: ResponseCacheEntry) => ( entry.response).pageInfo) + .distinctUntilChanged(); + const payload = Observable.race( this.objectCache.getBySelfLink(href, normalizedType), @@ -76,10 +83,12 @@ export class RemoteDataBuildService { isSuccessFul, errorMessage, statusCode, + pageInfo, payload ); } + //TODO refactor, nearly identical to buildSingle, only payload differs buildList( href: string, normalizedType: GenericConstructor @@ -104,6 +113,12 @@ export class RemoteDataBuildService { .map((entry: ResponseCacheEntry) => entry.response.statusCode) .distinctUntilChanged(); + const pageInfo = responseCacheObs + .filter((entry: ResponseCacheEntry) => hasValue(entry) + && hasValue(entry.response) && hasValue(entry.response['pageInfo'])) + .map((entry: ResponseCacheEntry) => ( entry.response).pageInfo) + .distinctUntilChanged(); + const payload = responseCacheObs .filter((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful) .map((entry: ResponseCacheEntry) => ( entry.response).resourceUUIDs) @@ -124,6 +139,7 @@ export class RemoteDataBuildService { isSuccessFul, errorMessage, statusCode, + pageInfo, payload ); } @@ -210,6 +226,8 @@ export class RemoteDataBuildService { .join(", ") ); + const pageInfo = Observable.of(undefined); + const payload = > Observable.combineLatest( ...input.map(rd => rd.payload) ); @@ -224,6 +242,7 @@ export class RemoteDataBuildService { isSuccessFul, errorMessage, statusCode, + pageInfo, payload ); } diff --git a/src/app/core/cache/response-cache.models.ts b/src/app/core/cache/response-cache.models.ts index 3f2b906bc9..b4137e8a22 100644 --- a/src/app/core/cache/response-cache.models.ts +++ b/src/app/core/cache/response-cache.models.ts @@ -1,4 +1,6 @@ import { RequestError } from "../data/request.models"; +import { PageInfo } from "../shared/page-info.model"; + export class Response { constructor( public isSuccessful: boolean, @@ -9,7 +11,8 @@ export class Response { export class SuccessResponse extends Response { constructor( public resourceUUIDs: Array, - public statusCode: string + public statusCode: string, + public pageInfo?: PageInfo ) { super(true, statusCode); } diff --git a/src/app/core/data/remote-data.ts b/src/app/core/data/remote-data.ts index 557d9eddb3..9c6cda96bd 100644 --- a/src/app/core/data/remote-data.ts +++ b/src/app/core/data/remote-data.ts @@ -1,4 +1,5 @@ import { Observable } from "rxjs"; +import { PageInfo } from "../shared/page-info.model"; export enum RemoteDataState { RequestPending, @@ -18,6 +19,7 @@ export class RemoteData { private isSuccessFul: Observable, public errorMessage: Observable, public statusCode: Observable, + public pageInfo: Observable, public payload: Observable ) { } diff --git a/src/app/core/data/request.effects.ts b/src/app/core/data/request.effects.ts index 1258003e60..c09bf7b236 100644 --- a/src/app/core/data/request.effects.ts +++ b/src/app/core/data/request.effects.ts @@ -19,6 +19,7 @@ import { RequestService } from "./request.service"; import { NormalizedObjectFactory } from "../cache/models/normalized-object-factory"; import { ResourceType } from "../shared/resource-type"; import { RequestError } from "./request.models"; +import { PageInfo } from "../shared/page-info.model"; function isObjectLevel(halObj: any) { return isNotEmpty(halObj._links) && hasValue(halObj._links.self); @@ -48,7 +49,7 @@ export class RequestEffects { }) .flatMap((entry: RequestEntry) => { return this.restApi.get(entry.request.href) - .map((data: DSpaceRESTV2Response) => new SuccessResponse(this.process(data.payload), data.statusCode)) + .map((data: DSpaceRESTV2Response) => new SuccessResponse(this.process(data.payload), data.statusCode, this.processPageInfo(data.payload.page))) .do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive)) .map((response: Response) => new RequestCompleteAction(entry.request.href)) .catch((error: RequestError) => Observable.of(new ErrorResponse(error)) @@ -60,7 +61,6 @@ export class RequestEffects { if (isNotEmpty(data)) { if (isPaginatedResponse(data)) { - //TODO parse page object return this.process(data._embedded); } else if (isObjectLevel(data)) { @@ -138,4 +138,14 @@ export class RequestEffects { } this.objectCache.add(co, this.EnvConfig.cache.msToLive); } + + protected processPageInfo(pageObj: any): PageInfo { + if (isNotEmpty(pageObj)) { + return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj); + } + else { + return undefined; + } + } + } diff --git a/src/app/core/dspace-rest-v2/dspace-rest-v2-response.model.ts b/src/app/core/dspace-rest-v2/dspace-rest-v2-response.model.ts index cf0b2dc06b..01af2a2c2b 100644 --- a/src/app/core/dspace-rest-v2/dspace-rest-v2-response.model.ts +++ b/src/app/core/dspace-rest-v2/dspace-rest-v2-response.model.ts @@ -2,6 +2,7 @@ export interface DSpaceRESTV2Response { payload: { _embedded?: any; _links?: any; + page?: any; }, statusCode: string } diff --git a/src/app/core/shared/page-info.model.ts b/src/app/core/shared/page-info.model.ts new file mode 100644 index 0000000000..b911c8b276 --- /dev/null +++ b/src/app/core/shared/page-info.model.ts @@ -0,0 +1,30 @@ +import { autoserialize, autoserializeAs } from "cerialize"; + +/** + * Represents the state of a paginated response + */ +export class PageInfo { + /** + * The number of elements on a page + */ + @autoserializeAs(Number, 'size') + elementsPerPage: number; + + /** + * The total number of elements in the entire set + */ + @autoserialize + totalElements: number; + + /** + * The total number of pages + */ + @autoserialize + totalPages: number; + + /** + * The number of the current page, zero-based + */ + @autoserializeAs(Number, 'number') + currentPage: number; +}