diff --git a/src/app/core/data-services/data.service.ts b/src/app/core/data-services/data.service.ts index 07414a0ce7..ddbfa03eb4 100644 --- a/src/app/core/data-services/data.service.ts +++ b/src/app/core/data-services/data.service.ts @@ -6,6 +6,7 @@ import { CacheableObject } from "../cache/object-cache.reducer"; import { ParamHash } from "../shared/param-hash"; import { isNotEmpty } from "../../shared/empty.util"; import { GenericConstructor } from "../shared/generic-constructor"; +import { RemoteData } from "./remote-data"; export abstract class DataService { abstract serviceName: OpaqueToken; @@ -16,29 +17,38 @@ export abstract class DataService { } - findAll(scopeID?: string): Observable> { + findAll(scopeID?: string): RemoteData> { const key = new ParamHash(this.serviceName, 'findAll', scopeID).toString(); - return this.requestCache.findAll(key, this.serviceName, scopeID) - //get an observable of the IDs from the RequestCache - .map(entry => entry.resourceUUIDs) - .flatMap((resourceUUIDs: Array) => { - // use those IDs to fetch the actual objects from the ObjectCache - return this.objectCache.getList(resourceUUIDs, this.modelType); - }); + const requestCacheObs = this.requestCache.findAll(key, this.serviceName, scopeID); + return new RemoteData( + requestCacheObs.map(entry => entry.isLoading).distinctUntilChanged(), + requestCacheObs.map(entry => entry.errorMessage).distinctUntilChanged(), + requestCacheObs + .map(entry => entry.resourceUUIDs) + .flatMap((resourceUUIDs: Array) => { + // use those IDs to fetch the actual objects from the ObjectCache + return this.objectCache.getList(resourceUUIDs, this.modelType); + }).distinctUntilChanged() + ); } - findById(id: string): Observable { + findById(id: string): RemoteData { const key = new ParamHash(this.serviceName, 'findById', id).toString(); - return this.requestCache.findById(key, this.serviceName, id) - .map(entry => entry.resourceUUIDs) - .flatMap((resourceUUIDs: Array) => { - if(isNotEmpty(resourceUUIDs)) { - return this.objectCache.get(resourceUUIDs[0], this.modelType); - } - else { - return Observable.of(undefined); - } - }); + const requestCacheObs = this.requestCache.findById(key, this.serviceName, id); + return new RemoteData( + requestCacheObs.map(entry => entry.isLoading).distinctUntilChanged(), + requestCacheObs.map(entry => entry.errorMessage).distinctUntilChanged(), + requestCacheObs + .map(entry => entry.resourceUUIDs) + .flatMap((resourceUUIDs: Array) => { + if (isNotEmpty(resourceUUIDs)) { + return this.objectCache.get(resourceUUIDs[0], this.modelType); + } + else { + return Observable.of(undefined); + } + }).distinctUntilChanged() + ); } } diff --git a/src/app/core/data-services/remote-data.ts b/src/app/core/data-services/remote-data.ts new file mode 100644 index 0000000000..1b9ff177ef --- /dev/null +++ b/src/app/core/data-services/remote-data.ts @@ -0,0 +1,75 @@ +import { Observable } from "rxjs"; +import { hasValue } from "../../shared/empty.util"; + +export enum RemoteDataState { + //TODO RequestPending will never happen: implement it in the store & DataEffects. + RequestPending, + ResponsePending, + Failed, + Success +} + +/** + * A class to represent the state of + */ +export class RemoteData { + + constructor( + private storeLoading: Observable, + public errorMessage: Observable, + public payload: Observable + ) { + } + + get state(): Observable { + return Observable.combineLatest( + this.storeLoading, + this.errorMessage.map(msg => hasValue(msg)), + (storeLoading, hasMsg) => { + if (storeLoading) { + return RemoteDataState.ResponsePending + } + else if (hasMsg) { + return RemoteDataState.Failed + } + else { + return RemoteDataState.Success + } + } + ).distinctUntilChanged(); + } + + get isRequestPending(): Observable { + return this.state + .map(state => state == RemoteDataState.RequestPending) + .distinctUntilChanged(); + } + + get isResponsePending(): Observable { + return this.state + .map(state => state == RemoteDataState.ResponsePending) + .distinctUntilChanged(); + } + + get isLoading(): Observable { + return this.state + .map(state => { + return state == RemoteDataState.RequestPending + || state === RemoteDataState.ResponsePending + }) + .distinctUntilChanged(); + } + + get hasFailed(): Observable { + return this.state + .map(state => state == RemoteDataState.Failed) + .distinctUntilChanged(); + } + + get hasSucceeded(): Observable { + return this.state + .map(state => state == RemoteDataState.Success) + .distinctUntilChanged(); + } + +}