From 58cda9cc7fb79ca9df6746de7f9662bc08dc156a Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Fri, 13 Oct 2017 12:29:40 +0200 Subject: initial commit --- src/stores/lib/Request.js | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/stores/lib/Request.js (limited to 'src/stores/lib/Request.js') diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js new file mode 100644 index 000000000..4a6925cc5 --- /dev/null +++ b/src/stores/lib/Request.js @@ -0,0 +1,112 @@ +import { observable, action, computed } from 'mobx'; +import { isEqual } from 'lodash/fp'; + +export default class Request { + static _hooks = []; + + static registerHook(hook) { + Request._hooks.push(hook); + } + + @observable result = null; + @observable error = null; + @observable isExecuting = false; + @observable isError = false; + @observable wasExecuted = false; + + _promise = Promise; + _api = {}; + _method = ''; + _isWaitingForResponse = false; + _currentApiCall = null; + + constructor(api, method) { + this._api = api; + this._method = method; + } + + execute(...callArgs) { + // Do not continue if this request is already loading + if (this._isWaitingForResponse) return this; + + if (!this._api[this._method]) { + throw new Error(`Missing method <${this._method}> on api object:`, this._api); + } + + // This timeout is necessary to avoid warnings from mobx + // regarding triggering actions as side-effect of getters + setTimeout(action(() => { + this.isExecuting = true; + }), 0); + + // Issue api call & save it as promise that is handled to update the results of the operation + this._promise = new Promise((resolve, reject) => { + this._api[this._method](...callArgs) + .then((result) => { + setTimeout(action(() => { + this.result = result; + if (this._currentApiCall) this._currentApiCall.result = result; + this.isExecuting = false; + this.isError = false; + this.wasExecuted = true; + this._isWaitingForResponse = false; + this._triggerHooks(); + resolve(result); + }), 1); + return result; + }) + .catch(action((error) => { + setTimeout(action(() => { + this.error = error; + this.isExecuting = false; + this.isError = true; + this.wasExecuted = true; + this._isWaitingForResponse = false; + this._triggerHooks(); + reject(error); + }), 1); + })); + }); + + this._isWaitingForResponse = true; + this._currentApiCall = { args: callArgs, result: null }; + return this; + } + + reload() { + return this.execute(...this._currentApiCall.args); + } + + isExecutingWithArgs(...args) { + return this.isExecuting && this._currentApiCall && isEqual(this._currentApiCall.args, args); + } + + @computed get isExecutingFirstTime() { + return !this.wasExecuted && this.isExecuting; + } + + then(...args) { + if (!this._promise) throw new Error('You have to call Request::execute before you can access it as promise'); + return this._promise.then(...args); + } + + catch(...args) { + if (!this._promise) throw new Error('You have to call Request::execute before you can access it as promise'); + return this._promise.catch(...args); + } + + _triggerHooks() { + Request._hooks.forEach(hook => hook(this)); + } + + reset() { + this.result = null; + this.isExecuting = false; + this.isError = false; + this.wasExecuted = false; + this._isWaitingForResponse = false; + this._promise = Promise; + + return this; + } +} -- cgit v1.2.3-70-g09d2