/
alt3rmann
/
cloudbeaver
Обзор
Документация
Войти
/
alt3rmann
/
cloudbeaver
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
devel
webapp/packages/plugin-sql-editor/src/SqlDataSource/SqlDataSourceService.ts
187 строк
6 KB
Ainur
dbeaver/pro#6243 add permissions for executing and updating results (#3634)
11 авг 2025, 12:55
Не верифицирован
11 авг 2025, 12:55
7e0ad33
Код
Авторство
О чём код?
/* * CloudBeaver - Cloud Database Manager * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ import { action, computed, makeObservable, observable } from 'mobx'; import type { IConnectionExecutionContextInfo } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { type ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor'; import type { ISqlEditorTabState } from '../ISqlEditorTabState.js'; import type { ISqlDataSource } from './ISqlDataSource.js'; import { MemorySqlDataSource } from './MemorySqlDataSource.js'; import type { QueryDataSource } from '../QueryDataSource.js'; export interface ISqlDataSourceOptions { name?: string; script?: string; executionContext?: IConnectionExecutionContextInfo; dataSourceState?: Record<string, any>; } type ISqlDataSourceFactory<TDataSource extends QueryDataSource> = (editorId: string, options?: ISqlDataSourceOptions) => ISqlDataSource<TDataSource>; interface ISqlDataSourceFabric<TDataSource extends QueryDataSource> { key: string; getDataSource: ISqlDataSourceFactory<TDataSource>; onDestroy?: (dataSource: ISqlDataSource<TDataSource>, editorId: string) => Promise<void> | void; onUnload?: (dataSource: ISqlDataSource<TDataSource>, editorId: string) => Promise<void> | void; canDestroy?: (dataSource: ISqlDataSource<TDataSource>, editorId: string) => Promise<boolean> | boolean; } interface ISqlDataSourceProvider { provider: ISqlDataSourceFabric<any>; dataSource: ISqlDataSource; isActionActive: boolean; } export interface ISQLDatasourceUpdateData { editorId: string; datasource: ISqlDataSource; } @injectable() export class SqlDataSourceService { get dataSources(): [string, ISqlDataSource][] { return Array.from(this.providers.entries()).map(([editorId, provider]) => [editorId, provider.dataSource]); } readonly onCreate: ISyncExecutor<[string, string]>; readonly onUpdate: ISyncExecutor<ISQLDatasourceUpdateData>; private readonly dataSourceProviders: Map<string, ISqlDataSourceFabric<any>>; private readonly providers: Map<string, ISqlDataSourceProvider>; constructor() { this.dataSourceProviders = new Map(); this.providers = new Map(); this.onCreate = new SyncExecutor(); this.onUpdate = new SyncExecutor(); this.onCreate.next<ISQLDatasourceUpdateData>(this.onUpdate, ([editorId]) => ({ editorId, datasource: this.get(editorId)!, })); this.register({ key: MemorySqlDataSource.key, getDataSource: (editorId, options) => new MemorySqlDataSource(options?.name, options?.script, options?.executionContext), }); makeObservable<this, 'providers'>(this, { dataSources: computed, providers: observable.shallow, create: action, destroy: action, }); } get<TDataSource extends QueryDataSource>(editorId: string): ISqlDataSource<TDataSource> | undefined { return this.providers.get(editorId)?.dataSource as ISqlDataSource<TDataSource> | undefined; } create<TDataSource extends QueryDataSource>(state: ISqlEditorTabState, key: string, options?: ISqlDataSourceOptions): ISqlDataSource<TDataSource> { const editorId = state.editorId; const provider = this.dataSourceProviders.get(key); if (!provider) { throw new Error(`SQL Data Source Provider with key (${key}) not found`); } let activeProvider = this.providers.get(editorId); if (activeProvider?.provider.key !== key) { if (activeProvider) { this.destroyProvider(editorId, activeProvider); } activeProvider = { provider, dataSource: provider.getDataSource(editorId, options), isActionActive: false, }; activeProvider.dataSource.onUpdate.next<ISQLDatasourceUpdateData>(this.onUpdate, () => ({ editorId, datasource: activeProvider!.dataSource, })); this.providers.set(editorId, activeProvider); state.datasourceKey = key; this.onCreate.execute([editorId, key]); } return activeProvider.dataSource as unknown as ISqlDataSource<TDataSource>; } async executeAction<T>(editorId: string, action: (dataSource: ISqlDataSource) => Promise<T> | T, notFound: () => void): Promise<T | undefined> { const provider = this.providers.get(editorId); if (!provider) { notFound(); return undefined; } if (provider.isActionActive) { return; } try { provider.isActionActive = true; return await action(provider.dataSource); } finally { provider.isActionActive = false; } } async canDestroy(editorId: string): Promise<boolean> { const activeProvider = this.providers.get(editorId); return (await activeProvider?.provider.canDestroy?.(activeProvider.dataSource, editorId)) ?? true; } async destroySilent(editorId: string): Promise<void> { const activeProvider = this.providers.get(editorId); if (activeProvider) { await this.destroyProvider(editorId, activeProvider); } } async destroy(editorId: string): Promise<void> { const activeProvider = this.providers.get(editorId); if (activeProvider) { await this.destroyProvider(editorId, activeProvider); } } async unload(editorId: string): Promise<void> { const activeProvider = this.providers.get(editorId); if (activeProvider) { await this.unloadProvider(editorId, activeProvider); } this.providers.delete(editorId); } register<TDataSource extends QueryDataSource>(dataSourceOptions: ISqlDataSourceFabric<TDataSource>) { if (this.dataSourceProviders.has(dataSourceOptions.key)) { throw new Error(`SQL Data Source with key (${dataSourceOptions.key}) already registered`); } this.dataSourceProviders.set(dataSourceOptions.key, dataSourceOptions); } private async unloadProvider(editorId: string, provider: ISqlDataSourceProvider): Promise<void> { await provider.provider.onUnload?.(provider.dataSource, editorId); await provider.dataSource.dispose(); } private async destroyProvider(editorId: string, provider: ISqlDataSourceProvider): Promise<void> { await provider.provider.onDestroy?.(provider.dataSource, editorId); await provider.dataSource.dispose(); } }