mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-14 13:33:03 +00:00
requestCacheReducer docs & tests
This commit is contained in:
37
src/app/core/cache/object-cache.actions.ts
vendored
37
src/app/core/cache/object-cache.actions.ts
vendored
@@ -2,12 +2,18 @@ import { Action } from "@ngrx/store";
|
|||||||
import { type } from "../../shared/ngrx/type";
|
import { type } from "../../shared/ngrx/type";
|
||||||
import { CacheableObject } from "./object-cache.reducer";
|
import { CacheableObject } from "./object-cache.reducer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of ObjectCacheAction type definitions
|
||||||
|
*/
|
||||||
export const ObjectCacheActionTypes = {
|
export const ObjectCacheActionTypes = {
|
||||||
ADD: type('dspace/core/cache/object/ADD'),
|
ADD: type('dspace/core/cache/object/ADD'),
|
||||||
REMOVE: type('dspace/core/cache/object/REMOVE'),
|
REMOVE: type('dspace/core/cache/object/REMOVE'),
|
||||||
RESET_TIMESTAMPS: type('dspace/core/cache/object/RESET_TIMESTAMPS')
|
RESET_TIMESTAMPS: type('dspace/core/cache/object/RESET_TIMESTAMPS')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to add an object to the cache
|
||||||
|
*/
|
||||||
export class AddToObjectCacheAction implements Action {
|
export class AddToObjectCacheAction implements Action {
|
||||||
type = ObjectCacheActionTypes.ADD;
|
type = ObjectCacheActionTypes.ADD;
|
||||||
payload: {
|
payload: {
|
||||||
@@ -16,29 +22,60 @@ export class AddToObjectCacheAction implements Action {
|
|||||||
msToLive: number;
|
msToLive: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new AddToObjectCacheAction
|
||||||
|
*
|
||||||
|
* @param objectToCache
|
||||||
|
* the object to add
|
||||||
|
* @param timeAdded
|
||||||
|
* the time it was added
|
||||||
|
* @param msToLive
|
||||||
|
* the amount of milliseconds before it should expire
|
||||||
|
*/
|
||||||
constructor(objectToCache: CacheableObject, timeAdded: number, msToLive: number) {
|
constructor(objectToCache: CacheableObject, timeAdded: number, msToLive: number) {
|
||||||
this.payload = { objectToCache, timeAdded, msToLive };
|
this.payload = { objectToCache, timeAdded, msToLive };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to remove an object from the cache
|
||||||
|
*/
|
||||||
export class RemoveFromObjectCacheAction implements Action {
|
export class RemoveFromObjectCacheAction implements Action {
|
||||||
type = ObjectCacheActionTypes.REMOVE;
|
type = ObjectCacheActionTypes.REMOVE;
|
||||||
payload: string;
|
payload: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RemoveFromObjectCacheAction
|
||||||
|
*
|
||||||
|
* @param uuid
|
||||||
|
* the UUID of the object to remove
|
||||||
|
*/
|
||||||
constructor(uuid: string) {
|
constructor(uuid: string) {
|
||||||
this.payload = uuid;
|
this.payload = uuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to reset the timeAdded property of all cached objects
|
||||||
|
*/
|
||||||
export class ResetObjectCacheTimestampsAction implements Action {
|
export class ResetObjectCacheTimestampsAction implements Action {
|
||||||
type = ObjectCacheActionTypes.RESET_TIMESTAMPS;
|
type = ObjectCacheActionTypes.RESET_TIMESTAMPS;
|
||||||
payload: number;
|
payload: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ResetObjectCacheTimestampsAction
|
||||||
|
*
|
||||||
|
* @param newTimestamp
|
||||||
|
* the new timeAdded all objects should get
|
||||||
|
*/
|
||||||
constructor(newTimestamp: number) {
|
constructor(newTimestamp: number) {
|
||||||
this.payload = newTimestamp;
|
this.payload = newTimestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type to encompass all ObjectCacheActions
|
||||||
|
*/
|
||||||
export type ObjectCacheAction
|
export type ObjectCacheAction
|
||||||
= AddToObjectCacheAction
|
= AddToObjectCacheAction
|
||||||
| RemoveFromObjectCacheAction
|
| RemoveFromObjectCacheAction
|
||||||
|
@@ -95,9 +95,11 @@ describe("objectCacheReducer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("shouldn't do anything in response to the REMOVE action for an object that isn't cached", () => {
|
it("shouldn't do anything in response to the REMOVE action for an object that isn't cached", () => {
|
||||||
const action = new RemoveFromObjectCacheAction("this isn't cached");
|
const wrongKey = "this isn't cached";
|
||||||
|
const action = new RemoveFromObjectCacheAction(wrongKey);
|
||||||
const newState = objectCacheReducer(testState, action);
|
const newState = objectCacheReducer(testState, action);
|
||||||
|
|
||||||
|
expect(testState[wrongKey]).toBeUndefined();
|
||||||
expect(newState).toEqual(testState);
|
expect(newState).toEqual(testState);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
83
src/app/core/cache/request-cache.actions.ts
vendored
83
src/app/core/cache/request-cache.actions.ts
vendored
@@ -4,6 +4,9 @@ import { type } from "../../shared/ngrx/type";
|
|||||||
import { PaginationOptions } from "../shared/pagination-options.model";
|
import { PaginationOptions } from "../shared/pagination-options.model";
|
||||||
import { SortOptions } from "../shared/sort-options.model";
|
import { SortOptions } from "../shared/sort-options.model";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of RequestCacheAction type definitions
|
||||||
|
*/
|
||||||
export const RequestCacheActionTypes = {
|
export const RequestCacheActionTypes = {
|
||||||
FIND_BY_ID: type('dspace/core/cache/request/FIND_BY_ID'),
|
FIND_BY_ID: type('dspace/core/cache/request/FIND_BY_ID'),
|
||||||
FIND_ALL: type('dspace/core/cache/request/FIND_ALL'),
|
FIND_ALL: type('dspace/core/cache/request/FIND_ALL'),
|
||||||
@@ -13,6 +16,9 @@ export const RequestCacheActionTypes = {
|
|||||||
RESET_TIMESTAMPS: type('dspace/core/cache/request/RESET_TIMESTAMPS')
|
RESET_TIMESTAMPS: type('dspace/core/cache/request/RESET_TIMESTAMPS')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to find all objects of a certain type
|
||||||
|
*/
|
||||||
export class RequestCacheFindAllAction implements Action {
|
export class RequestCacheFindAllAction implements Action {
|
||||||
type = RequestCacheActionTypes.FIND_ALL;
|
type = RequestCacheActionTypes.FIND_ALL;
|
||||||
payload: {
|
payload: {
|
||||||
@@ -23,6 +29,20 @@ export class RequestCacheFindAllAction implements Action {
|
|||||||
sortOptions: SortOptions
|
sortOptions: SortOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RequestCacheFindAllAction
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* the key under which to cache this request, should be unique
|
||||||
|
* @param service
|
||||||
|
* the name of the service that initiated the action
|
||||||
|
* @param scopeID
|
||||||
|
* the id of an optional scope object
|
||||||
|
* @param paginationOptions
|
||||||
|
* the pagination options
|
||||||
|
* @param sortOptions
|
||||||
|
* the sort options
|
||||||
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
key: string,
|
key: string,
|
||||||
service: OpaqueToken,
|
service: OpaqueToken,
|
||||||
@@ -40,6 +60,9 @@ export class RequestCacheFindAllAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to find objects by id
|
||||||
|
*/
|
||||||
export class RequestCacheFindByIDAction implements Action {
|
export class RequestCacheFindByIDAction implements Action {
|
||||||
type = RequestCacheActionTypes.FIND_BY_ID;
|
type = RequestCacheActionTypes.FIND_BY_ID;
|
||||||
payload: {
|
payload: {
|
||||||
@@ -48,6 +71,16 @@ export class RequestCacheFindByIDAction implements Action {
|
|||||||
resourceID: string
|
resourceID: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RequestCacheFindByIDAction
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* the key under which to cache this request, should be unique
|
||||||
|
* @param service
|
||||||
|
* the name of the service that initiated the action
|
||||||
|
* @param resourceID
|
||||||
|
* the ID of the resource to find
|
||||||
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
key: string,
|
key: string,
|
||||||
service: OpaqueToken,
|
service: OpaqueToken,
|
||||||
@@ -61,6 +94,9 @@ export class RequestCacheFindByIDAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to indicate a request was returned successful
|
||||||
|
*/
|
||||||
export class RequestCacheSuccessAction implements Action {
|
export class RequestCacheSuccessAction implements Action {
|
||||||
type = RequestCacheActionTypes.SUCCESS;
|
type = RequestCacheActionTypes.SUCCESS;
|
||||||
payload: {
|
payload: {
|
||||||
@@ -70,6 +106,20 @@ export class RequestCacheSuccessAction implements Action {
|
|||||||
msToLive: number
|
msToLive: number
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RequestCacheSuccessAction
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* the key under which cache this request is cached,
|
||||||
|
* should be identical to the one used in the corresponding
|
||||||
|
* find action
|
||||||
|
* @param resourceUUIDs
|
||||||
|
* the UUIDs returned from the backend
|
||||||
|
* @param timeAdded
|
||||||
|
* the time it was returned
|
||||||
|
* @param msToLive
|
||||||
|
* the amount of milliseconds before it should expire
|
||||||
|
*/
|
||||||
constructor(key: string, resourceUUIDs: Array<string>, timeAdded, msToLive: number) {
|
constructor(key: string, resourceUUIDs: Array<string>, timeAdded, msToLive: number) {
|
||||||
this.payload = {
|
this.payload = {
|
||||||
key,
|
key,
|
||||||
@@ -80,6 +130,9 @@ export class RequestCacheSuccessAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to indicate a request failed
|
||||||
|
*/
|
||||||
export class RequestCacheErrorAction implements Action {
|
export class RequestCacheErrorAction implements Action {
|
||||||
type = RequestCacheActionTypes.ERROR;
|
type = RequestCacheActionTypes.ERROR;
|
||||||
payload: {
|
payload: {
|
||||||
@@ -87,6 +140,16 @@ export class RequestCacheErrorAction implements Action {
|
|||||||
errorMessage: string
|
errorMessage: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RequestCacheErrorAction
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* the key under which cache this request is cached,
|
||||||
|
* should be identical to the one used in the corresponding
|
||||||
|
* find action
|
||||||
|
* @param errorMessage
|
||||||
|
* A message describing the reason the request failed
|
||||||
|
*/
|
||||||
constructor(key: string, errorMessage: string) {
|
constructor(key: string, errorMessage: string) {
|
||||||
this.payload = {
|
this.payload = {
|
||||||
key,
|
key,
|
||||||
@@ -95,24 +158,44 @@ export class RequestCacheErrorAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to remove a request from the cache
|
||||||
|
*/
|
||||||
export class RequestCacheRemoveAction implements Action {
|
export class RequestCacheRemoveAction implements Action {
|
||||||
type = RequestCacheActionTypes.REMOVE;
|
type = RequestCacheActionTypes.REMOVE;
|
||||||
payload: string;
|
payload: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RequestCacheRemoveAction
|
||||||
|
* @param key
|
||||||
|
* The key of the request to remove
|
||||||
|
*/
|
||||||
constructor(key: string) {
|
constructor(key: string) {
|
||||||
this.payload = key;
|
this.payload = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to reset the timeAdded property of all cached objects
|
||||||
|
*/
|
||||||
export class ResetRequestCacheTimestampsAction implements Action {
|
export class ResetRequestCacheTimestampsAction implements Action {
|
||||||
type = RequestCacheActionTypes.RESET_TIMESTAMPS;
|
type = RequestCacheActionTypes.RESET_TIMESTAMPS;
|
||||||
payload: number;
|
payload: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ResetObjectCacheTimestampsAction
|
||||||
|
*
|
||||||
|
* @param newTimestamp
|
||||||
|
* the new timeAdded all objects should get
|
||||||
|
*/
|
||||||
constructor(newTimestamp: number) {
|
constructor(newTimestamp: number) {
|
||||||
this.payload = newTimestamp;
|
this.payload = newTimestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type to encompass all RequestCacheActions
|
||||||
|
*/
|
||||||
export type RequestCacheAction
|
export type RequestCacheAction
|
||||||
= RequestCacheFindAllAction
|
= RequestCacheFindAllAction
|
||||||
| RequestCacheFindByIDAction
|
| RequestCacheFindByIDAction
|
||||||
|
227
src/app/core/cache/request-cache.reducer.spec.ts
vendored
Normal file
227
src/app/core/cache/request-cache.reducer.spec.ts
vendored
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
import { requestCacheReducer, RequestCacheState } from "./request-cache.reducer";
|
||||||
|
import {
|
||||||
|
RequestCacheRemoveAction, RequestCacheFindByIDAction,
|
||||||
|
RequestCacheFindAllAction, RequestCacheSuccessAction, RequestCacheErrorAction,
|
||||||
|
ResetRequestCacheTimestampsAction
|
||||||
|
} from "./request-cache.actions";
|
||||||
|
import deepFreeze = require("deep-freeze");
|
||||||
|
import { OpaqueToken } from "@angular/core";
|
||||||
|
|
||||||
|
class NullAction extends RequestCacheRemoveAction {
|
||||||
|
type = null;
|
||||||
|
payload = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("requestCacheReducer", () => {
|
||||||
|
const keys = ["125c17f89046283c5f0640722aac9feb", "a06c3006a41caec5d635af099b0c780c"];
|
||||||
|
const services = [new OpaqueToken('service1'), new OpaqueToken('service2')];
|
||||||
|
const msToLive = 900000;
|
||||||
|
const uuids = [
|
||||||
|
"9e32a2e2-6b91-4236-a361-995ccdc14c60",
|
||||||
|
"598ce822-c357-46f3-ab70-63724d02d6ad",
|
||||||
|
"be8325f7-243b-49f4-8a4b-df2b793ff3b5"
|
||||||
|
];
|
||||||
|
const resourceID = "9978";
|
||||||
|
const paginationOptions = { "resultsPerPage": 10, "currentPage": 1 };
|
||||||
|
const sortOptions = { "field": "id", "direction": 0 };
|
||||||
|
const testState = {
|
||||||
|
[keys[0]]: {
|
||||||
|
"key": keys[0],
|
||||||
|
"service": services[0],
|
||||||
|
"resourceUUIDs": [uuids[0], uuids[1]],
|
||||||
|
"isLoading": false,
|
||||||
|
"paginationOptions": paginationOptions,
|
||||||
|
"sortOptions": sortOptions,
|
||||||
|
"timeAdded": new Date().getTime(),
|
||||||
|
"msToLive": msToLive
|
||||||
|
},
|
||||||
|
[keys[1]]: {
|
||||||
|
"key": keys[1],
|
||||||
|
"service": services[1],
|
||||||
|
"resourceID": resourceID,
|
||||||
|
"resourceUUIDs": [uuids[2]],
|
||||||
|
"isLoading": false,
|
||||||
|
"timeAdded": new Date().getTime(),
|
||||||
|
"msToLive": msToLive
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deepFreeze(testState);
|
||||||
|
const errorState: {} = {
|
||||||
|
[keys[0]]: {
|
||||||
|
errorMessage: 'error',
|
||||||
|
resourceUUIDs: uuids
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deepFreeze(errorState);
|
||||||
|
|
||||||
|
|
||||||
|
it("should return the current state when no valid actions have been made", () => {
|
||||||
|
const action = new NullAction();
|
||||||
|
const newState = requestCacheReducer(testState, action);
|
||||||
|
|
||||||
|
expect(newState).toEqual(testState);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should start with an empty cache", () => {
|
||||||
|
const action = new NullAction();
|
||||||
|
const initialState = requestCacheReducer(undefined, action);
|
||||||
|
|
||||||
|
expect(initialState).toEqual(Object.create(null));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("FIND_BY_ID", () => {
|
||||||
|
const action = new RequestCacheFindByIDAction(keys[0], services[0], resourceID);
|
||||||
|
|
||||||
|
it("should perform the action without affecting the previous state", () => {
|
||||||
|
//testState has already been frozen above
|
||||||
|
requestCacheReducer(testState, action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add the request to the cache", () => {
|
||||||
|
const state = Object.create(null);
|
||||||
|
const newState = requestCacheReducer(state, action);
|
||||||
|
expect(newState[keys[0]].key).toBe(keys[0]);
|
||||||
|
expect(newState[keys[0]].service).toEqual(services[0]);
|
||||||
|
expect(newState[keys[0]].resourceID).toBe(resourceID);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set isLoading to true", () => {
|
||||||
|
const state = Object.create(null);
|
||||||
|
const newState = requestCacheReducer(state, action);
|
||||||
|
expect(newState[keys[0]].isLoading).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove any previous error message or resourceUUID for the request", () => {
|
||||||
|
const newState = requestCacheReducer(errorState, action);
|
||||||
|
expect(newState[keys[0]].resourceUUIDs.length).toBe(0);
|
||||||
|
expect(newState[keys[0]].errorMessage).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("FIND_ALL", () => {
|
||||||
|
const action = new RequestCacheFindAllAction(keys[0], services[0], resourceID, paginationOptions, sortOptions);
|
||||||
|
|
||||||
|
it("should perform the action without affecting the previous state", () => {
|
||||||
|
//testState has already been frozen above
|
||||||
|
requestCacheReducer(testState, action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add the request to the cache", () => {
|
||||||
|
const state = Object.create(null);
|
||||||
|
const newState = requestCacheReducer(state, action);
|
||||||
|
expect(newState[keys[0]].key).toBe(keys[0]);
|
||||||
|
expect(newState[keys[0]].service).toEqual(services[0]);
|
||||||
|
expect(newState[keys[0]].scopeID).toBe(resourceID);
|
||||||
|
expect(newState[keys[0]].paginationOptions).toEqual(paginationOptions);
|
||||||
|
expect(newState[keys[0]].sortOptions).toEqual(sortOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set isLoading to true", () => {
|
||||||
|
const state = Object.create(null);
|
||||||
|
const newState = requestCacheReducer(state, action);
|
||||||
|
expect(newState[keys[0]].isLoading).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove any previous error message or resourceUUIDs for the request", () => {
|
||||||
|
const newState = requestCacheReducer(errorState, action);
|
||||||
|
expect(newState[keys[0]].resourceUUIDs.length).toBe(0);
|
||||||
|
expect(newState[keys[0]].errorMessage).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("SUCCESS", () => {
|
||||||
|
const successUUIDs = [uuids[0], uuids[2]];
|
||||||
|
const successTimeAdded = new Date().getTime();
|
||||||
|
const successMsToLive = 5;
|
||||||
|
const action = new RequestCacheSuccessAction(keys[0], successUUIDs, successTimeAdded, successMsToLive);
|
||||||
|
|
||||||
|
it("should perform the action without affecting the previous state", () => {
|
||||||
|
//testState has already been frozen above
|
||||||
|
requestCacheReducer(testState, action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add the response to the cached request", () => {
|
||||||
|
const newState = requestCacheReducer(testState, action);
|
||||||
|
expect(newState[keys[0]].resourceUUIDs).toBe(successUUIDs);
|
||||||
|
expect(newState[keys[0]].timeAdded).toBe(successTimeAdded);
|
||||||
|
expect(newState[keys[0]].msToLive).toBe(successMsToLive);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set isLoading to false", () => {
|
||||||
|
const newState = requestCacheReducer(testState, action);
|
||||||
|
expect(newState[keys[0]].isLoading).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove any previous error message for the request", () => {
|
||||||
|
const newState = requestCacheReducer(errorState, action);
|
||||||
|
expect(newState[keys[0]].errorMessage).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("ERROR", () => {
|
||||||
|
const errorMsg = 'errorMsg';
|
||||||
|
const action = new RequestCacheErrorAction(keys[0], errorMsg);
|
||||||
|
|
||||||
|
it("should perform the action without affecting the previous state", () => {
|
||||||
|
//testState has already been frozen above
|
||||||
|
requestCacheReducer(testState, action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set an error message for the request", () => {
|
||||||
|
const newState = requestCacheReducer(errorState, action);
|
||||||
|
expect(newState[keys[0]].errorMessage).toBe(errorMsg);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set isLoading to false", () => {
|
||||||
|
const newState = requestCacheReducer(testState, action);
|
||||||
|
expect(newState[keys[0]].isLoading).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("REMOVE", () => {
|
||||||
|
it("should perform the action without affecting the previous state", () => {
|
||||||
|
const action = new RequestCacheRemoveAction(keys[0]);
|
||||||
|
//testState has already been frozen above
|
||||||
|
requestCacheReducer(testState, action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove the specified request from the cache", () => {
|
||||||
|
const action = new RequestCacheRemoveAction(keys[0]);
|
||||||
|
const newState = requestCacheReducer(testState, action);
|
||||||
|
expect(testState[keys[0]]).not.toBeUndefined();
|
||||||
|
expect(newState[keys[0]]).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shouldn't do anything when the specified key isn't cached", () => {
|
||||||
|
const wrongKey = "this isn't cached";
|
||||||
|
const action = new RequestCacheRemoveAction(wrongKey);
|
||||||
|
const newState = requestCacheReducer(testState, action);
|
||||||
|
expect(testState[wrongKey]).toBeUndefined();
|
||||||
|
expect(newState).toEqual(testState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("RESET_TIMESTAMPS", () => {
|
||||||
|
const newTimeStamp = new Date().getTime();
|
||||||
|
const action = new ResetRequestCacheTimestampsAction(newTimeStamp);
|
||||||
|
|
||||||
|
it("should perform the action without affecting the previous state", () => {
|
||||||
|
//testState has already been frozen above
|
||||||
|
requestCacheReducer(testState, action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the timestamp of all requests in the cache", () => {
|
||||||
|
const newState = requestCacheReducer(testState, action);
|
||||||
|
Object.keys(newState).forEach((key) => {
|
||||||
|
expect(newState[key].timeAdded).toEqual(newTimeStamp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
76
src/app/core/cache/request-cache.reducer.ts
vendored
76
src/app/core/cache/request-cache.reducer.ts
vendored
@@ -9,6 +9,9 @@ import { OpaqueToken } from "@angular/core";
|
|||||||
import { CacheEntry } from "./cache-entry";
|
import { CacheEntry } from "./cache-entry";
|
||||||
import { hasValue } from "../../shared/empty.util";
|
import { hasValue } from "../../shared/empty.util";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry in the RequestCache
|
||||||
|
*/
|
||||||
export class RequestCacheEntry implements CacheEntry {
|
export class RequestCacheEntry implements CacheEntry {
|
||||||
service: OpaqueToken;
|
service: OpaqueToken;
|
||||||
key: string;
|
key: string;
|
||||||
@@ -24,6 +27,9 @@ export class RequestCacheEntry implements CacheEntry {
|
|||||||
msToLive: number;
|
msToLive: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The RequestCache State
|
||||||
|
*/
|
||||||
export interface RequestCacheState {
|
export interface RequestCacheState {
|
||||||
[key: string]: RequestCacheEntry
|
[key: string]: RequestCacheEntry
|
||||||
}
|
}
|
||||||
@@ -31,6 +37,16 @@ export interface RequestCacheState {
|
|||||||
// Object.create(null) ensures the object has no default js properties (e.g. `__proto__`)
|
// Object.create(null) ensures the object has no default js properties (e.g. `__proto__`)
|
||||||
const initialState = Object.create(null);
|
const initialState = Object.create(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The RequestCache Reducer
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the current state
|
||||||
|
* @param action
|
||||||
|
* the action to perform on the state
|
||||||
|
* @return RequestCacheState
|
||||||
|
* the new state
|
||||||
|
*/
|
||||||
export const requestCacheReducer = (state = initialState, action: RequestCacheAction): RequestCacheState => {
|
export const requestCacheReducer = (state = initialState, action: RequestCacheAction): RequestCacheState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
@@ -64,6 +80,16 @@ export const requestCacheReducer = (state = initialState, action: RequestCacheAc
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a FindAll request to the cache
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the current state
|
||||||
|
* @param action
|
||||||
|
* a RequestCacheFindAllAction
|
||||||
|
* @return RequestCacheState
|
||||||
|
* the new state, with the request added, or overwritten
|
||||||
|
*/
|
||||||
function findAllRequest(state: RequestCacheState, action: RequestCacheFindAllAction): RequestCacheState {
|
function findAllRequest(state: RequestCacheState, action: RequestCacheFindAllAction): RequestCacheState {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.payload.key]: {
|
[action.payload.key]: {
|
||||||
@@ -79,6 +105,16 @@ function findAllRequest(state: RequestCacheState, action: RequestCacheFindAllAct
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a FindByID request to the cache
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the current state
|
||||||
|
* @param action
|
||||||
|
* a RequestCacheFindByIDAction
|
||||||
|
* @return RequestCacheState
|
||||||
|
* the new state, with the request added, or overwritten
|
||||||
|
*/
|
||||||
function findByIDRequest(state: RequestCacheState, action: RequestCacheFindByIDAction): RequestCacheState {
|
function findByIDRequest(state: RequestCacheState, action: RequestCacheFindByIDAction): RequestCacheState {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.payload.key]: {
|
[action.payload.key]: {
|
||||||
@@ -92,6 +128,16 @@ function findByIDRequest(state: RequestCacheState, action: RequestCacheFindByIDA
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a cached request with a successful response
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the current state
|
||||||
|
* @param action
|
||||||
|
* a RequestCacheSuccessAction
|
||||||
|
* @return RequestCacheState
|
||||||
|
* the new state, with the response added to the request
|
||||||
|
*/
|
||||||
function success(state: RequestCacheState, action: RequestCacheSuccessAction): RequestCacheState {
|
function success(state: RequestCacheState, action: RequestCacheSuccessAction): RequestCacheState {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.payload.key]: Object.assign({}, state[action.payload.key], {
|
[action.payload.key]: Object.assign({}, state[action.payload.key], {
|
||||||
@@ -104,6 +150,16 @@ function success(state: RequestCacheState, action: RequestCacheSuccessAction): R
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a cached request with an error
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the current state
|
||||||
|
* @param action
|
||||||
|
* a RequestCacheSuccessAction
|
||||||
|
* @return RequestCacheState
|
||||||
|
* the new state, with the error added to the request
|
||||||
|
*/
|
||||||
function error(state: RequestCacheState, action: RequestCacheErrorAction): RequestCacheState {
|
function error(state: RequestCacheState, action: RequestCacheErrorAction): RequestCacheState {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.payload.key]: Object.assign({}, state[action.payload.key], {
|
[action.payload.key]: Object.assign({}, state[action.payload.key], {
|
||||||
@@ -113,6 +169,16 @@ function error(state: RequestCacheState, action: RequestCacheErrorAction): Reque
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a request from the cache
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the current state
|
||||||
|
* @param action
|
||||||
|
* an RequestCacheRemoveAction
|
||||||
|
* @return RequestCacheState
|
||||||
|
* the new state, with the request removed if it existed.
|
||||||
|
*/
|
||||||
function removeFromCache(state: RequestCacheState, action: RequestCacheRemoveAction): RequestCacheState {
|
function removeFromCache(state: RequestCacheState, action: RequestCacheRemoveAction): RequestCacheState {
|
||||||
if (hasValue(state[action.payload])) {
|
if (hasValue(state[action.payload])) {
|
||||||
let newCache = Object.assign({}, state);
|
let newCache = Object.assign({}, state);
|
||||||
@@ -125,6 +191,16 @@ function removeFromCache(state: RequestCacheState, action: RequestCacheRemoveAct
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the timeAdded timestamp of every cached request to the specified value
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the current state
|
||||||
|
* @param action
|
||||||
|
* a ResetRequestCacheTimestampsAction
|
||||||
|
* @return RequestCacheState
|
||||||
|
* the new state, with all timeAdded timestamps set to the specified value
|
||||||
|
*/
|
||||||
function resetRequestCacheTimestamps(state: RequestCacheState, action: ResetRequestCacheTimestampsAction): RequestCacheState {
|
function resetRequestCacheTimestamps(state: RequestCacheState, action: ResetRequestCacheTimestampsAction): RequestCacheState {
|
||||||
let newState = Object.create(null);
|
let newState = Object.create(null);
|
||||||
Object.keys(state).forEach(key => {
|
Object.keys(state).forEach(key => {
|
||||||
|
Reference in New Issue
Block a user