Created
July 19, 2018 23:37
-
-
Save misantronic/52726a9ee930f88846aa8bd7ffe5d3fa to your computer and use it in GitHub Desktop.
WrapRequest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { observable, computed } from 'mobx'; | |
type WrapRequestState = 'loading' | 'fetched' | 'error'; | |
/** @see https://stackoverflow.com/a/4994244/1138860 */ | |
// tslint:disable-next-line:cyclomatic-complexity no-any | |
function isEmpty(obj: any): boolean { | |
if (!obj) return true; | |
if (obj > 0) return false; | |
if (obj.length > 0) return false; | |
if (obj.length === 0) return true; | |
if (typeof obj !== 'object') return true; | |
for (const key in obj) { | |
if (Object.prototype.hasOwnProperty.call(obj, key)) return false; | |
} | |
return true; | |
} | |
// tslint:disable-next-line:no-any | |
export class WrapRequest<T = any, U = any, X = any, Y = any, Z = T | X> { | |
@observable public error?: Error; | |
@observable private _$!: T | X; | |
// tslint:disable-next-line:no-any | |
@observable public transform?: (value: T | X) => Y; | |
@observable private state?: WrapRequestState; | |
private req: (params?: U) => Promise<T>; | |
constructor( | |
req: (params?: U) => Promise<T>, | |
$?: T | X, | |
transform?: ($: T | X) => Y | |
) { | |
this.req = req; | |
this.transform = transform; | |
if ($) { | |
this._$ = $; | |
} | |
} | |
public async request(params?: U): Promise<T> { | |
this.state = undefined; | |
this.error = undefined; | |
try { | |
this.state = 'loading'; | |
const result = await this.req(params); | |
this._$ = result; | |
this.state = 'fetched'; | |
} catch (e) { | |
this.error = e; | |
this.state = 'error'; | |
} | |
return this.$ as T; | |
} | |
@computed | |
public get $(): T | X { | |
if (this.transform) { | |
// tslint:disable-next-line:no-any | |
return this.transform(this._$) as any; | |
} | |
return this._$; | |
} | |
@computed | |
public get source(): Z { | |
// tslint:disable-next-line:no-any | |
return this._$ as any; | |
} | |
@computed | |
public get loading(): boolean { | |
return this.state === 'loading'; | |
} | |
public set loading(value: boolean) { | |
this.state = value ? 'loading' : undefined; | |
} | |
@computed | |
public get fetched(): boolean { | |
return this.state === 'fetched'; | |
} | |
public set fetched(value: boolean) { | |
this.state = value ? 'fetched' : undefined; | |
} | |
@computed | |
public get empty(): boolean { | |
if (this.fetched && isEmpty(this.$)) { | |
return true; | |
} | |
return false; | |
} | |
// tslint:disable-next-line:cyclomatic-complexity | |
public match(handlers: { | |
loading?(): React.ReactNode; | |
fetched?(value: T): React.ReactNode; | |
empty?(): React.ReactNode; | |
error?(e: Error): React.ReactNode; | |
}): React.ReactNode { | |
if (this.error && handlers.error) { | |
return handlers.error(this.error); | |
} | |
if (this.empty && handlers.empty) { | |
return handlers.empty(); | |
} | |
if (this.loading && handlers.loading) { | |
return handlers.loading(); | |
} | |
if (this.fetched && handlers.fetched) { | |
return handlers.fetched(this.$ as T); | |
} | |
return null; | |
} | |
public reset(value: T): void { | |
this._$ = value; | |
} | |
} | |
// tslint:disable-next-line:no-any | |
export function wrapRequest<T = any, U = any, X = undefined>( | |
request: (params: U) => Promise<T> | |
): WrapRequest<T, U, X>; | |
// tslint:disable-next-line:no-any | |
export function wrapRequest<T = any, U = any, X = T>( | |
request: (params: U) => Promise<T>, | |
// tslint:disable-next-line:unified-signatures | |
defaultData: T | |
): WrapRequest<T, U, X>; | |
// tslint:disable-next-line:no-any | |
export function wrapRequest<T = any, U = any, X = T, Y = any>( | |
request: (params: U) => Promise<T>, | |
// tslint:disable-next-line:unified-signatures | |
defaultData: T, | |
transform: ($: T | X) => Y | |
): WrapRequest<Y, U, Y, Y, T>; | |
/** | |
* @param request The request to perform when calling `wrapRequest.request` | |
* @param defaultData set a default value for `wrapRequest.$` e.g. `[]` | |
* @param transform a function which receives the request `$` and returns a new value | |
*/ | |
// tslint:disable-next-line:no-any | |
export function wrapRequest<T = any, U = any, X = any, Y = undefined>( | |
request: (params?: U) => Promise<T>, | |
defaultData?: T, | |
transform?: ($: T | X) => Y | |
): WrapRequest<T, U> { | |
return new WrapRequest<T, U, X, Y>(request, defaultData, transform); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
usage