@datorama/akita
Version:
State Management Tailored-Made for JS Applications
602 lines (591 loc) • 17 kB
JavaScript
import { HttpClient } from '@angular/common/http';
import { Subject, throwError } from 'rxjs';
import { filter, map, catchError, finalize, tap } from 'rxjs/operators';
import { Injectable, InjectionToken, defineInjectable, inject } from '@angular/core';
import { isFunction, isObject, isNumber, isString, EntityService, isDefined } from '@datorama/akita';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @enum {string} */
const HttpMethod = {
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
PATCH: 'PATCH',
DELETE: 'DELETE',
};
/** @type {?} */
const ofType = (/**
* @param {?} type
* @return {?}
*/
(type) => filter((/**
* @param {?} action
* @return {?}
*/
(action) => action.type === type)));
/** @type {?} */
const filterMethod = (/**
* @param {?} method
* @return {?}
*/
(method) => filter((/**
* @param {?} action
* @return {?}
*/
(action) => action.method === method)));
/** @type {?} */
const filterStore = (/**
* @param {?} name
* @return {?}
*/
(name) => filter((/**
* @param {?} action
* @return {?}
*/
(action) => action.storeName === name)));
class NgEntityServiceNotifier {
constructor() {
this.dispatcher = new Subject();
this.action$ = this.dispatcher.asObservable();
}
/**
* @param {?} event
* @return {?}
*/
dispatch(event) {
this.dispatcher.next(event);
}
}
NgEntityServiceNotifier.decorators = [
{ type: Injectable, args: [{ providedIn: 'root' },] }
];
/** @nocollapse */ NgEntityServiceNotifier.ngInjectableDef = defineInjectable({ factory: function NgEntityServiceNotifier_Factory() { return new NgEntityServiceNotifier(); }, token: NgEntityServiceNotifier, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgEntityServiceLoader {
constructor() {
this.dispatcher = new Subject();
this.loading$ = this.dispatcher.asObservable();
}
/**
* @param {?} event
* @return {?}
*/
dispatch(event) {
this.dispatcher.next(event);
}
/**
* @param {?=} name
* @return {?}
*/
loadersFor(name) {
/** @type {?} */
const filterStore$$1 = filter((/**
* @param {?} __0
* @return {?}
*/
({ storeName }) => (name ? storeName === name : true)));
/** @type {?} */
const filterMethod$$1 = (/**
* @param {?} mthd
* @return {?}
*/
mthd => filter((/**
* @param {?} __0
* @return {?}
*/
({ method }) => {
return isFunction(mthd) ? mthd(method) : method === mthd;
})));
/** @type {?} */
const actionBased = (/**
* @param {?} current
* @return {?}
*/
(current) => this.loading$.pipe(filterStore$$1, filterMethod$$1(current), map((/**
* @param {?} action
* @return {?}
*/
action => action.loading))));
/** @type {?} */
const idBased = (/**
* @param {?} id
* @param {?} mthd
* @return {?}
*/
(id, mthd) => this.loading$.pipe(filterStore$$1, filterMethod$$1(mthd), filter((/**
* @param {?} action
* @return {?}
*/
action => action.entityId === id)), map((/**
* @param {?} action
* @return {?}
*/
action => action.loading))));
return {
get$: actionBased(HttpMethod.GET),
add$: actionBased(HttpMethod.POST),
update$: actionBased((/**
* @param {?} method
* @return {?}
*/
method => method === HttpMethod.PUT || method === HttpMethod.PATCH)),
delete$: actionBased(HttpMethod.DELETE),
getEntity: (/**
* @param {?} id
* @return {?}
*/
(id) => idBased(id, HttpMethod.GET)),
updateEntity: (/**
* @param {?} id
* @return {?}
*/
(id) => idBased(id, (/**
* @param {?} method
* @return {?}
*/
method => method === HttpMethod.PUT || method === HttpMethod.PATCH))),
deleteEntity: (/**
* @param {?} id
* @return {?}
*/
(id) => idBased(id, HttpMethod.DELETE))
};
}
}
NgEntityServiceLoader.decorators = [
{ type: Injectable, args: [{ providedIn: 'root' },] }
];
/** @nocollapse */ NgEntityServiceLoader.ngInjectableDef = defineInjectable({ factory: function NgEntityServiceLoader_Factory() { return new NgEntityServiceLoader(); }, token: NgEntityServiceLoader, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const NG_ENTITY_SERVICE_CONFIG = new InjectionToken('NgEntityServiceGlobalConfig');
/** @type {?} */
const defaultConfig = {
httpMethods: {
GET: HttpMethod.GET,
POST: HttpMethod.POST,
PATCH: HttpMethod.PATCH,
PUT: HttpMethod.PUT,
DELETE: HttpMethod.DELETE
}
};
/**
* @param {?} target
* @param {...?} sources
* @return {?}
*/
function mergeDeep(target, ...sources) {
if (!sources.length)
return target;
/** @type {?} */
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key])
Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
}
else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
}
/**
* @param {?=} config
* @return {?}
*/
function NgEntityServiceConfig(config = {}) {
return (/**
* @param {?} constructor
* @return {?}
*/
function (constructor) {
if (config.baseUrl) {
constructor['baseUrl'] = config.baseUrl;
}
if (config.resourceName) {
constructor['resourceName'] = config.resourceName;
}
});
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} idOrConfig
* @return {?}
*/
function isID(idOrConfig) {
return isNumber(idOrConfig) || isString(idOrConfig);
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} storeName
* @param {?} notifier
* @return {?}
*/
function successAction(storeName, notifier) {
return (/**
* @param {?} __0
* @return {?}
*/
function ({ payload, method, successMsg }) {
notifier.dispatch({
type: 'success',
storeName,
payload,
method,
successMsg
});
});
}
/**
* @param {?} storeName
* @param {?} notifier
* @return {?}
*/
function errorAction(storeName, notifier) {
return (/**
* @param {?} __0
* @return {?}
*/
function ({ payload, method, errorMsg }) {
notifier.dispatch({
type: 'error',
storeName,
payload,
method,
errorMsg
});
});
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const mapResponse = (/**
* @param {?} config
* @return {?}
*/
(config) => map((/**
* @param {?} res
* @return {?}
*/
res => ((config || {}).mapResponseFn ? config.mapResponseFn(res) : res))));
/**
* @template S
*/
class NgEntityService extends EntityService {
/**
* @param {?} store
* @param {?=} config
*/
constructor(store, config = {}) {
super();
this.store = store;
this.config = config;
this.globalConfig = {};
this.http = inject(HttpClient);
this.loader = inject(NgEntityServiceLoader);
this.notifier = inject(NgEntityServiceNotifier);
this.globalConfig = inject(NG_ENTITY_SERVICE_CONFIG);
this.mergedConfig = mergeDeep(defaultConfig, this.globalConfig, config);
this.dispatchSuccess = successAction(this.store.storeName, this.notifier);
this.dispatchError = errorAction(this.store.storeName, this.notifier);
}
/**
* @return {?}
*/
get api() {
return `${this.baseUrl || this.getConfigValue('baseUrl')}/${this.resourceName}`;
}
/**
* @return {?}
*/
get resourceName() {
return this.getConfigValue('resourceName') || this.store.storeName;
}
/**
* @param {?} api
* @return {?}
*/
setBaseUrl(api) {
this.baseUrl = api;
}
/**
* @template T
* @param {?=} idOrConfig
* @param {?=} config
* @return {?}
*/
get(idOrConfig, config) {
/** @type {?} */
let url;
/** @type {?} */
const isSingle = isID(idOrConfig);
/** @type {?} */
const _config = (isSingle ? config : idOrConfig) || {};
/** @type {?} */
const method = this.getHttpMethod(HttpMethod.GET);
if (_config.url) {
url = _config.url;
}
else {
url = isSingle ? `${this.api}/${idOrConfig}` : this.api;
}
this.loader.dispatch({
method,
loading: true,
entityId: isSingle ? idOrConfig : null,
storeName: this.store.storeName
});
return (/** @type {?} */ (this.http[method.toLowerCase()](url, _config).pipe(mapResponse(_config), tap((/**
* @param {?} data
* @return {?}
*/
(data) => {
if (isSingle) {
this.store.upsert((/** @type {?} */ (idOrConfig)), data);
}
else {
_config.append ? this.store.add(data) : this.store.set(data);
}
this.dispatchSuccess({
method,
payload: data,
successMsg: _config.successMsg
});
})), catchError((/**
* @param {?} error
* @return {?}
*/
error => this.handleError(method, error, _config.errorMsg))), finalize((/**
* @return {?}
*/
() => {
this.loader.dispatch({
method,
loading: false,
storeName: this.store.storeName
});
})))));
}
/**
*
* Add a new entity - Creates a POST request
*
* service.add(entity)
* service.add(entity, config)
*
* @template T
* @param {?} entity
* @param {?=} config
* @return {?}
*/
add(entity, config) {
/** @type {?} */
const method = this.getHttpMethod(HttpMethod.POST);
this.loader.dispatch({
method,
loading: true,
storeName: this.store.storeName
});
return (/** @type {?} */ (this.http[method.toLowerCase()](this.resolveUrl(config), entity, config).pipe(mapResponse(config), tap((/**
* @param {?} entity
* @return {?}
*/
(entity) => {
this.store.add(entity, config);
this.dispatchSuccess({
method,
payload: entity,
successMsg: config && config.successMsg
});
})), catchError((/**
* @param {?} error
* @return {?}
*/
error => this.handleError(method, error, config && config.errorMsg))), finalize((/**
* @return {?}
*/
() => {
this.loader.dispatch({
method,
loading: false,
storeName: this.store.storeName
});
})))));
}
/**
*
* Update an entity - Creates a PUT/PATCH request
*
* service.update(id, entity)
* service.update(id, entity, config)
*
* @template T
* @param {?} id
* @param {?} entity
* @param {?=} config
* @return {?}
*/
update(id, entity, config) {
/** @type {?} */
const method = config && config.method ? config.method : this.getHttpMethod(HttpMethod.PUT);
this.loader.dispatch({
method,
loading: true,
entityId: id,
storeName: this.store.storeName
});
return (/** @type {?} */ (this.http[method.toLocaleLowerCase()](this.resolveUrl(config, id), entity, config).pipe(mapResponse(config), tap((/**
* @param {?} entity
* @return {?}
*/
entity => {
this.store.update(id, (/** @type {?} */ (entity)));
this.dispatchSuccess({
method,
payload: entity,
successMsg: config && config.successMsg
});
})), catchError((/**
* @param {?} error
* @return {?}
*/
error => this.handleError(method, error, config && config.errorMsg))), finalize((/**
* @return {?}
*/
() => {
this.loader.dispatch({
method,
loading: false,
entityId: id,
storeName: this.store.storeName
});
})))));
}
/**
*
* Delete an entity - Creates a DELETE request
*
* service.delete(id)
* service.delete(id, config)
*
* @template T
* @param {?} id
* @param {?=} config
* @return {?}
*/
delete(id, config) {
/** @type {?} */
const method = this.getHttpMethod(HttpMethod.DELETE);
this.loader.dispatch({
method,
loading: true,
entityId: id,
storeName: this.store.storeName
});
return (/** @type {?} */ (this.http[method.toLowerCase()](this.resolveUrl(config, id), config).pipe(mapResponse(config), tap((/**
* @param {?} res
* @return {?}
*/
res => {
this.store.remove(id);
this.dispatchSuccess({
method,
payload: res,
successMsg: config && config.successMsg
});
})), catchError((/**
* @param {?} error
* @return {?}
*/
error => this.handleError(method, error, config && config.errorMsg))), finalize((/**
* @return {?}
*/
() => {
this.loader.dispatch({
method,
loading: false,
entityId: id,
storeName: this.store.storeName
});
})))));
}
/**
* @private
* @param {?} type
* @return {?}
*/
getHttpMethod(type) {
return this.mergedConfig.httpMethods[type];
}
/**
* @private
* @param {?} key
* @return {?}
*/
getConfigValue(key) {
return this.constructor[key] || this.mergedConfig[key];
}
/**
* @private
* @param {?} config
* @param {?=} id
* @return {?}
*/
resolveUrl(config, id) {
/** @type {?} */
const customUrl = (config || {}).url;
if (isDefined(id)) {
return customUrl || `${this.api}/${id}`;
}
return customUrl || this.api;
}
/**
* @private
* @param {?} method
* @param {?} error
* @param {?} errorMsg
* @return {?}
*/
handleError(method, error, errorMsg) {
this.dispatchError({
method,
errorMsg,
payload: error
});
return throwError(error);
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { mapResponse, NgEntityService, mergeDeep, NgEntityServiceConfig, NG_ENTITY_SERVICE_CONFIG, defaultConfig, HttpMethod, ofType, filterMethod, filterStore, NgEntityServiceNotifier, isID, NgEntityServiceLoader, successAction, errorAction };
//# sourceMappingURL=datorama-akita-angular-playground-projects-ng-entity-service.js.map