made use of embedded resources for relationships in the response that contain a single link for a set of resources rather than enumerate the self link of each resource

This commit is contained in:
Art Lowel
2017-06-21 16:51:37 +02:00
parent 0bccc7c201
commit b46ad36eaf
6 changed files with 82 additions and 55 deletions

View File

@@ -185,7 +185,12 @@ export class RemoteDataBuildService {
rdArr.push(this.buildSingle(href, resourceConstructor));
});
links[relationship] = this.aggregate(rdArr);
if (rdArr.length === 1) {
links[relationship] = rdArr[0];
}
else {
links[relationship] = this.aggregate(rdArr);
}
}
else {
// without the setTimeout, the actions inside requestService.configure

View File

@@ -48,9 +48,8 @@ export class NormalizedItem extends NormalizedDSpaceObject {
/**
* The Collection that owns this Item
*/
@autoserializeAs(String, 'owningCollection')
@relationship(ResourceType.Collection, false)
owner: string;
owningCollection: string;
@autoserialize
@relationship(ResourceType.Bitstream, true)

View File

@@ -2,10 +2,10 @@ import { Observable } from "rxjs";
import { PageInfo } from "../shared/page-info.model";
export enum RemoteDataState {
RequestPending,
ResponsePending,
Failed,
Success
RequestPending = <any> "RequestPending",
ResponsePending = <any> "ResponsePending",
Failed = <any> "Failed",
Success = <any> "Success"
}
/**

View File

@@ -20,6 +20,7 @@ import { NormalizedObjectFactory } from "../cache/models/normalized-object-facto
import { ResourceType } from "../shared/resource-type";
import { RequestError } from "./request.models";
import { PageInfo } from "../shared/page-info.model";
import { NormalizedObject } from "../cache/models/normalized-object.model";
function isObjectLevel(halObj: any) {
return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
@@ -29,6 +30,19 @@ function isPaginatedResponse(halObj: any) {
return isNotEmpty(halObj.page) && hasValue(halObj._embedded);
}
function flattenSingleKeyObject(obj: any): any {
const keys = Object.keys(obj);
if (keys.length !== 1) {
throw new Error(`Expected an object with a single key, got: ${JSON.stringify(obj)}`);
}
return obj[keys[0]];
}
class ProcessRequestDTO {
[key: string]: NormalizedObject[]
}
@Injectable()
export class RequestEffects {
@@ -49,85 +63,90 @@ export class RequestEffects {
})
.flatMap((entry: RequestEntry) => {
return this.restApi.get(entry.request.href)
.map((data: DSpaceRESTV2Response) => new SuccessResponse(this.process(data.payload, entry.request.href), data.statusCode, this.processPageInfo(data.payload.page)))
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
.map((data: DSpaceRESTV2Response) => {
const processRequestDTO = this.process(data.payload, entry.request.href);
const uuids = flattenSingleKeyObject(processRequestDTO).map(no => no.uuid);
return new SuccessResponse(uuids, 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))
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
.map((response: Response) => new RequestCompleteAction(entry.request.href)));
});
protected process(data: any, requestHref: string): Array<string> {
protected process(data: any, requestHref: string): ProcessRequestDTO {
if (isNotEmpty(data)) {
if (isPaginatedResponse(data)) {
return this.process(data._embedded, requestHref);
}
else if (isObjectLevel(data)) {
return this.deserializeAndCache(data, requestHref);
return { "topLevel": this.deserializeAndCache(data, requestHref) };
}
else {
let uuids = [];
Object.keys(data)
.filter(property => data.hasOwnProperty(property))
.filter(property => hasValue(data[property]))
.forEach(property => {
let propertyUUIDs;
if (isPaginatedResponse(data[property])) {
propertyUUIDs = this.process(data[property], requestHref);
let result = new ProcessRequestDTO();
if (Array.isArray(data)) {
result['topLevel'] = [];
data.forEach(datum => {
if (isPaginatedResponse(datum)) {
const obj = this.process(datum, requestHref);
result['topLevel'] = [...result['topLevel'], ...flattenSingleKeyObject(obj)];
}
else {
propertyUUIDs = this.deserializeAndCache(data[property], requestHref);
result['topLevel'] = [...result['topLevel'], ...this.deserializeAndCache(datum, requestHref)];
}
uuids = [...uuids, ...propertyUUIDs];
});
return uuids;
}
else {
Object.keys(data)
.filter(property => data.hasOwnProperty(property))
.filter(property => hasValue(data[property]))
.forEach(property => {
if (isPaginatedResponse(data[property])) {
const obj = this.process(data[property], requestHref);
result[property] = flattenSingleKeyObject(obj);
}
else {
result[property] = this.deserializeAndCache(data[property], requestHref);
}
});
}
return result;
}
}
}
protected deserializeAndCache(obj, requestHref: string): Array<string> {
let type: ResourceType;
const isArray = Array.isArray(obj);
if (isArray && isEmpty(obj)) {
return [];
}
if (isArray) {
type = obj[0]["type"];
}
else {
type = obj["type"];
protected deserializeAndCache(obj, requestHref: string): NormalizedObject[] {
if(Array.isArray(obj)) {
let result = [];
obj.forEach(o => result = [...result, ...this.deserializeAndCache(o, requestHref)])
return result;
}
let type: ResourceType = obj["type"];
if (hasValue(type)) {
const normObjConstructor = NormalizedObjectFactory.getConstructor(type);
if (hasValue(normObjConstructor)) {
const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
if (isArray) {
obj.forEach(o => {
if (isNotEmpty(o._embedded)) {
this.process(o._embedded, requestHref);
}
let processed;
if (isNotEmpty(obj._embedded)) {
processed = this.process(obj._embedded, requestHref);
}
let normalizedObj = serializer.deserialize(obj);
if (isNotEmpty(processed)) {
let linksOnly = {};
Object.keys(processed).forEach(key => {
linksOnly[key] = processed[key].map((no: NormalizedObject) => no.self);
});
const normalizedObjArr = serializer.deserializeArray(obj);
normalizedObjArr.forEach(t => this.addToObjectCache(t, requestHref));
return normalizedObjArr.map(t => t.uuid);
}
else {
if (isNotEmpty(obj._embedded)) {
this.process(obj._embedded, requestHref);
}
const normalizedObj = serializer.deserialize(obj);
this.addToObjectCache(normalizedObj, requestHref);
return [normalizedObj.uuid];
Object.assign(normalizedObj, linksOnly);
}
this.addToObjectCache(normalizedObj, requestHref);
return [normalizedObj];
}
else {
//TODO move check to Validator?

View File

@@ -23,7 +23,7 @@ export class DSpaceRESTv2Service {
* @param options
* A RequestOptionsArgs object, with options for the http call.
* @return {Observable<string>}
* An Observablse<string> containing the response from the server
* An Observable<string> containing the response from the server
*/
get(absoluteURL: string, options?: RequestOptionsArgs): Observable<DSpaceRESTV2Response> {
return this.http.get(absoluteURL, options)

View File

@@ -40,7 +40,11 @@ export class Item extends DSpaceObject {
/**
* The Collection that owns this Item
*/
owner: RemoteData<Collection>;
owningCollection: RemoteData<Collection>;
get owner(): RemoteData<Collection> {
return this.owningCollection;
}
bitstreams: RemoteData<Bitstream[]>;