|
import { Observable } from 'rxjs/Observable'; |
|
import { Store } from '@ngrx/store'; |
|
|
|
export interface EntityHttpService<T> { |
|
query: () => Observable<T[]>; |
|
create: () => Observable<T>; |
|
update: () => Observable<T>; |
|
delete: () => {}; |
|
} |
|
|
|
export interface EntityState { |
|
collection: any[]; |
|
loading: boolean; |
|
} |
|
|
|
export interface Action { |
|
type: string; |
|
payload?: any; |
|
} |
|
|
|
export const initialEntityState = { |
|
collection: [], |
|
loading: false |
|
}; |
|
|
|
export class EntityService<T> { |
|
constructor( |
|
private _store: Store<any>, |
|
private _name: string, |
|
private _service: EntityHttpService<T>) {} |
|
|
|
query() { return this._createHttp('query'); } |
|
create() { return this._createHttp('create'); } |
|
update() { return this._createHttp('update'); } |
|
delete() { return this._createHttp('delete'); } |
|
|
|
private _createHttp(method: string) { |
|
const obs = this._service[method](); |
|
|
|
this._store.dispatch({ |
|
type: `[${method} ${this._name}] ${method} start` |
|
}); |
|
|
|
obs.subscribe(res => { |
|
this._store.dispatch({ |
|
type: `[${method} ${this._name}] ${method} success`, |
|
payload: res |
|
}); |
|
}, (err) => { |
|
this._store.dispatch({ |
|
type: `[${method} ${this._name}] ${method} error`, |
|
payload: err |
|
}); |
|
}); |
|
|
|
return obs; |
|
} |
|
} |
|
|
|
export function entityReducer(name: string, keyProp: string = 'id') { |
|
return function(state: EntityState = initialEntityState, action: Action) { |
|
switch (action.type) { |
|
case `[query ${this._name}] query`: |
|
return { ...state, collection: [], loading: true }; |
|
case `[query ${this._name}] query success`: |
|
return { ...state, collection: [...action.payload] }; |
|
case `[query ${this._name}] query error`: |
|
return { ...state, loading: false }; |
|
case `[create ${this._name}] create`: |
|
return { ...state, collection: [], loading: true }; |
|
case `[create ${this._name}] create success`: |
|
return { ...state, collection: [...state.collection, { ...action.payload }] }; |
|
case `[create ${this._name}] create error`: |
|
return { ...state, loading: false }; |
|
case `[update ${this._name}] update`: |
|
return { ...state, loading: true }; |
|
case `[update ${this._name}] update success`: |
|
const updateCollection = [...state.collection]; |
|
const updateIdx = updateCollection.findIndex(c => c[keyProp] === action.payload[keyProp]); |
|
if (updateIdx > -1) { updateCollection.splice(updateIdx, 1); } |
|
return { ...state, collection: updateCollection }; |
|
case `[update ${this._name}] update error`: |
|
return { ...state, loading: false }; |
|
case `[delete ${this._name}] delete`: |
|
return { ...state, loading: true }; |
|
case `[delete ${this._name}] delete success`: |
|
const deleteCollection = [...state.collection]; |
|
const deleteIdx = deleteCollection.findIndex(c => c[keyProp] === action.payload[keyProp]); |
|
if (deleteIdx > -1) { deleteCollection.splice(deleteIdx, 1); } |
|
return { ...state, collection: deleteCollection }; |
|
case `[delete ${this._name}] delete error`: |
|
return { ...state, loading: false }; |
|
default: |
|
return state; |
|
} |
|
}; |
|
} |