mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Refactored Data Services
This commit is contained in:
17
src/app/core/cache/cache.reducers.ts
vendored
Normal file
17
src/app/core/cache/cache.reducers.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { combineReducers } from "@ngrx/store";
|
||||||
|
import { RequestCacheState, requestCacheReducer } from "./request-cache.reducer";
|
||||||
|
import { ObjectCacheState, objectCacheReducer } from "./object-cache.reducer";
|
||||||
|
|
||||||
|
export interface CacheState {
|
||||||
|
request: RequestCacheState,
|
||||||
|
object: ObjectCacheState
|
||||||
|
}
|
||||||
|
|
||||||
|
export const reducers = {
|
||||||
|
request: requestCacheReducer,
|
||||||
|
object: objectCacheReducer
|
||||||
|
};
|
||||||
|
|
||||||
|
export function cacheReducer(state: any, action: any) {
|
||||||
|
return combineReducers(reducers)(state, action);
|
||||||
|
}
|
33
src/app/core/cache/object-cache.actions.ts
vendored
Normal file
33
src/app/core/cache/object-cache.actions.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Action } from "@ngrx/store";
|
||||||
|
import { type } from "../../shared/ngrx/type";
|
||||||
|
import { CacheableObject } from "./object-cache.reducer";
|
||||||
|
|
||||||
|
export const ObjectCacheActionTypes = {
|
||||||
|
ADD: type('dspace/core/cache/object/ADD'),
|
||||||
|
REMOVE: type('dspace/core/cache/object/REMOVE')
|
||||||
|
};
|
||||||
|
|
||||||
|
export class AddToObjectCacheAction implements Action {
|
||||||
|
type = ObjectCacheActionTypes.ADD;
|
||||||
|
payload: {
|
||||||
|
objectToCache: CacheableObject;
|
||||||
|
msToLive: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(objectToCache: CacheableObject, msToLive: number) {
|
||||||
|
this.payload = { objectToCache, msToLive };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RemoveFromObjectCacheAction implements Action {
|
||||||
|
type = ObjectCacheActionTypes.REMOVE;
|
||||||
|
payload: string;
|
||||||
|
|
||||||
|
constructor(uuid: string) {
|
||||||
|
this.payload = uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ObjectCacheAction
|
||||||
|
= AddToObjectCacheAction
|
||||||
|
| RemoveFromObjectCacheAction
|
58
src/app/core/cache/object-cache.reducer.ts
vendored
Normal file
58
src/app/core/cache/object-cache.reducer.ts
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { ObjectCacheAction, ObjectCacheActionTypes, AddToObjectCacheAction, RemoveFromObjectCacheAction } from "./object-cache.actions";
|
||||||
|
import { hasValue } from "../../shared/empty.util";
|
||||||
|
|
||||||
|
export interface CacheableObject {
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ObjectCacheEntry {
|
||||||
|
data: CacheableObject;
|
||||||
|
timeAdded: number;
|
||||||
|
msToLive: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ObjectCacheState {
|
||||||
|
[uuid: string]: ObjectCacheEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object.create(null) ensures the object has no default js properties (e.g. `__proto__`)
|
||||||
|
const initialState: ObjectCacheState = Object.create(null);
|
||||||
|
|
||||||
|
export const objectCacheReducer = (state = initialState, action: ObjectCacheAction): ObjectCacheState => {
|
||||||
|
switch (action.type) {
|
||||||
|
|
||||||
|
case ObjectCacheActionTypes.ADD: {
|
||||||
|
return addToObjectCache(state, <AddToObjectCacheAction>action);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ObjectCacheActionTypes.REMOVE: {
|
||||||
|
return removeFromObjectCache(state, <RemoveFromObjectCacheAction>action)
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function addToObjectCache(state: ObjectCacheState, action: AddToObjectCacheAction): ObjectCacheState {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
[action.payload.objectToCache.uuid]: {
|
||||||
|
data: action.payload.objectToCache,
|
||||||
|
timeAdded: new Date().getTime(),
|
||||||
|
msToLive: action.payload.msToLive
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFromObjectCache(state: ObjectCacheState, action: RemoveFromObjectCacheAction): ObjectCacheState {
|
||||||
|
if (hasValue(state[action.payload])) {
|
||||||
|
let newObjectCache = Object.assign({}, state);
|
||||||
|
delete newObjectCache[action.payload];
|
||||||
|
|
||||||
|
return newObjectCache;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,28 +1,28 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { Store } from "@ngrx/store";
|
import { Store } from "@ngrx/store";
|
||||||
import { CacheState, CacheEntry, CacheableObject } from "./cache.reducer";
|
import { ObjectCacheState, ObjectCacheEntry, CacheableObject } from "./object-cache.reducer";
|
||||||
import { AddToCacheAction, RemoveFromCacheAction } from "./cache.actions";
|
import { AddToObjectCacheAction, RemoveFromObjectCacheAction } from "./object-cache.actions";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { hasNoValue } from "../../../shared/empty.util";
|
import { hasNoValue } from "../../shared/empty.util";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CacheService {
|
export class ObjectCacheService {
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<CacheState>
|
private store: Store<ObjectCacheState>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
add(objectToCache: CacheableObject, msToLive: number): void {
|
add(objectToCache: CacheableObject, msToLive: number): void {
|
||||||
this.store.dispatch(new AddToCacheAction(objectToCache, msToLive));
|
this.store.dispatch(new AddToObjectCacheAction(objectToCache, msToLive));
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(uuid: string): void {
|
remove(uuid: string): void {
|
||||||
this.store.dispatch(new RemoveFromCacheAction(uuid));
|
this.store.dispatch(new RemoveFromObjectCacheAction(uuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
get<T extends CacheableObject>(uuid: string): Observable<T> {
|
get<T extends CacheableObject>(uuid: string): Observable<T> {
|
||||||
return this.store.select<CacheEntry>('core', 'cache', uuid)
|
return this.store.select<ObjectCacheEntry>('core', 'cache', 'object', uuid)
|
||||||
.filter(entry => this.isValid(entry))
|
.filter(entry => this.isValid(entry))
|
||||||
.map((entry: CacheEntry) => <T> entry.data);
|
.map((entry: ObjectCacheEntry) => <T> entry.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
getList<T extends CacheableObject>(uuids: Array<string>): Observable<Array<T>> {
|
getList<T extends CacheableObject>(uuids: Array<string>): Observable<Array<T>> {
|
||||||
@@ -34,14 +34,14 @@ export class CacheService {
|
|||||||
has(uuid: string): boolean {
|
has(uuid: string): boolean {
|
||||||
let result: boolean;
|
let result: boolean;
|
||||||
|
|
||||||
this.store.select<CacheEntry>('core', 'cache', uuid)
|
this.store.select<ObjectCacheEntry>('core', 'cache', 'object', uuid)
|
||||||
.take(1)
|
.take(1)
|
||||||
.subscribe(entry => result = this.isValid(entry));
|
.subscribe(entry => result = this.isValid(entry));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isValid(entry: CacheEntry): boolean {
|
private isValid(entry: ObjectCacheEntry): boolean {
|
||||||
if (hasNoValue(entry)) {
|
if (hasNoValue(entry)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ export class CacheService {
|
|||||||
const timeOutdated = entry.timeAdded + entry.msToLive;
|
const timeOutdated = entry.timeAdded + entry.msToLive;
|
||||||
const isOutDated = new Date().getTime() > timeOutdated;
|
const isOutDated = new Date().getTime() > timeOutdated;
|
||||||
if (isOutDated) {
|
if (isOutDated) {
|
||||||
this.store.dispatch(new RemoveFromCacheAction(entry.data.uuid));
|
this.store.dispatch(new RemoveFromObjectCacheAction(entry.data.uuid));
|
||||||
}
|
}
|
||||||
return !isOutDated;
|
return !isOutDated;
|
||||||
}
|
}
|
@@ -4,15 +4,15 @@ 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";
|
||||||
|
|
||||||
export const DataActionTypes = {
|
export const RequestCacheActionTypes = {
|
||||||
FIND_BY_ID_REQUEST: type('dspace/core/data/FIND_BY_ID_REQUEST'),
|
FIND_BY_ID_REQUEST: type('dspace/core/cache/request/FIND_BY_ID_REQUEST'),
|
||||||
FIND_ALL_REQUEST: type('dspace/core/data/FIND_ALL_REQUEST'),
|
FIND_ALL_REQUEST: type('dspace/core/cache/request/FIND_ALL_REQUEST'),
|
||||||
SUCCESS: type('dspace/core/data/SUCCESS'),
|
SUCCESS: type('dspace/core/cache/request/SUCCESS'),
|
||||||
ERROR: type('dspace/core/data/ERROR')
|
ERROR: type('dspace/core/cache/request/ERROR')
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DataFindAllRequestAction implements Action {
|
export class FindAllRequestCacheAction implements Action {
|
||||||
type = DataActionTypes.FIND_ALL_REQUEST;
|
type = RequestCacheActionTypes.FIND_ALL_REQUEST;
|
||||||
payload: {
|
payload: {
|
||||||
key: string,
|
key: string,
|
||||||
service: OpaqueToken,
|
service: OpaqueToken,
|
||||||
@@ -38,8 +38,8 @@ export class DataFindAllRequestAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DataFindByIDRequestAction implements Action {
|
export class FindByIDRequestCacheAction implements Action {
|
||||||
type = DataActionTypes.FIND_BY_ID_REQUEST;
|
type = RequestCacheActionTypes.FIND_BY_ID_REQUEST;
|
||||||
payload: {
|
payload: {
|
||||||
key: string,
|
key: string,
|
||||||
service: OpaqueToken,
|
service: OpaqueToken,
|
||||||
@@ -59,8 +59,8 @@ export class DataFindByIDRequestAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DataSuccessAction implements Action {
|
export class RequestCacheSuccessAction implements Action {
|
||||||
type = DataActionTypes.SUCCESS;
|
type = RequestCacheActionTypes.SUCCESS;
|
||||||
payload: {
|
payload: {
|
||||||
key: string,
|
key: string,
|
||||||
resourceUUIDs: Array<string>
|
resourceUUIDs: Array<string>
|
||||||
@@ -74,8 +74,8 @@ export class DataSuccessAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DataErrorAction implements Action {
|
export class RequestCacheErrorAction implements Action {
|
||||||
type = DataActionTypes.ERROR;
|
type = RequestCacheActionTypes.ERROR;
|
||||||
payload: {
|
payload: {
|
||||||
key: string,
|
key: string,
|
||||||
errorMessage: string
|
errorMessage: string
|
||||||
@@ -89,8 +89,8 @@ export class DataErrorAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DataAction
|
export type RequestCacheAction
|
||||||
= DataFindAllRequestAction
|
= FindAllRequestCacheAction
|
||||||
| DataFindByIDRequestAction
|
| FindByIDRequestCacheAction
|
||||||
| DataSuccessAction
|
| RequestCacheSuccessAction
|
||||||
| DataErrorAction;
|
| RequestCacheErrorAction;
|
@@ -1,12 +1,12 @@
|
|||||||
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";
|
||||||
import {
|
import {
|
||||||
DataAction, DataActionTypes, DataFindAllRequestAction,
|
RequestCacheAction, RequestCacheActionTypes, FindAllRequestCacheAction,
|
||||||
DataSuccessAction, DataErrorAction, DataFindByIDRequestAction
|
RequestCacheSuccessAction, RequestCacheErrorAction, FindByIDRequestCacheAction
|
||||||
} from "./data.actions";
|
} from "./request-cache.actions";
|
||||||
import { OpaqueToken } from "@angular/core";
|
import { OpaqueToken } from "@angular/core";
|
||||||
|
|
||||||
export interface DataRequestState {
|
export interface CachedRequest {
|
||||||
service: OpaqueToken
|
service: OpaqueToken
|
||||||
scopeID: string;
|
scopeID: string;
|
||||||
resourceID: string;
|
resourceID: string;
|
||||||
@@ -20,30 +20,30 @@ export interface DataRequestState {
|
|||||||
msToLive: number;
|
msToLive: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DataState {
|
export interface RequestCacheState {
|
||||||
[key: string]: DataRequestState
|
[key: string]: CachedRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
export const dataReducer = (state = initialState, action: DataAction): DataState => {
|
export const requestCacheReducer = (state = initialState, action: RequestCacheAction): RequestCacheState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
case DataActionTypes.FIND_ALL_REQUEST: {
|
case RequestCacheActionTypes.FIND_ALL_REQUEST: {
|
||||||
return findAllRequest(state, <DataFindAllRequestAction> action);
|
return findAllRequest(state, <FindAllRequestCacheAction> action);
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataActionTypes.FIND_BY_ID_REQUEST: {
|
case RequestCacheActionTypes.FIND_BY_ID_REQUEST: {
|
||||||
return findByIDRequest(state, <DataFindByIDRequestAction> action);
|
return findByIDRequest(state, <FindByIDRequestCacheAction> action);
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataActionTypes.SUCCESS: {
|
case RequestCacheActionTypes.SUCCESS: {
|
||||||
return success(state, <DataSuccessAction> action);
|
return success(state, <RequestCacheSuccessAction> action);
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataActionTypes.ERROR: {
|
case RequestCacheActionTypes.ERROR: {
|
||||||
return error(state, <DataErrorAction> action);
|
return error(state, <RequestCacheErrorAction> action);
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@@ -52,7 +52,7 @@ export const dataReducer = (state = initialState, action: DataAction): DataState
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function findAllRequest(state: DataState, action: DataFindAllRequestAction): DataState {
|
function findAllRequest(state: RequestCacheState, action: FindAllRequestCacheAction): RequestCacheState {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.payload.key]: {
|
[action.payload.key]: {
|
||||||
service: action.payload.service,
|
service: action.payload.service,
|
||||||
@@ -66,7 +66,7 @@ function findAllRequest(state: DataState, action: DataFindAllRequestAction): Dat
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function findByIDRequest(state: DataState, action: DataFindByIDRequestAction): DataState {
|
function findByIDRequest(state: RequestCacheState, action: FindByIDRequestCacheAction): RequestCacheState {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.payload.key]: {
|
[action.payload.key]: {
|
||||||
service: action.payload.service,
|
service: action.payload.service,
|
||||||
@@ -78,7 +78,7 @@ function findByIDRequest(state: DataState, action: DataFindByIDRequestAction): D
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function success(state: DataState, action: DataSuccessAction): DataState {
|
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], {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@@ -88,7 +88,7 @@ function success(state: DataState, action: DataSuccessAction): DataState {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function error(state: DataState, action: DataErrorAction): DataState {
|
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], {
|
||||||
isLoading: false,
|
isLoading: false,
|
@@ -4,7 +4,7 @@ import { SharedModule } from "../shared/shared.module";
|
|||||||
import { isNotEmpty } from "../shared/empty.util";
|
import { isNotEmpty } from "../shared/empty.util";
|
||||||
import { FooterComponent } from "./footer/footer.component";
|
import { FooterComponent } from "./footer/footer.component";
|
||||||
import { DSpaceRESTv2Service } from "./dspace-rest-v2/dspace-rest-v2.service";
|
import { DSpaceRESTv2Service } from "./dspace-rest-v2/dspace-rest-v2.service";
|
||||||
import { CacheService } from "./data-services/cache/cache.service";
|
import { ObjectCacheService } from "./cache/object-cache.service";
|
||||||
import { CollectionDataService } from "./data-services/collection-data.service";
|
import { CollectionDataService } from "./data-services/collection-data.service";
|
||||||
import { ItemDataService } from "./data-services/item-data.service";
|
import { ItemDataService } from "./data-services/item-data.service";
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ const PROVIDERS = [
|
|||||||
CollectionDataService,
|
CollectionDataService,
|
||||||
ItemDataService,
|
ItemDataService,
|
||||||
DSpaceRESTv2Service,
|
DSpaceRESTv2Service,
|
||||||
CacheService
|
ObjectCacheService
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -1,14 +1,11 @@
|
|||||||
import { combineReducers } from "@ngrx/store";
|
import { combineReducers } from "@ngrx/store";
|
||||||
import { CacheState, cacheReducer } from "./data-services/cache/cache.reducer";
|
import { CacheState, cacheReducer } from "./cache/cache.reducers";
|
||||||
import { dataReducer, DataState } from "./data-services/data.reducer";
|
|
||||||
|
|
||||||
export interface CoreState {
|
export interface CoreState {
|
||||||
data: DataState,
|
|
||||||
cache: CacheState
|
cache: CacheState
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reducers = {
|
export const reducers = {
|
||||||
data: dataReducer,
|
|
||||||
cache: cacheReducer
|
cache: cacheReducer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,33 +0,0 @@
|
|||||||
import { Action } from "@ngrx/store";
|
|
||||||
import { type } from "../../../shared/ngrx/type";
|
|
||||||
import { CacheableObject } from "./cache.reducer";
|
|
||||||
|
|
||||||
export const CacheActionTypes = {
|
|
||||||
ADD: type('dspace/core/data/cache/ADD'),
|
|
||||||
REMOVE: type('dspace/core/data/cache/REMOVE')
|
|
||||||
};
|
|
||||||
|
|
||||||
export class AddToCacheAction implements Action {
|
|
||||||
type = CacheActionTypes.ADD;
|
|
||||||
payload: {
|
|
||||||
objectToCache: CacheableObject;
|
|
||||||
msToLive: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(objectToCache: CacheableObject, msToLive: number) {
|
|
||||||
this.payload = { objectToCache, msToLive };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RemoveFromCacheAction implements Action {
|
|
||||||
type = CacheActionTypes.REMOVE;
|
|
||||||
payload: string;
|
|
||||||
|
|
||||||
constructor(uuid: string) {
|
|
||||||
this.payload = uuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CacheAction
|
|
||||||
= AddToCacheAction
|
|
||||||
| RemoveFromCacheAction
|
|
@@ -1,58 +0,0 @@
|
|||||||
import { CacheAction, CacheActionTypes, AddToCacheAction, RemoveFromCacheAction } from "./cache.actions";
|
|
||||||
import { hasValue } from "../../../shared/empty.util";
|
|
||||||
|
|
||||||
export interface CacheableObject {
|
|
||||||
uuid: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CacheEntry {
|
|
||||||
data: CacheableObject;
|
|
||||||
timeAdded: number;
|
|
||||||
msToLive: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CacheState {
|
|
||||||
[uuid: string]: CacheEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
// Object.create(null) ensures the object has no default js properties (e.g. `__proto__`)
|
|
||||||
const initialState: CacheState = Object.create(null);
|
|
||||||
|
|
||||||
export const cacheReducer = (state = initialState, action: CacheAction): CacheState => {
|
|
||||||
switch (action.type) {
|
|
||||||
|
|
||||||
case CacheActionTypes.ADD: {
|
|
||||||
return addToCache(state, <AddToCacheAction>action);
|
|
||||||
}
|
|
||||||
|
|
||||||
case CacheActionTypes.REMOVE: {
|
|
||||||
return removeFromCache(state, <RemoveFromCacheAction>action)
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function addToCache(state: CacheState, action: AddToCacheAction): CacheState {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
[action.payload.objectToCache.uuid]: {
|
|
||||||
data: action.payload.objectToCache,
|
|
||||||
timeAdded: new Date().getTime(),
|
|
||||||
msToLive: action.payload.msToLive
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeFromCache(state: CacheState, action: RemoveFromCacheAction): CacheState {
|
|
||||||
if (hasValue(state[action.payload])) {
|
|
||||||
let newCache = Object.assign({}, state);
|
|
||||||
delete newCache[action.payload];
|
|
||||||
|
|
||||||
return newCache;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -3,10 +3,10 @@ import { DataEffects } from "./data.effects";
|
|||||||
import { Serializer } from "../serializer";
|
import { Serializer } from "../serializer";
|
||||||
import { Collection } from "../shared/collection.model";
|
import { Collection } from "../shared/collection.model";
|
||||||
import { DSpaceRESTv2Serializer } from "../dspace-rest-v2/dspace-rest-v2.serializer";
|
import { DSpaceRESTv2Serializer } from "../dspace-rest-v2/dspace-rest-v2.serializer";
|
||||||
import { CacheService } from "./cache/cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { DSpaceRESTv2Service } from "../dspace-rest-v2/dspace-rest-v2.service";
|
import { DSpaceRESTv2Service } from "../dspace-rest-v2/dspace-rest-v2.service";
|
||||||
import { Actions, Effect } from "@ngrx/effects";
|
import { Actions, Effect } from "@ngrx/effects";
|
||||||
import { DataFindAllRequestAction, DataFindByIDRequestAction } from "./data.actions";
|
import { FindAllRequestCacheAction, FindByIDRequestCacheAction } from "../cache/request-cache.actions";
|
||||||
import { CollectionDataService } from "./collection-data.service";
|
import { CollectionDataService } from "./collection-data.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -14,17 +14,17 @@ export class CollectionDataEffects extends DataEffects<Collection> {
|
|||||||
constructor(
|
constructor(
|
||||||
actions$: Actions,
|
actions$: Actions,
|
||||||
restApi: DSpaceRESTv2Service,
|
restApi: DSpaceRESTv2Service,
|
||||||
cache: CacheService,
|
cache: ObjectCacheService,
|
||||||
dataService: CollectionDataService
|
dataService: CollectionDataService
|
||||||
) {
|
) {
|
||||||
super(actions$, restApi, cache, dataService);
|
super(actions$, restApi, cache, dataService);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getFindAllEndpoint(action: DataFindAllRequestAction): string {
|
protected getFindAllEndpoint(action: FindAllRequestCacheAction): string {
|
||||||
return '/collections';
|
return '/collections';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getFindByIdEndpoint(action: DataFindByIDRequestAction): string {
|
protected getFindByIdEndpoint(action: FindByIDRequestCacheAction): string {
|
||||||
return `/collections/${action.payload.resourceID}`;
|
return `/collections/${action.payload.resourceID}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,16 +2,16 @@ import { Injectable, OpaqueToken } from "@angular/core";
|
|||||||
import { Store } from "@ngrx/store";
|
import { Store } from "@ngrx/store";
|
||||||
import { DataService } from "./data.service";
|
import { DataService } from "./data.service";
|
||||||
import { Collection } from "../shared/collection.model";
|
import { Collection } from "../shared/collection.model";
|
||||||
import { CacheService } from "./cache/cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { DataState } from "./data.reducer";
|
import { RequestCacheState } from "../cache/request-cache.reducer";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CollectionDataService extends DataService<Collection> {
|
export class CollectionDataService extends DataService<Collection> {
|
||||||
name = new OpaqueToken('CollectionDataService');
|
name = new OpaqueToken('CollectionDataService');
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
store: Store<DataState>,
|
store: Store<RequestCacheState>,
|
||||||
cache: CacheService
|
cache: ObjectCacheService
|
||||||
) {
|
) {
|
||||||
super(store, cache);
|
super(store, cache);
|
||||||
}
|
}
|
||||||
|
@@ -2,25 +2,25 @@ import { Actions, Effect } from "@ngrx/effects";
|
|||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { DSpaceRESTV2Response } from "../dspace-rest-v2/dspace-rest-v2-response.model";
|
import { DSpaceRESTV2Response } from "../dspace-rest-v2/dspace-rest-v2-response.model";
|
||||||
import { DSpaceRESTv2Service } from "../dspace-rest-v2/dspace-rest-v2.service";
|
import { DSpaceRESTv2Service } from "../dspace-rest-v2/dspace-rest-v2.service";
|
||||||
import { CacheService } from "./cache/cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { GlobalConfig } from "../../../config";
|
import { GlobalConfig } from "../../../config";
|
||||||
import { CacheableObject } from "./cache/cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { Serializer } from "../serializer";
|
import { Serializer } from "../serializer";
|
||||||
import {
|
import {
|
||||||
DataActionTypes, DataFindAllRequestAction, DataSuccessAction,
|
RequestCacheActionTypes, FindAllRequestCacheAction, RequestCacheSuccessAction,
|
||||||
DataErrorAction, DataFindByIDRequestAction, DataAction
|
RequestCacheErrorAction, FindByIDRequestCacheAction
|
||||||
} from "./data.actions";
|
} from "../cache/request-cache.actions";
|
||||||
import { DataService } from "./data.service";
|
import { DataService } from "./data.service";
|
||||||
|
|
||||||
export abstract class DataEffects<T extends CacheableObject> {
|
export abstract class DataEffects<T extends CacheableObject> {
|
||||||
protected abstract getFindAllEndpoint(action: DataFindAllRequestAction): string;
|
protected abstract getFindAllEndpoint(action: FindAllRequestCacheAction): string;
|
||||||
protected abstract getFindByIdEndpoint(action: DataFindByIDRequestAction): string;
|
protected abstract getFindByIdEndpoint(action: FindByIDRequestCacheAction): string;
|
||||||
protected abstract getSerializer(): Serializer<T>;
|
protected abstract getSerializer(): Serializer<T>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private actions$: Actions,
|
private actions$: Actions,
|
||||||
private restApi: DSpaceRESTv2Service,
|
private restApi: DSpaceRESTv2Service,
|
||||||
private cache: CacheService,
|
private objectCache: ObjectCacheService,
|
||||||
private dataService: DataService<T>
|
private dataService: DataService<T>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -28,33 +28,33 @@ export abstract class DataEffects<T extends CacheableObject> {
|
|||||||
// because currently the cache is more of an object store. We need to move
|
// because currently the cache is more of an object store. We need to move
|
||||||
// more towards memoization for things like this.
|
// more towards memoization for things like this.
|
||||||
protected findAll = this.actions$
|
protected findAll = this.actions$
|
||||||
.ofType(DataActionTypes.FIND_ALL_REQUEST)
|
.ofType(RequestCacheActionTypes.FIND_ALL_REQUEST)
|
||||||
.filter((action: DataFindAllRequestAction) => action.payload.service === this.dataService.name)
|
.filter((action: FindAllRequestCacheAction) => action.payload.service === this.dataService.name)
|
||||||
.switchMap((action: DataFindAllRequestAction) => {
|
.switchMap((action: FindAllRequestCacheAction) => {
|
||||||
//TODO scope, pagination, sorting -> when we know how that works in rest
|
//TODO scope, pagination, sorting -> when we know how that works in rest
|
||||||
return this.restApi.get(this.getFindAllEndpoint(action))
|
return this.restApi.get(this.getFindAllEndpoint(action))
|
||||||
.map((data: DSpaceRESTV2Response) => this.getSerializer().deserializeArray(data))
|
.map((data: DSpaceRESTV2Response) => this.getSerializer().deserializeArray(data))
|
||||||
.do((ts: T[]) => {
|
.do((ts: T[]) => {
|
||||||
ts.forEach((t) => {
|
ts.forEach((t) => {
|
||||||
this.cache.add(t, GlobalConfig.cache.msToLive);
|
this.objectCache.add(t, GlobalConfig.cache.msToLive);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.map((ts: Array<T>) => ts.map(t => t.uuid))
|
.map((ts: Array<T>) => ts.map(t => t.uuid))
|
||||||
.map((ids: Array<string>) => new DataSuccessAction(action.payload.key, ids))
|
.map((ids: Array<string>) => new RequestCacheSuccessAction(action.payload.key, ids))
|
||||||
.catch((errorMsg: string) => Observable.of(new DataErrorAction(action.payload.key, errorMsg)));
|
.catch((errorMsg: string) => Observable.of(new RequestCacheErrorAction(action.payload.key, errorMsg)));
|
||||||
});
|
});
|
||||||
|
|
||||||
protected findById = this.actions$
|
protected findById = this.actions$
|
||||||
.ofType(DataActionTypes.FIND_BY_ID_REQUEST)
|
.ofType(RequestCacheActionTypes.FIND_BY_ID_REQUEST)
|
||||||
.filter((action: DataFindAllRequestAction) => action.payload.service === this.dataService.name)
|
.filter((action: FindAllRequestCacheAction) => action.payload.service === this.dataService.name)
|
||||||
.switchMap((action: DataFindByIDRequestAction) => {
|
.switchMap((action: FindByIDRequestCacheAction) => {
|
||||||
return this.restApi.get(this.getFindByIdEndpoint(action))
|
return this.restApi.get(this.getFindByIdEndpoint(action))
|
||||||
.map((data: DSpaceRESTV2Response) => this.getSerializer().deserialize(data))
|
.map((data: DSpaceRESTV2Response) => this.getSerializer().deserialize(data))
|
||||||
.do((t: T) => {
|
.do((t: T) => {
|
||||||
this.cache.add(t, GlobalConfig.cache.msToLive);
|
this.objectCache.add(t, GlobalConfig.cache.msToLive);
|
||||||
})
|
})
|
||||||
.map((t: T) => new DataSuccessAction(action.payload.key, [t.uuid]))
|
.map((t: T) => new RequestCacheSuccessAction(action.payload.key, [t.uuid]))
|
||||||
.catch((errorMsg: string) => Observable.of(new DataErrorAction(action.payload.key, errorMsg)));
|
.catch((errorMsg: string) => Observable.of(new RequestCacheErrorAction(action.payload.key, errorMsg)));
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
import { OpaqueToken } from "@angular/core";
|
import { OpaqueToken } from "@angular/core";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { Store } from "@ngrx/store";
|
import { Store } from "@ngrx/store";
|
||||||
import { CacheService } from "./cache/cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { CacheableObject } from "./cache/cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { DataState } from "./data.reducer";
|
import { RequestCacheState } from "../cache/request-cache.reducer";
|
||||||
import { DataFindAllRequestAction, DataFindByIDRequestAction } from "./data.actions";
|
import { FindAllRequestCacheAction, FindByIDRequestCacheAction } from "../cache/request-cache.actions";
|
||||||
import { ParamHash } from "../shared/param-hash";
|
import { ParamHash } from "../shared/param-hash";
|
||||||
import { isNotEmpty } from "../../shared/empty.util";
|
import { isNotEmpty } from "../../shared/empty.util";
|
||||||
|
|
||||||
@@ -12,28 +12,28 @@ export abstract class DataService<T extends CacheableObject> {
|
|||||||
abstract name: OpaqueToken;
|
abstract name: OpaqueToken;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<DataState>,
|
private store: Store<RequestCacheState>,
|
||||||
private cache: CacheService
|
private objectCache: ObjectCacheService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
findAll(scopeID?: string): Observable<Array<T>> {
|
findAll(scopeID?: string): Observable<Array<T>> {
|
||||||
const key = new ParamHash(this.name, 'findAll', scopeID).toString();
|
const key = new ParamHash(this.name, 'findAll', scopeID).toString();
|
||||||
this.store.dispatch(new DataFindAllRequestAction(key, this.name, scopeID));
|
this.store.dispatch(new FindAllRequestCacheAction(key, this.name, scopeID));
|
||||||
//get an observable of the IDs from the store
|
//get an observable of the IDs from the store
|
||||||
return this.store.select<Array<string>>('core', 'data', key, 'resourceUUIDs')
|
return this.store.select<Array<string>>('core', 'cache', 'request', key, 'resourceUUIDs')
|
||||||
.flatMap((resourceUUIDs: Array<string>) => {
|
.flatMap((resourceUUIDs: Array<string>) => {
|
||||||
// use those IDs to fetch the actual objects from the cache
|
// use those IDs to fetch the actual objects from the cache
|
||||||
return this.cache.getList<T>(resourceUUIDs);
|
return this.objectCache.getList<T>(resourceUUIDs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
findById(id: string): Observable<T> {
|
findById(id: string): Observable<T> {
|
||||||
const key = new ParamHash(this.name, 'findById', id).toString();
|
const key = new ParamHash(this.name, 'findById', id).toString();
|
||||||
this.store.dispatch(new DataFindByIDRequestAction(key, this.name, id));
|
this.store.dispatch(new FindByIDRequestCacheAction(key, this.name, id));
|
||||||
return this.store.select<Array<string>>('core', 'data', key, 'resourceUUIDs')
|
return this.store.select<Array<string>>('core', 'cache', 'request', key, 'resourceUUIDs')
|
||||||
.flatMap((resourceUUIDs: Array<string>) => {
|
.flatMap((resourceUUIDs: Array<string>) => {
|
||||||
if(isNotEmpty(resourceUUIDs)) {
|
if(isNotEmpty(resourceUUIDs)) {
|
||||||
return this.cache.get<T>(resourceUUIDs[0]);
|
return this.objectCache.get<T>(resourceUUIDs[0]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Observable.of(undefined);
|
return Observable.of(undefined);
|
||||||
|
@@ -3,10 +3,10 @@ import { DataEffects } from "./data.effects";
|
|||||||
import { Serializer } from "../serializer";
|
import { Serializer } from "../serializer";
|
||||||
import { Item } from "../shared/item.model";
|
import { Item } from "../shared/item.model";
|
||||||
import { DSpaceRESTv2Serializer } from "../dspace-rest-v2/dspace-rest-v2.serializer";
|
import { DSpaceRESTv2Serializer } from "../dspace-rest-v2/dspace-rest-v2.serializer";
|
||||||
import { CacheService } from "./cache/cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { DSpaceRESTv2Service } from "../dspace-rest-v2/dspace-rest-v2.service";
|
import { DSpaceRESTv2Service } from "../dspace-rest-v2/dspace-rest-v2.service";
|
||||||
import { Actions, Effect } from "@ngrx/effects";
|
import { Actions, Effect } from "@ngrx/effects";
|
||||||
import { DataFindAllRequestAction, DataFindByIDRequestAction } from "./data.actions";
|
import { FindAllRequestCacheAction, FindByIDRequestCacheAction } from "../cache/request-cache.actions";
|
||||||
import { ItemDataService } from "./item-data.service";
|
import { ItemDataService } from "./item-data.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -14,17 +14,17 @@ export class ItemDataEffects extends DataEffects<Item> {
|
|||||||
constructor(
|
constructor(
|
||||||
actions$: Actions,
|
actions$: Actions,
|
||||||
restApi: DSpaceRESTv2Service,
|
restApi: DSpaceRESTv2Service,
|
||||||
cache: CacheService,
|
cache: ObjectCacheService,
|
||||||
dataService: ItemDataService
|
dataService: ItemDataService
|
||||||
) {
|
) {
|
||||||
super(actions$, restApi, cache, dataService);
|
super(actions$, restApi, cache, dataService);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getFindAllEndpoint(action: DataFindAllRequestAction): string {
|
protected getFindAllEndpoint(action: FindAllRequestCacheAction): string {
|
||||||
return '/items';
|
return '/items';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getFindByIdEndpoint(action: DataFindByIDRequestAction): string {
|
protected getFindByIdEndpoint(action: FindByIDRequestCacheAction): string {
|
||||||
return `/items/${action.payload.resourceID}`;
|
return `/items/${action.payload.resourceID}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,16 +2,16 @@ import { Injectable, OpaqueToken } from "@angular/core";
|
|||||||
import { Store } from "@ngrx/store";
|
import { Store } from "@ngrx/store";
|
||||||
import { DataService } from "./data.service";
|
import { DataService } from "./data.service";
|
||||||
import { Item } from "../shared/item.model";
|
import { Item } from "../shared/item.model";
|
||||||
import { CacheService } from "./cache/cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { DataState } from "./data.reducer";
|
import { RequestCacheState } from "../cache/request-cache.reducer";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ItemDataService extends DataService<Item> {
|
export class ItemDataService extends DataService<Item> {
|
||||||
name = new OpaqueToken('ItemDataService');
|
name = new OpaqueToken('ItemDataService');
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
store: Store<DataState>,
|
store: Store<RequestCacheState>,
|
||||||
cache: CacheService
|
cache: ObjectCacheService
|
||||||
) {
|
) {
|
||||||
super(store, cache);
|
super(store, cache);
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { autoserialize, autoserializeAs } from "cerialize";
|
import { autoserialize, autoserializeAs } from "cerialize";
|
||||||
import { Metadatum } from "./metadatum.model"
|
import { Metadatum } from "./metadatum.model"
|
||||||
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
||||||
import { CacheableObject } from "../data-services/cache/cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* An abstract model class for a DSpaceObject.
|
||||||
|
@@ -92,7 +92,7 @@ export function createMockApi() {
|
|||||||
|
|
||||||
router.route('/collections/:collection_id')
|
router.route('/collections/:collection_id')
|
||||||
.get(function(req, res) {
|
.get(function(req, res) {
|
||||||
console.log('GET', util.inspect(req.collection.id, { colors: true }));
|
// console.log('GET', util.inspect(req.collection.id, { colors: true }));
|
||||||
res.json(toHALResponse(req, req.collection));
|
res.json(toHALResponse(req, req.collection));
|
||||||
// })
|
// })
|
||||||
// .put(function(req, res) {
|
// .put(function(req, res) {
|
||||||
@@ -154,7 +154,7 @@ export function createMockApi() {
|
|||||||
|
|
||||||
router.route('/items/:item_id')
|
router.route('/items/:item_id')
|
||||||
.get(function(req, res) {
|
.get(function(req, res) {
|
||||||
console.log('GET', util.inspect(req.item, { colors: true }));
|
// console.log('GET', util.inspect(req.item, { colors: true }));
|
||||||
res.json(toHALResponse(req, req.item));
|
res.json(toHALResponse(req, req.item));
|
||||||
// })
|
// })
|
||||||
// .put(function(req, res) {
|
// .put(function(req, res) {
|
||||||
@@ -199,7 +199,7 @@ export function createMockApi() {
|
|||||||
|
|
||||||
router.route('/bundles/:bundle_id')
|
router.route('/bundles/:bundle_id')
|
||||||
.get(function(req, res) {
|
.get(function(req, res) {
|
||||||
console.log('GET', util.inspect(req.bundle, { colors: true }));
|
// console.log('GET', util.inspect(req.bundle, { colors: true }));
|
||||||
res.json(toHALResponse(req, req.bundle));
|
res.json(toHALResponse(req, req.bundle));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ export function createMockApi() {
|
|||||||
|
|
||||||
router.route('/bitstreams/:bitstream_id')
|
router.route('/bitstreams/:bitstream_id')
|
||||||
.get(function(req, res) {
|
.get(function(req, res) {
|
||||||
console.log('GET', util.inspect(req.bitstream, { colors: true }));
|
// console.log('GET', util.inspect(req.bitstream, { colors: true }));
|
||||||
res.json(toHALResponse(req, req.bitstream));
|
res.json(toHALResponse(req, req.bitstream));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user