import { ObjectFetcher } from "graphql-ts-client-api" ; import { EntityChangeEvent } from "../.." ; import { EntityEvictEvent } from "../../entities/EntityEvent" ; import { EntityManager } from "../../entities/EntityManager" ; import { QueryResult } from "../../entities/QueryResult" ; import { toRuntimeShape } from "../../entities/RuntimeShape" ; import { Network } from "../../meta/Network" ; import { SchemaMetadata } from "../../meta/impl/SchemaMetadata" ; import { SchemaType } from "../../meta/SchemaType" ; import { StateManager } from "../StateManager" ; import { ReleasePolicy } from "../Types" ; import { ScopedStateManager } from "./ScopedStateManager" ; import { StateValue } from "./StateValue" ; import { GraphSnapshot , postSimpleStateMessage , SimpleStateScope } from "../Monitor" ; export class StateManagerImpl < TSchema extends SchemaType > implements StateManager < TSchema > { readonly id = `${ new Date ( ) . getTime ( ) }-${ ++ sequenceNumber }` ; releasePolicy : ReleasePolicy < any > ; private _rootScope = new ScopedStateManager ( this ) ; private _stateValueChangeListeners = new Set < StateValueChangeListener > ( ) ; private _queryResultChangeListeners = new Set < QueryResultChangeListener > ( ) ; private _entityManager : EntityManager ; constructor ( schema ? , readonly network ? ) { this . _entityManager = new EntityManager ( this , schema ?? new SchemaMetadata ( ) ) ; this . releasePolicy = ( aliveTime , variables ) => { if ( aliveTime < 1000 ) { return 0 ; } if ( variables !== undefined ) { return Math . min ( aliveTime , 30000 ) ; } return Math . min ( aliveTime , 60000 ) ; } ; } get entityManager ( ) : EntityManager { return this . _entityManager ; } save < T extends object , TVariables extends object = { } > ( fetcher , obj , variables ? ) { if ( ! this . entityManager . schema . isAcceptable ( fetcher . fetchableType ) ) { throw new Error ( "Cannot accept that fetcher because it is not configured in the state manager" ) ; } this . entityManager . save ( toRuntimeShape ( fetcher , undefined , variables ) , obj ) ; } delete < TName extends keyof TSchema [ "entities" ] & string > ( typeName , idOrArray ) { this . entityManager . delete ( typeName , idOrArray ) ; } evict < TName extends keyof TSchema [ "entities" ] & string > ( typeName , idOrArray ? , fieldOrArray ? ) { this . entityManager . evict ( typeName , idOrArray , fieldOrArray ) ; } addEntityEvictListener ( listener ) { this . entityManager . addEvictListener ( undefined , listener ) ; } removeEntityEvictListener ( listener ) { this . entityManager . removeEvictListener ( undefined , listener ) ; } addEntityEvictListeners ( listeners ) { for ( const typeName in listeners ) { const listener = listeners [ typeName ] ; if ( listener !== undefined && listener !== null ) { this . entityManager . addEvictListener ( typeName , listener ) ; } } } removeEntityEvictListeners ( listeners ) { for ( const typeName in listeners ) { const listener = listeners [ typeName ] ; if ( listener !== undefined && listener !== null ) { this . entityManager . removeEvictListener ( typeName , listener ) ; } } } addEntityChangeListener ( listener ) { this . entityManager . addChangeListener ( undefined , listener ) ; } removeEntityChangeListener ( listener ) { this . entityManager . removeChangeListener ( undefined , listener ) ; } addEntityChangeListeners ( listeners ) { for ( const typeName in listeners ) { const listener = listeners [ typeName ] ; if ( listener !== undefined && listener !== null ) { this . entityManager . addChangeListener ( typeName , listener ) ; } } } removeEntityChangeListeners ( listeners ) { for ( const typeName in listeners ) { const listener = listeners [ typeName ] ; if ( listener !== undefined && listener !== null ) { this . entityManager . removeChangeListener ( typeName , listener ) ; } } } scope ( path ) { return this . _rootScope . subScope ( path ) ; } addStateValueChangeListener ( listener ) { if ( this . _stateValueChangeListeners . has ( listener ) ) { throw new Error ( `Cannot add existing listener` ) ; } if ( listener !== undefined && listener !== null ) { this . _stateValueChangeListeners . add ( listener ) ; } } removeStateValueChangeListener ( listener ) { this . _stateValueChangeListeners . delete ( listener ) ; } publishStateValueChangeEvent ( e ) { postSimpleStateMessage ( e . stateValue , "update" , e . stateValue . rawData ) ; for ( const listener of this . _stateValueChangeListeners ) { listener ( e ) ; } } addQueryResultChangeListener ( listener ) { if ( this . _queryResultChangeListeners . has ( listener ) ) { throw new Error ( `Cannot add existing listener` ) ; } if ( listener !== undefined && listener !== null ) { this . _queryResultChangeListeners . add ( listener ) ; } } removeQueryResultChangeListener ( listener ) { this . _queryResultChangeListeners . delete ( listener ) ; } publishQueryResultChangeEvent ( e ) { for ( const listener of this . _queryResultChangeListeners ) { listener ( e ) ; } } suspendBidirectionalAssociationManagement < T > ( action ) { return this . entityManager . suspendBidirectionalAssociationManagement ( action ) ; } dispose ( ) { this . _stateValueChangeListeners . clear ( ) ; this . _queryResultChangeListeners . clear ( ) ; this . _entityManager = new EntityManager ( this , this . _entityManager . schema ) ; this . _rootScope . dispose ( ) ; } simpleStateMonitor ( ) { return this . _rootScope . monitor ( ) ; } graphStateMonitor ( ) { return this . entityManager . monitor ( ) ; } } export type StateValueChangeListener = ( e : StateValueChangeEvent ) => void ; export interface StateValueChangeEvent { readonly stateValue : StateValue ; readonly changedType : "RESULT_CHANGE" | "ASYNC_STATE_CHANGE" ; } export type QueryResultChangeListener = ( e : QueryResultChangeEvent ) => void ; export interface QueryResultChangeEvent { readonly queryResult : QueryResult ; readonly changedType : "RESULT_CHANGE" | "ASYNC_STATE_CHANGE" ; } let sequenceNumber = 0 ;