Added item services.

This commit is contained in:
Art Lowel
2017-02-16 13:39:34 +01:00
parent 2e5441d6f7
commit 45a2f5b240
14 changed files with 336 additions and 12 deletions

View File

@@ -1,6 +1,8 @@
import { EffectsModule } from "@ngrx/effects";
import { CollectionDataEffects } from "./data-services/collection/collection-data.effects";
import { ItemDataEffects } from "./data-services/item/item-data.effects";
export const coreEffects = [
EffectsModule.run(CollectionDataEffects)
EffectsModule.run(CollectionDataEffects),
EffectsModule.run(ItemDataEffects)
];

View File

@@ -5,6 +5,7 @@ import { isNotEmpty } from "../shared/empty.util";
import { DSpaceRESTv2Service } from "./dspace-rest-v2/dspace-rest-v2.service";
import { CollectionDataService } from "./data-services/collection/collection-data.service";
import { CacheService } from "./data-services/cache/cache.service";
import { ItemDataService } from "./data-services/item/item-data.service";
const IMPORTS = [
CommonModule,
@@ -19,6 +20,7 @@ const EXPORTS = [
const PROVIDERS = [
CollectionDataService,
ItemDataService,
DSpaceRESTv2Service,
CacheService
];

View File

@@ -4,14 +4,17 @@ import {
collectionDataReducer
} from "./data-services/collection/collection-data.reducer";
import { CacheState, cacheReducer } from "./data-services/cache/cache.reducer";
import { ItemDataState, itemDataReducer } from "./data-services/item/item-data.reducer";
export interface CoreState {
collectionData: CollectionDataState,
itemData: ItemDataState,
cache: CacheState
}
export const reducers = {
collectionData: collectionDataReducer,
itemData: itemDataReducer,
cache: cacheReducer
};

View File

@@ -1,5 +1,5 @@
import { Injectable } from "@angular/core";
import { Actions, Effect, toPayload } from "@ngrx/effects";
import { Actions, Effect } from "@ngrx/effects";
import { Collection } from "../../shared/collection.model";
import { Observable } from "rxjs";
import {

View File

@@ -15,8 +15,8 @@ export class CollectionDataService {
private cache: CacheService
) { }
findAll(scope?: Collection): Observable<Collection[]> {
this.store.dispatch(new CollectionFindMultipleRequestAction(scope));
findAll(scopeID?: string): Observable<Collection[]> {
this.store.dispatch(new CollectionFindMultipleRequestAction(scopeID));
//get an observable of the IDs from the collectionData store
return this.store.select<Array<string>>('core', 'collectionData', 'findMultiple', 'collectionsIDs')
.flatMap((collectionIds: Array<string>) => {

View File

@@ -1,6 +1,5 @@
import { Action } from "@ngrx/store";
import { type } from "../../../shared/ngrx/type";
import { Collection } from "../../shared/collection.model";
import { PaginationOptions } from "../../shared/pagination-options.model";
import { SortOptions } from "../../shared/sort-options.model";
@@ -13,18 +12,18 @@ export const CollectionFindMultipleActionTypes = {
export class CollectionFindMultipleRequestAction implements Action {
type = CollectionFindMultipleActionTypes.FIND_MULTI_REQUEST;
payload: {
scope: Collection,
scopeID: string,
paginationOptions: PaginationOptions,
sortOptions: SortOptions
};
constructor(
scope?: Collection,
scopeID?: string,
paginationOptions: PaginationOptions = new PaginationOptions(),
sortOptions: SortOptions = new SortOptions()
) {
this.payload = {
scope,
scopeID,
paginationOptions,
sortOptions
}

View File

@@ -1,4 +1,3 @@
import { Collection } from "../../shared/collection.model";
import { PaginationOptions } from "../../shared/pagination-options.model";
import { SortOptions } from "../../shared/sort-options.model";
import {
@@ -7,7 +6,7 @@ import {
} from "./collection-find-multiple.actions";
export interface CollectionFindMultipleState {
scope: Collection;
scopeID: string;
collectionsIDs: Array<String>;
isLoading: boolean;
errorMessage: string;
@@ -16,7 +15,7 @@ export interface CollectionFindMultipleState {
}
const initialState: CollectionFindMultipleState = {
scope: undefined,
scopeID: undefined,
collectionsIDs: [],
isLoading: false,
errorMessage: undefined,
@@ -29,7 +28,7 @@ export const findMultipleReducer = (state = initialState, action: CollectionFind
case CollectionFindMultipleActionTypes.FIND_MULTI_REQUEST: {
return Object.assign({}, state, {
scope: action.payload.scope,
scopeID: action.payload.scopeID,
collectionsIDs: [],
isLoading: true,
errorMessage: undefined,

View File

@@ -0,0 +1,66 @@
import { Injectable } from "@angular/core";
import { Actions, Effect } from "@ngrx/effects";
import { Item } from "../../shared/item.model";
import { Observable } from "rxjs";
import {
ItemFindMultipleActionTypes,
ItemFindMultipleSuccessAction,
ItemFindMultipleErrorAction
} from "./item-find-multiple.actions";
import {
ItemFindSingleActionTypes,
ItemFindByIdSuccessAction,
ItemFindByIdErrorAction
} from "./item-find-single.actions";
import { DSpaceRESTV2Response } from "../../dspace-rest-v2/dspace-rest-v2-response.model";
import { DSpaceRESTv2Serializer } from "../../dspace-rest-v2/dspace-rest-v2.serializer";
import { DSpaceRESTv2Service } from "../../dspace-rest-v2/dspace-rest-v2.service";
import { CacheService } from "../cache/cache.service";
import { GlobalConfig } from "../../../../config";
@Injectable()
export class ItemDataEffects {
constructor(
private actions$: Actions,
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$
.ofType(ItemFindMultipleActionTypes.FIND_MULTI_REQUEST)
.switchMap(() => {
return this.restApi.get('/items')
.map((data: DSpaceRESTV2Response) => new DSpaceRESTv2Serializer(Item).deserializeArray(data))
.do((items: Item[]) => {
items.forEach((item) => {
this.cache.add(item, GlobalConfig.cache.msToLive);
});
})
.map((items: Array<Item>) => items.map(item => item.id))
.map((ids: Array<string>) => new ItemFindMultipleSuccessAction(ids))
.catch((errorMsg: string) => Observable.of(new ItemFindMultipleErrorAction(errorMsg)));
});
@Effect() findById$ = this.actions$
.ofType(ItemFindSingleActionTypes.FIND_BY_ID_REQUEST)
.switchMap(action => {
if (this.cache.has(action.payload)) {
return this.cache.get<Item>(action.payload)
.map(item => new ItemFindByIdSuccessAction(item.id));
}
else {
return this.restApi.get(`/items/${action.payload}`)
.map((data: DSpaceRESTV2Response) => new DSpaceRESTv2Serializer(Item).deserialize(data))
.do((item: Item) => {
this.cache.add(item, GlobalConfig.cache.msToLive);
})
.map((item: Item) => new ItemFindByIdSuccessAction(item.id))
.catch((errorMsg: string) => Observable.of(new ItemFindByIdErrorAction(errorMsg)));
}
});
}

View File

@@ -0,0 +1,17 @@
import { combineReducers } from "@ngrx/store";
import { ItemFindMultipleState, findMultipleReducer } from "./item-find-multiple.reducer";
import { ItemFindSingleState, findSingleReducer } from "./item-find-single.reducer";
export interface ItemDataState {
findMultiple: ItemFindMultipleState,
findSingle: ItemFindSingleState
}
const reducers = {
findMultiple: findMultipleReducer,
findSingle: findSingleReducer
};
export function itemDataReducer(state: any, action: any) {
return combineReducers(reducers)(state, action);
}

View File

@@ -0,0 +1,33 @@
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { ItemDataState } from "./item-data.reducer";
import { Store } from "@ngrx/store";
import { Item } from "../../shared/item.model";
import { ItemFindMultipleRequestAction } from "./item-find-multiple.actions";
import { ItemFindByIdRequestAction } from "./item-find-single.actions";
import { CacheService } from "../cache/cache.service";
import 'rxjs/add/observable/forkJoin';
@Injectable()
export class ItemDataService {
constructor(
private store: Store<ItemDataState>,
private cache: CacheService
) { }
findAll(scopeID?: string): Observable<Item[]> {
this.store.dispatch(new ItemFindMultipleRequestAction(scopeID));
//get an observable of the IDs from the itemData store
return this.store.select<Array<string>>('core', 'itemData', 'findMultiple', 'itemsIDs')
.flatMap((itemIds: Array<string>) => {
// use those IDs to fetch the actual item objects from the cache
return this.cache.getList<Item>(itemIds);
});
}
findById(id: string): Observable<Item> {
this.store.dispatch(new ItemFindByIdRequestAction(id));
return this.cache.get<Item>(id);
}
}

View File

@@ -0,0 +1,54 @@
import { Action } from "@ngrx/store";
import { type } from "../../../shared/ngrx/type";
import { PaginationOptions } from "../../shared/pagination-options.model";
import { SortOptions } from "../../shared/sort-options.model";
export const ItemFindMultipleActionTypes = {
FIND_MULTI_REQUEST: type('dspace/core/data/item/FIND_MULTI_REQUEST'),
FIND_MULTI_SUCCESS: type('dspace/core/data/item/FIND_MULTI_SUCCESS'),
FIND_MULTI_ERROR: type('dspace/core/data/item/FIND_MULTI_ERROR')
};
export class ItemFindMultipleRequestAction implements Action {
type = ItemFindMultipleActionTypes.FIND_MULTI_REQUEST;
payload: {
scopeID: string,
paginationOptions: PaginationOptions,
sortOptions: SortOptions
};
constructor(
scopeID?: string,
paginationOptions: PaginationOptions = new PaginationOptions(),
sortOptions: SortOptions = new SortOptions()
) {
this.payload = {
scopeID,
paginationOptions,
sortOptions
}
}
}
export class ItemFindMultipleSuccessAction implements Action {
type = ItemFindMultipleActionTypes.FIND_MULTI_SUCCESS;
payload: Array<string>;
constructor(itemIDs: Array<string>) {
this.payload = itemIDs;
}
}
export class ItemFindMultipleErrorAction implements Action {
type = ItemFindMultipleActionTypes.FIND_MULTI_ERROR;
payload: string;
constructor(errorMessage: string) {
this.payload = errorMessage;
}
}
export type ItemFindMultipleAction
= ItemFindMultipleRequestAction
| ItemFindMultipleSuccessAction
| ItemFindMultipleErrorAction;

View File

@@ -0,0 +1,59 @@
import { PaginationOptions } from "../../shared/pagination-options.model";
import { SortOptions } from "../../shared/sort-options.model";
import {
ItemFindMultipleAction,
ItemFindMultipleActionTypes
} from "./item-find-multiple.actions";
export interface ItemFindMultipleState {
scopeID: string;
itemsIDs: Array<String>;
isLoading: boolean;
errorMessage: string;
paginationOptions: PaginationOptions;
sortOptions: SortOptions;
}
const initialState: ItemFindMultipleState = {
scopeID: undefined,
itemsIDs: [],
isLoading: false,
errorMessage: undefined,
paginationOptions: undefined,
sortOptions: undefined
};
export const findMultipleReducer = (state = initialState, action: ItemFindMultipleAction): ItemFindMultipleState => {
switch (action.type) {
case ItemFindMultipleActionTypes.FIND_MULTI_REQUEST: {
return Object.assign({}, state, {
scopeID: action.payload.scopeID,
itemsIDs: [],
isLoading: true,
errorMessage: undefined,
paginationOptions: action.payload.paginationOptions,
sortOptions: action.payload.sortOptions
});
}
case ItemFindMultipleActionTypes.FIND_MULTI_SUCCESS: {
return Object.assign({}, state, {
isLoading: false,
itemsIDs: action.payload,
errorMessage: undefined
});
}
case ItemFindMultipleActionTypes.FIND_MULTI_ERROR: {
return Object.assign({}, state, {
isLoading: false,
errorMessage: action.payload
});
}
default: {
return state;
}
}
};

View File

@@ -0,0 +1,42 @@
import { Action } from "@ngrx/store";
import { type } from "../../../shared/ngrx/type";
import { Item } from "../../shared/item.model";
export const ItemFindSingleActionTypes = {
FIND_BY_ID_REQUEST: type('dspace/core/data/item/FIND_BY_ID_REQUEST'),
FIND_BY_ID_SUCCESS: type('dspace/core/data/item/FIND_BY_ID_SUCCESS'),
FIND_BY_ID_ERROR: type('dspace/core/data/item/FIND_BY_ID_ERROR')
};
export class ItemFindByIdRequestAction implements Action {
type = ItemFindSingleActionTypes.FIND_BY_ID_REQUEST;
payload: string;
constructor(id: string) {
this.payload = id;
}
}
export class ItemFindByIdSuccessAction implements Action {
type = ItemFindSingleActionTypes.FIND_BY_ID_SUCCESS;
payload: string;
constructor(itemID: string) {
this.payload = itemID;
}
}
export class ItemFindByIdErrorAction implements Action {
type = ItemFindSingleActionTypes.FIND_BY_ID_ERROR;
payload: string;
constructor(errorMessage: string) {
this.payload = errorMessage;
}
}
export type ItemFindSingleAction
= ItemFindByIdRequestAction
| ItemFindByIdSuccessAction
| ItemFindByIdErrorAction;

View File

@@ -0,0 +1,48 @@
import { Item } from "../../shared/item.model";
import {
ItemFindSingleAction,
ItemFindSingleActionTypes
} from "./item-find-single.actions";
export interface ItemFindSingleState {
isLoading: boolean;
errorMessage: string;
itemID: string;
}
const initialState: ItemFindSingleState = {
isLoading: false,
errorMessage: undefined,
itemID: undefined
};
export const findSingleReducer = (state = initialState, action: ItemFindSingleAction): ItemFindSingleState => {
switch (action.type) {
case ItemFindSingleActionTypes.FIND_BY_ID_REQUEST: {
return Object.assign({}, state, {
isLoading: true,
errorMessage: undefined,
itemID: action.payload
});
}
case ItemFindSingleActionTypes.FIND_BY_ID_SUCCESS: {
return Object.assign({}, state, {
isLoading: false,
errorMessage: undefined,
});
}
case ItemFindSingleActionTypes.FIND_BY_ID_ERROR: {
return Object.assign({}, state, {
isLoading: false,
errorMessage: action.payload
});
}
default: {
return state;
}
}
};