import { observable , makeObservable } from 'mobx' ; import { Executor , ExecutorInterrupter , IExecutor } from '@cloudbeaver/core-executor' ; import type { ResultDataFormat } from '@cloudbeaver/core-sdk' ; import { uuid } from '@cloudbeaver/core-utils' ; import type { IDatabaseDataModel , IRequestEventData } from './IDatabaseDataModel' ; import type { IDatabaseDataResult } from './IDatabaseDataResult' ; import type { DatabaseDataAccessMode , IDatabaseDataSource , IRequestInfo } from './IDatabaseDataSource' ; export class DatabaseDataModel < TOptions , TResult extends IDatabaseDataResult = IDatabaseDataResult > implements IDatabaseDataModel < TOptions , TResult > { id : string ; name : string | null ; source : IDatabaseDataSource < TOptions , TResult > ; countGain : number ; get requestInfo ( ) : IRequestInfo { return this . source . requestInfo ; } get supportedDataFormats ( ) : ResultDataFormat [ ] { return this . source . supportedDataFormats ; } readonly onOptionsChange : IExecutor ; readonly onRequest : IExecutor < IRequestEventData < TOptions , TResult > > ; private currentTask : Promise < void > | null ; constructor ( source ) { this . id = uuid ( ) ; this . name = null ; this . source = source ; this . countGain = 0 ; this . onOptionsChange = new Executor ( ) ; this . onRequest = new Executor ( ) ; this . currentTask = null ; makeObservable ( this , { countGain : observable , } ) ; } isLoading ( ) { return this . source . isLoading ( ) ; } isDisabled ( resultIndex ) { return this . source . isDisabled ( resultIndex ) ; } isReadonly ( ) { return this . source . isReadonly ( ) ; } isDataAvailable ( offset , count ) { return this . source . offset <= offset && this . source . count >= count ; } getResults ( ) { return this . source . results ; } getResult ( index ) { return this . source . getResult ( index ) ; } setName ( name ) { this . name = name ; return this ; } setResults ( results ) { this . source . setResults ( results ) ; return this ; } setAccess ( access ) { this . source . setAccess ( access ) ; return this ; } setCountGain ( count ) { this . countGain = count ; return this ; } setSlice ( offset , count = this . countGain ) { this . source . setSlice ( offset , count ) ; return this ; } setDataFormat ( dataFormat ) { this . source . setDataFormat ( dataFormat ) ; return this ; } setSupportedDataFormats ( dataFormats ) { this . source . setSupportedDataFormats ( dataFormats ) ; return this ; } setOptions ( options ) { this . source . setOptions ( options ) ; return this ; } async requestOptionsChange ( ) { const contexts = await this . onOptionsChange . execute ( ) ; return ExecutorInterrupter . isInterrupted ( contexts ) === false ; } async save ( ) { await this . requestSaveAction ( ( ) => this . source . saveData ( ) ) ; } async retry ( ) { await this . requestDataAction ( ( ) => this . source . retry ( ) ) ; } async refresh ( concurrent ? ) { if ( concurrent ) { await this . source . refreshData ( ) ; return ; } await this . requestDataAction ( ( ) => this . source . refreshData ( ) ) ; } async request ( concurrent ? ) { if ( concurrent ) { await this . source . requestData ( ) ; return ; } await this . requestDataAction ( ( ) => this . source . requestData ( ) ) ; } async reload ( ) { await this . requestDataAction ( ( ) => this . source . setSlice ( 0 , this . countGain ) . requestData ( ) ) ; } async requestDataPortion ( offset , count ) { if ( ! this . isDataAvailable ( offset , count ) ) { await this . requestDataAction ( ( ) => this . source . setSlice ( offset , count ) . requestData ( ) ) ; } } cancel ( ) { return this . source . cancel ( ) ; } resetData ( ) { this . source . resetData ( ) ; } async dispose ( ) { await this . source . dispose ( ) ; } async requestSaveAction ( action ) { return action ( ) ; } async requestDataAction ( action ) { if ( this . currentTask ) { return this . currentTask ; } try { this . currentTask = this . requestDataActionTask ( action ) ; return await this . currentTask ; } finally { this . currentTask = null ; } } private async requestDataActionTask ( action ) { let contexts = await this . onRequest . execute ( { type : 'on' , model : this } ) ; if ( ExecutorInterrupter . isInterrupted ( contexts ) ) { return ; } contexts = await this . onRequest . execute ( { type : 'before' , model : this } ) ; if ( ExecutorInterrupter . isInterrupted ( contexts ) ) { return ; } await action ( ) ; await this . onRequest . execute ( { type : 'after' , model : this } ) ; } }