import { LoadingAction , LOADING_CATEGORY , TYPE_SET_LOADING , } from '../actions/loading' ; import type { EffectCtx } from './defineModel' ; import { isPromise } from '../utils/isPromise' ; import { toArgs } from '../utils/toArgs' ; import { loadingStore } from '../store/loadingStore' ; interface AssignFunc < P extends any [ ] = any [ ] , R = Promise < any > > { ( category ) : { execute ( ... args ) : R ; } ; } interface AsyncAssignEffect < P extends any [ ] = any [ ] , R = Promise < any > > extends AssignFunc < P , R > { readonly _ : { readonly model : string ; readonly method : string ; readonly assign : true ; } ; } interface AsyncEffect < P extends any [ ] = any [ ] , R = Promise < any > > extends EffectFunc < P , R > { readonly _ : { readonly model : string ; readonly method : string ; readonly assign : '' ; } ; see useLoading see getLoading readonly assign : AsyncAssignEffect < P , R > ; } export type PromiseEffect = AsyncEffect ; export type PromiseAssignEffect = AsyncAssignEffect ; interface EffectFunc < P extends any [ ] = any [ ] , R = Promise < any > > { ( ... args ) : R ; } export type EnhancedEffect < P extends any [ ] = any [ ] , R = Promise < any > > = R extends Promise < any > ? AsyncEffect < P , R > : EffectFunc < P , R > ; type NonReadonly < T extends object > = { - readonly [ K in keyof T ] : T [ K ] ; } ; export const enhanceEffect = < State extends object > ( ctx , methodName , effect ) : EnhancedEffect => { const fn = function ( ) { return execute ( ctx , methodName , effect , toArgs ( arguments ) ) ; } ; fn . _ = { model : ctx . name , method : methodName , assign : '' , } ; const assign = ( category ) => ( { execute ( ) { return execute ( ctx , methodName , effect , toArgs ( arguments ) , category ) ; } , } ) ; assign . _ = Object . assign ( { } , fn . _ , { assign : true as const , } ) ; fn . assign = assign ; return fn ; } ; const dispatchLoading = ( modelName , methodName , loading , category = LOADING_CATEGORY ) => { loadingStore . dispatch < LoadingAction > ( { type : TYPE_SET_LOADING , model : modelName , method : methodName , payload : { category , loading } , } ) ; } ; const execute = < State extends object > ( ctx , methodName , effect , args , category ? ) => { const modelName = ctx . name ; const resultOrPromise = effect . apply ( ctx , args ) ; if ( ! isPromise ( resultOrPromise ) ) { return resultOrPromise ; } dispatchLoading ( modelName , methodName , true , category ) ; return resultOrPromise . then ( ( result ) => { return dispatchLoading ( modelName , methodName , false , category ) , result ; } , ( e ) => { dispatchLoading ( modelName , methodName , false , category ) ; throw e ; } ) ; } ;