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 d01959d3dd..727eef41d4 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -70,10 +70,10 @@ export class RemoteDataBuildService { this.objectCache.getBySelfLink(href, normalizedType).startWith(undefined), responseCacheObs .filter((entry: ResponseCacheEntry) => entry.response.isSuccessful) - .map((entry: ResponseCacheEntry) => (entry.response as SuccessResponse).resourceUUIDs) - .flatMap((resourceUUIDs: string[]) => { - if (isNotEmpty(resourceUUIDs)) { - return this.objectCache.get(resourceUUIDs[0], normalizedType); + .map((entry: ResponseCacheEntry) => (entry.response as SuccessResponse).resourceSelfLinks) + .flatMap((resourceSelfLinks: string[]) => { + if (isNotEmpty(resourceSelfLinks)) { + return this.objectCache.getBySelfLink(resourceSelfLinks[0], normalizedType); } else { return Observable.of(undefined); } @@ -137,7 +137,7 @@ export class RemoteDataBuildService { const payload = responseCacheObs .filter((entry: ResponseCacheEntry) => entry.response.isSuccessful) - .map((entry: ResponseCacheEntry) => (entry.response as SuccessResponse).resourceUUIDs) + .map((entry: ResponseCacheEntry) => (entry.response as SuccessResponse).resourceSelfLinks) .flatMap((resourceUUIDs: string[]) => { return this.objectCache.getList(resourceUUIDs, normalizedType) .map((normList: TNormalized[]) => { diff --git a/src/app/core/cache/object-cache.reducer.spec.ts b/src/app/core/cache/object-cache.reducer.spec.ts index d02e1faab7..2c059c4dd3 100644 --- a/src/app/core/cache/object-cache.reducer.spec.ts +++ b/src/app/core/cache/object-cache.reducer.spec.ts @@ -16,26 +16,26 @@ class NullAction extends RemoveFromObjectCacheAction { } describe('objectCacheReducer', () => { - const uuid1 = '1698f1d3-be98-4c51-9fd8-6bfedcbd59b7'; - const uuid2 = '28b04544-1766-4e82-9728-c4e93544ecd3'; + const selfLink1 = 'https://localhost:8080/api/core/items/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7'; + const selfLink2 = 'https://localhost:8080/api/core/items/28b04544-1766-4e82-9728-c4e93544ecd3'; const testState = { - [uuid1]: { + [selfLink1]: { data: { - uuid: uuid1, + self: selfLink1, foo: 'bar' }, timeAdded: new Date().getTime(), msToLive: 900000, - requestHref: 'https://rest.api/endpoint/uuid1' + requestHref: selfLink1 }, - [uuid2]: { + [selfLink2]: { data: { - uuid: uuid2, + self: selfLink2, foo: 'baz' }, timeAdded: new Date().getTime(), msToLive: 900000, - requestHref: 'https://rest.api/endpoint/uuid2' + requestHref: selfLink2 } }; deepFreeze(testState); @@ -56,38 +56,38 @@ describe('objectCacheReducer', () => { it('should add the payload to the cache in response to an ADD action', () => { const state = Object.create(null); - const objectToCache = { uuid: uuid1 }; + const objectToCache = { self: selfLink1 }; const timeAdded = new Date().getTime(); const msToLive = 900000; - const requestHref = 'https://rest.api/endpoint/uuid1'; + const requestHref = 'https://rest.api/endpoint/selfLink1'; const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive, requestHref); const newState = objectCacheReducer(state, action); - expect(newState[uuid1].data).toEqual(objectToCache); - expect(newState[uuid1].timeAdded).toEqual(timeAdded); - expect(newState[uuid1].msToLive).toEqual(msToLive); + expect(newState[selfLink1].data).toEqual(objectToCache); + expect(newState[selfLink1].timeAdded).toEqual(timeAdded); + expect(newState[selfLink1].msToLive).toEqual(msToLive); }); it('should overwrite an object in the cache in response to an ADD action if it already exists', () => { - const objectToCache = { uuid: uuid1, foo: 'baz', somethingElse: true }; + const objectToCache = { self: selfLink1, foo: 'baz', somethingElse: true }; const timeAdded = new Date().getTime(); const msToLive = 900000; - const requestHref = 'https://rest.api/endpoint/uuid1'; + const requestHref = 'https://rest.api/endpoint/selfLink1'; const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive, requestHref); const newState = objectCacheReducer(testState, action); /* tslint:disable:no-string-literal */ - expect(newState[uuid1].data['foo']).toBe('baz'); - expect(newState[uuid1].data['somethingElse']).toBe(true); + expect(newState[selfLink1].data['foo']).toBe('baz'); + expect(newState[selfLink1].data['somethingElse']).toBe(true); /* tslint:enable:no-string-literal */ }); it('should perform the ADD action without affecting the previous state', () => { const state = Object.create(null); - const objectToCache = { uuid: uuid1 }; + const objectToCache = { self: selfLink1 }; const timeAdded = new Date().getTime(); const msToLive = 900000; - const requestHref = 'https://rest.api/endpoint/uuid1'; + const requestHref = 'https://rest.api/endpoint/selfLink1'; const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive, requestHref); deepFreeze(state); @@ -95,11 +95,11 @@ describe('objectCacheReducer', () => { }); it('should remove the specified object from the cache in response to the REMOVE action', () => { - const action = new RemoveFromObjectCacheAction(uuid1); + const action = new RemoveFromObjectCacheAction(selfLink1); const newState = objectCacheReducer(testState, action); - expect(testState[uuid1]).not.toBeUndefined(); - expect(newState[uuid1]).toBeUndefined(); + expect(testState[selfLink1]).not.toBeUndefined(); + expect(newState[selfLink1]).toBeUndefined(); }); it("shouldn't do anything in response to the REMOVE action for an object that isn't cached", () => { @@ -112,7 +112,7 @@ describe('objectCacheReducer', () => { }); it('should perform the REMOVE action without affecting the previous state', () => { - const action = new RemoveFromObjectCacheAction(uuid1); + const action = new RemoveFromObjectCacheAction(selfLink1); // testState has already been frozen above objectCacheReducer(testState, action); }); diff --git a/src/app/core/cache/object-cache.reducer.ts b/src/app/core/cache/object-cache.reducer.ts index 494db4c34d..3af7209b24 100644 --- a/src/app/core/cache/object-cache.reducer.ts +++ b/src/app/core/cache/object-cache.reducer.ts @@ -8,11 +8,11 @@ import { CacheEntry } from './cache-entry'; /** * An interface to represent objects that can be cached * - * A cacheable object should have a uuid + * A cacheable object should have a self link */ export interface CacheableObject { - uuid: string; - self?: string; + uuid?: string; + self: string; } /** @@ -28,11 +28,11 @@ export class ObjectCacheEntry implements CacheEntry { /** * The ObjectCache State * - * Consists of a map with UUIDs as keys, + * Consists of a map with self links as keys, * and ObjectCacheEntries as values */ export interface ObjectCacheState { - [uuid: string]: ObjectCacheEntry + [href: string]: ObjectCacheEntry } // Object.create(null) ensures the object has no default js properties (e.g. `__proto__`) @@ -81,7 +81,7 @@ export function objectCacheReducer(state = initialState, action: ObjectCacheActi */ function addToObjectCache(state: ObjectCacheState, action: AddToObjectCacheAction): ObjectCacheState { return Object.assign({}, state, { - [action.payload.objectToCache.uuid]: { + [action.payload.objectToCache.self]: { data: action.payload.objectToCache, timeAdded: action.payload.timeAdded, msToLive: action.payload.msToLive, diff --git a/src/app/core/cache/object-cache.service.spec.ts b/src/app/core/cache/object-cache.service.spec.ts index 54b49d3cf6..2cf7eebd0a 100644 --- a/src/app/core/cache/object-cache.service.spec.ts +++ b/src/app/core/cache/object-cache.service.spec.ts @@ -8,12 +8,12 @@ import { CoreState } from '../core.reducers'; class TestClass implements CacheableObject { constructor( - public uuid: string, + public self: string, public foo: string ) { } test(): string { - return this.foo + this.uuid; + return this.foo + this.self; } } @@ -21,12 +21,11 @@ describe('ObjectCacheService', () => { let service: ObjectCacheService; let store: Store; - const uuid = '1698f1d3-be98-4c51-9fd8-6bfedcbd59b7'; - const requestHref = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7'; + const selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7'; const timestamp = new Date().getTime(); const msToLive = 900000; const objectToCache = { - uuid: uuid, + self: selfLink, foo: 'bar' }; const cacheEntry = { @@ -48,73 +47,73 @@ describe('ObjectCacheService', () => { describe('add', () => { it('should dispatch an ADD action with the object to add, the time to live, and the current timestamp', () => { - service.add(objectToCache, msToLive, requestHref); - expect(store.dispatch).toHaveBeenCalledWith(new AddToObjectCacheAction(objectToCache, timestamp, msToLive, requestHref)); + service.add(objectToCache, msToLive, selfLink); + expect(store.dispatch).toHaveBeenCalledWith(new AddToObjectCacheAction(objectToCache, timestamp, msToLive, selfLink)); }); }); describe('remove', () => { - it('should dispatch a REMOVE action with the UUID of the object to remove', () => { - service.remove(uuid); - expect(store.dispatch).toHaveBeenCalledWith(new RemoveFromObjectCacheAction(uuid)); + it('should dispatch a REMOVE action with the self link of the object to remove', () => { + service.remove(selfLink); + expect(store.dispatch).toHaveBeenCalledWith(new RemoveFromObjectCacheAction(selfLink)); }); }); - describe('get', () => { - it('should return an observable of the cached object with the specified UUID and type', () => { + describe('getBySelfLink', () => { + it('should return an observable of the cached object with the specified self link and type', () => { spyOn(store, 'select').and.returnValue(Observable.of(cacheEntry)); let testObj: any; // due to the implementation of spyOn above, this subscribe will be synchronous - service.get(uuid, TestClass).take(1).subscribe((o) => testObj = o); - expect(testObj.uuid).toBe(uuid); + service.getBySelfLink(selfLink, TestClass).take(1).subscribe((o) => testObj = o); + expect(testObj.self).toBe(selfLink); expect(testObj.foo).toBe('bar'); // this only works if testObj is an instance of TestClass - expect(testObj.test()).toBe('bar' + uuid); + expect(testObj.test()).toBe('bar' + selfLink); }); it('should not return a cached object that has exceeded its time to live', () => { spyOn(store, 'select').and.returnValue(Observable.of(invalidCacheEntry)); let getObsHasFired = false; - const subscription = service.get(uuid, TestClass).subscribe((o) => getObsHasFired = true); + const subscription = service.getBySelfLink(selfLink, TestClass).subscribe((o) => getObsHasFired = true); expect(getObsHasFired).toBe(false); subscription.unsubscribe(); }); }); describe('getList', () => { - it('should return an observable of the array of cached objects with the specified UUID and type', () => { - spyOn(service, 'get').and.returnValue(Observable.of(new TestClass(uuid, 'bar'))); + it('should return an observable of the array of cached objects with the specified self link and type', () => { + spyOn(service, 'getBySelfLink').and.returnValue(Observable.of(new TestClass(selfLink, 'bar'))); let testObjs: any[]; - service.getList([uuid, uuid], TestClass).take(1).subscribe((arr) => testObjs = arr); - expect(testObjs[0].uuid).toBe(uuid); + service.getList([selfLink, selfLink], TestClass).take(1).subscribe((arr) => testObjs = arr); + expect(testObjs[0].self).toBe(selfLink); expect(testObjs[0].foo).toBe('bar'); - expect(testObjs[0].test()).toBe('bar' + uuid); - expect(testObjs[1].uuid).toBe(uuid); + expect(testObjs[0].test()).toBe('bar' + selfLink); + expect(testObjs[1].self).toBe(selfLink); expect(testObjs[1].foo).toBe('bar'); - expect(testObjs[1].test()).toBe('bar' + uuid); + expect(testObjs[1].test()).toBe('bar' + selfLink); }); }); describe('has', () => { - it('should return true if the object with the supplied UUID is cached and still valid', () => { + it('should return true if the object with the supplied self link is cached and still valid', () => { spyOn(store, 'select').and.returnValue(Observable.of(cacheEntry)); - expect(service.has(uuid)).toBe(true); + expect(service.hasBySelfLink(selfLink)).toBe(true); }); - it("should return false if the object with the supplied UUID isn't cached", () => { + it("should return false if the object with the supplied self link isn't cached", () => { spyOn(store, 'select').and.returnValue(Observable.of(undefined)); - expect(service.has(uuid)).toBe(false); + expect(service.hasBySelfLink(selfLink)).toBe(false); }); - it('should return false if the object with the supplied UUID is cached but has exceeded its time to live', () => { + it('should return false if the object with the supplied self link is cached but has exceeded its time to live', () => { spyOn(store, 'select').and.returnValue(Observable.of(invalidCacheEntry)); - expect(service.has(uuid)).toBe(false); + expect(service.hasBySelfLink(selfLink)).toBe(false); }); }); diff --git a/src/app/core/cache/object-cache.service.ts b/src/app/core/cache/object-cache.service.ts index 0755b268cf..31eb2d0b6a 100644 --- a/src/app/core/cache/object-cache.service.ts +++ b/src/app/core/cache/object-cache.service.ts @@ -10,12 +10,12 @@ import { GenericConstructor } from '../shared/generic-constructor'; import { CoreState } from '../core.reducers'; import { keySelector } from '../shared/selectors'; -function objectFromUuidSelector(uuid: string): MemoizedSelector { - return keySelector('data/object', uuid); +function selfLinkFromUuidSelector(uuid: string): MemoizedSelector { + return keySelector('index/uuid', uuid); } -function uuidFromHrefSelector(href: string): MemoizedSelector { - return keySelector('index/href', href); +function entryFromSelfLinkSelector(selfLink: string): MemoizedSelector { + return keySelector('data/object', selfLink); } /** @@ -35,7 +35,7 @@ export class ObjectCacheService { * @param msToLive * The number of milliseconds it should be cached for * @param requestHref - * The href of the request that resulted in this object + * The selfLink of the request that resulted in this object * This isn't necessarily the same as the object's self * link, it could have been part of a list for example */ @@ -69,55 +69,55 @@ export class ObjectCacheService { * @return Observable * An observable of the requested object */ - get(uuid: string, type: GenericConstructor): Observable { - return this.getEntry(uuid) + getByUUID(uuid: string, type: GenericConstructor): Observable { + return this.store.select(selfLinkFromUuidSelector(uuid)) + .flatMap((selfLink: string) => this.getBySelfLink(selfLink, type)) + } + + getBySelfLink(selfLink: string, type: GenericConstructor): Observable { + return this.getEntry(selfLink) .map((entry: ObjectCacheEntry) => Object.assign(new type(), entry.data) as T); } - getBySelfLink(href: string, type: GenericConstructor): Observable { - return this.store.select(uuidFromHrefSelector(href)) - .flatMap((uuid: string) => this.get(uuid, type)) - } - - private getEntry(uuid: string): Observable { - return this.store.select(objectFromUuidSelector(uuid)) + private getEntry(selfLink: string): Observable { + return this.store.select(entryFromSelfLinkSelector(selfLink)) .filter((entry) => this.isValid(entry)) .distinctUntilChanged(); } - getRequestHref(uuid: string): Observable { - return this.getEntry(uuid) + getRequestHrefBySelfLink(selfLink: string): Observable { + return this.getEntry(selfLink) .map((entry: ObjectCacheEntry) => entry.requestHref) .distinctUntilChanged(); } - getRequestHrefBySelfLink(self: string): Observable { - return this.store.select(uuidFromHrefSelector(self)) - .flatMap((uuid: string) => this.getRequestHref(uuid)); + getRequestHrefByUUID(uuid: string): Observable { + return this.store.select(selfLinkFromUuidSelector(uuid)) + .flatMap((selfLink: string) => this.getRequestHrefBySelfLink(selfLink)); } /** * Get an observable for an array of objects of the same type - * with the specified UUIDs + * with the specified self links * * The type needs to be specified as well, in order to turn * the cached plain javascript object in to an instance of * a class. * * e.g. getList([ - * 'c96588c6-72d3-425d-9d47-fa896255a695', - * 'cff860da-cf5f-4fda-b8c9-afb7ec0b2d9e' + * 'http://localhost:8080/api/core/collections/c96588c6-72d3-425d-9d47-fa896255a695', + * 'http://localhost:8080/api/core/collections/cff860da-cf5f-4fda-b8c9-afb7ec0b2d9e' * ], Collection) * - * @param uuids - * An array of UUIDs of the objects to get + * @param selfLinks + * An array of self links of the objects to get * @param type * The type of the objects to get * @return Observable> */ - getList(uuids: string[], type: GenericConstructor): Observable { + getList(selfLinks: string[], type: GenericConstructor): Observable { return Observable.combineLatest( - uuids.map((id: string) => this.get(id, type)) + selfLinks.map((selfLink: string) => this.getBySelfLink(selfLink, type)) ); } @@ -130,12 +130,12 @@ export class ObjectCacheService { * true if the object with the specified UUID is cached, * false otherwise */ - has(uuid: string): boolean { + hasByUUID(uuid: string): boolean { let result: boolean; - this.store.select(objectFromUuidSelector(uuid)) + this.store.select(selfLinkFromUuidSelector(uuid)) .take(1) - .subscribe((entry) => result = this.isValid(entry)); + .subscribe((selfLink: string) => result = this.hasBySelfLink(selfLink)); return result; } @@ -143,18 +143,18 @@ export class ObjectCacheService { /** * Check whether the object with the specified self link is cached * - * @param href + * @param selfLink * 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 { + hasBySelfLink(selfLink: string): boolean { let result = false; - this.store.select(uuidFromHrefSelector(href)) + this.store.select(entryFromSelfLinkSelector(selfLink)) .take(1) - .subscribe((uuid: string) => result = this.has(uuid)); + .subscribe((entry: ObjectCacheEntry) => result = this.isValid(entry)); return result; } @@ -175,7 +175,7 @@ export class ObjectCacheService { const timeOutdated = entry.timeAdded + entry.msToLive; const isOutDated = new Date().getTime() > timeOutdated; if (isOutDated) { - this.store.dispatch(new RemoveFromObjectCacheAction(entry.data.uuid)); + this.store.dispatch(new RemoveFromObjectCacheAction(entry.data.self)); } return !isOutDated; } diff --git a/src/app/core/cache/response-cache.models.ts b/src/app/core/cache/response-cache.models.ts index ef1bfb0925..a860d682bf 100644 --- a/src/app/core/cache/response-cache.models.ts +++ b/src/app/core/cache/response-cache.models.ts @@ -11,7 +11,7 @@ export class Response { export class SuccessResponse extends Response { constructor( - public resourceUUIDs: string[], + public resourceSelfLinks: string[], public statusCode: string, public pageInfo?: PageInfo ) { diff --git a/src/app/core/core.effects.ts b/src/app/core/core.effects.ts index 51a2cb7e06..593b17e0f5 100644 --- a/src/app/core/core.effects.ts +++ b/src/app/core/core.effects.ts @@ -1,12 +1,12 @@ import { ObjectCacheEffects } from './data/object-cache.effects'; import { RequestCacheEffects } from './data/request-cache.effects'; -import { HrefIndexEffects } from './index/href-index.effects'; +import { UUIDIndexEffects } from './index/uuid-index.effects'; import { RequestEffects } from './data/request.effects'; export const coreEffects = [ RequestCacheEffects, RequestEffects, ObjectCacheEffects, - HrefIndexEffects, + UUIDIndexEffects, ]; diff --git a/src/app/core/core.reducers.ts b/src/app/core/core.reducers.ts index 29959f7b43..493c9e96d9 100644 --- a/src/app/core/core.reducers.ts +++ b/src/app/core/core.reducers.ts @@ -2,21 +2,21 @@ import { ActionReducerMap, createFeatureSelector } from '@ngrx/store'; import { responseCacheReducer, ResponseCacheState } from './cache/response-cache.reducer'; import { objectCacheReducer, ObjectCacheState } from './cache/object-cache.reducer'; -import { hrefIndexReducer, HrefIndexState } from './index/href-index.reducer'; +import { uuidIndexReducer, UUIDIndexState } from './index/uuid-index.reducer'; import { requestReducer, RequestState } from './data/request.reducer'; export interface CoreState { 'data/object': ObjectCacheState, 'data/response': ResponseCacheState, 'data/request': RequestState, - 'index/href': HrefIndexState + 'index/uuid': UUIDIndexState } export const coreReducers: ActionReducerMap = { 'data/object': objectCacheReducer, 'data/response': responseCacheReducer, 'data/request': requestReducer, - 'index/href': hrefIndexReducer + 'index/uuid': uuidIndexReducer }; export const coreSelector = createFeatureSelector('core'); diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index 56aac053b0..3d7a724709 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -5,14 +5,13 @@ import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { RemoteData } from './remote-data'; import { FindAllOptions, FindAllRequest, FindByIDRequest, Request } from './request.models'; import { Store } from '@ngrx/store'; -import { RequestConfigureAction, RequestExecuteAction } from './request.actions'; import { CoreState } from '../core.reducers'; import { RequestService } from './request.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { GenericConstructor } from '../shared/generic-constructor'; -import { Inject } from '@angular/core'; -import { GLOBAL_CONFIG, GlobalConfig } from '../../../config'; +import { GlobalConfig } from '../../../config'; import { RESTURLCombiner } from '../url-combiner/rest-url-combiner'; +import { Observable } from 'rxjs/Observable'; export abstract class DataService { protected abstract objectCache: ObjectCacheService; @@ -30,6 +29,13 @@ export abstract class DataService } + private getEndpoint(linkName: string): Observable { + const apiUrl = new RESTURLCombiner(this.EnvConfig, '/').toString(); + this.requestService.configure(new Request(apiUrl)); + // TODO fetch from store + return Observable.of(undefined); + } + protected getFindAllHref(options: FindAllOptions = {}): string { let result; const args = []; diff --git a/src/app/core/data/request.actions.ts b/src/app/core/data/request.actions.ts index 9747294c2d..b17046005d 100644 --- a/src/app/core/data/request.actions.ts +++ b/src/app/core/data/request.actions.ts @@ -15,10 +15,10 @@ export const RequestActionTypes = { /* tslint:disable:max-classes-per-file */ export class RequestConfigureAction implements Action { type = RequestActionTypes.CONFIGURE; - payload: Request; + payload: Request; constructor( - request: Request + request: Request ) { this.payload = request; } diff --git a/src/app/core/data/request.effects.ts b/src/app/core/data/request.effects.ts index df4205bf32..c5d7eb57f0 100644 --- a/src/app/core/data/request.effects.ts +++ b/src/app/core/data/request.effects.ts @@ -57,8 +57,8 @@ export class RequestEffects { return this.restApi.get(entry.request.href) .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)) + const selfLinks = flattenSingleKeyObject(processRequestDTO).map((no) => no.self); + return new SuccessResponse(selfLinks, 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)) @@ -157,7 +157,7 @@ export class RequestEffects { } protected addToObjectCache(co: CacheableObject, requestHref: string): void { - if (hasNoValue(co) || hasNoValue(co.uuid)) { + if (hasNoValue(co) || hasNoValue(co.self)) { throw new Error('The server returned an invalid object'); } this.objectCache.add(co, this.EnvConfig.cache.msToLive, requestHref); diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts index 47888a5e61..ec29fa1c5e 100644 --- a/src/app/core/data/request.models.ts +++ b/src/app/core/data/request.models.ts @@ -3,13 +3,13 @@ import { PaginationComponentOptions } from '../../shared/pagination/pagination-c import { GenericConstructor } from '../shared/generic-constructor'; /* tslint:disable:max-classes-per-file */ -export class Request { +export class Request { constructor( public href: string, ) { } } -export class FindByIDRequest extends Request { +export class FindByIDRequest extends Request { constructor( href: string, public resourceID: string @@ -25,7 +25,7 @@ export class FindAllOptions { sort?: SortOptions; } -export class FindAllRequest extends Request { +export class FindAllRequest extends Request { constructor( href: string, public options?: FindAllOptions, diff --git a/src/app/core/data/request.reducer.ts b/src/app/core/data/request.reducer.ts index 6b84fbb77c..af7140bbf4 100644 --- a/src/app/core/data/request.reducer.ts +++ b/src/app/core/data/request.reducer.ts @@ -6,7 +6,7 @@ import { import { Request } from './request.models'; export class RequestEntry { - request: Request; + request: Request; requestPending: boolean; responsePending: boolean; completed: boolean; diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index f9f296a666..7b401ca03a 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -45,7 +45,7 @@ export class RequestService { return this.store.select(entryFromHrefSelector(href)); } - configure(request: Request): void { + configure(request: Request): void { let isCached = this.objectCache.hasBySelfLink(request.href); if (!isCached && this.responseCache.has(request.href)) { @@ -54,8 +54,8 @@ export class RequestService { this.responseCache.get(request.href) .take(1) .filter((entry: ResponseCacheEntry) => entry.response.isSuccessful) - .map((entry: ResponseCacheEntry) => (entry.response as SuccessResponse).resourceUUIDs) - .map((resourceUUIDs: string[]) => resourceUUIDs.every((uuid) => this.objectCache.has(uuid))) + .map((entry: ResponseCacheEntry) => (entry.response as SuccessResponse).resourceSelfLinks) + .map((resourceSelfLinks: string[]) => resourceSelfLinks.every((selfLink) => this.objectCache.hasBySelfLink(selfLink))) .subscribe((c) => isCached = c); } diff --git a/src/app/core/index/href-index.actions.ts b/src/app/core/index/href-index.actions.ts deleted file mode 100644 index bf854abff7..0000000000 --- a/src/app/core/index/href-index.actions.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Action } from '@ngrx/store'; - -import { type } from '../../shared/ngrx/type'; - -/** - * The list of HrefIndexAction type definitions - */ -export const HrefIndexActionTypes = { - ADD: type('dspace/core/index/href/ADD'), - REMOVE_UUID: type('dspace/core/index/href/REMOVE_UUID') -}; - -/* tslint:disable:max-classes-per-file */ -/** - * An ngrx action to add an href to the index - */ -export class AddToHrefIndexAction implements Action { - type = HrefIndexActionTypes.ADD; - payload: { - href: string; - uuid: string; - }; - - /** - * Create a new AddToHrefIndexAction - * - * @param href - * the href to add - * @param uuid - * the uuid of the resource the href links to - */ - constructor(href: string, uuid: string) { - this.payload = { href, uuid }; - } -} - -/** - * An ngrx action to remove an href from the index - */ -export class RemoveUUIDFromHrefIndexAction implements Action { - type = HrefIndexActionTypes.REMOVE_UUID; - payload: string; - - /** - * Create a new RemoveUUIDFromHrefIndexAction - * - * @param uuid - * the uuid to remove all hrefs for - */ - constructor(uuid: string) { - this.payload = uuid; - } - -} -/* tslint:enable:max-classes-per-file */ - -/** - * A type to encompass all HrefIndexActions - */ -export type HrefIndexAction = AddToHrefIndexAction | RemoveUUIDFromHrefIndexAction; diff --git a/src/app/core/index/href-index.reducer.ts b/src/app/core/index/href-index.reducer.ts deleted file mode 100644 index 160b04f5b3..0000000000 --- a/src/app/core/index/href-index.reducer.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - HrefIndexAction, - HrefIndexActionTypes, - AddToHrefIndexAction, - RemoveUUIDFromHrefIndexAction -} from './href-index.actions'; - -export interface HrefIndexState { - [href: string]: string -} - -// Object.create(null) ensures the object has no default js properties (e.g. `__proto__`) -const initialState: HrefIndexState = Object.create(null); - -export function hrefIndexReducer(state = initialState, action: HrefIndexAction): HrefIndexState { - switch (action.type) { - - case HrefIndexActionTypes.ADD: { - return addToHrefIndex(state, action as AddToHrefIndexAction); - } - - case HrefIndexActionTypes.REMOVE_UUID: { - return removeUUIDFromHrefIndex(state, action as RemoveUUIDFromHrefIndexAction) - } - - default: { - return state; - } - } -} - -function addToHrefIndex(state: HrefIndexState, action: AddToHrefIndexAction): HrefIndexState { - return Object.assign({}, state, { - [action.payload.href]: action.payload.uuid - }); -} - -function removeUUIDFromHrefIndex(state: HrefIndexState, action: RemoveUUIDFromHrefIndexAction): HrefIndexState { - const newState = Object.create(null); - for (const href in state) { - if (state[href] !== action.payload) { - newState[href] = state[href]; - } - } - return newState; -} diff --git a/src/app/core/index/uuid-index.actions.ts b/src/app/core/index/uuid-index.actions.ts new file mode 100644 index 0000000000..0bea11204c --- /dev/null +++ b/src/app/core/index/uuid-index.actions.ts @@ -0,0 +1,60 @@ +import { Action } from '@ngrx/store'; + +import { type } from '../../shared/ngrx/type'; + +/** + * The list of HrefIndexAction type definitions + */ +export const UUIDIndexActionTypes = { + ADD: type('dspace/core/index/uuid/ADD'), + REMOVE_HREF: type('dspace/core/index/uuid/REMOVE_HREF') +}; + +/* tslint:disable:max-classes-per-file */ +/** + * An ngrx action to add an href to the index + */ +export class AddToUUIDIndexAction implements Action { + type = UUIDIndexActionTypes.ADD; + payload: { + href: string; + uuid: string; + }; + + /** + * Create a new AddToUUIDIndexAction + * + * @param uuid + * the uuid to add + * @param href + * the self link of the resource the uuid belongs to + */ + constructor(uuid: string, href: string) { + this.payload = { href, uuid }; + } +} + +/** + * An ngrx action to remove an href from the index + */ +export class RemoveHrefFromUUIDIndexAction implements Action { + type = UUIDIndexActionTypes.REMOVE_HREF; + payload: string; + + /** + * Create a new RemoveHrefFromUUIDIndexAction + * + * @param href + * the href to remove the UUID for + */ + constructor(href: string) { + this.payload = href; + } + +} +/* tslint:enable:max-classes-per-file */ + +/** + * A type to encompass all HrefIndexActions + */ +export type UUIDIndexAction = AddToUUIDIndexAction | RemoveHrefFromUUIDIndexAction; diff --git a/src/app/core/index/href-index.effects.ts b/src/app/core/index/uuid-index.effects.ts similarity index 66% rename from src/app/core/index/href-index.effects.ts rename to src/app/core/index/uuid-index.effects.ts index f7a4ad5d91..2f5900ed04 100644 --- a/src/app/core/index/href-index.effects.ts +++ b/src/app/core/index/uuid-index.effects.ts @@ -5,26 +5,26 @@ import { ObjectCacheActionTypes, AddToObjectCacheAction, RemoveFromObjectCacheAction } from '../cache/object-cache.actions'; -import { AddToHrefIndexAction, RemoveUUIDFromHrefIndexAction } from './href-index.actions'; +import { AddToUUIDIndexAction, RemoveHrefFromUUIDIndexAction } from './uuid-index.actions'; import { hasValue } from '../../shared/empty.util'; @Injectable() -export class HrefIndexEffects { +export class UUIDIndexEffects { @Effect() add$ = this.actions$ .ofType(ObjectCacheActionTypes.ADD) - .filter((action: AddToObjectCacheAction) => hasValue(action.payload.objectToCache.self)) + .filter((action: AddToObjectCacheAction) => hasValue(action.payload.objectToCache.uuid)) .map((action: AddToObjectCacheAction) => { - return new AddToHrefIndexAction( - action.payload.objectToCache.self, - action.payload.objectToCache.uuid + return new AddToUUIDIndexAction( + action.payload.objectToCache.uuid, + action.payload.objectToCache.self ); }); @Effect() remove$ = this.actions$ .ofType(ObjectCacheActionTypes.REMOVE) .map((action: RemoveFromObjectCacheAction) => { - return new RemoveUUIDFromHrefIndexAction(action.payload); + return new RemoveHrefFromUUIDIndexAction(action.payload); }); constructor(private actions$: Actions) { diff --git a/src/app/core/index/uuid-index.reducer.ts b/src/app/core/index/uuid-index.reducer.ts new file mode 100644 index 0000000000..191dd8f463 --- /dev/null +++ b/src/app/core/index/uuid-index.reducer.ts @@ -0,0 +1,46 @@ +import { + UUIDIndexAction, + UUIDIndexActionTypes, + AddToUUIDIndexAction, + RemoveHrefFromUUIDIndexAction +} from './uuid-index.actions'; + +export interface UUIDIndexState { + [uuid: string]: string +} + +// Object.create(null) ensures the object has no default js properties (e.g. `__proto__`) +const initialState: UUIDIndexState = Object.create(null); + +export function uuidIndexReducer(state = initialState, action: UUIDIndexAction): UUIDIndexState { + switch (action.type) { + + case UUIDIndexActionTypes.ADD: { + return addToUUIDIndex(state, action as AddToUUIDIndexAction); + } + + case UUIDIndexActionTypes.REMOVE_HREF: { + return removeHrefFromUUIDIndex(state, action as RemoveHrefFromUUIDIndexAction) + } + + default: { + return state; + } + } +} + +function addToUUIDIndex(state: UUIDIndexState, action: AddToUUIDIndexAction): UUIDIndexState { + return Object.assign({}, state, { + [action.payload.uuid]: action.payload.href + }); +} + +function removeHrefFromUUIDIndex(state: UUIDIndexState, action: RemoveHrefFromUUIDIndexAction): UUIDIndexState { + const newState = Object.create(null); + for (const uuid in state) { + if (state[uuid] !== action.payload) { + newState[uuid] = state[uuid]; + } + } + return newState; +}