refactor(plugin-sql-editor): CB-2093 use data from data source

This commit is contained in:
Wroud
2022-06-20 16:11:30 +03:00
parent 3c393c63bd
commit fcd766417e
16 changed files with 238 additions and 131 deletions
@@ -30,9 +30,9 @@ export class ConnectionExecutionContext implements IConnectionExecutionContext {
private currentTask: ITask<any> | null;
constructor(
private scheduler: TaskScheduler<string>,
private connectionExecutionContextResource: ConnectionExecutionContextResource,
private contextId: string
private readonly scheduler: TaskScheduler<string>,
private readonly connectionExecutionContextResource: ConnectionExecutionContextResource,
private readonly contextId: string
) {
this.currentTask = null;
makeObservable<this, 'currentTask'>(this, {
@@ -75,11 +75,14 @@ export class ConnectionExecutionContext implements IConnectionExecutionContext {
await this.connectionExecutionContextResource.destroy(this.contextId);
}
async update(defaultCatalog?: string, defaultSchema?: string): Promise<void> {
async update(
defaultCatalog?: string,
defaultSchema?: string
): Promise<IConnectionExecutionContextInfo> {
if (!this.context) {
throw new Error('Execution Context not found');
}
await this.connectionExecutionContextResource.update(this.contextId, defaultCatalog, defaultSchema);
return await this.connectionExecutionContextResource.update(this.contextId, defaultCatalog, defaultSchema);
}
}
@@ -22,5 +22,5 @@ export interface IConnectionExecutionContext {
) => ITask<T>;
cancel: () => Promise<void>;
destroy: () => Promise<void>;
update: (defaultCatalog?: string, defaultSchema?: string) => Promise<void>;
update: (defaultCatalog?: string, defaultSchema?: string) => Promise<IConnectionExecutionContextInfo>;
}
@@ -14,7 +14,7 @@ import { SessionExpireService } from '@cloudbeaver/core-root';
import { createPath } from '@cloudbeaver/core-utils';
import { ActionService, ACTION_SAVE, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view';
import { NavResourceNodeService, RESOURCE_NODE_TYPE, SaveScriptDialog, ResourceManagerService, ProjectsResource, RESOURCES_NODE_PATH } from '@cloudbeaver/plugin-resource-manager';
import { DATA_CONTEXT_SQL_EDITOR_STATE, getSqlEditorName, SqlEditorService, SQL_EDITOR_ACTIONS_MENU } from '@cloudbeaver/plugin-sql-editor';
import { DATA_CONTEXT_SQL_EDITOR_STATE, getSqlEditorName, SqlDataSourceService, SqlEditorService, SQL_EDITOR_ACTIONS_MENU } from '@cloudbeaver/plugin-sql-editor';
import { SqlEditorNavigatorService } from '@cloudbeaver/plugin-sql-editor-navigation-tab';
import { isScript } from './isScript';
@@ -38,7 +38,8 @@ export class PluginBootstrap extends Bootstrap {
private readonly commonDialogService: CommonDialogService,
private readonly actionService: ActionService,
private readonly menuService: MenuService,
private readonly sessionExpireService: SessionExpireService
private readonly sessionExpireService: SessionExpireService,
private readonly sqlDataSourceService: SqlDataSourceService
) {
super();
}
@@ -60,8 +61,13 @@ export class PluginBootstrap extends Bootstrap {
},
handler: async (context, action) => {
const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE);
const dataSource = this.sqlDataSourceService.get(state.editorId);
const tab = this.navigationTabsService.currentTab;
if (!dataSource) {
return;
}
if (action === ACTION_SAVE) {
const name = getSqlEditorName(state);
const result = await this.commonDialogService.open(SaveScriptDialog, {
@@ -73,7 +79,7 @@ export class PluginBootstrap extends Bootstrap {
await this.projectsResource.load();
const scriptName = `${result.trim()}.${SCRIPT_EXTENSION}`;
const folder = createPath([RESOURCES_NODE_PATH, this.projectsResource.userProject?.name]);
const nodeId = await this.navResourceNodeService.saveScript(folder, scriptName, state.query);
const nodeId = await this.navResourceNodeService.saveScript(folder, scriptName, dataSource.script);
await this.navTreeResource.preloadNodeParents(NodeManagerUtils.parentsFromPath(nodeId), nodeId);
const node = await this.navNodeInfoResource.load(nodeId);
@@ -19,7 +19,7 @@ import { ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
import { LocalStorageSaveService } from '@cloudbeaver/core-settings';
import { debounce, throttle } from '@cloudbeaver/core-utils';
import { NavResourceNodeService, ResourceManagerService } from '@cloudbeaver/plugin-resource-manager';
import { IQueryChangeData, ISqlEditorTabState, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
import { IQueryChangeData, ISqlEditorTabState, SqlDataSourceService, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
import { SqlEditorTabService } from '@cloudbeaver/plugin-sql-editor-navigation-tab';
const SYNC_DELAY = 5 * 1000;
@@ -49,6 +49,7 @@ export class SqlEditorTabResourceService {
private readonly localStorageSaveService: LocalStorageSaveService,
private readonly userInfoResource: UserInfoResource,
private readonly commonDialogService: CommonDialogService,
private readonly sqlDataSourceService: SqlDataSourceService
) {
this.state = new Map();
@@ -164,8 +165,14 @@ export class SqlEditorTabResourceService {
tab: ITab<ISqlEditorTabState>,
contexts: IExecutionContextProvider<any>
) {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
if (!dataSource) {
return;
}
try {
await this.updateResource(tab, tab.handlerState.query);
await this.updateResource(tab, dataSource.script);
} catch {
const result = await this.commonDialogService.open(ConfirmationDialog, {
title: 'plugin_resource_manager_save_script_error_confirmation_title',
@@ -12,7 +12,7 @@ import { NotificationService } from '@cloudbeaver/core-events';
import { IExecutor, Executor, IExecutionContextProvider } from '@cloudbeaver/core-executor';
import { NavigationService } from '@cloudbeaver/core-ui';
import { uuid } from '@cloudbeaver/core-utils';
import { ISqlEditorTabState, MemorySqlDataSource, SqlResultTabsService } from '@cloudbeaver/plugin-sql-editor';
import { ISqlEditorTabState, MemorySqlDataSource, SqlDataSourceService, SqlResultTabsService } from '@cloudbeaver/plugin-sql-editor';
import { SQL_EDITOR_SOURCE_ACTION } from './SQL_EDITOR_SOURCE_ACTION';
import { SqlEditorTabService, isSQLEditorTab } from './SqlEditorTabService';
@@ -57,7 +57,8 @@ export class SqlEditorNavigatorService {
private readonly notificationService: NotificationService,
private readonly sqlEditorTabService: SqlEditorTabService,
private readonly sqlResultTabsService: SqlResultTabsService,
navigationService: NavigationService
navigationService: NavigationService,
private readonly sqlDataSourceService: SqlDataSourceService
) {
this.navigator = new Executor<SQLCreateAction | SQLEditorAction>(
null,
@@ -101,10 +102,14 @@ export class SqlEditorNavigatorService {
if (data.type === SQLEditorNavigationAction.create) {
if (data.source === SQL_EDITOR_SOURCE_ACTION) {
tab = this.navigationTabsService.findTab(isSQLEditorTab(tab => (
tab.handlerState.source === SQL_EDITOR_SOURCE_ACTION
&& tab.handlerState.executionContext?.connectionId === data.connectionId
)));
tab = this.navigationTabsService.findTab(isSQLEditorTab(tab => {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
return (
tab.handlerState.source === SQL_EDITOR_SOURCE_ACTION
&& dataSource?.executionContext?.connectionId === data.connectionId
);
}));
}
if (!tab) {
@@ -16,7 +16,7 @@ import { useService } from '@cloudbeaver/core-di';
import { useStyles } from '@cloudbeaver/core-theming';
import { TabIcon, Tab, TabTitle, ITabData } from '@cloudbeaver/core-ui';
import { CaptureViewContext, useDataContext } from '@cloudbeaver/core-view';
import { DATA_CONTEXT_SQL_EDITOR_STATE, getSqlEditorName, ISqlEditorTabState } from '@cloudbeaver/plugin-sql-editor';
import { DATA_CONTEXT_SQL_EDITOR_STATE, getSqlEditorName, ISqlEditorTabState, SqlDataSourceService } from '@cloudbeaver/plugin-sql-editor';
import { DATA_CONTEXT_SQL_EDITOR_TAB } from './DATA_CONTEXT_SQL_EDITOR_TAB';
@@ -29,9 +29,11 @@ export const SqlEditorTab: TabHandlerTabComponent<ISqlEditorTabState> = observer
tabMenuContext.set(DATA_CONTEXT_SQL_EDITOR_TAB, true);
tabMenuContext.set(DATA_CONTEXT_SQL_EDITOR_STATE, tab.handlerState);
const sqlDataSourceService = useService(SqlDataSourceService);
const connectionInfo = useService(ConnectionInfoResource);
const connection = connectionInfo.get(tab.handlerState.executionContext?.connectionId || '');
const dataSource = sqlDataSourceService.get(tab.handlerState.editorId);
const connection = connectionInfo.get(dataSource?.executionContext?.connectionId || '');
const name = getSqlEditorName(tab.handlerState, connection);
const handleSelect = ({ tabId }: ITabData<any>) => onSelect(tabId);
@@ -33,7 +33,7 @@ import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { Executor, ExecutorInterrupter } from '@cloudbeaver/core-executor';
import { CachedMapAllKey, ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
import { SqlResultTabsService, ISqlEditorTabState, SqlEditorService, getSqlEditorName } from '@cloudbeaver/plugin-sql-editor';
import { SqlResultTabsService, ISqlEditorTabState, SqlEditorService, getSqlEditorName, SqlDataSourceService } from '@cloudbeaver/plugin-sql-editor';
import { SqlEditorPanel } from './SqlEditorPanel';
import { SqlEditorTab } from './SqlEditorTab';
@@ -57,7 +57,8 @@ export class SqlEditorTabService extends Bootstrap {
private readonly connectionExecutionContextResource: ConnectionExecutionContextResource,
private readonly connectionInfoResource: ConnectionInfoResource,
private readonly connectionSchemaManagerService: ConnectionSchemaManagerService,
private readonly navNodeManagerService: NavNodeManagerService
private readonly navNodeManagerService: NavNodeManagerService,
private readonly sqlDataSourceService: SqlDataSourceService
) {
super();
@@ -96,7 +97,8 @@ export class SqlEditorTabService extends Bootstrap {
load(): void { }
getName(tabState: ISqlEditorTabState): string {
const connection = this.connectionInfoResource.get(tabState.executionContext?.connectionId || '');
const dataSource = this.sqlDataSourceService.get(tabState.editorId);
const connection = this.connectionInfoResource.get(dataSource?.executionContext?.connectionId || '');
return getSqlEditorName(tabState, connection);
}
@@ -106,11 +108,13 @@ export class SqlEditorTabService extends Bootstrap {
dataSourceKey: string,
name?: string,
source?: string,
query?: string,
script?: string,
): ITabOptions<ISqlEditorTabState> | null {
const order = this.getFreeEditorId();
this.sqlDataSourceService.create(editorId, dataSourceKey, script);
return {
id: editorId,
handlerId: sqlEditorTabHandlerKey,
@@ -120,23 +124,28 @@ export class SqlEditorTabService extends Bootstrap {
order,
name,
source,
query,
undefined
),
};
}
resetConnectionInfo(state: ISqlEditorTabState): void {
state.executionContext = undefined;
const dataSource = this.sqlDataSourceService.get(state.editorId);
dataSource?.setExecutionContext(undefined);
}
private async handleConnectionDelete(key: ResourceKey<string>) {
const tabs = this.navigationTabsService.findTabs<ISqlEditorTabState>(
isSQLEditorTab(tab => !!tab.handlerState.executionContext)
isSQLEditorTab(tab => {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
return !!dataSource?.executionContext;
})
);
for (const tab of tabs) {
if (ResourceKeyUtils.includes(key, tab.handlerState.executionContext?.connectionId)) {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
if (ResourceKeyUtils.includes(key, dataSource?.executionContext?.connectionId)) {
this.resetConnectionInfo(tab.handlerState);
}
}
@@ -168,31 +177,41 @@ export class SqlEditorTabService extends Bootstrap {
private async handleExecutionContextUpdate(key: ResourceKey<string>) {
const tabs = this.navigationTabsService.findTabs<ISqlEditorTabState>(
isSQLEditorTab(tab => !!tab.handlerState.executionContext)
isSQLEditorTab(tab => {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
return !!dataSource?.executionContext;
})
);
for (const tab of tabs) {
const executionContext = this.connectionExecutionContextService.get(tab.handlerState.executionContext!.id);
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId)!;
const executionContext = this.connectionExecutionContextService.get(dataSource.executionContext!.id);
if (!executionContext?.context) {
if (!this.connectionInfoResource.has(tab.handlerState.executionContext?.connectionId || '')) {
if (!this.connectionInfoResource.has(dataSource.executionContext?.connectionId || '')) {
this.resetConnectionInfo(tab.handlerState);
}
} else {
tab.handlerState.executionContext = { ...executionContext.context };
dataSource.setExecutionContext({ ...executionContext.context });
}
}
}
private async handleExecutionContextDelete(key: ResourceKey<string>) {
const tabs = this.navigationTabsService.findTabs<ISqlEditorTabState>(
isSQLEditorTab(tab => !!tab.handlerState.executionContext)
isSQLEditorTab(tab => {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
return !!dataSource?.executionContext;
})
);
for (const tab of tabs) {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId)!;
if (
ResourceKeyUtils.includes(key, tab.handlerState.executionContext!.id)
&& !this.connectionInfoResource.has(tab.handlerState.executionContext!.connectionId)
ResourceKeyUtils.includes(key, dataSource.executionContext!.id)
&& !this.connectionInfoResource.has(dataSource.executionContext!.connectionId)
) {
this.resetConnectionInfo(tab.handlerState);
}
@@ -205,32 +224,33 @@ export class SqlEditorTabService extends Bootstrap {
}
private async handleTabRestore(tab: ITab<ISqlEditorTabState>): Promise<boolean> {
if (typeof tab.handlerState.query !== 'string'
|| typeof tab.handlerState.editorId !== 'string'
|| typeof tab.handlerState.order !== 'number'
|| !['undefined', 'object'].includes(typeof tab.handlerState.executionContext)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.executionContext?.connectionId)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.executionContext?.id)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.executionContext?.defaultCatalog)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.executionContext?.defaultSchema)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.currentTabId)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.name)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.source)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.currentModeId)
|| !Array.isArray(tab.handlerState.modeState)
|| !Array.isArray(tab.handlerState.tabs)
|| !Array.isArray(tab.handlerState.executionPlanTabs)
|| !Array.isArray(tab.handlerState.resultGroups)
|| !Array.isArray(tab.handlerState.resultTabs)
|| !Array.isArray(tab.handlerState.statisticsTabs)
if (
typeof tab.handlerState.editorId !== 'string'
|| typeof tab.handlerState.editorId !== 'string'
|| typeof tab.handlerState.order !== 'number'
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.currentTabId)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.name)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.source)
|| !['string', 'undefined', 'object'].includes(typeof tab.handlerState.currentModeId)
|| !Array.isArray(tab.handlerState.modeState)
|| !Array.isArray(tab.handlerState.tabs)
|| !Array.isArray(tab.handlerState.executionPlanTabs)
|| !Array.isArray(tab.handlerState.resultGroups)
|| !Array.isArray(tab.handlerState.resultTabs)
|| !Array.isArray(tab.handlerState.statisticsTabs)
) {
return false;
}
if (tab.handlerState.executionContext) {
const dataSource = this.sqlDataSourceService.create(
tab.handlerState.editorId,
tab.handlerState.datasourceKey
);
if (dataSource.executionContext) {
await this.connectionInfoResource.load(CachedMapAllKey);
if (!this.connectionInfoResource.has(tab.handlerState.executionContext.connectionId)) {
if (!this.connectionInfoResource.has(dataSource.executionContext.connectionId)) {
this.resetConnectionInfo(tab.handlerState);
}
}
@@ -247,16 +267,19 @@ export class SqlEditorTabService extends Bootstrap {
}
private getConnectionId(tab: ITab<ISqlEditorTabState>) {
return tab.handlerState.executionContext?.connectionId;
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
return dataSource?.executionContext?.connectionId;
}
private getObjectCatalogId(tab: ITab<ISqlEditorTabState>) {
const context = this.connectionExecutionContextResource.get(tab.handlerState.executionContext?.id ?? '');
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
const context = this.connectionExecutionContextResource.get(dataSource?.executionContext?.id ?? '');
return context?.defaultCatalog;
}
private getObjectSchemaId(tab: ITab<ISqlEditorTabState>) {
const context = this.connectionExecutionContextResource.get(tab.handlerState.executionContext?.id ?? '');
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
const context = this.connectionExecutionContextResource.get(dataSource?.executionContext?.id ?? '');
return context?.defaultSchema;
}
@@ -270,22 +293,25 @@ export class SqlEditorTabService extends Bootstrap {
}
private async setObjectCatalogId(containerId: string, tab: ITab<ISqlEditorTabState>) {
if (!tab.handlerState.executionContext) {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
if (!dataSource?.executionContext) {
return false;
}
const executionContext = this.connectionExecutionContextService.get(tab.handlerState.executionContext.id);
const executionContext = this.connectionExecutionContextService.get(dataSource.executionContext.id);
if (!executionContext) {
return false;
}
try {
await executionContext.update(
const context = await executionContext.update(
containerId,
tab.handlerState.executionContext.defaultSchema,
dataSource.executionContext.defaultSchema,
);
tab.handlerState.executionContext.defaultCatalog = containerId;
dataSource.setExecutionContext({ ...context });
return true;
} catch (exception: any) {
this.notificationService.logException(exception, 'Failed to change SQL-editor catalog');
@@ -294,22 +320,25 @@ export class SqlEditorTabService extends Bootstrap {
}
private async setObjectSchemaId(containerId: string, tab: ITab<ISqlEditorTabState>) {
if (!tab.handlerState.executionContext) {
const dataSource = this.sqlDataSourceService.get(tab.handlerState.editorId);
if (!dataSource?.executionContext) {
return false;
}
const executionContext = this.connectionExecutionContextService.get(tab.handlerState.executionContext.id);
const executionContext = this.connectionExecutionContextService.get(dataSource.executionContext.id);
if (!executionContext) {
return false;
}
try {
await executionContext.update(
tab.handlerState.executionContext.defaultCatalog,
const context = await executionContext.update(
dataSource.executionContext.defaultCatalog,
containerId
);
tab.handlerState.executionContext.defaultSchema = containerId;
dataSource.setExecutionContext({ ...context });
return true;
} catch (exception: any) {
this.notificationService.logException(exception, 'Failed to change SQL-editor schema');
@@ -327,8 +356,10 @@ export class SqlEditorTabService extends Bootstrap {
}
private async handleTabClose(editorTab: ITab<ISqlEditorTabState>) {
if (editorTab.handlerState.executionContext) {
await this.sqlEditorService.destroyContext(editorTab.handlerState.executionContext);
const dataSource = this.sqlDataSourceService.get(editorTab.handlerState.editorId);
if (dataSource?.executionContext) {
await this.sqlEditorService.destroyContext(dataSource.executionContext);
}
this.sqlResultTabsService.removeResultTabs(editorTab.handlerState);
@@ -10,7 +10,7 @@ import { injectable, Bootstrap } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { MENU_TAB } from '@cloudbeaver/core-ui';
import { ActionService, ACTION_OPEN_IN_TAB, DATA_CONTEXT_MENU, IDataContextProvider, KeyBindingService, KEY_BINDING_OPEN_IN_TAB, MenuService, IAction } from '@cloudbeaver/core-view';
import { DATA_CONTEXT_SQL_EDITOR_STATE } from '@cloudbeaver/plugin-sql-editor';
import { DATA_CONTEXT_SQL_EDITOR_STATE, SqlDataSourceService } from '@cloudbeaver/plugin-sql-editor';
import { DATA_CONTEXT_SQL_EDITOR_TAB } from '@cloudbeaver/plugin-sql-editor-navigation-tab';
import { SqlEditorScreenService } from './Screen/SqlEditorScreenService';
@@ -22,7 +22,8 @@ export class PluginBootstrap extends Bootstrap {
private readonly keyBindingService: KeyBindingService,
private readonly sqlEditorScreenService: SqlEditorScreenService,
private readonly notificationService: NotificationService,
private readonly menuService: MenuService
private readonly menuService: MenuService,
private readonly sqlDataSourceService: SqlDataSourceService
) {
super();
}
@@ -34,7 +35,16 @@ export class PluginBootstrap extends Bootstrap {
action === ACTION_OPEN_IN_TAB
&& contexts.has(DATA_CONTEXT_SQL_EDITOR_STATE)
),
isDisabled: (context, action) => context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE)?.executionContext === undefined,
isDisabled: (context, action) => {
const state = context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE);
if (!state) {
return false;
}
const dataSource = this.sqlDataSourceService.get(state.editorId);
return dataSource?.executionContext === undefined;
},
handler: this.openTab.bind(this),
});
@@ -60,8 +70,9 @@ export class PluginBootstrap extends Bootstrap {
private openTab(contexts: IDataContextProvider, action: IAction) {
const context = contexts.get(DATA_CONTEXT_SQL_EDITOR_STATE);
const dataSource = this.sqlDataSourceService.get(context.editorId);
if (!context.executionContext) {
if (!dataSource?.executionContext) {
this.notificationService.logError({
title: 'sql_editor_screen_no_context_title',
message: 'sql_editor_screen_no_context_message',
@@ -70,7 +81,7 @@ export class PluginBootstrap extends Bootstrap {
}
const url = this.sqlEditorScreenService.createURL({
contextId: context.executionContext.id,
contextId: dataSource.executionContext.id,
});
window.open(url, '_blank')?.focus();
@@ -16,7 +16,7 @@ import { useTranslate } from '@cloudbeaver/core-localization';
import type { ScreenComponent } from '@cloudbeaver/core-routing';
import { CachedMapAllKey } from '@cloudbeaver/core-sdk';
import { uuid } from '@cloudbeaver/core-utils';
import { ISqlEditorTabState, MemorySqlDataSource, SqlEditor, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
import { ISqlEditorTabState, MemorySqlDataSource, SqlDataSourceService, SqlEditor, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
import type { ISqlEditorScreenParams } from './ISqlEditorScreenParams';
@@ -29,30 +29,41 @@ export const SqlEditorScreen: ScreenComponent<ISqlEditorScreenParams> = observer
ConnectionExecutionContextResource,
CachedMapAllKey
);
const sqlDataSourceService = useService(SqlDataSourceService);
const sqlEditorService = useService(SqlEditorService);
const connectionExecutionContextService = useService(ConnectionExecutionContextService);
const context = connectionExecutionContextService.get(contextId);
const state = useObservableRef(() => ({
get dataSource() {
if (!this.state) {
return undefined;
}
return sqlDataSourceService.get(this.state.editorId);
},
state: null as null | ISqlEditorTabState,
setState(contextInfo: IConnectionExecutionContextInfo | undefined) {
if (contextInfo) {
const editorId = uuid();
sqlDataSourceService.create(editorId, MemorySqlDataSource.key, '', contextInfo);
this.state = sqlEditorService.getState(
uuid(),
editorId,
MemorySqlDataSource.key,
0,
undefined,
undefined,
undefined,
contextInfo
);
} else {
this.state = null;
}
},
}), { state: observable }, false);
if (context?.context?.id !== state.state?.executionContext?.id) {
if (context?.context?.id !== state.dataSource?.executionContext?.id) {
state.setState(context?.context);
}
@@ -51,9 +51,6 @@ export interface ISqlEditorTabState {
source?: string;
order: number;
query: string;
executionContext?: IConnectionExecutionContextInfo;
currentTabId?: string;
tabs: ISqlEditorResultTab[];
resultGroups: IResultGroup[];
@@ -19,6 +19,7 @@ import { useStyles } from '@cloudbeaver/core-theming';
import { CaptureView } from '@cloudbeaver/core-view';
import type { ISqlEditorTabState } from './ISqlEditorTabState';
import { SqlDataSourceService } from './SqlDataSource/SqlDataSourceService';
import { SqlEditorLoader } from './SqlEditor/SqlEditorLoader';
import { SqlEditorService } from './SqlEditorService';
import { SqlEditorView } from './SqlEditorView';
@@ -50,8 +51,14 @@ export const SqlEditor = observer<Props>(function SqlEditor({ state }) {
const translate = useTranslate();
const sqlEditorView = useService(SqlEditorView);
const sqlEditorService = useService(SqlEditorService);
const sqlDataSourceService = useService(SqlDataSourceService);
const styles = useStyles(splitStyles, splitHorizontalStyles, viewerStyles);
const connection = useMapResource(SqlEditor, ConnectionInfoResource, state.executionContext?.connectionId ?? null);
const dataSource = sqlDataSourceService.get(state.editorId);
const connection = useMapResource(
SqlEditor,
ConnectionInfoResource,
dataSource?.executionContext?.connectionId ?? null
);
const driver = useMapResource(SqlEditor, DBDriverResource, connection.data?.driverId ?? null);
const splitState = useSplitUserState('sql-editor');
@@ -60,11 +67,14 @@ export const SqlEditor = observer<Props>(function SqlEditor({ state }) {
const context = useMapResource(
SqlEditor,
ConnectionExecutionContextResource,
connected ? (state.executionContext?.id ?? null) : null
connected ? (dataSource?.executionContext?.id ?? null) : null
);
const initializingContext = getComputed(() => connection.isLoading() || context.isLoading());
const initExecutionContext = getComputed(() => context.data === undefined && state.executionContext !== undefined);
const initExecutionContext = getComputed(() => (
context.data === undefined
&& dataSource?.executionContext !== undefined
));
async function cancelConnection() {
await sqlEditorService.resetExecutionContext(state);
@@ -75,8 +85,8 @@ export const SqlEditor = observer<Props>(function SqlEditor({ state }) {
}
const dataContainer = getComputed(() => NodeManagerUtils.concatSchemaAndCatalog(
state.executionContext?.defaultCatalog,
state.executionContext?.defaultSchema
dataSource?.executionContext?.defaultCatalog,
dataSource?.executionContext?.defaultSchema
));
useEffect(() => {
@@ -18,6 +18,8 @@ import type { SqlDialectInfo } from '@cloudbeaver/core-sdk';
import { throttleAsync } from '@cloudbeaver/core-utils';
import type { ISqlEditorTabState } from '../ISqlEditorTabState';
import type { ISqlDataSource } from '../SqlDataSource/ISqlDataSource';
import { SqlDataSourceService } from '../SqlDataSource/SqlDataSourceService';
import { SqlDialectInfoService } from '../SqlDialectInfoService';
import { SqlEditorService } from '../SqlEditorService';
import { ISQLScriptSegment, SQLParser } from '../SQLParser';
@@ -35,6 +37,7 @@ interface ISQLEditorDataPrivate extends ISQLEditorData {
readonly sqlExecutionPlanService: SqlExecutionPlanService;
readonly commonDialogService: CommonDialogService;
readonly sqlResultTabsService: SqlResultTabsService;
readonly dataSource: ISqlDataSource | undefined;
cursor: ICursor;
readonlyState: boolean;
@@ -55,14 +58,18 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
const sqlExecutionPlanService = useService(SqlExecutionPlanService);
const sqlResultTabsService = useService(SqlResultTabsService);
const commonDialogService = useService(CommonDialogService);
const sqlDataSourceService = useService(SqlDataSourceService);
const data = useObservableRef<ISQLEditorDataPrivate>(() => ({
get dataSource(): ISqlDataSource | undefined {
return sqlDataSourceService.get(this.state.editorId);
},
get dialect(): SqlDialectInfo | undefined {
if (!this.state.executionContext) {
if (!this.dataSource?.executionContext) {
return undefined;
}
return this.sqlDialectInfoService.getDialectInfo(this.state.executionContext.connectionId);
return this.sqlDialectInfoService.getDialectInfo(this.dataSource.executionContext.connectionId);
},
get activeSegmentMode(): ISQLEditorMode {
@@ -93,17 +100,17 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
},
get isDisabled(): boolean {
if (!this.state.executionContext) {
if (!this.dataSource?.executionContext) {
return true;
}
const context = this.connectionExecutionContextService.get(this.state.executionContext.id);
const context = this.connectionExecutionContextService.get(this.dataSource.executionContext.id);
return context?.executing || false;
},
get value(): string {
return this.state.query;
return this.dataSource?.script ?? '';
},
onMode: new SyncExecutor(),
@@ -127,11 +134,11 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
this.parser.setScript(this.value);
this.reactionDisposer = autorun(() => {
if (this.state.executionContext) {
const context = this.connectionExecutionContextService.get(this.state.executionContext.id);
if (this.dataSource?.executionContext) {
const context = this.connectionExecutionContextService.get(this.dataSource.executionContext.id);
if (context) {
const connectionId = this.state.executionContext.connectionId;
const connectionId = this.dataSource.executionContext.connectionId;
untracked(() => {
this.sqlDialectInfoService
@@ -159,14 +166,14 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
},
getHintProposals: throttleAsync(async function getHintProposals(this: ISQLEditorDataPrivate, position, simple) {
if (!this.state.executionContext) {
if (!this.dataSource?.executionContext) {
return [];
}
const proposals = await this.sqlEditorService
.getAutocomplete(
this.state.executionContext.connectionId,
this.state.executionContext.id,
this.dataSource.executionContext.connectionId,
this.dataSource.executionContext.id,
this.value,
position,
undefined,
@@ -177,7 +184,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
}, 1000 / 3),
async formatScript(): Promise<void> {
if (this.isDisabled || this.isScriptEmpty || !this.state.executionContext) {
if (this.isDisabled || this.isScriptEmpty || !this.dataSource?.executionContext) {
return;
}
@@ -191,7 +198,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
this.onExecute.execute(true);
try {
this.readonlyState = true;
const formatted = await this.sqlDialectInfoService.formatScript(this.state.executionContext, script.query);
const formatted = await this.sqlDialectInfoService.formatScript(this.dataSource.executionContext, script.query);
this.onFormat.execute([script, formatted]);
this.setQuery(
@@ -312,7 +319,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
}, 1000 / 2),
async updateParserScripts() {
const connectionId = this.state.executionContext?.connectionId;
const connectionId = this.dataSource?.executionContext?.connectionId;
const script = this.parser.actualScript;
if (!connectionId || !script) {
@@ -364,7 +371,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
},
async getResolvedSegment(): Promise<ISQLScriptSegment | undefined> {
const connectionId = this.state.executionContext?.connectionId;
const connectionId = this.dataSource?.executionContext?.connectionId;
if (!connectionId || this.cursor.begin !== this.cursor.end) {
return this.getSubQuery();
@@ -17,6 +17,7 @@ import { download, generateFileName, getTextFileReadingProcess } from '@cloudbea
import { getSqlEditorName } from '../getSqlEditorName';
import type { ISqlEditorTabState } from '../ISqlEditorTabState';
import { SqlDataSourceService } from '../SqlDataSource/SqlDataSourceService';
import { SqlEditorSettingsService } from '../SqlEditorSettingsService';
import { ScriptImportDialog } from './ScriptImportDialog';
@@ -32,6 +33,7 @@ export function useTools(state: ISqlEditorTabState): Readonly<State> {
const notificationService = useService(NotificationService);
const connectionInfoResource = useService(ConnectionInfoResource);
const sqlEditorSettingsService = useService(SqlEditorSettingsService);
const sqlDataSourceService = useService(SqlDataSourceService);
return useObservableRef(() => ({
async tryReadScript(file: File, prevScript: string) {
@@ -95,7 +97,8 @@ export function useTools(state: ISqlEditorTabState): Readonly<State> {
type: 'application/sql',
});
const connection = this.connectionInfoResource.get(this.state.executionContext?.connectionId ?? '');
const dataSource = sqlDataSourceService.get(this.state.editorId);
const connection = this.connectionInfoResource.get(dataSource?.executionContext?.connectionId ?? '');
const name = getSqlEditorName(this.state, connection);
download(blob, generateFileName(name, '.sql'));
@@ -11,7 +11,7 @@ import { injectable } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { Executor } from '@cloudbeaver/core-executor';
import { GraphQLService, SqlCompletionProposal, SqlScriptInfoFragment } from '@cloudbeaver/core-sdk';
import type { ISqlEditorTabState } from '@cloudbeaver/plugin-sql-editor';
import { SqlDataSourceService, ISqlEditorTabState } from '@cloudbeaver/plugin-sql-editor';
export type SQLProposal = SqlCompletionProposal;
@@ -30,7 +30,8 @@ export class SqlEditorService {
private readonly connectionsManagerService: ConnectionsManagerService,
private readonly notificationService: NotificationService,
private readonly connectionExecutionContextService: ConnectionExecutionContextService,
private readonly connectionExecutionContextResource: ConnectionExecutionContextResource
private readonly connectionExecutionContextResource: ConnectionExecutionContextResource,
private readonly sqlDataSourceService: SqlDataSourceService
) {
this.onQueryChange = new Executor();
}
@@ -41,17 +42,13 @@ export class SqlEditorService {
order: number,
name?: string,
source?: string,
query?: string,
contextInfo?: IConnectionExecutionContextInfo,
): ISqlEditorTabState {
return {
editorId,
datasourceKey,
name,
source,
query: query ?? '',
order,
executionContext: contextInfo ? { ...contextInfo } : undefined,
tabs: [],
resultGroups: [],
resultTabs: [],
@@ -113,18 +110,24 @@ export class SqlEditorService {
}
setQuery(query: string, state: ISqlEditorTabState) {
const prevQuery = state.query;
const dataSource = this.sqlDataSourceService.get(state.editorId);
state.query = query;
this.onQueryChange.execute({ prevQuery, query, state });
if (dataSource) {
const prevQuery = dataSource.script;
dataSource.setScript(query);
this.onQueryChange.execute({ prevQuery, query, state });
}
}
async resetExecutionContext(state: ISqlEditorTabState) {
if (state.executionContext) {
await this.destroyContext(state.executionContext);
}
const dataSource = this.sqlDataSourceService.get(state.editorId);
state.executionContext = undefined;
if (dataSource?.executionContext) {
await this.destroyContext(dataSource.executionContext);
dataSource.setExecutionContext(undefined);
}
}
async setConnection(
@@ -135,13 +138,14 @@ export class SqlEditorService {
): Promise<boolean> {
try {
const executionContext = await this.initContext(connectionId, catalogId, schemaId);
const dataSource = this.sqlDataSourceService.get(state.editorId);
if (!executionContext?.context) {
if (!executionContext?.context || !dataSource) {
return false;
}
const previousContext = state.executionContext;
state.executionContext = { ...executionContext.context };
const previousContext = dataSource.executionContext;
dataSource.setExecutionContext({ ...executionContext.context });
if (previousContext) {
await this.destroyContext(previousContext);
@@ -154,15 +158,17 @@ export class SqlEditorService {
}
async initEditorConnection(state: ISqlEditorTabState): Promise<IConnectionExecutionContext | undefined> {
if (!state.executionContext) {
const dataSource = this.sqlDataSourceService.get(state.editorId);
if (!dataSource?.executionContext) {
console.error('executeEditorQuery executionContext is not provided');
return;
}
const context = await this.initContext(
state.executionContext.connectionId,
state.executionContext.defaultCatalog,
state.executionContext.defaultSchema
dataSource.executionContext.connectionId,
dataSource.executionContext.defaultCatalog,
dataSource.executionContext.defaultSchema
);
if (!context?.context) {
@@ -170,7 +176,7 @@ export class SqlEditorService {
return;
}
state.executionContext = { ...context.context };
dataSource.setExecutionContext({ ...context.context });
return context;
}
@@ -16,6 +16,7 @@ import { AsyncTaskInfoService, GraphQLService, SqlExecutionPlan } from '@cloudbe
import { uuid } from '@cloudbeaver/core-utils';
import type { ISqlEditorTabState } from '../../ISqlEditorTabState';
import { SqlDataSourceService } from '../../SqlDataSource/SqlDataSourceService';
interface IExecutionPlanData {
task: ITask<SqlExecutionPlan>;
@@ -30,7 +31,8 @@ export class SqlExecutionPlanService {
private readonly graphQLService: GraphQLService,
private readonly notificationService: NotificationService,
private readonly asyncTaskInfoService: AsyncTaskInfoService,
private readonly connectionExecutionContextService: ConnectionExecutionContextService
private readonly connectionExecutionContextService: ConnectionExecutionContextService,
private readonly sqlDataSourceService: SqlDataSourceService
) {
this.data = new Map();
@@ -43,7 +45,8 @@ export class SqlExecutionPlanService {
editorState: ISqlEditorTabState,
query: string,
): Promise<void> {
const contextInfo = editorState.executionContext;
const dataSource = this.sqlDataSourceService.get(editorState.editorId);
const contextInfo = dataSource?.executionContext;
const executionContext = contextInfo && this.connectionExecutionContextService.get(contextInfo.id);
@@ -138,8 +141,9 @@ export class SqlExecutionPlanService {
}
private createExecutionPlanTab(state: ISqlEditorTabState, query: string) {
if (!state.executionContext) {
throw new Error('ExecutionContext is not provided');
const dataSource = this.sqlDataSourceService.get(state.editorId);
if (!dataSource) {
throw new Error('SQL Data Source is not provided');
}
const id = uuid();
@@ -19,6 +19,7 @@ import {
import type { IResultGroup, ISqlEditorTabState } from '../ISqlEditorTabState';
import { IDataQueryOptions, QueryDataSource } from '../QueryDataSource';
import { SqlDataSourceService } from '../SqlDataSource/SqlDataSourceService';
import { SqlQueryResultService } from './SqlQueryResultService';
interface IQueryExecutionOptions {
@@ -49,6 +50,7 @@ export class SqlQueryService {
private readonly asyncTaskInfoService: AsyncTaskInfoService,
private readonly dataViewerDataChangeConfirmationService: DataViewerDataChangeConfirmationService,
private readonly dataViewerService: DataViewerService,
private readonly sqlDataSourceService: SqlDataSourceService
) {
this.statisticsMap = new Map();
@@ -66,7 +68,8 @@ export class SqlQueryService {
query: string,
inNewTab: boolean
): Promise<void> {
const contextInfo = editorState.executionContext;
const dataSource = this.sqlDataSourceService.get(editorState.editorId);
const contextInfo = dataSource?.executionContext;
const executionContext = contextInfo && this.connectionExecutionContextService.get(contextInfo.id);
if (!contextInfo || !executionContext) {
@@ -143,7 +146,8 @@ export class SqlQueryService {
queries: string[],
options?: IQueryExecutionOptions
): Promise<void> {
const contextInfo = editorState.executionContext;
const dataSource = this.sqlDataSourceService.get(editorState.editorId);
const contextInfo = dataSource?.executionContext;
const executionContext = contextInfo && this.connectionExecutionContextService.get(contextInfo.id);
if (!contextInfo || !executionContext) {