From d9502c7516bc2d4ae467c6ea8a2e4816b0885f37 Mon Sep 17 00:00:00 2001 From: muhamedsalih-tw <104364298+muhamedsalih-tw@users.noreply.github.com> Date: Thu, 17 Nov 2022 05:45:39 +0530 Subject: Transfrom workspace components to ts (#775) --- src/stores/lib/CachedRequest.ts | 126 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/stores/lib/CachedRequest.ts (limited to 'src/stores/lib/CachedRequest.ts') diff --git a/src/stores/lib/CachedRequest.ts b/src/stores/lib/CachedRequest.ts new file mode 100644 index 000000000..25cc365e2 --- /dev/null +++ b/src/stores/lib/CachedRequest.ts @@ -0,0 +1,126 @@ +import { action } from 'mobx'; +import { isEqual, remove } from 'lodash'; +import Request from './Request'; + +export default class CachedRequest extends Request { + _apiCalls: any[] = []; + + _isInvalidated = true; + + execute(...callArgs): this { + // Do not continue if this request is already loading + if (this.isWaitingForResponse) { + return this; + } + + // Very simple caching strategy -> only continue if the call / args changed + // or the request was invalidated manually from outside + const existingApiCall = this._findApiCall(callArgs); + + // Invalidate if new or different api call will be done + if (existingApiCall && existingApiCall !== this.currentApiCall) { + this._isInvalidated = true; + this.currentApiCall = existingApiCall; + } else if (!existingApiCall) { + this._isInvalidated = true; + this.currentApiCall = this._addApiCall(callArgs); + } + + // Do not continue if this request is not invalidated (see above) + if (!this._isInvalidated) { + return this; + } + + // This timeout is necessary to avoid warnings from mobx + // regarding triggering actions as side-effect of getters + setTimeout( + action(() => { + this.isExecuting = true; + // Apply the previous result from this call immediately (cached) + if (existingApiCall) { + this.result = existingApiCall.result; + } + }), + 0, + ); + + // Issue api call & save it as promise that is handled to update the results of the operation + this.promise = new Promise(resolve => { + 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._isInvalidated = false; + 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; + return this; + } + + static defaultOptions = { immediately: false }; + + invalidate(options = CachedRequest.defaultOptions): this { + this._isInvalidated = true; + if (options.immediately && this.currentApiCall) { + return this.execute(...this.currentApiCall.args); + } + return this; + } + + patch(modify): Promise { + return new Promise(resolve => { + setTimeout( + action(() => { + const override = modify(this.result); + if (override !== undefined) this.result = override; + if (this.currentApiCall) this.currentApiCall.result = this.result; + resolve(this); + }), + 0, + ); + }); + } + + removeCacheForCallWith(...args: any): void { + remove(this._apiCalls, c => isEqual(c.args, args)); + } + + _addApiCall(args: any) { + const newCall = { args, result: null }; + this._apiCalls.push(newCall); + return newCall; + } + + _findApiCall(args: any) { + return this._apiCalls.find(c => isEqual(c.args, args)); + } +} -- cgit v1.2.3-54-g00ecf