import { buildContext , getNameOfMutation , isMutationAsAction , Metadata , EffectMethod , Action , EffectContext , StateClass , METADATA_KEY , buildGetCacheKey , } from '@loona/core' ; import { Injectable , Inject , OnDestroy , Injector } from '@angular/core' ; import { ApolloCache } from 'apollo-cache' ; import { Apollo } from 'apollo-angular' ; import { Subscription } from 'rxjs' ; import { Loona } from './client' ; import { LOONA_CACHE } from './tokens' ; import { ScannedActions } from './actions' ; @ Injectable ( ) export class Effects { effects : Record < string , Array < EffectMethod > > = { } ; getContext : ( ) => EffectContext ; constructor ( loona , apollo , @ Inject ( LOONA_CACHE ) cache ) { this . getContext = ( ) => ( { ... buildContext ( { cache , getCacheKey : buildGetCacheKey ( cache ) , } , apollo . getClient ( ) ) , dispatch : loona . dispatch . bind ( loona ) , } ) ; } addEffects ( instance , meta ? ) { if ( ! meta ) { return ; } for ( const type in meta ) { if ( ! this . effects [ type ] ) { this . effects [ type ] = [ ] ; } meta [ type ] . forEach ( ( { propName } ) => { this . effects [ type ] . push ( instance [ propName ] . bind ( instance ) ) ; } ) ; } } runEffects ( action ) { let type = action . type ; if ( isMutationAsAction ( action ) ) { type = getNameOfMutation ( action . options . mutation ) ; } const effectsToRun = this . effects [ type ] ; if ( effectsToRun ) { effectsToRun . forEach ( effect => { effect ( action , this . getContext ( ) ) ; } ) ; } } } @ Injectable ( ) export class EffectsRunner implements OnDestroy { private actionsSubscription : Subscription | null = null ; constructor ( private effects , private scannedActions ) { } start ( ) { if ( ! this . actionsSubscription ) { this . actionsSubscription = this . scannedActions . subscribe ( action => { this . effects . runEffects ( action ) ; } ) ; } } ngOnDestroy ( ) { if ( this . actionsSubscription ) { this . actionsSubscription . unsubscribe ( ) ; this . actionsSubscription = null ; } } } export function mapStates ( ) { const names = [ ] ; const add = ( state ) => { names . push ( state . constructor && state . constructor . name ) ; } ; return { names , add } ; } export function extractState ( state , injector ) { return { instance : injector . get ( state ) , meta : state [ METADATA_KEY ] , } ; }