mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 21:13:07 +00:00
Moved all objects to a single data store: the cache.
This commit is contained in:
@@ -10,5 +10,9 @@ module.exports = {
|
|||||||
"ui": {
|
"ui": {
|
||||||
"nameSpace": "/",
|
"nameSpace": "/",
|
||||||
"baseURL": "http://localhost:3000"
|
"baseURL": "http://localhost:3000"
|
||||||
|
},
|
||||||
|
"cache": {
|
||||||
|
// how long should objects be cached for by default
|
||||||
|
"msToLive": 15 * 60 * 1000 //15 minutes
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@@ -4,6 +4,7 @@ import { SharedModule } from "../shared/shared.module";
|
|||||||
import { isNotEmpty } from "../shared/empty.util";
|
import { isNotEmpty } from "../shared/empty.util";
|
||||||
import { DSpaceRESTv2Service } from "./dspace-rest-v2/dspace-rest-v2.service";
|
import { DSpaceRESTv2Service } from "./dspace-rest-v2/dspace-rest-v2.service";
|
||||||
import { CollectionDataService } from "./data-services/collection/collection-data.service";
|
import { CollectionDataService } from "./data-services/collection/collection-data.service";
|
||||||
|
import { CacheService } from "./data-services/cache/cache.service";
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -18,7 +19,8 @@ const EXPORTS = [
|
|||||||
|
|
||||||
const PROVIDERS = [
|
const PROVIDERS = [
|
||||||
CollectionDataService,
|
CollectionDataService,
|
||||||
DSpaceRESTv2Service
|
DSpaceRESTv2Service,
|
||||||
|
CacheService
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -3,13 +3,16 @@ import {
|
|||||||
CollectionDataState,
|
CollectionDataState,
|
||||||
collectionDataReducer
|
collectionDataReducer
|
||||||
} from "./data-services/collection/collection-data.reducer";
|
} from "./data-services/collection/collection-data.reducer";
|
||||||
|
import { CacheState, cacheReducer } from "./data-services/cache/cache.reducer";
|
||||||
|
|
||||||
export interface CoreState {
|
export interface CoreState {
|
||||||
collectionData: CollectionDataState
|
collectionData: CollectionDataState,
|
||||||
|
cache: CacheState
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reducers = {
|
export const reducers = {
|
||||||
collectionData: collectionDataReducer,
|
collectionData: collectionDataReducer,
|
||||||
|
cache: cacheReducer
|
||||||
};
|
};
|
||||||
|
|
||||||
export function coreReducer(state: any, action: any) {
|
export function coreReducer(state: any, action: any) {
|
||||||
|
33
src/app/core/data-services/cache/cache.actions.ts
vendored
Normal file
33
src/app/core/data-services/cache/cache.actions.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
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
|
58
src/app/core/data-services/cache/cache.reducer.ts
vendored
Normal file
58
src/app/core/data-services/cache/cache.reducer.ts
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
58
src/app/core/data-services/cache/cache.service.ts
vendored
Normal file
58
src/app/core/data-services/cache/cache.service.ts
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { Store } from "@ngrx/store";
|
||||||
|
import { CacheState, CacheEntry, CacheableObject } from "./cache.reducer";
|
||||||
|
import { AddToCacheAction, RemoveFromCacheAction } from "./cache.actions";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
import { hasNoValue } from "../../../shared/empty.util";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CacheService {
|
||||||
|
constructor(
|
||||||
|
private store: Store<CacheState>
|
||||||
|
) {}
|
||||||
|
|
||||||
|
add(objectToCache: CacheableObject, msToLive: number): void {
|
||||||
|
this.store.dispatch(new AddToCacheAction(objectToCache, msToLive));
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(uuid: string): void {
|
||||||
|
this.store.dispatch(new RemoveFromCacheAction(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
get<T extends CacheableObject>(uuid: string): Observable<T> {
|
||||||
|
return this.store.select<CacheEntry>('core', 'cache', uuid)
|
||||||
|
.filter(entry => this.isValid(entry))
|
||||||
|
.map((entry: CacheEntry) => <T> entry.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
getList<T extends CacheableObject>(uuids: Array<string>): Observable<Array<T>> {
|
||||||
|
return Observable.combineLatest(
|
||||||
|
uuids.map((id: string) => this.get<T>(id))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
has(uuid: string): boolean {
|
||||||
|
let result: boolean;
|
||||||
|
|
||||||
|
this.store.select<CacheEntry>('core', 'cache', uuid)
|
||||||
|
.take(1)
|
||||||
|
.subscribe(entry => result = this.isValid(entry));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isValid(entry: CacheEntry): boolean {
|
||||||
|
if (hasNoValue(entry)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const timeOutdated = entry.timeAdded + entry.msToLive;
|
||||||
|
const isOutDated = new Date().getTime() > timeOutdated;
|
||||||
|
if (isOutDated) {
|
||||||
|
this.store.dispatch(new RemoveFromCacheAction(entry.data.uuid));
|
||||||
|
}
|
||||||
|
return !isOutDated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { Actions, Effect } from "@ngrx/effects";
|
import { Actions, Effect, toPayload } from "@ngrx/effects";
|
||||||
import { Collection } from "../../shared/collection.model";
|
import { Collection } from "../../shared/collection.model";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import {
|
import {
|
||||||
@@ -15,33 +15,52 @@ import {
|
|||||||
import { DSpaceRESTV2Response } from "../../dspace-rest-v2/dspace-rest-v2-response.model";
|
import { DSpaceRESTV2Response } from "../../dspace-rest-v2/dspace-rest-v2-response.model";
|
||||||
import { DSpaceRESTv2Serializer } from "../../dspace-rest-v2/dspace-rest-v2.serializer";
|
import { DSpaceRESTv2Serializer } from "../../dspace-rest-v2/dspace-rest-v2.serializer";
|
||||||
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 { GlobalConfig } from "../../../../config";
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CollectionDataEffects {
|
export class CollectionDataEffects {
|
||||||
constructor(
|
constructor(
|
||||||
private actions$: Actions,
|
private actions$: Actions,
|
||||||
private restApiService: DSpaceRESTv2Service
|
private restApi: DSpaceRESTv2Service,
|
||||||
|
private cache: CacheService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
// TODO, results of a findall aren't retrieved from cache for now,
|
||||||
|
// because currently the cache is more of an object store. We need to move
|
||||||
|
// more towards memoization for things like this.
|
||||||
@Effect() findAll$ = this.actions$
|
@Effect() findAll$ = this.actions$
|
||||||
.ofType(CollectionFindMultipleActionTypes.FIND_MULTI_REQUEST)
|
.ofType(CollectionFindMultipleActionTypes.FIND_MULTI_REQUEST)
|
||||||
.switchMap(() => {
|
.switchMap(() => {
|
||||||
return this.restApiService.get('/collections')
|
return this.restApi.get('/collections')
|
||||||
.map((data: DSpaceRESTV2Response) => new DSpaceRESTv2Serializer(Collection).deserializeArray(data))
|
.map((data: DSpaceRESTV2Response) => new DSpaceRESTv2Serializer(Collection).deserializeArray(data))
|
||||||
.map((collections: Collection[]) => new CollectionFindMultipleSuccessAction(collections))
|
.do((collections: Collection[]) => {
|
||||||
|
collections.forEach((collection) => {
|
||||||
|
this.cache.add(collection, GlobalConfig.cache.msToLive);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.map((collections: Array<Collection>) => collections.map(collection => collection.id))
|
||||||
|
.map((ids: Array<string>) => new CollectionFindMultipleSuccessAction(ids))
|
||||||
.catch((errorMsg: string) => Observable.of(new CollectionFindMultipleErrorAction(errorMsg)));
|
.catch((errorMsg: string) => Observable.of(new CollectionFindMultipleErrorAction(errorMsg)));
|
||||||
});
|
});
|
||||||
|
|
||||||
@Effect() findById$ = this.actions$
|
@Effect() findById$ = this.actions$
|
||||||
.ofType(CollectionFindSingleActionTypes.FIND_BY_ID_REQUEST)
|
.ofType(CollectionFindSingleActionTypes.FIND_BY_ID_REQUEST)
|
||||||
.switchMap(action => {
|
.switchMap(action => {
|
||||||
return this.restApiService.get(`/collections/${action.payload}`)
|
if (this.cache.has(action.payload)) {
|
||||||
.map((data: DSpaceRESTV2Response) => {
|
return this.cache.get<Collection>(action.payload)
|
||||||
const t = new DSpaceRESTv2Serializer(Collection).deserialize(data);
|
.map(collection => new CollectionFindByIdSuccessAction(collection.id));
|
||||||
return t;
|
}
|
||||||
})
|
else {
|
||||||
.map((collection: Collection) => new CollectionFindByIdSuccessAction(collection))
|
return this.restApi.get(`/collections/${action.payload}`)
|
||||||
.catch((errorMsg: string) => Observable.of(new CollectionFindByIdErrorAction(errorMsg)));
|
.map((data: DSpaceRESTV2Response) => new DSpaceRESTv2Serializer(Collection).deserialize(data))
|
||||||
});
|
.do((collection: Collection) => {
|
||||||
|
this.cache.add(collection, GlobalConfig.cache.msToLive);
|
||||||
|
})
|
||||||
|
.map((collection: Collection) => new CollectionFindByIdSuccessAction(collection.id))
|
||||||
|
.catch((errorMsg: string) => Observable.of(new CollectionFindByIdErrorAction(errorMsg)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -5,26 +5,29 @@ import { Store } from "@ngrx/store";
|
|||||||
import { Collection } from "../../shared/collection.model";
|
import { Collection } from "../../shared/collection.model";
|
||||||
import { CollectionFindMultipleRequestAction } from "./collection-find-multiple.actions";
|
import { CollectionFindMultipleRequestAction } from "./collection-find-multiple.actions";
|
||||||
import { CollectionFindByIdRequestAction } from "./collection-find-single.actions";
|
import { CollectionFindByIdRequestAction } from "./collection-find-single.actions";
|
||||||
import { isNotEmpty } from "../../../shared/empty.util";
|
import { CacheService } from "../cache/cache.service";
|
||||||
import 'rxjs/add/operator/filter';
|
import 'rxjs/add/observable/forkJoin';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CollectionDataService {
|
export class CollectionDataService {
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<CollectionDataState>
|
private store: Store<CollectionDataState>,
|
||||||
|
private cache: CacheService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
findAll(scope?: Collection): Observable<Collection[]> {
|
findAll(scope?: Collection): Observable<Collection[]> {
|
||||||
this.store.dispatch(new CollectionFindMultipleRequestAction(scope));
|
this.store.dispatch(new CollectionFindMultipleRequestAction(scope));
|
||||||
return this.store.select<Collection[]>('core', 'collectionData', 'findMultiple', 'collections');
|
//get an observable of the IDs from the collectionData store
|
||||||
|
return this.store.select<Array<string>>('core', 'collectionData', 'findMultiple', 'collectionsIDs')
|
||||||
|
.flatMap((collectionIds: Array<string>) => {
|
||||||
|
// use those IDs to fetch the actual collection objects from the cache
|
||||||
|
return this.cache.getList<Collection>(collectionIds);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
findById(id: string): Observable<Collection> {
|
findById(id: string): Observable<Collection> {
|
||||||
this.store.dispatch(new CollectionFindByIdRequestAction(id));
|
this.store.dispatch(new CollectionFindByIdRequestAction(id));
|
||||||
return this.store.select<Collection>('core', 'collectionData', 'findSingle', 'collection')
|
return this.cache.get<Collection>(id);
|
||||||
//this filter is necessary because the same collection
|
|
||||||
//object in the state is used for every findById call
|
|
||||||
.filter(collection => isNotEmpty(collection) && collection.id === id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -33,10 +33,10 @@ export class CollectionFindMultipleRequestAction implements Action {
|
|||||||
|
|
||||||
export class CollectionFindMultipleSuccessAction implements Action {
|
export class CollectionFindMultipleSuccessAction implements Action {
|
||||||
type = CollectionFindMultipleActionTypes.FIND_MULTI_SUCCESS;
|
type = CollectionFindMultipleActionTypes.FIND_MULTI_SUCCESS;
|
||||||
payload: Collection[];
|
payload: Array<string>;
|
||||||
|
|
||||||
constructor(collections: Collection[]) {
|
constructor(collectionIDs: Array<string>) {
|
||||||
this.payload = collections;
|
this.payload = collectionIDs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ import {
|
|||||||
|
|
||||||
export interface CollectionFindMultipleState {
|
export interface CollectionFindMultipleState {
|
||||||
scope: Collection;
|
scope: Collection;
|
||||||
collections: Collection[];
|
collectionsIDs: Array<String>;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
errorMessage: string;
|
errorMessage: string;
|
||||||
paginationOptions: PaginationOptions;
|
paginationOptions: PaginationOptions;
|
||||||
@@ -17,7 +17,7 @@ export interface CollectionFindMultipleState {
|
|||||||
|
|
||||||
const initialState: CollectionFindMultipleState = {
|
const initialState: CollectionFindMultipleState = {
|
||||||
scope: undefined,
|
scope: undefined,
|
||||||
collections: [],
|
collectionsIDs: [],
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
errorMessage: undefined,
|
errorMessage: undefined,
|
||||||
paginationOptions: undefined,
|
paginationOptions: undefined,
|
||||||
@@ -30,7 +30,7 @@ export const findMultipleReducer = (state = initialState, action: CollectionFind
|
|||||||
case CollectionFindMultipleActionTypes.FIND_MULTI_REQUEST: {
|
case CollectionFindMultipleActionTypes.FIND_MULTI_REQUEST: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
scope: action.payload.scope,
|
scope: action.payload.scope,
|
||||||
collections: [],
|
collectionsIDs: [],
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
errorMessage: undefined,
|
errorMessage: undefined,
|
||||||
paginationOptions: action.payload.paginationOptions,
|
paginationOptions: action.payload.paginationOptions,
|
||||||
@@ -41,7 +41,7 @@ export const findMultipleReducer = (state = initialState, action: CollectionFind
|
|||||||
case CollectionFindMultipleActionTypes.FIND_MULTI_SUCCESS: {
|
case CollectionFindMultipleActionTypes.FIND_MULTI_SUCCESS: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
collections: action.payload,
|
collectionsIDs: action.payload,
|
||||||
errorMessage: undefined
|
errorMessage: undefined
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -19,10 +19,10 @@ export class CollectionFindByIdRequestAction implements Action {
|
|||||||
|
|
||||||
export class CollectionFindByIdSuccessAction implements Action {
|
export class CollectionFindByIdSuccessAction implements Action {
|
||||||
type = CollectionFindSingleActionTypes.FIND_BY_ID_SUCCESS;
|
type = CollectionFindSingleActionTypes.FIND_BY_ID_SUCCESS;
|
||||||
payload: Collection;
|
payload: string;
|
||||||
|
|
||||||
constructor(collection: Collection) {
|
constructor(collectionID: string) {
|
||||||
this.payload = collection;
|
this.payload = collectionID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,17 +5,15 @@ import {
|
|||||||
} from "./collection-find-single.actions";
|
} from "./collection-find-single.actions";
|
||||||
|
|
||||||
export interface CollectionFindSingleState {
|
export interface CollectionFindSingleState {
|
||||||
collection: Collection;
|
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
errorMessage: string;
|
errorMessage: string;
|
||||||
id: string;
|
collectionID: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: CollectionFindSingleState = {
|
const initialState: CollectionFindSingleState = {
|
||||||
collection: undefined,
|
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
errorMessage: undefined,
|
errorMessage: undefined,
|
||||||
id: undefined,
|
collectionID: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
export const findSingleReducer = (state = initialState, action: CollectionFindSingleAction): CollectionFindSingleState => {
|
export const findSingleReducer = (state = initialState, action: CollectionFindSingleAction): CollectionFindSingleState => {
|
||||||
@@ -24,17 +22,15 @@ export const findSingleReducer = (state = initialState, action: CollectionFindSi
|
|||||||
case CollectionFindSingleActionTypes.FIND_BY_ID_REQUEST: {
|
case CollectionFindSingleActionTypes.FIND_BY_ID_REQUEST: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
id: action.payload,
|
|
||||||
collections: undefined,
|
|
||||||
errorMessage: undefined,
|
errorMessage: undefined,
|
||||||
|
collectionID: action.payload
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
case CollectionFindSingleActionTypes.FIND_BY_ID_SUCCESS: {
|
case CollectionFindSingleActionTypes.FIND_BY_ID_SUCCESS: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
collection: action.payload,
|
errorMessage: undefined,
|
||||||
errorMessage: undefined
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
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";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* An abstract model class for a DSpaceObject.
|
||||||
*/
|
*/
|
||||||
export abstract class DSpaceObject {
|
export abstract class DSpaceObject implements CacheableObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of this DSpaceObject
|
* The identifier of this DSpaceObject
|
||||||
@@ -64,4 +65,12 @@ export abstract class DSpaceObject {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get uuid(): string {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
set uuid(val: string) {
|
||||||
|
this.id = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { Inject, Injectable, isDevMode } from '@angular/core';
|
import { Inject, Injectable, isDevMode } from '@angular/core';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CacheService {
|
export class DemoCacheService {
|
||||||
static KEY = 'CacheService';
|
static KEY = 'DemoCacheService';
|
||||||
|
|
||||||
constructor( @Inject('LRU') public _cache: Map<string, any>) {
|
constructor( @Inject('LRU') public _cache: Map<string, any>) {
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ export class CacheService {
|
|||||||
*/
|
*/
|
||||||
normalizeKey(key: string | number): string {
|
normalizeKey(key: string | number): string {
|
||||||
if (isDevMode() && this._isInvalidValue(key)) {
|
if (isDevMode() && this._isInvalidValue(key)) {
|
||||||
throw new Error('Please provide a valid key to save in the CacheService');
|
throw new Error('Please provide a valid key to save in the DemoCacheService');
|
||||||
}
|
}
|
||||||
|
|
||||||
return key + '';
|
return key + '';
|
@@ -4,7 +4,7 @@ import 'rxjs/add/observable/of';
|
|||||||
import 'rxjs/add/operator/do';
|
import 'rxjs/add/operator/do';
|
||||||
import 'rxjs/add/operator/share';
|
import 'rxjs/add/operator/share';
|
||||||
|
|
||||||
import { CacheService } from '../cache.service';
|
import { DemoCacheService } from '../demo-cache.service';
|
||||||
import { ApiService } from '../api.service';
|
import { ApiService } from '../api.service';
|
||||||
|
|
||||||
export function hashCodeString(str: string): string {
|
export function hashCodeString(str: string): string {
|
||||||
@@ -24,7 +24,7 @@ export function hashCodeString(str: string): string {
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class ModelService {
|
export class ModelService {
|
||||||
// This is only one example of one Model depending on your domain
|
// This is only one example of one Model depending on your domain
|
||||||
constructor(public _api: ApiService, public _cache: CacheService) {
|
constructor(public _api: ApiService, public _cache: DemoCacheService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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, { 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) {
|
||||||
|
@@ -10,7 +10,7 @@ import { TranslateLoader, TranslateModule, TranslateStaticLoader } from 'ng2-tra
|
|||||||
|
|
||||||
import { AppModule, AppComponent } from './app/app.module';
|
import { AppModule, AppComponent } from './app/app.module';
|
||||||
import { SharedModule } from './app/shared/shared.module';
|
import { SharedModule } from './app/shared/shared.module';
|
||||||
import { CacheService } from './app/shared/cache.service';
|
import { DemoCacheService } from './app/shared/demo-cache.service';
|
||||||
import { CoreModule } from "./app/core/core.module";
|
import { CoreModule } from "./app/core/core.module";
|
||||||
|
|
||||||
// Will be merged into @angular/platform-browser in a later release
|
// Will be merged into @angular/platform-browser in a later release
|
||||||
@@ -70,7 +70,7 @@ export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE';
|
|||||||
|
|
||||||
{ provide: 'LRU', useFactory: getLRU, deps: [] },
|
{ provide: 'LRU', useFactory: getLRU, deps: [] },
|
||||||
|
|
||||||
CacheService,
|
DemoCacheService,
|
||||||
|
|
||||||
Meta,
|
Meta,
|
||||||
|
|
||||||
@@ -78,14 +78,14 @@ export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class MainModule {
|
export class MainModule {
|
||||||
constructor(public cache: CacheService) {
|
constructor(public cache: DemoCacheService) {
|
||||||
// TODO(gdi2290): refactor into a lifecycle hook
|
// TODO(gdi2290): refactor into a lifecycle hook
|
||||||
this.doRehydrate();
|
this.doRehydrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
doRehydrate() {
|
doRehydrate() {
|
||||||
let defaultValue = {};
|
let defaultValue = {};
|
||||||
let serverCache = this._getCacheValue(CacheService.KEY, defaultValue);
|
let serverCache = this._getCacheValue(DemoCacheService.KEY, defaultValue);
|
||||||
this.cache.rehydrate(serverCache);
|
this.cache.rehydrate(serverCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@ import { TranslateLoader, TranslateModule, TranslateStaticLoader } from 'ng2-tra
|
|||||||
|
|
||||||
import { AppModule, AppComponent } from './app/app.module';
|
import { AppModule, AppComponent } from './app/app.module';
|
||||||
import { SharedModule } from './app/shared/shared.module';
|
import { SharedModule } from './app/shared/shared.module';
|
||||||
import { CacheService } from './app/shared/cache.service';
|
import { DemoCacheService } from './app/shared/demo-cache.service';
|
||||||
import { CoreModule } from "./app/core/core.module";
|
import { CoreModule } from "./app/core/core.module";
|
||||||
|
|
||||||
// Will be merged into @angular/platform-browser in a later release
|
// Will be merged into @angular/platform-browser in a later release
|
||||||
@@ -61,13 +61,13 @@ export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE';
|
|||||||
|
|
||||||
{ provide: 'LRU', useFactory: getLRU, deps: [] },
|
{ provide: 'LRU', useFactory: getLRU, deps: [] },
|
||||||
|
|
||||||
CacheService,
|
DemoCacheService,
|
||||||
|
|
||||||
Meta,
|
Meta,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class MainModule {
|
export class MainModule {
|
||||||
constructor(public cache: CacheService) {
|
constructor(public cache: DemoCacheService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ export class MainModule {
|
|||||||
* in Universal for now until it's fixed
|
* in Universal for now until it's fixed
|
||||||
*/
|
*/
|
||||||
universalDoDehydrate = (universalCache) => {
|
universalDoDehydrate = (universalCache) => {
|
||||||
universalCache[CacheService.KEY] = JSON.stringify(this.cache.dehydrate());
|
universalCache[DemoCacheService.KEY] = JSON.stringify(this.cache.dehydrate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user