mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
added normalized models and builders
This commit is contained in:
93
src/app/core/cache/models/collection-builder.ts
vendored
Normal file
93
src/app/core/cache/models/collection-builder.ts
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import { Collection } from "../../shared/collection.model";
|
||||||
|
import { hasValue } from "../../../shared/empty.util";
|
||||||
|
import { Item } from "../../shared/item.model";
|
||||||
|
import { RequestConfigureAction, RequestExecuteAction } from "../../data/request.actions";
|
||||||
|
import { ObjectCacheService } from "../object-cache.service";
|
||||||
|
import { ResponseCacheService } from "../response-cache.service";
|
||||||
|
import { RequestService } from "../../data/request.service";
|
||||||
|
import { Store } from "@ngrx/store";
|
||||||
|
import { CoreState } from "../../core.reducers";
|
||||||
|
import { NormalizedCollection } from "./normalized-collection.model";
|
||||||
|
import { Request } from "../../data/request.models";
|
||||||
|
import { ListRemoteDataBuilder, SingleRemoteDataBuilder } from "./remote-data-builder";
|
||||||
|
import { ItemRDBuilder } from "./item-builder";
|
||||||
|
|
||||||
|
export class CollectionBuilder {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected responseCache: ResponseCacheService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected href: string,
|
||||||
|
protected nc: NormalizedCollection
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): Collection {
|
||||||
|
let links: any = {};
|
||||||
|
|
||||||
|
if (hasValue(this.nc.items)) {
|
||||||
|
this.nc.items.forEach((href: string) => {
|
||||||
|
const isCached = this.objectCache.hasBySelfLink(href);
|
||||||
|
const isPending = this.requestService.isPending(href);
|
||||||
|
|
||||||
|
console.log('href', href, 'isCached', isCached, "isPending", isPending);
|
||||||
|
|
||||||
|
if (!(isCached || isPending)) {
|
||||||
|
const request = new Request(href, Item);
|
||||||
|
this.store.dispatch(new RequestConfigureAction(request));
|
||||||
|
this.store.dispatch(new RequestExecuteAction(href));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
links.items = this.nc.items.map((href: string) => {
|
||||||
|
return new ItemRDBuilder(
|
||||||
|
this.objectCache,
|
||||||
|
this.responseCache,
|
||||||
|
this.requestService,
|
||||||
|
this.store,
|
||||||
|
href
|
||||||
|
).build();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(new Collection(), this.nc, links);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CollectionRDBuilder extends SingleRemoteDataBuilder<Collection, NormalizedCollection> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
objectCache: ObjectCacheService,
|
||||||
|
responseCache: ResponseCacheService,
|
||||||
|
requestService: RequestService,
|
||||||
|
store: Store<CoreState>,
|
||||||
|
href: string
|
||||||
|
) {
|
||||||
|
super(objectCache, responseCache, requestService, store, href, NormalizedCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected normalizedToDomain(normalized: NormalizedCollection): Collection {
|
||||||
|
return new CollectionBuilder(this.objectCache, this.responseCache, this.requestService, this.store, this.href, normalized).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CollectionListRDBuilder extends ListRemoteDataBuilder<Collection, NormalizedCollection> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
objectCache: ObjectCacheService,
|
||||||
|
responseCache: ResponseCacheService,
|
||||||
|
requestService: RequestService,
|
||||||
|
store: Store<CoreState>,
|
||||||
|
href: string
|
||||||
|
) {
|
||||||
|
super(objectCache, responseCache, requestService, store, href, NormalizedCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected normalizedToDomain(normalized: NormalizedCollection): Collection {
|
||||||
|
return new CollectionBuilder(this.objectCache, this.responseCache, this.requestService, this.store, this.href, normalized).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
61
src/app/core/cache/models/item-builder.ts
vendored
Normal file
61
src/app/core/cache/models/item-builder.ts
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { Item } from "../../shared/item.model";
|
||||||
|
import { ObjectCacheService } from "../object-cache.service";
|
||||||
|
import { ResponseCacheService } from "../response-cache.service";
|
||||||
|
import { RequestService } from "../../data/request.service";
|
||||||
|
import { Store } from "@ngrx/store";
|
||||||
|
import { CoreState } from "../../core.reducers";
|
||||||
|
import { NormalizedItem } from "./normalized-item.model";
|
||||||
|
import { ListRemoteDataBuilder, SingleRemoteDataBuilder } from "./remote-data-builder";
|
||||||
|
|
||||||
|
export class ItemBuilder {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected responseCache: ResponseCacheService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected href: string,
|
||||||
|
protected nc: NormalizedItem
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): Item {
|
||||||
|
//TODO
|
||||||
|
return Object.assign(new Item(), this.nc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ItemRDBuilder extends SingleRemoteDataBuilder<Item, NormalizedItem> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
objectCache: ObjectCacheService,
|
||||||
|
responseCache: ResponseCacheService,
|
||||||
|
requestService: RequestService,
|
||||||
|
store: Store<CoreState>,
|
||||||
|
href: string
|
||||||
|
) {
|
||||||
|
super(objectCache, responseCache, requestService, store, href, NormalizedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected normalizedToDomain(normalized: NormalizedItem): Item {
|
||||||
|
return new ItemBuilder(this.objectCache, this.responseCache, this.requestService, this.store, this.href, normalized).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ItemListRDBuilder extends ListRemoteDataBuilder<Item, NormalizedItem> {
|
||||||
|
constructor(
|
||||||
|
objectCache: ObjectCacheService,
|
||||||
|
responseCache: ResponseCacheService,
|
||||||
|
requestService: RequestService,
|
||||||
|
store: Store<CoreState>,
|
||||||
|
href: string
|
||||||
|
) {
|
||||||
|
super(objectCache, responseCache, requestService, store, href, NormalizedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected normalizedToDomain(normalized: NormalizedItem): Item {
|
||||||
|
return new ItemBuilder(this.objectCache, this.responseCache, this.requestService, this.store, this.href, normalized).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
src/app/core/cache/models/normalized-bitstream.model.ts
vendored
Normal file
36
src/app/core/cache/models/normalized-bitstream.model.ts
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { inheritSerialization } from "cerialize";
|
||||||
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
|
|
||||||
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
|
export class NormalizedBitstream extends NormalizedDSpaceObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of this bitstream in bytes(?)
|
||||||
|
*/
|
||||||
|
size: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relative path to this Bitstream's file
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mime type of this Bitstream
|
||||||
|
*/
|
||||||
|
mimetype: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of this Bitstream
|
||||||
|
*/
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of Bundles that are direct parents of this Bitstream
|
||||||
|
*/
|
||||||
|
parents: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Bundle that owns this Bitstream
|
||||||
|
*/
|
||||||
|
owner: string;
|
||||||
|
}
|
21
src/app/core/cache/models/normalized-bundle.model.ts
vendored
Normal file
21
src/app/core/cache/models/normalized-bundle.model.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { inheritSerialization } from "cerialize";
|
||||||
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
|
|
||||||
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
|
export class NormalizedBundle extends NormalizedDSpaceObject {
|
||||||
|
/**
|
||||||
|
* The primary bitstream of this Bundle
|
||||||
|
*/
|
||||||
|
primaryBitstream: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of Items that are direct parents of this Bundle
|
||||||
|
*/
|
||||||
|
parents: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Item that owns this Bundle
|
||||||
|
*/
|
||||||
|
owner: string;
|
||||||
|
|
||||||
|
}
|
31
src/app/core/cache/models/normalized-collection.model.ts
vendored
Normal file
31
src/app/core/cache/models/normalized-collection.model.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize";
|
||||||
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
|
|
||||||
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
|
export class NormalizedCollection extends NormalizedDSpaceObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the unique handle of this Collection
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
handle: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Bitstream that represents the logo of this Collection
|
||||||
|
*/
|
||||||
|
logo: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of Collections that are direct parents of this Collection
|
||||||
|
*/
|
||||||
|
parents: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Collection that owns this Collection
|
||||||
|
*/
|
||||||
|
owner: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
items: Array<string>;
|
||||||
|
|
||||||
|
}
|
51
src/app/core/cache/models/normalized-dspace-object.model.ts
vendored
Normal file
51
src/app/core/cache/models/normalized-dspace-object.model.ts
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { autoserialize, autoserializeAs } from "cerialize";
|
||||||
|
import { CacheableObject } from "../object-cache.reducer";
|
||||||
|
import { Metadatum } from "../../shared/metadatum.model";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract model class for a DSpaceObject.
|
||||||
|
*/
|
||||||
|
export abstract class NormalizedDSpaceObject implements CacheableObject {
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
self: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The human-readable identifier of this DSpaceObject
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The universally unique identifier of this DSpaceObject
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
uuid: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name for this DSpaceObject
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array containing all metadata of this DSpaceObject
|
||||||
|
*/
|
||||||
|
@autoserializeAs(Metadatum)
|
||||||
|
metadata: Array<Metadatum>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||||
|
*/
|
||||||
|
parents: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DSpaceObject that owns this DSpaceObject
|
||||||
|
*/
|
||||||
|
owner: string;
|
||||||
|
}
|
38
src/app/core/cache/models/normalized-item.model.ts
vendored
Normal file
38
src/app/core/cache/models/normalized-item.model.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { inheritSerialization, autoserialize } from "cerialize";
|
||||||
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
|
|
||||||
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
|
export class NormalizedItem extends NormalizedDSpaceObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the unique handle of this Item
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
handle: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Date of the last modification of this Item
|
||||||
|
*/
|
||||||
|
lastModified: Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this Item is currently archived or not
|
||||||
|
*/
|
||||||
|
isArchived: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this Item is currently withdrawn or not
|
||||||
|
*/
|
||||||
|
isWithdrawn: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of Collections that are direct parents of this Item
|
||||||
|
*/
|
||||||
|
parents: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Collection that owns this Item
|
||||||
|
*/
|
||||||
|
owner: string;
|
||||||
|
|
||||||
|
}
|
131
src/app/core/cache/models/remote-data-builder.ts
vendored
Normal file
131
src/app/core/cache/models/remote-data-builder.ts
vendored
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import { RemoteData } from "../../data/remote-data";
|
||||||
|
import { Observable } from "rxjs/Observable";
|
||||||
|
import { RequestEntry } from "../../data/request.reducer";
|
||||||
|
import { ResponseCacheEntry } from "../response-cache.reducer";
|
||||||
|
import { ErrorResponse, SuccessResponse } from "../response-cache.models";
|
||||||
|
import { Store } from "@ngrx/store";
|
||||||
|
import { CoreState } from "../../core.reducers";
|
||||||
|
import { ResponseCacheService } from "../response-cache.service";
|
||||||
|
import { ObjectCacheService } from "../object-cache.service";
|
||||||
|
import { RequestService } from "../../data/request.service";
|
||||||
|
import { CacheableObject } from "../object-cache.reducer";
|
||||||
|
import { GenericConstructor } from "../../shared/generic-constructor";
|
||||||
|
import { hasValue, isNotEmpty } from "../../../shared/empty.util";
|
||||||
|
|
||||||
|
export interface RemoteDataBuilder<T> {
|
||||||
|
build(): RemoteData<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class SingleRemoteDataBuilder<TDomain, TNormalized extends CacheableObject> implements RemoteDataBuilder<TDomain> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected responseCache: ResponseCacheService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected href: string,
|
||||||
|
protected normalizedType: GenericConstructor<TNormalized>
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract normalizedToDomain(normalized: TNormalized): TDomain;
|
||||||
|
|
||||||
|
build(): RemoteData<TDomain> {
|
||||||
|
const requestObs = this.store.select<RequestEntry>('core', 'data', 'request', this.href);
|
||||||
|
const responseCacheObs = this.responseCache.get(this.href);
|
||||||
|
|
||||||
|
const requestPending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.requestPending).distinctUntilChanged();
|
||||||
|
|
||||||
|
const responsePending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.responsePending).distinctUntilChanged();
|
||||||
|
|
||||||
|
const isSuccessFul = responseCacheObs
|
||||||
|
.map((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful).distinctUntilChanged();
|
||||||
|
|
||||||
|
const errorMessage = responseCacheObs
|
||||||
|
.filter((entry: ResponseCacheEntry) => hasValue(entry) && !entry.response.isSuccessful)
|
||||||
|
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
|
const payload =
|
||||||
|
Observable.race(
|
||||||
|
this.objectCache.getBySelfLink<TNormalized>(this.href, this.normalizedType),
|
||||||
|
responseCacheObs
|
||||||
|
.filter((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful)
|
||||||
|
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
||||||
|
.flatMap((resourceUUIDs: Array<string>) => {
|
||||||
|
if (isNotEmpty(resourceUUIDs)) {
|
||||||
|
return this.objectCache.get(resourceUUIDs[0], this.normalizedType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Observable.of(undefined);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.distinctUntilChanged()
|
||||||
|
).map((normalized: TNormalized) => this.normalizedToDomain(normalized));
|
||||||
|
|
||||||
|
return new RemoteData(
|
||||||
|
this.href,
|
||||||
|
requestPending,
|
||||||
|
responsePending,
|
||||||
|
isSuccessFul,
|
||||||
|
errorMessage,
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class ListRemoteDataBuilder<TDomain, TNormalized extends CacheableObject> implements RemoteDataBuilder<TDomain[]> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected responseCache: ResponseCacheService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected href: string,
|
||||||
|
protected normalizedType: GenericConstructor<TNormalized>
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract normalizedToDomain(normalized: TNormalized): TDomain;
|
||||||
|
|
||||||
|
build(): RemoteData<TDomain[]> {
|
||||||
|
const requestObs = this.store.select<RequestEntry>('core', 'data', 'request', this.href);
|
||||||
|
const responseCacheObs = this.responseCache.get(this.href);
|
||||||
|
|
||||||
|
const requestPending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.requestPending).distinctUntilChanged();
|
||||||
|
|
||||||
|
const responsePending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.responsePending).distinctUntilChanged();
|
||||||
|
|
||||||
|
const isSuccessFul = responseCacheObs
|
||||||
|
.map((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful).distinctUntilChanged();
|
||||||
|
|
||||||
|
const errorMessage = responseCacheObs
|
||||||
|
.filter((entry: ResponseCacheEntry) => hasValue(entry) && !entry.response.isSuccessful)
|
||||||
|
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
|
const payload = responseCacheObs
|
||||||
|
.filter((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful)
|
||||||
|
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
||||||
|
.flatMap((resourceUUIDs: Array<string>) => {
|
||||||
|
return this.objectCache.getList(resourceUUIDs, this.normalizedType)
|
||||||
|
.map((normList: TNormalized[]) => {
|
||||||
|
return normList.map((normalized: TNormalized) => {
|
||||||
|
return this.normalizedToDomain(normalized);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
|
return new RemoteData(
|
||||||
|
this.href,
|
||||||
|
requestPending,
|
||||||
|
responsePending,
|
||||||
|
isSuccessFul,
|
||||||
|
errorMessage,
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/app/core/cache/object-cache.service.ts
vendored
24
src/app/core/cache/object-cache.service.ts
vendored
@@ -60,6 +60,11 @@ export class ObjectCacheService {
|
|||||||
.map((entry: ObjectCacheEntry) => <T> Object.assign(new type(), entry.data));
|
.map((entry: ObjectCacheEntry) => <T> Object.assign(new type(), entry.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBySelfLink<T extends CacheableObject>(href: string, type: GenericConstructor<T>): Observable<T> {
|
||||||
|
return this.store.select<string>('core', 'index', 'href', href)
|
||||||
|
.flatMap((uuid: string) => this.get(uuid, type))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an observable for an array of objects of the same type
|
* Get an observable for an array of objects of the same type
|
||||||
* with the specified UUIDs
|
* with the specified UUIDs
|
||||||
@@ -104,6 +109,25 @@ export class ObjectCacheService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the object with the specified self link is cached
|
||||||
|
*
|
||||||
|
* @param href
|
||||||
|
* The self link of the object to check
|
||||||
|
* @return boolean
|
||||||
|
* true if the object with the specified self link is cached,
|
||||||
|
* false otherwise
|
||||||
|
*/
|
||||||
|
hasBySelfLink(href: string): boolean {
|
||||||
|
let result: boolean = false;
|
||||||
|
|
||||||
|
this.store.select<string>('core', 'index', 'href', href)
|
||||||
|
.take(1)
|
||||||
|
.subscribe((uuid: string) => result = this.has(uuid));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether an ObjectCacheEntry should still be cached
|
* Check whether an ObjectCacheEntry should still be cached
|
||||||
*
|
*
|
||||||
|
6
src/app/core/cache/response-cache.actions.ts
vendored
6
src/app/core/cache/response-cache.actions.ts
vendored
@@ -6,9 +6,9 @@ import { Response } from "./response-cache.models";
|
|||||||
* The list of ResponseCacheAction type definitions
|
* The list of ResponseCacheAction type definitions
|
||||||
*/
|
*/
|
||||||
export const ResponseCacheActionTypes = {
|
export const ResponseCacheActionTypes = {
|
||||||
ADD: type('dspace/core/cache/request/ADD'),
|
ADD: type('dspace/core/cache/response/ADD'),
|
||||||
REMOVE: type('dspace/core/cache/request/REMOVE'),
|
REMOVE: type('dspace/core/cache/response/REMOVE'),
|
||||||
RESET_TIMESTAMPS: type('dspace/core/cache/request/RESET_TIMESTAMPS')
|
RESET_TIMESTAMPS: type('dspace/core/cache/response/RESET_TIMESTAMPS')
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ResponseCacheAddAction implements Action {
|
export class ResponseCacheAddAction implements Action {
|
||||||
|
4
src/app/core/cache/response-cache.service.ts
vendored
4
src/app/core/cache/response-cache.service.ts
vendored
@@ -56,7 +56,9 @@ export class ResponseCacheService {
|
|||||||
|
|
||||||
this.store.select<ResponseCacheEntry>('core', 'cache', 'response', key)
|
this.store.select<ResponseCacheEntry>('core', 'cache', 'response', key)
|
||||||
.take(1)
|
.take(1)
|
||||||
.subscribe(entry => result = this.isValid(entry));
|
.subscribe(entry => {
|
||||||
|
result = this.isValid(entry);
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import { ObjectCacheService } from "./cache/object-cache.service";
|
|||||||
import { ResponseCacheService } from "./cache/response-cache.service";
|
import { ResponseCacheService } from "./cache/response-cache.service";
|
||||||
import { CollectionDataService } from "./data/collection-data.service";
|
import { CollectionDataService } from "./data/collection-data.service";
|
||||||
import { ItemDataService } from "./data/item-data.service";
|
import { ItemDataService } from "./data/item-data.service";
|
||||||
|
import { RequestService } from "./data/request.service";
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -27,7 +28,8 @@ const PROVIDERS = [
|
|||||||
ItemDataService,
|
ItemDataService,
|
||||||
DSpaceRESTv2Service,
|
DSpaceRESTv2Service,
|
||||||
ObjectCacheService,
|
ObjectCacheService,
|
||||||
ResponseCacheService
|
ResponseCacheService,
|
||||||
|
RequestService
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -3,34 +3,43 @@ import { DataService } from "./data.service";
|
|||||||
import { Collection } from "../shared/collection.model";
|
import { Collection } from "../shared/collection.model";
|
||||||
import { ObjectCacheService } from "../cache/object-cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
import { RemoteData } from "./remote-data";
|
|
||||||
import { ItemDataService } from "./item-data.service";
|
|
||||||
import { Store } from "@ngrx/store";
|
import { Store } from "@ngrx/store";
|
||||||
import { RequestState } from "./request.reducer";
|
import { NormalizedCollection } from "../cache/models/normalized-collection.model";
|
||||||
|
import { CoreState } from "../core.reducers";
|
||||||
|
import { RequestService } from "./request.service";
|
||||||
|
import { CollectionListRDBuilder, CollectionRDBuilder } from "../cache/models/collection-builder";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CollectionDataService extends DataService<Collection> {
|
export class CollectionDataService extends DataService<Collection, NormalizedCollection> {
|
||||||
protected endpoint = '/collections';
|
protected endpoint = '/collections';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected responseCache: ResponseCacheService,
|
protected responseCache: ResponseCacheService,
|
||||||
protected store: Store<RequestState>,
|
protected requestService: RequestService,
|
||||||
protected ids: ItemDataService
|
protected store: Store<CoreState>
|
||||||
) {
|
) {
|
||||||
super(Collection);
|
super(NormalizedCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getListDataBuilder(href: string): CollectionListRDBuilder {
|
||||||
|
return new CollectionListRDBuilder (
|
||||||
|
this.objectCache,
|
||||||
|
this.responseCache,
|
||||||
|
this.requestService,
|
||||||
|
this.store,
|
||||||
|
href,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getSingleDataBuilder(href: string): CollectionRDBuilder {
|
||||||
|
return new CollectionRDBuilder (
|
||||||
|
this.objectCache,
|
||||||
|
this.responseCache,
|
||||||
|
this.requestService,
|
||||||
|
this.store,
|
||||||
|
href,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// findAll(scopeID?: string): RemoteData<Array<Collection>> {
|
|
||||||
// let remoteData = super.findAll(scopeID);
|
|
||||||
// remoteData.payload = remoteData.payload.map(collections => {
|
|
||||||
// return collections.map(collection => {
|
|
||||||
// collection.items = collection.itemLinks.map(item => {
|
|
||||||
// return this.ids.findById(item.self);
|
|
||||||
// });
|
|
||||||
// return collection
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// return remoteData;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@@ -1,27 +1,30 @@
|
|||||||
import { Observable } from "rxjs";
|
|
||||||
import { ObjectCacheService } from "../cache/object-cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { isNotEmpty, hasValue } from "../../shared/empty.util";
|
import { hasValue } from "../../shared/empty.util";
|
||||||
import { GenericConstructor } from "../shared/generic-constructor";
|
import { GenericConstructor } from "../shared/generic-constructor";
|
||||||
import { RemoteData } from "./remote-data";
|
import { RemoteData } from "./remote-data";
|
||||||
import { SuccessResponse, ErrorResponse } from "../cache/response-cache.models";
|
import { FindAllRequest, FindByIDRequest, Request } from "./request.models";
|
||||||
import { FindAllRequest, FindByIDRequest } from "./request.models";
|
|
||||||
import { RequestState, RequestEntry } from "./request.reducer";
|
|
||||||
import { Store } from "@ngrx/store";
|
import { Store } from "@ngrx/store";
|
||||||
import { RequestConfigureAction, RequestExecuteAction } from "./request.actions";
|
import { RequestConfigureAction, RequestExecuteAction } from "./request.actions";
|
||||||
import { ResponseCacheEntry } from "../cache/response-cache.reducer";
|
import { CoreState } from "../core.reducers";
|
||||||
|
import { RemoteDataBuilder } from "../cache/models/remote-data-builder";
|
||||||
|
import { RequestService } from "./request.service";
|
||||||
|
|
||||||
export abstract class DataService<T extends CacheableObject> {
|
export abstract class DataService<T, U extends CacheableObject> {
|
||||||
protected abstract objectCache: ObjectCacheService;
|
protected abstract objectCache: ObjectCacheService;
|
||||||
protected abstract responseCache: ResponseCacheService;
|
protected abstract responseCache: ResponseCacheService;
|
||||||
protected abstract store: Store<RequestState>;
|
protected abstract requestService: RequestService;
|
||||||
|
protected abstract store: Store<CoreState>;
|
||||||
protected abstract endpoint: string;
|
protected abstract endpoint: string;
|
||||||
|
|
||||||
constructor(private resourceType: GenericConstructor<T>) {
|
constructor(private normalizedResourceType: GenericConstructor<U>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract getListDataBuilder(href: string): RemoteDataBuilder<T[]>;
|
||||||
|
protected abstract getSingleDataBuilder(href: string): RemoteDataBuilder<T>;
|
||||||
|
|
||||||
protected getFindAllHref(scopeID?): string {
|
protected getFindAllHref(scopeID?): string {
|
||||||
let result = this.endpoint;
|
let result = this.endpoint;
|
||||||
if (hasValue(scopeID)) {
|
if (hasValue(scopeID)) {
|
||||||
@@ -32,28 +35,12 @@ export abstract class DataService<T extends CacheableObject> {
|
|||||||
|
|
||||||
findAll(scopeID?: string): RemoteData<Array<T>> {
|
findAll(scopeID?: string): RemoteData<Array<T>> {
|
||||||
const href = this.getFindAllHref(scopeID);
|
const href = this.getFindAllHref(scopeID);
|
||||||
const request = new FindAllRequest(href, this.resourceType, scopeID);
|
if (!this.responseCache.has(href) && !this.requestService.isPending(href)) {
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
const request = new FindAllRequest(href, this.normalizedResourceType, scopeID);
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
this.store.dispatch(new RequestConfigureAction(request));
|
||||||
const requestObs = this.store.select('core', 'data', 'request', href);
|
this.store.dispatch(new RequestExecuteAction(href));
|
||||||
const responseCacheObs = this.responseCache.get(href);
|
}
|
||||||
return new RemoteData(
|
return this.getListDataBuilder(href).build();
|
||||||
requestObs.map((entry: RequestEntry) => entry.requestPending).distinctUntilChanged(),
|
|
||||||
requestObs.map((entry: RequestEntry) => entry.responsePending).distinctUntilChanged(),
|
|
||||||
responseCacheObs
|
|
||||||
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful).distinctUntilChanged(),
|
|
||||||
responseCacheObs
|
|
||||||
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
|
||||||
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
|
||||||
.distinctUntilChanged(),
|
|
||||||
responseCacheObs
|
|
||||||
.filter((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
|
||||||
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
|
||||||
.flatMap((resourceUUIDs: Array<string>) => {
|
|
||||||
// use those IDs to fetch the actual objects from the ObjectCache
|
|
||||||
return this.objectCache.getList<T>(resourceUUIDs, this.resourceType);
|
|
||||||
}).distinctUntilChanged()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getFindByIDHref(resourceID): string {
|
protected getFindByIDHref(resourceID): string {
|
||||||
@@ -62,32 +49,21 @@ export abstract class DataService<T extends CacheableObject> {
|
|||||||
|
|
||||||
findById(id: string): RemoteData<T> {
|
findById(id: string): RemoteData<T> {
|
||||||
const href = this.getFindByIDHref(id);
|
const href = this.getFindByIDHref(id);
|
||||||
const request = new FindByIDRequest(href, this.resourceType, id);
|
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
const request = new FindByIDRequest(href, this.normalizedResourceType, id);
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
this.store.dispatch(new RequestConfigureAction(request));
|
||||||
const requestObs = this.store.select('core', 'data', 'request', href);
|
this.store.dispatch(new RequestExecuteAction(href));
|
||||||
const responseCacheObs = this.responseCache.get(href);
|
}
|
||||||
return new RemoteData(
|
return this.getSingleDataBuilder(href).build();
|
||||||
requestObs.map((entry: RequestEntry) => entry.requestPending).distinctUntilChanged(),
|
}
|
||||||
requestObs.map((entry: RequestEntry) => entry.responsePending).distinctUntilChanged(),
|
|
||||||
responseCacheObs
|
findByHref(href: string): RemoteData<T> {
|
||||||
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful).distinctUntilChanged(),
|
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
|
||||||
responseCacheObs
|
const request = new Request(href, this.normalizedResourceType);
|
||||||
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
this.store.dispatch(new RequestConfigureAction(request));
|
||||||
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
this.store.dispatch(new RequestExecuteAction(href));
|
||||||
.distinctUntilChanged(),
|
}
|
||||||
responseCacheObs
|
return this.getSingleDataBuilder(href).build();
|
||||||
.filter((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
|
||||||
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
|
||||||
.flatMap((resourceUUIDs: Array<string>) => {
|
|
||||||
if (isNotEmpty(resourceUUIDs)) {
|
|
||||||
return this.objectCache.get<T>(resourceUUIDs[0], this.resourceType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Observable.of(undefined);
|
|
||||||
}
|
|
||||||
}).distinctUntilChanged()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -4,18 +4,41 @@ import { Item } from "../shared/item.model";
|
|||||||
import { ObjectCacheService } from "../cache/object-cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
import { Store } from "@ngrx/store";
|
import { Store } from "@ngrx/store";
|
||||||
import { RequestState } from "./request.reducer";
|
import { CoreState } from "../core.reducers";
|
||||||
|
import { NormalizedItem } from "../cache/models/normalized-item.model";
|
||||||
|
import { RequestService } from "./request.service";
|
||||||
|
import { ItemListRDBuilder, ItemRDBuilder } from "../cache/models/item-builder";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ItemDataService extends DataService<Item> {
|
export class ItemDataService extends DataService<Item, NormalizedItem> {
|
||||||
protected endpoint = '/items';
|
protected endpoint = '/items';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected responseCache: ResponseCacheService,
|
protected responseCache: ResponseCacheService,
|
||||||
protected store: Store<RequestState>
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>
|
||||||
) {
|
) {
|
||||||
super(Item);
|
super(NormalizedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getListDataBuilder(href: string): ItemListRDBuilder {
|
||||||
|
return new ItemListRDBuilder(
|
||||||
|
this.objectCache,
|
||||||
|
this.responseCache,
|
||||||
|
this.requestService,
|
||||||
|
this.store,
|
||||||
|
href,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getSingleDataBuilder(href: string): ItemRDBuilder {
|
||||||
|
return new ItemRDBuilder(
|
||||||
|
this.objectCache,
|
||||||
|
this.responseCache,
|
||||||
|
this.requestService,
|
||||||
|
this.store,
|
||||||
|
href,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,8 +11,8 @@ export enum RemoteDataState {
|
|||||||
* A class to represent the state of a remote resource
|
* A class to represent the state of a remote resource
|
||||||
*/
|
*/
|
||||||
export class RemoteData<T> {
|
export class RemoteData<T> {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
public self: string,
|
||||||
private requestPending: Observable<boolean>,
|
private requestPending: Observable<boolean>,
|
||||||
private responsePending: Observable<boolean>,
|
private responsePending: Observable<boolean>,
|
||||||
private isSuccessFul: Observable<boolean>,
|
private isSuccessFul: Observable<boolean>,
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
import { Action } from "@ngrx/store";
|
import { Action } from "@ngrx/store";
|
||||||
import { type } from "../../shared/ngrx/type";
|
import { type } from "../../shared/ngrx/type";
|
||||||
import { PaginationOptions } from "../shared/pagination-options.model";
|
|
||||||
import { SortOptions } from "../shared/sort-options.model";
|
|
||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { Request } from "./request.models";
|
import { Request } from "./request.models";
|
||||||
|
|
||||||
|
@@ -12,10 +12,11 @@ import { hasNoValue } from "../../shared/empty.util";
|
|||||||
import { GlobalConfig, GLOBAL_CONFIG } from "../../../config";
|
import { GlobalConfig, GLOBAL_CONFIG } from "../../../config";
|
||||||
import { RequestState, RequestEntry } from "./request.reducer";
|
import { RequestState, RequestEntry } from "./request.reducer";
|
||||||
import {
|
import {
|
||||||
RequestActionTypes, RequestConfigureAction, RequestExecuteAction,
|
RequestActionTypes, RequestExecuteAction,
|
||||||
RequestCompleteAction
|
RequestCompleteAction
|
||||||
} from "./request.actions";
|
} from "./request.actions";
|
||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
|
import { RequestService } from "./request.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RequestEffects {
|
export class RequestEffects {
|
||||||
@@ -26,13 +27,14 @@ export class RequestEffects {
|
|||||||
private restApi: DSpaceRESTv2Service,
|
private restApi: DSpaceRESTv2Service,
|
||||||
private objectCache: ObjectCacheService,
|
private objectCache: ObjectCacheService,
|
||||||
private responseCache: ResponseCacheService,
|
private responseCache: ResponseCacheService,
|
||||||
|
protected requestService: RequestService,
|
||||||
private store: Store<RequestState>
|
private store: Store<RequestState>
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@Effect() execute = this.actions$
|
@Effect() execute = this.actions$
|
||||||
.ofType(RequestActionTypes.EXECUTE)
|
.ofType(RequestActionTypes.EXECUTE)
|
||||||
.flatMap((action: RequestExecuteAction) => {
|
.flatMap((action: RequestExecuteAction) => {
|
||||||
return this.store.select<RequestEntry>('core', 'data', 'request', action.payload)
|
return this.requestService.get(action.payload)
|
||||||
.take(1);
|
.take(1);
|
||||||
})
|
})
|
||||||
.flatMap((entry: RequestEntry) => {
|
.flatMap((entry: RequestEntry) => {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { SortOptions } from "../shared/sort-options.model";
|
import { SortOptions } from "../cache/models/sort-options.model";
|
||||||
import { PaginationOptions } from "../shared/pagination-options.model";
|
import { PaginationOptions } from "../cache/models/pagination-options.model";
|
||||||
import { GenericConstructor } from "../shared/generic-constructor";
|
import { GenericConstructor } from "../shared/generic-constructor";
|
||||||
|
|
||||||
export class Request<T> {
|
export class Request<T> {
|
||||||
|
27
src/app/core/data/request.service.ts
Normal file
27
src/app/core/data/request.service.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { RequestEntry, RequestState } from "./request.reducer";
|
||||||
|
import { Store } from "@ngrx/store";
|
||||||
|
import { hasValue } from "../../shared/empty.util";
|
||||||
|
import { Observable } from "rxjs/Observable";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RequestService {
|
||||||
|
|
||||||
|
constructor(private store: Store<RequestState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
isPending(href: string): boolean {
|
||||||
|
let isPending = false;
|
||||||
|
this.store.select<RequestEntry>('core', 'data', 'request', href)
|
||||||
|
.take(1)
|
||||||
|
.subscribe((re: RequestEntry) => {
|
||||||
|
isPending = (hasValue(re) && !re.completed)
|
||||||
|
});
|
||||||
|
|
||||||
|
return isPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(href: string): Observable<RequestEntry> {
|
||||||
|
return this.store.select<RequestEntry>('core', 'data', 'request', href);
|
||||||
|
}
|
||||||
|
}
|
@@ -140,19 +140,20 @@ describe("DSpaceRESTv2Serializer", () => {
|
|||||||
|
|
||||||
describe("deserializeArray", () => {
|
describe("deserializeArray", () => {
|
||||||
|
|
||||||
it("should turn a valid document describing a collection of objects in to an array of valid models", () => {
|
//TODO rewrite to incorporate normalisation.
|
||||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
// it("should turn a valid document describing a collection of objects in to an array of valid models", () => {
|
||||||
const doc = {
|
// const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||||
"_embedded": testResponses
|
// const doc = {
|
||||||
};
|
// "_embedded": testResponses
|
||||||
|
// };
|
||||||
const models = serializer.deserializeArray(doc);
|
//
|
||||||
|
// const models = serializer.deserializeArray(doc);
|
||||||
expect(models[0].id).toBe(doc._embedded[0].id);
|
//
|
||||||
expect(models[0].name).toBe(doc._embedded[0].name);
|
// expect(models[0].id).toBe(doc._embedded[0].id);
|
||||||
expect(models[1].id).toBe(doc._embedded[1].id);
|
// expect(models[0].name).toBe(doc._embedded[0].name);
|
||||||
expect(models[1].name).toBe(doc._embedded[1].name);
|
// expect(models[1].id).toBe(doc._embedded[1].id);
|
||||||
});
|
// expect(models[1].name).toBe(doc._embedded[1].name);
|
||||||
|
// });
|
||||||
|
|
||||||
//TODO cant implement/test this yet - depends on how relationships
|
//TODO cant implement/test this yet - depends on how relationships
|
||||||
// will be handled in the rest api
|
// will be handled in the rest api
|
||||||
|
@@ -55,7 +55,7 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
|
|||||||
if (Array.isArray(response._embedded)) {
|
if (Array.isArray(response._embedded)) {
|
||||||
throw new Error('Expected a single model, use deserializeArray() instead');
|
throw new Error('Expected a single model, use deserializeArray() instead');
|
||||||
}
|
}
|
||||||
let normalized = Object.assign({}, response._embedded, this.normalizeLinks(response._links));
|
let normalized = Object.assign({}, response._embedded, this.normalizeLinks(response._embedded._links));
|
||||||
return <T> Deserialize(normalized, this.modelType);
|
return <T> Deserialize(normalized, this.modelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
|
|||||||
for (let link in normalizedLinks) {
|
for (let link in normalizedLinks) {
|
||||||
if (Array.isArray(normalizedLinks[link])) {
|
if (Array.isArray(normalizedLinks[link])) {
|
||||||
normalizedLinks[link] = normalizedLinks[link].map(linkedResource => {
|
normalizedLinks[link] = normalizedLinks[link].map(linkedResource => {
|
||||||
return {'self': linkedResource.href };
|
return linkedResource.href;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -1,16 +1,13 @@
|
|||||||
import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize";
|
|
||||||
import { DSpaceObject } from "./dspace-object.model";
|
import { DSpaceObject } from "./dspace-object.model";
|
||||||
import { Bitstream } from "./bitstream.model";
|
import { Bitstream } from "./bitstream.model";
|
||||||
import { Item } from "./item.model";
|
import { Item } from "./item.model";
|
||||||
import { RemoteData } from "../data/remote-data";
|
import { RemoteData } from "../data/remote-data";
|
||||||
|
|
||||||
@inheritSerialization(DSpaceObject)
|
|
||||||
export class Collection extends DSpaceObject {
|
export class Collection extends DSpaceObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string representing the unique handle of this Collection
|
* A string representing the unique handle of this Collection
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
|
||||||
handle: string;
|
handle: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,7 +65,6 @@ export class Collection extends DSpaceObject {
|
|||||||
*/
|
*/
|
||||||
owner: Collection;
|
owner: Collection;
|
||||||
|
|
||||||
@autoserializeAs(RemoteData)
|
items: Array<RemoteData<Item>>;
|
||||||
items: RemoteData<Item[]>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,22 +1,3 @@
|
|||||||
<div class="home">
|
<div class="home">
|
||||||
<div *ngIf="collections">
|
Home component
|
||||||
<h3>Collections</h3>
|
|
||||||
<p *ngIf="(collections.isLoading | async)">Loading…</p>
|
|
||||||
<p *ngIf="(collections.hasFailed | async)">Failed: {{(remoteData.errorMessage | async)}}</p>
|
|
||||||
<ul *ngIf="(collections.hasSucceeded | async)">
|
|
||||||
<li *ngFor="let collection of (collections.payload | async)">
|
|
||||||
{{collection?.name}}<br>
|
|
||||||
<span class="text-muted">{{collection?.shortDescription}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="items">
|
|
||||||
<h3>Items</h3>
|
|
||||||
<ul>
|
|
||||||
<li *ngFor="let item of (items.payload | async)">
|
|
||||||
{{item?.name}}<br>
|
|
||||||
<span class="text-muted">{{item?.findMetadata('dc.description.abstract')}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,11 +1,4 @@
|
|||||||
import { Component, ChangeDetectionStrategy, ViewEncapsulation, OnInit } from '@angular/core';
|
import { Component, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
|
||||||
import { Observable } from "rxjs";
|
|
||||||
import { Collection } from "../core/shared/collection.model";
|
|
||||||
import { Item } from "../core/shared/item.model";
|
|
||||||
import { CollectionDataService } from "../core/data/collection-data.service";
|
|
||||||
import { ItemDataService } from "../core/data/item-data.service";
|
|
||||||
import { ObjectCacheService } from "../core/cache/object-cache.service";
|
|
||||||
import { RemoteData } from "../core/data/remote-data";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
changeDetection: ChangeDetectionStrategy.Default,
|
changeDetection: ChangeDetectionStrategy.Default,
|
||||||
@@ -14,16 +7,11 @@ import { RemoteData } from "../core/data/remote-data";
|
|||||||
styleUrls: ['./home.component.css'],
|
styleUrls: ['./home.component.css'],
|
||||||
templateUrl: './home.component.html'
|
templateUrl: './home.component.html'
|
||||||
})
|
})
|
||||||
export class HomeComponent implements OnInit {
|
export class HomeComponent {
|
||||||
data: any = {};
|
|
||||||
collections: RemoteData<Collection[]>;
|
|
||||||
items: RemoteData<Item[]>;
|
|
||||||
|
|
||||||
constructor(
|
data: any = {};
|
||||||
private cds: CollectionDataService,
|
|
||||||
private ids: ItemDataService,
|
constructor() {
|
||||||
private objectCache: ObjectCacheService
|
|
||||||
) {
|
|
||||||
this.universalInit();
|
this.universalInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,13 +19,4 @@ export class HomeComponent implements OnInit {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.collections = this.cds.findAll();
|
|
||||||
this.items = this.ids.findAll();
|
|
||||||
this.cds.findById('5179').payload.subscribe(o => console.log('collection 1', o));
|
|
||||||
this.cds.findById('6547').payload.subscribe(o => console.log('collection 2', o));
|
|
||||||
this.ids.findById('8871').payload.subscribe(o => console.log('item 1', o));
|
|
||||||
this.ids.findById('9978').payload.subscribe(o => console.log('item 2', o));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -124,5 +124,5 @@ app.get('*', function(req, res) {
|
|||||||
|
|
||||||
// Server
|
// Server
|
||||||
let server = app.listen(app.get('port'), app.get('address'), () => {
|
let server = app.listen(app.get('port'), app.get('address'), () => {
|
||||||
console.log(`Listening on: ${EnvConfig.ui.ssl ? 'https://' : 'http://'}://${server.address().address}:${server.address().port}`);
|
console.log(`[${new Date().toTimeString()}] Listening on ${EnvConfig.ui.ssl ? 'https://' : 'http://'}${server.address().address}:${server.address().port}`);
|
||||||
});
|
});
|
||||||
|
@@ -118,5 +118,5 @@ app.get('*', function(req, res) {
|
|||||||
|
|
||||||
// Server
|
// Server
|
||||||
let server = app.listen(app.get('port'), app.get('address'), () => {
|
let server = app.listen(app.get('port'), app.get('address'), () => {
|
||||||
console.log(`Listening on: ${EnvConfig.ui.ssl ? 'https://' : 'http://'}://${server.address().address}:${server.address().port}`);
|
console.log(`[${new Date().toTimeString()}] Listening on ${EnvConfig.ui.ssl ? 'https://' : 'http://'}${server.address().address}:${server.address().port}`);
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user