import { serialize } from './serialize' ; import { isFunction , isUndefined , mergeObjects , UNDEFINED } from './helper' ; import { SWRGlobalState , GlobalState } from './global-state' ; import { broadcastState } from './broadcast-state' ; import { getTimestamp } from './timestamp' ; import { Key , Cache , MutatorCallback , MutatorOptions } from '../types' ; export const internalMutate = async < Data > ( ... args ) => { const [ cache , _key , _data , _opts ] = args ; const options = typeof _opts === 'boolean' ? { revalidate : _opts } : _opts || { } ; let populateCache = options . populateCache !== false ; const revalidate = options . revalidate !== false ; const rollbackOnError = options . rollbackOnError !== false ; const optimisticData = options . optimisticData ; const [ key , , keyInfo ] = serialize ( _key ) ; if ( ! key ) return ; const [ , , MUTATION ] = SWRGlobalState . get ( cache ) as GlobalState ; if ( args . length < 3 ) { return broadcastState ( cache , key , cache . get ( key ) , UNDEFINED , UNDEFINED , revalidate , populateCache ) ; } let data = _data ; let error ; const beforeMutationTs = getTimestamp ( ) ; MUTATION [ key ] = [ beforeMutationTs , 0 ] ; const hasOptimisticData = ! isUndefined ( optimisticData ) ; const rollbackData = cache . get ( key ) ; if ( hasOptimisticData ) { cache . set ( key , optimisticData ) ; broadcastState ( cache , key , optimisticData ) ; } if ( isFunction ( data ) ) { try { data = ( data as MutatorCallback < Data > ) ( cache . get ( key ) ) ; } catch ( err ) { error = err ; } } if ( data && isFunction ( ( data as Promise < Data > ) . then ) ) { data = await ( data as Promise < Data > ) . catch ( err => { error = err ; } ) ; if ( beforeMutationTs !== MUTATION [ key ] [ 0 ] ) { if ( error ) throw error ; return data ; } else if ( error && hasOptimisticData && rollbackOnError ) { populateCache = true ; data = rollbackData ; cache . set ( key , rollbackData ) ; } } if ( populateCache ) { if ( ! error ) { cache . set ( key , data ) ; } cache . set ( keyInfo , mergeObjects ( cache . get ( keyInfo ) , { error } ) ) ; } MUTATION [ key ] [ 1 ] = getTimestamp ( ) ; const res = await broadcastState ( cache , key , data , error , UNDEFINED , revalidate , populateCache ) ; if ( error ) throw error ; return populateCache ? res : data ; } ;