mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-18 07:23:03 +00:00
finished tests and docs
This commit is contained in:
@@ -25,14 +25,14 @@ export abstract class BaseResponseParsingService {
|
||||
protected abstract objectFactory: any;
|
||||
protected abstract toCache: boolean;
|
||||
|
||||
protected process<ObjectDomain, ObjectType>(data: any, requestHref: string): any {
|
||||
protected process<ObjectDomain, ObjectType>(data: any, requestUUID: string): any {
|
||||
if (isNotEmpty(data)) {
|
||||
if (hasNoValue(data) || (typeof data !== 'object')) {
|
||||
return data;
|
||||
} else if (isPaginatedResponse(data)) {
|
||||
return this.processPaginatedList(data, requestHref);
|
||||
return this.processPaginatedList(data, requestUUID);
|
||||
} else if (Array.isArray(data)) {
|
||||
return this.processArray(data, requestHref);
|
||||
return this.processArray(data, requestUUID);
|
||||
} else if (isObjectLevel(data)) {
|
||||
data = this.fixBadEPersonRestResponse(data);
|
||||
const object = this.deserialize(data);
|
||||
@@ -41,7 +41,7 @@ export abstract class BaseResponseParsingService {
|
||||
.keys(data._embedded)
|
||||
.filter((property) => data._embedded.hasOwnProperty(property))
|
||||
.forEach((property) => {
|
||||
const parsedObj = this.process<ObjectDomain, ObjectType>(data._embedded[property], requestHref);
|
||||
const parsedObj = this.process<ObjectDomain, ObjectType>(data._embedded[property], requestUUID);
|
||||
if (isNotEmpty(parsedObj)) {
|
||||
if (isPaginatedResponse(data._embedded[property])) {
|
||||
object[property] = parsedObj;
|
||||
@@ -55,7 +55,7 @@ export abstract class BaseResponseParsingService {
|
||||
});
|
||||
}
|
||||
|
||||
this.cache(object, requestHref);
|
||||
this.cache(object, requestUUID);
|
||||
return object;
|
||||
}
|
||||
const result = {};
|
||||
@@ -63,7 +63,7 @@ export abstract class BaseResponseParsingService {
|
||||
.filter((property) => data.hasOwnProperty(property))
|
||||
.filter((property) => hasValue(data[property]))
|
||||
.forEach((property) => {
|
||||
const obj = this.process(data[property], requestHref);
|
||||
const obj = this.process(data[property], requestUUID);
|
||||
result[property] = obj;
|
||||
});
|
||||
return result;
|
||||
@@ -71,7 +71,7 @@ export abstract class BaseResponseParsingService {
|
||||
}
|
||||
}
|
||||
|
||||
protected processPaginatedList<ObjectDomain, ObjectType>(data: any, requestHref: string): PaginatedList<ObjectDomain> {
|
||||
protected processPaginatedList<ObjectDomain, ObjectType>(data: any, requestUUID: string): PaginatedList<ObjectDomain> {
|
||||
const pageInfo: PageInfo = this.processPageInfo(data);
|
||||
let list = data._embedded;
|
||||
|
||||
@@ -79,14 +79,14 @@ export abstract class BaseResponseParsingService {
|
||||
if (!Array.isArray(list)) {
|
||||
list = this.flattenSingleKeyObject(list);
|
||||
}
|
||||
const page: ObjectDomain[] = this.processArray(list, requestHref);
|
||||
const page: ObjectDomain[] = this.processArray(list, requestUUID);
|
||||
return new PaginatedList<ObjectDomain>(pageInfo, page);
|
||||
}
|
||||
|
||||
protected processArray<ObjectDomain, ObjectType>(data: any, requestHref: string): ObjectDomain[] {
|
||||
protected processArray<ObjectDomain, ObjectType>(data: any, requestUUID: string): ObjectDomain[] {
|
||||
let array: ObjectDomain[] = [];
|
||||
data.forEach((datum) => {
|
||||
array = [...array, this.process(datum, requestHref)];
|
||||
array = [...array, this.process(datum, requestUUID)];
|
||||
}
|
||||
);
|
||||
return array;
|
||||
@@ -114,17 +114,17 @@ export abstract class BaseResponseParsingService {
|
||||
}
|
||||
}
|
||||
|
||||
protected cache<ObjectDomain, ObjectType>(obj, requestHref) {
|
||||
protected cache<ObjectDomain, ObjectType>(obj, requestUUID) {
|
||||
if (this.toCache) {
|
||||
this.addToObjectCache(obj, requestHref);
|
||||
this.addToObjectCache(obj, requestUUID);
|
||||
}
|
||||
}
|
||||
|
||||
protected addToObjectCache(co: CacheableObject, requestHref: string): void {
|
||||
protected addToObjectCache(co: CacheableObject, requestUUID: string): void {
|
||||
if (hasNoValue(co) || hasNoValue(co.self)) {
|
||||
throw new Error('The server returned an invalid object');
|
||||
}
|
||||
this.objectCache.add(co, this.EnvConfig.cache.msToLive.default, requestHref);
|
||||
this.objectCache.add(co, this.EnvConfig.cache.msToLive.default, requestUUID);
|
||||
}
|
||||
|
||||
processPageInfo(payload: any): PageInfo {
|
||||
|
@@ -28,7 +28,7 @@ export class ConfigResponseParsingService extends BaseResponseParsingService imp
|
||||
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||
if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && (data.statusCode === '201' || data.statusCode === '200' || data.statusCode === 'OK')) {
|
||||
const configDefinition = this.process<ConfigObject,ConfigType>(data.payload, request.href);
|
||||
const configDefinition = this.process<ConfigObject,ConfigType>(data.payload, request.uuid);
|
||||
return new ConfigSuccessResponse(configDefinition, data.statusCode, this.processPageInfo(data.payload));
|
||||
} else {
|
||||
return new ErrorResponse(
|
||||
|
@@ -28,7 +28,7 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem
|
||||
}
|
||||
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||
const processRequestDTO = this.process<NormalizedObject, ResourceType>(data.payload, request.href);
|
||||
const processRequestDTO = this.process<NormalizedObject, ResourceType>(data.payload, request.uuid);
|
||||
let objectList = processRequestDTO;
|
||||
|
||||
if (hasNoValue(processRequestDTO)) {
|
||||
|
@@ -9,8 +9,6 @@ import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { PageInfo } from '../shared/page-info.model';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { FacetValue } from '../../+search-page/search-service/facet-value.model';
|
||||
import { BaseResponseParsingService } from './base-response-parsing.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
|
@@ -1,16 +1,9 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import {
|
||||
FacetValueMap,
|
||||
FacetValueMapSuccessResponse,
|
||||
FacetValueSuccessResponse,
|
||||
RestResponse
|
||||
} from '../cache/response.models';
|
||||
import { FacetValueSuccessResponse, RestResponse } from '../cache/response.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { PageInfo } from '../shared/page-info.model';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { FacetValue } from '../../+search-page/search-service/facet-value.model';
|
||||
import { BaseResponseParsingService } from './base-response-parsing.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
|
@@ -42,7 +42,6 @@ export class RequestEffects {
|
||||
}),
|
||||
filter((entry: RequestEntry) => hasValue(entry)),
|
||||
map((entry: RequestEntry) => entry.request),
|
||||
tap((entry: RequestEntry) => console.log(entry)),
|
||||
flatMap((request: RestRequest) => {
|
||||
let body;
|
||||
if (isNotEmpty(request.body)) {
|
||||
|
@@ -174,7 +174,7 @@ describe('RequestService', () => {
|
||||
// b: undefined
|
||||
// });
|
||||
|
||||
scheduler.expectObservable(result).toBe('b', {b: undefined});
|
||||
scheduler.expectObservable(result).toBe('b', { b: undefined });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -458,4 +458,105 @@ describe('RequestService', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isReusable', () => {
|
||||
describe('when the given UUID is has no value', () => {
|
||||
let reusable;
|
||||
beforeEach(() => {
|
||||
const uuid = undefined;
|
||||
reusable = serviceAsAny.isReusable(uuid);
|
||||
});
|
||||
it('return an observable emitting false', () => {
|
||||
reusable.subscribe((isReusable) => expect(isReusable).toBe(false));
|
||||
})
|
||||
});
|
||||
|
||||
describe('when the given UUID has a value, but no cached entry is found', () => {
|
||||
let reusable;
|
||||
beforeEach(() => {
|
||||
spyOn(service, 'getByUUID').and.returnValue(observableOf(undefined));
|
||||
const uuid = 'a45bb291-1adb-40d9-b2fc-7ad9080607be';
|
||||
reusable = serviceAsAny.isReusable(uuid);
|
||||
});
|
||||
it('return an observable emitting false', () => {
|
||||
reusable.subscribe((isReusable) => expect(isReusable).toBe(false));
|
||||
})
|
||||
});
|
||||
|
||||
describe('when the given UUID has a value, a cached entry is found, but it has no response', () => {
|
||||
let reusable;
|
||||
beforeEach(() => {
|
||||
spyOn(service, 'getByUUID').and.returnValue(observableOf({ response: undefined }));
|
||||
const uuid = '53c9b814-ad8b-4567-9bc1-d9bb6cfba6c8';
|
||||
reusable = serviceAsAny.isReusable(uuid);
|
||||
});
|
||||
it('return an observable emitting false', () => {
|
||||
reusable.subscribe((isReusable) => expect(isReusable).toBe(false));
|
||||
})
|
||||
});
|
||||
|
||||
describe('when the given UUID has a value, a cached entry is found, but its response was not successful', () => {
|
||||
let reusable;
|
||||
beforeEach(() => {
|
||||
spyOn(service, 'getByUUID').and.returnValue(observableOf({ response: { isSuccessful: false } }));
|
||||
const uuid = '694c9b32-7b2e-4788-835b-ef3fc2252e6c';
|
||||
reusable = serviceAsAny.isReusable(uuid);
|
||||
});
|
||||
it('return an observable emitting false', () => {
|
||||
reusable.subscribe((isReusable) => expect(isReusable).toBe(false));
|
||||
})
|
||||
});
|
||||
|
||||
describe('when the given UUID has a value, a cached entry is found, its response was successful, but the response is outdated', () => {
|
||||
let reusable;
|
||||
const now = 100000;
|
||||
const timeAdded = 99899;
|
||||
const msToLive = 100;
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(Date.prototype, 'getTime').and.returnValue(now);
|
||||
spyOn(service, 'getByUUID').and.returnValue(observableOf({
|
||||
response: {
|
||||
isSuccessful: true,
|
||||
timeAdded: timeAdded
|
||||
},
|
||||
request: {
|
||||
responseMsToLive: msToLive
|
||||
}
|
||||
}));
|
||||
const uuid = 'f9b85788-881c-4994-86b6-bae8dad024d2';
|
||||
reusable = serviceAsAny.isReusable(uuid);
|
||||
});
|
||||
|
||||
it('return an observable emitting false', () => {
|
||||
reusable.subscribe((isReusable) => expect(isReusable).toBe(false));
|
||||
})
|
||||
});
|
||||
|
||||
describe('when the given UUID has a value, a cached entry is found, its response was successful, and the response is not outdated', () => {
|
||||
let reusable;
|
||||
const now = 100000;
|
||||
const timeAdded = 99999;
|
||||
const msToLive = 100;
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(Date.prototype, 'getTime').and.returnValue(now);
|
||||
spyOn(service, 'getByUUID').and.returnValue(observableOf({
|
||||
response: {
|
||||
isSuccessful: true,
|
||||
timeAdded: timeAdded
|
||||
},
|
||||
request: {
|
||||
responseMsToLive: msToLive
|
||||
}
|
||||
}));
|
||||
const uuid = 'f9b85788-881c-4994-86b6-bae8dad024d2';
|
||||
reusable = serviceAsAny.isReusable(uuid);
|
||||
});
|
||||
|
||||
it('return an observable emitting true', () => {
|
||||
reusable.subscribe((isReusable) => expect(isReusable).toBe(true));
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
@@ -76,7 +76,7 @@ export class RequestService {
|
||||
}
|
||||
|
||||
getByUUID(uuid: string): Observable<RequestEntry> {
|
||||
return observableRace(
|
||||
return observableRace(
|
||||
this.store.pipe(select(this.entryFromUUIDSelector(uuid))),
|
||||
this.store.pipe(
|
||||
select(this.originalUUIDFromUUIDSelector(uuid)),
|
||||
@@ -94,6 +94,12 @@ export class RequestService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a certain request
|
||||
* Used to make sure a request is in the cache
|
||||
* @param {RestRequest} request The request to send out
|
||||
* @param {boolean} forceBypassCache When true, a new request is always dispatched
|
||||
*/
|
||||
// TODO to review "overrideRequest" param when https://github.com/DSpace/dspace-angular/issues/217 will be fixed
|
||||
configure<T extends CacheableObject>(request: RestRequest, forceBypassCache: boolean = false): void {
|
||||
const isGetRequest = request.method === RestRequestMethod.GET;
|
||||
@@ -113,6 +119,11 @@ export class RequestService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a request is in the cache or if it's still pending
|
||||
* @param {GetRequest} request The request to check
|
||||
* @returns {boolean} True if the request is cached or still pending
|
||||
*/
|
||||
private isCachedOrPending(request: GetRequest) {
|
||||
let isCached = this.objectCache.hasBySelfLink(request.href);
|
||||
if (isCached) {
|
||||
@@ -142,6 +153,10 @@ export class RequestService {
|
||||
return isCached || isPending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure and execute the request
|
||||
* @param {RestRequest} request to dispatch
|
||||
*/
|
||||
private dispatchRequest(request: RestRequest) {
|
||||
this.store.dispatch(new RequestConfigureAction(request));
|
||||
this.store.dispatch(new RequestExecuteAction(request.uuid));
|
||||
@@ -164,6 +179,10 @@ export class RequestService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch commit action to send all changes (for a certain method) to the server (buffer)
|
||||
* @param {RestRequestMethod} method RestRequestMethod for which the changes should be committed
|
||||
*/
|
||||
commit(method?: RestRequestMethod) {
|
||||
this.store.dispatch(new CommitSSBAction(method))
|
||||
}
|
||||
@@ -171,11 +190,11 @@ export class RequestService {
|
||||
/**
|
||||
* Check whether a Response should still be cached
|
||||
*
|
||||
* @param entry
|
||||
* the entry to check
|
||||
* @param uuid
|
||||
* the uuid of the entry to check
|
||||
* @return boolean
|
||||
* false if the entry is null, undefined, or its time to
|
||||
* live has been exceeded, true otherwise
|
||||
* false if the uuid has no value, no entry could be found, the response was nog successful or its time to
|
||||
* live has exceeded, true otherwise
|
||||
*/
|
||||
private isReusable(uuid: string): Observable<boolean> {
|
||||
if (hasNoValue(uuid)) {
|
||||
@@ -194,7 +213,6 @@ export class RequestService {
|
||||
}
|
||||
})
|
||||
);
|
||||
return observableOf(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user