From 76a97bfa8677cd805a55b86e562da94a0958682d Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Mon, 20 May 2024 16:57:57 +0100 Subject: [PATCH 01/15] remove ping --- package.json | 10 --- src/services/connectionManagerService.ts | 65 -------------------- src/utils/core.ts | 28 --------- test/suite/services.test.ts | 49 --------------- test/suite/utils.test.ts | 78 ------------------------ 5 files changed, 230 deletions(-) diff --git a/package.json b/package.json index e831f057..b865c1ab 100644 --- a/package.json +++ b/package.json @@ -170,16 +170,6 @@ "description": "Hide detailed console query output", "default": true }, - "kdb.networkChangesWatcher": { - "type": "boolean", - "description": "Watch for network changes, if changes are detected, check if the Insights connection is still valid", - "default": true - }, - "kdb.insightsHydrate": { - "type": "boolean", - "description": "Hydrate the insights connection every 1 minute to keep it alive", - "default": true - }, "kdb.qHomeDirectory": { "type": "string", "description": "QHOME directory for q runtime" diff --git a/src/services/connectionManagerService.ts b/src/services/connectionManagerService.ts index 6271d44e..57286620 100644 --- a/src/services/connectionManagerService.ts +++ b/src/services/connectionManagerService.ts @@ -22,8 +22,6 @@ import { sanitizeQuery } from "../utils/queryUtils"; import { getHash, getInsights, - getInsightsHydrate, - getNetworkChangesWatcher, getServerName, getServers, removeLocalConnectionContext, @@ -122,11 +120,6 @@ export class ConnectionManagementService { } refreshDataSourcesPanel(); } - if (ext.connectedConnectionList.length === 1) { - getNetworkChangesWatcher(); - this.startMonitoringNetworkConn(); - this.rehidrateInsightsConnections(); - } } public setActiveConnection(node: KdbNode | InsightsNode): void { @@ -331,62 +324,4 @@ export class ConnectionManagementService { ); } } - - public async checkInsightsConnectionIsAlive( - whoTriggered: string, - ): Promise { - const checks = ext.connectedConnectionList.map(async (connection) => { - if (connection instanceof InsightsConnection) { - const res = await connection.pingInsights(); - if (!res) { - this.disconnect(connection.connLabel); - } - } - }); - await Promise.all(checks); - if (ext.connectedConnectionList.length > 0) { - if (whoTriggered === "networkMonitoring") { - this.startMonitoringNetworkConn(); - } else { - this.rehidrateInsightsConnections(); - } - } - } - - /* istanbul ignore next */ - public async startMonitoringNetworkConn(): Promise { - let previousNetworkState = os.networkInterfaces(); - const intervalId = setInterval(() => { - const currentNetworkState = os.networkInterfaces(); - if ( - JSON.stringify(previousNetworkState) !== - JSON.stringify(currentNetworkState) - ) { - getNetworkChangesWatcher(); - if (ext.networkChangesWatcher) { - clearInterval(intervalId); - previousNetworkState = currentNetworkState; - this.checkInsightsConnectionIsAlive("networkMonitoring"); - } - } - if (ext.connectedConnectionList.length === 0) { - clearInterval(intervalId); - } - }, 2000); - } - - /* istanbul ignore next */ - public async rehidrateInsightsConnections(): Promise { - const intervalConns = setInterval(() => { - getInsightsHydrate(); - if (ext.insightsHydrate) { - if (ext.connectedConnectionList.length > 0) { - clearInterval(intervalConns); - this.checkInsightsConnectionIsAlive("rehidrateConnections"); - } else { - clearInterval(intervalConns); - } - } - }, 60000); - } } diff --git a/src/utils/core.ts b/src/utils/core.ts index fca0fba8..c3b08b94 100644 --- a/src/utils/core.ts +++ b/src/utils/core.ts @@ -189,34 +189,6 @@ export function getHideDetailedConsoleQueryOutput(): void { } } -export function getNetworkChangesWatcher(): void { - const setting = workspace - .getConfiguration() - .get("kdb.networkChangesWatcher"); - if (setting === undefined) { - workspace - .getConfiguration() - .update("kdb.networkChangesWatcher", true, ConfigurationTarget.Global); - ext.networkChangesWatcher = true; - } else { - ext.networkChangesWatcher = setting; - } -} - -export function getInsightsHydrate(): void { - const setting = workspace - .getConfiguration() - .get("kdb.insightsHydrate"); - if (setting === undefined) { - workspace - .getConfiguration() - .update("kdb.insightsHydrate", true, ConfigurationTarget.Global); - ext.insightsHydrate = true; - } else { - ext.insightsHydrate = setting; - } -} - export function setOutputWordWrapper(): void { let existWrap = false; const logConfig = workspace.getConfiguration("[Log]"); diff --git a/test/suite/services.test.ts b/test/suite/services.test.ts index d5bbe87a..fe16c610 100644 --- a/test/suite/services.test.ts +++ b/test/suite/services.test.ts @@ -1044,55 +1044,6 @@ describe("connectionManagerService", () => { sinon.assert.notCalled(resetScratchpadStub); }); }); - - describe("checkInsightsConnectionIsAlive()", () => { - let pingInsightsStub, disconnectStub: sinon.SinonStub; - beforeEach(() => { - pingInsightsStub = sinon.stub(insightsConn, "pingInsights"); - disconnectStub = sinon.stub(connectionManagerService, "disconnect"); - ext.connectedConnectionList.length = 0; - }); - - afterEach(() => { - ext.connectedConnectionList.length = 0; - sinon.restore(); - }); - - it("should not call pingInsights if connection is not an instance of InsightsConnection", async () => { - ext.connectedConnectionList.push(localConn); - await connectionManagerService.checkInsightsConnectionIsAlive( - "networkMonitoring", - ); - sinon.assert.notCalled(pingInsightsStub); - }); - - it("should not call pingInsights if there is no connection connected", async () => { - await connectionManagerService.checkInsightsConnectionIsAlive( - "networkMonitoring", - ); - sinon.assert.notCalled(pingInsightsStub); - }); - - it("should call pingInsights if connection is an instance of InsightsConnection", async () => { - ext.connectedConnectionList.push(insightsConn); - pingInsightsStub.resolves(true); - await connectionManagerService.checkInsightsConnectionIsAlive( - "rehidrateConn", - ); - sinon.assert.calledOnce(pingInsightsStub); - sinon.assert.notCalled(disconnectStub); - }); - - it("should call disconnect if pingInsights returns false", async () => { - ext.connectedConnectionList.push(insightsConn); - pingInsightsStub.resolves(false); - await connectionManagerService.checkInsightsConnectionIsAlive( - "networkMonitoring", - ); - sinon.assert.calledOnce(pingInsightsStub); - sinon.assert.calledOnce(disconnectStub); - }); - }); }); describe("dataSourceEditorProvider", () => { diff --git a/test/suite/utils.test.ts b/test/suite/utils.test.ts index 820247b5..c41b4241 100644 --- a/test/suite/utils.test.ts +++ b/test/suite/utils.test.ts @@ -136,84 +136,6 @@ describe("Utils", () => { }); }); - describe("getNetworkChangesWatcher", () => { - let getConfigurationStub: sinon.SinonStub; - - beforeEach(() => { - getConfigurationStub = sinon.stub( - vscode.workspace, - "getConfiguration", - ) as sinon.SinonStub; - }); - - afterEach(() => { - getConfigurationStub.restore(); - }); - - it("should update configuration and set getNetworkChangesWatcher to true when setting is undefined", async () => { - getConfigurationStub.returns({ - get: sinon.stub().returns(undefined), - update: sinon.stub(), - }); - - await coreUtils.getNetworkChangesWatcher(); - - sinon.assert.calledTwice(getConfigurationStub); - assert.strictEqual(ext.networkChangesWatcher, true); - }); - - it("should set getNetworkChangesWatcher to setting when setting is defined", async () => { - getConfigurationStub.returns({ - get: sinon.stub().returns(false), - update: sinon.stub(), - }); - - await coreUtils.getNetworkChangesWatcher(); - - sinon.assert.calledOnce(getConfigurationStub); - assert.strictEqual(ext.networkChangesWatcher, false); - }); - }); - - describe("getInsightsHydrate", () => { - let getConfigurationStub: sinon.SinonStub; - - beforeEach(() => { - getConfigurationStub = sinon.stub( - vscode.workspace, - "getConfiguration", - ) as sinon.SinonStub; - }); - - afterEach(() => { - getConfigurationStub.restore(); - }); - - it("should update configuration and set getInsightsHydrate to true when setting is undefined", async () => { - getConfigurationStub.returns({ - get: sinon.stub().returns(undefined), - update: sinon.stub(), - }); - - await coreUtils.getInsightsHydrate(); - - sinon.assert.calledTwice(getConfigurationStub); - assert.strictEqual(ext.insightsHydrate, true); - }); - - it("should set getInsightsHydrate to setting when setting is defined", async () => { - getConfigurationStub.returns({ - get: sinon.stub().returns(false), - update: sinon.stub(), - }); - - await coreUtils.getInsightsHydrate(); - - sinon.assert.calledOnce(getConfigurationStub); - assert.strictEqual(ext.insightsHydrate, false); - }); - }); - describe("server alias", () => { beforeEach(() => { ext.kdbConnectionAliasList.length = 0; From 68997a8d54feeffa5314945a674f5471afa62f75 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Tue, 21 May 2024 10:48:52 +0100 Subject: [PATCH 02/15] update license header --- resources/license-header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/license-header.js b/resources/license-header.js index 798e0f00..e0c9a63f 100644 --- a/resources/license-header.js +++ b/resources/license-header.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2023 Kx Systems Inc. + * Copyright (c) 1998-2024 Kx Systems Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at From e20e006af1d9063c4bf15a492e0585b962c17283 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Tue, 21 May 2024 11:15:59 +0100 Subject: [PATCH 03/15] Revert "update license header" This reverts commit 68997a8d54feeffa5314945a674f5471afa62f75. --- resources/license-header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/license-header.js b/resources/license-header.js index e0c9a63f..798e0f00 100644 --- a/resources/license-header.js +++ b/resources/license-header.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2024 Kx Systems Inc. + * Copyright (c) 1998-2023 Kx Systems Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at From 283f10fbb49254c62de3d046f88fe4f16c140007 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Tue, 21 May 2024 13:48:39 +0100 Subject: [PATCH 04/15] fix for scratchpad and workbook multiple conn --- src/commands/serverCommand.ts | 155 +++++++++++++++++------ src/commands/workspaceCommand.ts | 23 ++-- src/extension.ts | 8 +- src/services/connectionManagerService.ts | 26 ++-- src/services/resultsPanelProvider.ts | 19 ++- src/utils/executionConsole.ts | 46 +++---- src/utils/queryUtils.ts | 4 + 7 files changed, 191 insertions(+), 90 deletions(-) diff --git a/src/commands/serverCommand.ts b/src/commands/serverCommand.ts index 094a28f9..58014f38 100644 --- a/src/commands/serverCommand.ts +++ b/src/commands/serverCommand.ts @@ -323,27 +323,45 @@ export async function disconnect(connLabel: string): Promise { export async function executeQuery( query: string, - context?: string, - isPython?: boolean, + connLabel: string, + executorName: string, + context: string, + isPython: boolean, + isWorkbook: boolean, ): Promise { const connMngService = new ConnectionManagementService(); const queryConsole = ExecutionConsole.start(); - if (ext.activeConnection === undefined && ext.connectionNode === undefined) { - window.showInformationMessage( - "Please connect to a KDB instance or Insights Instance to execute a query", - ); + if (connLabel === "") { + if (ext.activeConnection === undefined) { + window.showInformationMessage( + "No active connection founded. Connect to one connection.", + ); + //TODO ADD ERROR TO CONSOLE HERE + return undefined; + } else { + connLabel = ext.activeConnection.connLabel; + } + } + const isConnected = connMngService.isConnected(connLabel); + if (!isConnected) { + window.showInformationMessage("The selected connection is not connected."); + //TODO ADD ERROR TO CONSOLE HERE return undefined; } + const selectedConn = connMngService.retrieveConnectedConnection(connLabel); + const isInsights = selectedConn instanceof InsightsConnection; if (query.length === 0) { - const isConnected = ext.activeConnection - ? ext.activeConnection.connected - : !!ext.activeConnection; queryConsole.appendQueryError( query, "Query is empty", + connLabel, + executorName, isConnected, - ext.connectionNode?.label ? ext.connectionNode.label : "", + isInsights, + isWorkbook ? "WORKBOOK" : "SCRATCHPAD", + isPython, + false, ); return undefined; } @@ -351,6 +369,7 @@ export async function executeQuery( const startTime = Date.now(); const results = await connMngService.executeQuery( query, + connLabel, context, isStringfy, isPython, @@ -359,13 +378,39 @@ export async function executeQuery( const duration = (endTime - startTime).toString(); // set context for root nodes - if (ext.activeConnection instanceof InsightsConnection) { - writeScratchpadResult(results, query, duration, isPython); + if (selectedConn instanceof InsightsConnection) { + writeScratchpadResult( + results, + query, + connLabel, + executorName, + isPython, + isWorkbook, + duration, + ); } else { if (ext.resultsViewProvider.isVisible()) { - writeQueryResultsToView(results, query, undefined, false, duration); + writeQueryResultsToView( + results, + query, + connLabel, + executorName, + isInsights, + isWorkbook ? "WORKBOOK" : "SCRATCHPAD", + isPython, + duration, + ); } else { - writeQueryResultsToConsole(results, query, undefined, false, duration); + writeQueryResultsToConsole( + results, + query, + connLabel, + executorName, + isInsights, + isWorkbook ? "WORKBOOK" : "SCRATCHPAD", + isPython, + duration, + ); } } } @@ -418,7 +463,13 @@ export function getConextForRerunQuery(query: string): string { return context; } -export function runQuery(type: ExecutionTypes, rerunQuery?: string) { +export function runQuery( + type: ExecutionTypes, + connLabel: string, + executorName: string, + isWorkbook: boolean, + rerunQuery?: string, +) { const editor = ext.activeTextEditor; if (!editor) { return false; @@ -451,7 +502,7 @@ export function runQuery(type: ExecutionTypes, rerunQuery?: string) { } break; } - executeQuery(query, context, isPython); + executeQuery(query, connLabel, executorName, context, isPython, isWorkbook); } export function rerunQuery(rerunQueryElement: QueryHistory) { @@ -462,8 +513,11 @@ export function rerunQuery(rerunQueryElement: QueryHistory) { const context = getConextForRerunQuery(rerunQueryElement.query); executeQuery( rerunQueryElement.query, + rerunQueryElement.connectionName, + rerunQueryElement.executorName, context, rerunQueryElement.language !== "q", + !!rerunQueryElement.isWorkbook, ); } else { const dsFile = rerunQueryElement.query as DataSourceFiles; @@ -503,7 +557,10 @@ export async function loadServerObjects(): Promise { export function writeQueryResultsToConsole( result: string | string[], query: string, - dataSourceType?: string, + connLabel: string, + executorName: string, + isInsights: boolean, + type?: string, isPython?: boolean, duration?: string, ): void { @@ -511,27 +568,29 @@ export function writeQueryResultsToConsole( const res = Array.isArray(result) ? decodeQUTF(result[0]) : decodeQUTF(result); - if ( - (ext.activeConnection || ext.connectionNode) && - !res.startsWith(queryConstants.error) - ) { + if (!res.startsWith(queryConstants.error)) { queryConsole.append( res, query, - ext.connectionNode?.label ? ext.connectionNode.label : "", - dataSourceType, + executorName, + connLabel, + isInsights, + type, isPython, duration, ); } else { - if (!checkIfIsDatasource(dataSourceType)) { + if (!checkIfIsDatasource(type)) { queryConsole.appendQueryError( query, res.substring(queryConstants.error.length), - !!ext.activeConnection, - ext.connectionNode?.label ? ext.connectionNode.label : "", + connLabel, + executorName, + true, + isInsights, + type, isPython, - undefined, + false, duration, ); } @@ -541,22 +600,23 @@ export function writeQueryResultsToConsole( export function writeQueryResultsToView( result: any, query: string, - dataSourceType?: string, + connLabel: string, + executorName: string, + isInsights: boolean, + type?: string, isPython?: boolean, duration?: string, ): void { - commands.executeCommand("kdb.resultsPanel.update", result, dataSourceType); - const connectionType: ServerType = - ext.connectionNode instanceof KdbNode - ? ServerType.KDB - : ServerType.INSIGHTS; - if (!checkIfIsDatasource(dataSourceType)) { + commands.executeCommand("kdb.resultsPanel.update", result, isInsights, type); + if (!checkIfIsDatasource(type)) { addQueryHistory( query, - ext.connectionNode?.label ? ext.connectionNode.label : "", - connectionType, + executorName, + connLabel, + isInsights ? ServerType.INSIGHTS : ServerType.KDB, true, isPython, + type === "WORKBOOK", undefined, undefined, duration, @@ -567,8 +627,11 @@ export function writeQueryResultsToView( export function writeScratchpadResult( result: ScratchpadResult, query: string, + connLabel: string, + executorName: string, + isPython: boolean, + isWorkbook: boolean, duration: string, - isPython?: boolean, ): void { const queryConsole = ExecutionConsole.start(); @@ -576,15 +639,24 @@ export function writeScratchpadResult( queryConsole.appendQueryError( query, result.errorMsg, + connLabel, + executorName, true, - ext.connectionNode?.label ? ext.connectionNode.label : "", + true, + isWorkbook ? "WORKBOOK" : "SCRATCHPAD", + isPython, + false, + duration, ); } else { if (ext.resultsViewProvider.isVisible()) { writeQueryResultsToView( result.data, query, - "SCRATCHPAD", + connLabel, + executorName, + true, + isWorkbook ? "WORKBOOK" : "SCRATCHPAD", isPython, duration, ); @@ -592,7 +664,10 @@ export function writeScratchpadResult( writeQueryResultsToConsole( result.data, query, - undefined, + connLabel, + executorName, + true, + isWorkbook ? "WORKBOOK" : "SCRATCHPAD", isPython, duration, ); diff --git a/src/commands/workspaceCommand.ts b/src/commands/workspaceCommand.ts index 82ff73eb..8c96e662 100644 --- a/src/commands/workspaceCommand.ts +++ b/src/commands/workspaceCommand.ts @@ -229,21 +229,28 @@ export async function activateConnectionForServer(server: string) { export async function runActiveEditor(type?: ExecutionTypes) { if (ext.activeTextEditor) { const uri = ext.activeTextEditor.document.uri; - if (isScratchpad(uri)) { - let server = getServerForUri(uri); - if (!server) { - server = await pickConnection(uri); - } - if (server) { - await activateConnectionForServer(server); - } + const isWorkbook = uri.path.endsWith(".kdb.q"); + + let server = getServerForUri(uri); + if (!server && isWorkbook) { + server = await pickConnection(uri); + } + if (!server) { + server = ""; } + const executorName = ext.activeTextEditor.document.fileName + .split("/") + .pop(); + runQuery( type === undefined ? isPython(uri) ? ExecutionTypes.PythonQueryFile : ExecutionTypes.QueryFile : type, + server, + executorName ? executorName : "", + isWorkbook, ); } } diff --git a/src/extension.ts b/src/extension.ts index 31d2a70a..1120b4fc 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -168,8 +168,12 @@ export async function activate(context: ExtensionContext) { ), commands.registerCommand( "kdb.resultsPanel.update", - (results: string, dataSourceType?: string) => { - ext.resultsViewProvider.updateResults(results, dataSourceType); + (results: string, isInsights: boolean, dataSourceType?: string) => { + ext.resultsViewProvider.updateResults( + results, + isInsights, + dataSourceType, + ); }, ), commands.registerCommand("kdb.resultsPanel.clear", () => { diff --git a/src/services/connectionManagerService.ts b/src/services/connectionManagerService.ts index 57286620..a2c3aced 100644 --- a/src/services/connectionManagerService.ts +++ b/src/services/connectionManagerService.ts @@ -262,26 +262,28 @@ export class ConnectionManagementService { public async executeQuery( command: string, + connLabel?: string, context?: string, stringfy?: boolean, isPython?: boolean, ): Promise { - if (!ext.activeConnection) { + let selectedConn; + if (connLabel) { + selectedConn = this.retrieveConnectedConnection(connLabel); + } else { + if (!ext.activeConnection) { + return; + } + selectedConn = ext.activeConnection; + } + if (!selectedConn) { return; } command = sanitizeQuery(command); - if (ext.activeConnection instanceof LocalConnection) { - return await ext.activeConnection.executeQuery( - command, - context, - stringfy, - ); + if (selectedConn instanceof LocalConnection) { + return await selectedConn.executeQuery(command, context, stringfy); } else { - return await ext.activeConnection.getScratchpadQuery( - command, - context, - isPython, - ); + return await selectedConn.getScratchpadQuery(command, context, isPython); } } diff --git a/src/services/resultsPanelProvider.ts b/src/services/resultsPanelProvider.ts index 383e6c44..8c1d7f3a 100644 --- a/src/services/resultsPanelProvider.ts +++ b/src/services/resultsPanelProvider.ts @@ -23,7 +23,6 @@ import { ext } from "../extensionVariables"; import * as utils from "../utils/execution"; import { getNonce } from "../utils/getNonce"; import { getUri } from "../utils/getUri"; -import { InsightsConnection } from "../classes/insightsConnection"; export class KdbResultsViewProvider implements WebviewViewProvider { public static readonly viewType = "kdb-results"; @@ -55,12 +54,17 @@ export class KdbResultsViewProvider implements WebviewViewProvider { }); } - public updateResults(queryResults: any, dataSourceType?: string) { + public updateResults( + queryResults: any, + isInsights?: boolean, + dataSourceType?: string, + ) { if (this._view) { this._view.show?.(true); this._view.webview.postMessage(queryResults); this._view.webview.html = this._getWebviewContent( queryResults, + isInsights, dataSourceType, ); } @@ -164,8 +168,7 @@ export class KdbResultsViewProvider implements WebviewViewProvider { } } - convertToGrid(results: any): string { - const isInsights = ext.activeConnection instanceof InsightsConnection; + convertToGrid(results: any, isInsights: boolean): string { const queryResult = isInsights ? results.rows : results; const columnDefs = this.generateCoumnDefs(results, isInsights); @@ -240,7 +243,11 @@ export class KdbResultsViewProvider implements WebviewViewProvider { : ""; } - private _getWebviewContent(queryResult: any, _dataSourceType?: string) { + private _getWebviewContent( + queryResult: any, + isInsights?: boolean, + _dataSourceType?: string, + ) { ext.resultPanelCSV = ""; this._results = queryResult; const agGridTheme = this.defineAgGridTheme(); @@ -263,7 +270,7 @@ export class KdbResultsViewProvider implements WebviewViewProvider { : "

No results to show

"; } else if (queryResult) { isGrid = true; - gridOptionsString = this.convertToGrid(queryResult); + gridOptionsString = this.convertToGrid(queryResult, !!isInsights); } result = diff --git a/src/utils/executionConsole.ts b/src/utils/executionConsole.ts index 7ee4388b..20b66986 100644 --- a/src/utils/executionConsole.ts +++ b/src/utils/executionConsole.ts @@ -14,7 +14,6 @@ import { OutputChannel, commands, window } from "vscode"; import { ext } from "../extensionVariables"; import { ServerType } from "../models/server"; -import { KdbNode } from "../services/kdbTreeProvider"; import { getHideDetailedConsoleQueryOutput, setOutputWordWrapper, @@ -56,7 +55,7 @@ export class ExecutionConsole { public checkOutput( output: string | string[], - query: string, + _query: string, ): string | string[] { if (output.length === 0) { return "No results found."; @@ -78,8 +77,10 @@ export class ExecutionConsole { public append( output: string | string[], query = "", - serverName: string, - dataSourceType?: string, + executorName: string, + connLabel: string, + isInsights?: boolean, + type?: string, isPhython?: boolean, duration?: string, ): void { @@ -87,24 +88,22 @@ export class ExecutionConsole { const hideDetails = ext.hideDetailedConsoleQueryOutput; output = this.checkOutput(output, query); let dataSourceRes: string[] = []; - if (dataSourceType === undefined) { + if (type === undefined) { this._console.show(true); } else { if (Array.isArray(output)) { dataSourceRes = convertRowsToConsole(output); } } - const connectionType: ServerType = - ext.connectionNode instanceof KdbNode - ? ServerType.KDB - : ServerType.INSIGHTS; - if (!checkIfIsDatasource(dataSourceType)) { + if (!checkIfIsDatasource(type)) { addQueryHistory( query, - serverName, - connectionType, + executorName, + connLabel, + isInsights ? ServerType.INSIGHTS : ServerType.KDB, true, isPhython, + type === "WORKBOOK", undefined, undefined, duration, @@ -115,11 +114,11 @@ export class ExecutionConsole { const date = new Date(); if (!hideDetails) { this._console.appendLine( - `>>> ${serverName} @ ${date.toLocaleTimeString()} <<<`, + `>>> ${connLabel} @ ${date.toLocaleTimeString()} <<<`, ); this.appendQuery(query); } - if (Array.isArray(output) && dataSourceType === undefined) { + if (Array.isArray(output) && type === undefined) { this._console.appendLine(output[0]); output.forEach((o) => this._console.appendLine(o)); } else if (dataSourceRes.length > 0) { @@ -136,8 +135,11 @@ export class ExecutionConsole { public appendQueryError( query: string, result: string, + connLabel: string, + executorName: string, isConnected: boolean, - serverName: string, + isInsights?: boolean, + type?: string, isPython?: boolean, isDatasource?: boolean, duration?: string, @@ -149,14 +151,10 @@ export class ExecutionConsole { const date = new Date(); if (!hideDetails) { this._console.appendLine( - `<<< ERROR - ${serverName} @ ${date.toLocaleTimeString()} >>>`, + `<<< ERROR - ${connLabel} @ ${date.toLocaleTimeString()} >>>`, ); } if (isConnected) { - const connectionType: ServerType = - ext.connectionNode instanceof KdbNode - ? ServerType.KDB - : ServerType.INSIGHTS; if (!hideDetails) { this._console.appendLine(`ERROR Query executed: ${query}\n`); this._console.appendLine(result); @@ -166,10 +164,12 @@ export class ExecutionConsole { if (!isDatasource) { addQueryHistory( query, - serverName, - connectionType, + executorName, + connLabel, + isInsights ? ServerType.INSIGHTS : ServerType.KDB, false, isPython, + type === "WORKBOOK", undefined, undefined, duration, @@ -181,10 +181,12 @@ export class ExecutionConsole { commands.executeCommand("kdb.disconnect"); addQueryHistory( query, + executorName, "No connection", ServerType.undefined, false, isPython, + type === "WORKBOOK", ); } if (!hideDetails) { diff --git a/src/utils/queryUtils.ts b/src/utils/queryUtils.ts index d1520e96..3d3bd003 100644 --- a/src/utils/queryUtils.ts +++ b/src/utils/queryUtils.ts @@ -329,21 +329,25 @@ export function selectDSType( export function addQueryHistory( query: string | DataSourceFiles, + executorName: string, connectionName: string, connectionType: ServerType, success: boolean, isPython?: boolean, + isWorkbook?: boolean, isDatasource?: boolean, datasourceType?: DataSourceTypes, duration?: string, ) { const newQueryHistory: QueryHistory = { query: query, + executorName, time: new Date().toLocaleString(), success, connectionName, connectionType, language: isPython ? "python" : "q", + isWorkbook, isDatasource, datasourceType, duration, From 8c07d0ab493bb1f20ad9027371e04e4882c6486e Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Tue, 21 May 2024 13:52:14 +0100 Subject: [PATCH 05/15] query history fixes --- src/models/queryHistory.ts | 2 ++ src/services/queryHistoryProvider.ts | 30 +++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/models/queryHistory.ts b/src/models/queryHistory.ts index b1f9ead9..1fcb9be7 100644 --- a/src/models/queryHistory.ts +++ b/src/models/queryHistory.ts @@ -15,6 +15,7 @@ import { DataSourceFiles, DataSourceTypes } from "./dataSource"; import { ServerType } from "./server"; export interface QueryHistory { + executorName: string; connectionName: string; connectionType: ServerType; query: string | DataSourceFiles; @@ -23,5 +24,6 @@ export interface QueryHistory { language?: string; isDatasource?: boolean; datasourceType?: DataSourceTypes; + isWorkbook?: boolean; duration?: string; } diff --git a/src/services/queryHistoryProvider.ts b/src/services/queryHistoryProvider.ts index 9f7b9826..35ff9fe8 100644 --- a/src/services/queryHistoryProvider.ts +++ b/src/services/queryHistoryProvider.ts @@ -104,12 +104,22 @@ export class QueryHistoryTreeItem extends TreeItem { ); tooltipMd.appendMarkdown("- Connection Type: **" + connType + "** \n"); tooltipMd.appendMarkdown("- Time: **" + this.details.time + "** \n"); - if (typeof this.details.query === "string") { - tooltipMd.appendMarkdown("- Query:"); + if (!this.details.isDatasource && typeof this.details.query === "string") { + if (this.details.isWorkbook) { + tooltipMd.appendMarkdown( + "- Workbook: " + this.details.executorName + " \n", + ); + } else { + tooltipMd.appendMarkdown( + "- File: " + this.details.executorName + " \n", + ); + } + tooltipMd.appendMarkdown("- Query: \n"); tooltipMd.appendCodeblock(this.details.query, codeType); } else { - tooltipMd.appendMarkdown("- Data Source: "); - tooltipMd.appendMarkdown("**" + this.details.query.name + "** \n"); + tooltipMd.appendMarkdown( + "- Data Source: **" + this.details.executorName + "** \n", + ); tooltipMd.appendMarkdown( "- Data Source Type: **" + this.details.datasourceType + "** \n", ); @@ -122,15 +132,3 @@ export class QueryHistoryTreeItem extends TreeItem { return tooltipMd; } } - -// export class QueryHistoryNode extends TreeItem { -// constructor(public readonly details: QueryHistory) { -// super(path.basename(resourceUri.fsPath)); -// this.iconPath = new ThemeIcon("circuit-board"); -// this.command = { -// command: "kdb.queryHistory.rerun", -// title: "Rerun Query", -// arguments: [resourceUri], -// }; -// } -// } From 1e60906f91e6b048c753aeaeda75b9c116360f46 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 09:28:59 +0100 Subject: [PATCH 06/15] fix datasource --- src/classes/insightsConnection.ts | 5 +- src/commands/dataSourceCommand.ts | 233 ++++++----------------- src/commands/serverCommand.ts | 2 +- src/services/connectionManagerService.ts | 11 ++ src/services/dataSourceEditorProvider.ts | 52 +++-- test/suite/commands.test.ts | 161 ---------------- 6 files changed, 112 insertions(+), 352 deletions(-) diff --git a/src/classes/insightsConnection.ts b/src/classes/insightsConnection.ts index 8b1e3708..06582e14 100644 --- a/src/classes/insightsConnection.ts +++ b/src/classes/insightsConnection.ts @@ -43,8 +43,11 @@ export class InsightsConnection { await getCurrentToken( this.node.details.server, this.node.details.alias, - ).then((token) => { + ).then(async (token) => { this.connected = token ? true : false; + if (token) { + await this.getMeta(); + } }); return this.connected; } diff --git a/src/commands/dataSourceCommand.ts b/src/commands/dataSourceCommand.ts index 5d44e36e..4cad27e7 100644 --- a/src/commands/dataSourceCommand.ts +++ b/src/commands/dataSourceCommand.ts @@ -13,7 +13,7 @@ import * as fs from "fs"; import path from "path"; -import { InputBoxOptions, Uri, window } from "vscode"; +import { InputBoxOptions, window } from "vscode"; import { ext } from "../extensionVariables"; import { GetDataError, getDataBodyPayload } from "../models/data"; import { @@ -23,7 +23,6 @@ import { } from "../models/dataSource"; import { scratchpadVariableInput } from "../models/items/server"; import { DataSourcesPanel } from "../panels/datasource"; -import { KdbDataSourceTreeItem } from "../services/dataSourceTreeProvider"; import { checkIfTimeParamIsCorrect, convertTimeToTimestamp, @@ -44,6 +43,8 @@ import { import { ServerType } from "../models/server"; import { Telemetry } from "../utils/telemetryClient"; import { LocalConnection } from "../classes/localConnection"; +import { ConnectionManagementService } from "../services/connectionManagerService"; +import { InsightsConnection } from "../classes/insightsConnection"; export async function addDataSource(): Promise { const kdbDataSourcesFolderPath = createKdbDataSourcesFolder(); @@ -70,137 +71,9 @@ export async function addDataSource(): Promise { Telemetry.sendEvent("Datasource.Created"); } -export async function renameDataSource( - oldName: string, - newName: string, -): Promise { - const kdbDataSourcesFolderPath = createKdbDataSourcesFolder(); - if (!kdbDataSourcesFolderPath) { - return; - } - - const oldFilePath = path.join( - kdbDataSourcesFolderPath, - `${oldName}${ext.kdbDataSourceFileExtension}`, - ); - const newFilePath = path.join( - kdbDataSourcesFolderPath, - `${newName}${ext.kdbDataSourceFileExtension}`, - ); - - const dataSourceContent = fs.readFileSync(oldFilePath, "utf8"); - const data = JSON.parse(dataSourceContent) as DataSourceFiles; - data.name = newName; - const newFileContent = JSON.stringify(data); - fs.writeFileSync(oldFilePath, newFileContent); - - fs.renameSync(oldFilePath, newFilePath); - - const panel = DataSourcesPanel.currentPanel; - if (panel) { - panel.reload(data); - } -} - -export async function deleteDataSource( - dataSource: KdbDataSourceTreeItem, -): Promise { - const kdbDataSourcesFolderPath = createKdbDataSourcesFolder(); - if (!kdbDataSourcesFolderPath) { - return; - } - - const dataSourceFilePath = path.join( - kdbDataSourcesFolderPath, - `${dataSource.label}${ext.kdbDataSourceFileExtension}`, - ); - if (fs.existsSync(dataSourceFilePath)) { - fs.unlinkSync(dataSourceFilePath); - window.showInformationMessage( - `Deleted ${dataSource.label} from ${kdbDataSourcesFolderPath}.`, - ); - } -} - -export async function openDataSource( - dataSource: KdbDataSourceTreeItem, - uri: Uri, -): Promise { - const kdbDataSourcesFolderPath = createKdbDataSourcesFolder(); - if ( - ext.activeConnection instanceof LocalConnection || - !ext.activeConnection - ) { - window.showErrorMessage("No Insights active connection found"); - DataSourcesPanel.running = false; - return; - } - Object.assign(ext.insightsMeta, await ext.activeConnection.getMeta()); - if (!ext.insightsMeta.assembly) { - ext.outputChannel.appendLine( - `To edit or run a datasource you need to be connected to an Insights server`, - ); - window.showErrorMessage( - "To edit or run a datasource you need to be connected to an Insights server", - ); - } - if (!kdbDataSourcesFolderPath) { - return; - } - fs.readFile( - path.join( - kdbDataSourcesFolderPath, - `${dataSource.label}${ext.kdbDataSourceFileExtension}`, - ), - (err, data) => { - if (err) { - ext.outputChannel.appendLine( - `Error reading the file ${dataSource.label}${ext.kdbDataSourceFileExtension}, this file maybe doesn't exist`, - ); - window.showErrorMessage("Error reading file"); - return; - } - if (data) { - const datasourceContent: DataSourceFiles = JSON.parse(data.toString()); - DataSourcesPanel.render(uri, datasourceContent); - } - }, - ); -} - -export async function saveDataSource( - dataSourceForm: DataSourceFiles, -): Promise { - const kdbDataSourcesFolderPath = createKdbDataSourcesFolder(); - if (!kdbDataSourcesFolderPath) { - return; - } - - if (!dataSourceForm.originalName || dataSourceForm.name === "") { - window.showErrorMessage("Name is required"); - return; - } - - if (dataSourceForm.name !== dataSourceForm.originalName) { - await renameDataSource(dataSourceForm.originalName, dataSourceForm.name); - } - - dataSourceForm.insightsNode = getConnectedInsightsNode(); - const fileContent = dataSourceForm; - - const dataSourceFilePath = path.join( - kdbDataSourcesFolderPath, - `${dataSourceForm.name}${ext.kdbDataSourceFileExtension}`, - ); - - if (fs.existsSync(dataSourceFilePath)) { - fs.writeFileSync(dataSourceFilePath, JSON.stringify(fileContent)); - window.showInformationMessage(`DataSource ${dataSourceForm.name} saved.`); - } -} - export async function populateScratchpad( dataSourceForm: DataSourceFiles, + connLabel: string, ): Promise { const scratchpadVariable: InputBoxOptions = { prompt: scratchpadVariableInput.prompt, @@ -211,15 +84,19 @@ export async function populateScratchpad( window.showInputBox(scratchpadVariable).then(async (outputVariable) => { if (outputVariable !== undefined && outputVariable !== "") { + const connMngService = new ConnectionManagementService(); + const selectedConnection = + connMngService.retrieveConnectedConnection(connLabel); + if ( - ext.activeConnection instanceof LocalConnection || - !ext.activeConnection + selectedConnection instanceof LocalConnection || + !selectedConnection ) { window.showErrorMessage("No Insights active connection found"); DataSourcesPanel.running = false; return; } - await ext.activeConnection.importScratchpad( + await selectedConnection.importScratchpad( outputVariable!, dataSourceForm!, ); @@ -233,30 +110,34 @@ export async function populateScratchpad( export async function runDataSource( dataSourceForm: DataSourceFiles, + connLabel: string, ): Promise { if (DataSourcesPanel.running) { return; } DataSourcesPanel.running = true; + const executorName = ext.activeTextEditor?.document.fileName.split("/").pop(); + const connMngService = new ConnectionManagementService(); + const selectedConnection = + connMngService.retrieveConnectedConnection(connLabel); - if ( - ext.activeConnection instanceof LocalConnection || - !ext.activeConnection - ) { + if (selectedConnection && selectedConnection instanceof LocalConnection) { window.showErrorMessage("No Insights active connection found"); DataSourcesPanel.running = false; + //TODO ADD ERROR TO CONSOLE HERE return; } try { - Object.assign(ext.insightsMeta, await ext.activeConnection.getMeta()); - if (!ext.insightsMeta.assembly) { + selectedConnection?.getMeta(); + if (!selectedConnection?.meta?.payload.assembly) { ext.outputChannel.appendLine( `To run a datasource you need to be connected to an Insights server`, ); window.showErrorMessage( "To run a datasource you need to be connected to an Insights server", ); + //TODO ADD ERROR TO CONSOLE HERE return; } @@ -270,39 +151,60 @@ export async function runDataSource( Telemetry.sendEvent("Datasource." + selectedType + ".Run"); switch (selectedType) { case "API": - res = await runApiDataSource(fileContent); + res = await runApiDataSource(fileContent, selectedConnection); break; case "QSQL": - res = await runQsqlDataSource(fileContent); + res = await runQsqlDataSource(fileContent, selectedConnection); break; case "SQL": default: - res = await runSqlDataSource(fileContent); + res = await runSqlDataSource(fileContent, selectedConnection); break; } ext.isDatasourceExecution = false; if (res.error) { window.showErrorMessage(res.error); - addDStoQueryHistory(dataSourceForm, false); + addDStoQueryHistory( + dataSourceForm, + false, + connLabel, + executorName ? executorName : "", + ); } else if (ext.resultsViewProvider.isVisible()) { ext.outputChannel.appendLine( `Results: ${typeof res === "string" ? "0" : res.rows.length} rows`, ); - addDStoQueryHistory(dataSourceForm, true); + addDStoQueryHistory( + dataSourceForm, + true, + connLabel, + executorName ? executorName : "", + ); writeQueryResultsToView( res, getQuery(fileContent, selectedType), + connLabel, + executorName ? executorName : "", + true, selectedType, ); } else { ext.outputChannel.appendLine( `Results is a string with length: ${res.length}`, ); - addDStoQueryHistory(dataSourceForm, true); + addDStoQueryHistory( + dataSourceForm, + true, + connLabel, + executorName ? executorName : "", + ); writeQueryResultsToConsole( res, getQuery(fileContent, selectedType), + connLabel, + executorName ? executorName : "", + true, selectedType, ); } @@ -314,13 +216,17 @@ export async function runDataSource( export function addDStoQueryHistory( dataSourceForm: DataSourceFiles, success: boolean, + connLabel: string, + executrorName: string, ) { addQueryHistory( dataSourceForm, - ext.connectionNode?.label ? ext.connectionNode.label : "", + executrorName, + connLabel, ServerType.INSIGHTS, success, false, + false, true, dataSourceForm.dataSource.selectedType, ); @@ -342,15 +248,8 @@ export function getSelectedType(fileContent: DataSourceFiles): string { export async function runApiDataSource( fileContent: DataSourceFiles, + selectedConn: InsightsConnection, ): Promise { - if ( - ext.activeConnection instanceof LocalConnection || - !ext.activeConnection - ) { - window.showErrorMessage("No Insights active connection found"); - DataSourcesPanel.running = false; - return; - } const isTimeCorrect = checkIfTimeParamIsCorrect( fileContent.dataSource.api.startTS, fileContent.dataSource.api.endTS, @@ -362,7 +261,7 @@ export async function runApiDataSource( return; } const apiBody = getApiBody(fileContent); - const apiCall = await ext.activeConnection.getDataInsights( + const apiCall = await selectedConn.getDataInsights( ext.insightsServiceGatewayUrls.data, JSON.stringify(apiBody), ); @@ -455,15 +354,8 @@ export function getApiBody( export async function runQsqlDataSource( fileContent: DataSourceFiles, + selectedConn: InsightsConnection, ): Promise { - if ( - ext.activeConnection instanceof LocalConnection || - !ext.activeConnection - ) { - window.showErrorMessage("No Insights active connection found"); - DataSourcesPanel.running = false; - return; - } const assembly = fileContent.dataSource.qsql.selectedTarget.slice(0, -4); const target = fileContent.dataSource.qsql.selectedTarget.slice(-3); const qsqlBody = { @@ -471,7 +363,7 @@ export async function runQsqlDataSource( target: target, query: fileContent.dataSource.qsql.query, }; - const qsqlCall = await ext.activeConnection.getDataInsights( + const qsqlCall = await selectedConn.getDataInsights( ext.insightsServiceGatewayUrls.qsql, JSON.stringify(qsqlBody), ); @@ -488,19 +380,12 @@ export async function runQsqlDataSource( export async function runSqlDataSource( fileContent: DataSourceFiles, + selectedConn: InsightsConnection, ): Promise { - if ( - ext.activeConnection instanceof LocalConnection || - !ext.activeConnection - ) { - window.showErrorMessage("No Insights active connection found"); - DataSourcesPanel.running = false; - return; - } const sqlBody = { query: fileContent.dataSource.sql.query, }; - const sqlCall = await ext.activeConnection.getDataInsights( + const sqlCall = await selectedConn.getDataInsights( ext.insightsServiceGatewayUrls.sql, JSON.stringify(sqlBody), ); diff --git a/src/commands/serverCommand.ts b/src/commands/serverCommand.ts index 58014f38..6095ccea 100644 --- a/src/commands/serverCommand.ts +++ b/src/commands/serverCommand.ts @@ -521,7 +521,7 @@ export function rerunQuery(rerunQueryElement: QueryHistory) { ); } else { const dsFile = rerunQueryElement.query as DataSourceFiles; - runDataSource(dsFile); + runDataSource(dsFile, rerunQueryElement.connectionName); } } diff --git a/src/services/connectionManagerService.ts b/src/services/connectionManagerService.ts index a2c3aced..459de4a3 100644 --- a/src/services/connectionManagerService.ts +++ b/src/services/connectionManagerService.ts @@ -326,4 +326,15 @@ export class ConnectionManagementService { ); } } + + public async refreshGetMetas(): Promise { + if (ext.connectedConnectionList.length > 0) { + const promises = ext.connectedConnectionList.map(async (connection) => { + if (connection instanceof InsightsConnection) { + await connection.getMeta(); + } + }); + await Promise.all(promises); + } + } } diff --git a/src/services/dataSourceEditorProvider.ts b/src/services/dataSourceEditorProvider.ts index e7b23cb5..6912601f 100644 --- a/src/services/dataSourceEditorProvider.ts +++ b/src/services/dataSourceEditorProvider.ts @@ -26,9 +26,7 @@ import { } from "vscode"; import { getUri } from "../utils/getUri"; import { getNonce } from "../utils/getNonce"; -import { ext } from "../extensionVariables"; import { - activateConnectionForServer, getInsightsServers, getServerForUri, setServerForUri, @@ -41,6 +39,7 @@ import { } from "../commands/dataSourceCommand"; import { InsightsConnection } from "../classes/insightsConnection"; import { MetaObjectPayload } from "../models/meta"; +import { ConnectionManagementService } from "./connectionManagerService"; export class DataSourceEditorProvider implements CustomTextEditorProvider { static readonly viewType = "kdb.dataSourceEditor"; @@ -57,15 +56,39 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { constructor(private readonly context: ExtensionContext) {} - getMeta(alias: string) { - let meta = this.cache.get(alias); - if (!meta) { - if (ext.activeConnection instanceof InsightsConnection) { - if (ext.activeConnection.node.details.alias === alias) { - meta = ext.activeConnection.getMeta(); - this.cache.set(alias, meta); - } + getMeta(connLabel: string) { + let meta = this.cache.get(connLabel); + const connMngService = new ConnectionManagementService(); + const isConnected = connMngService.isConnected(connLabel); + if (!isConnected) { + this.cache.set(connLabel, Promise.resolve({})); + return Promise.resolve({}); + } + const selectedConnection = + connMngService.retrieveConnectedConnection(connLabel); + if ( + selectedConnection && + !(selectedConnection instanceof InsightsConnection) + ) { + window.showErrorMessage("The connection selected is not Insights"); + //TODO ADD ERROR TO CONSOLE HERE + this.cache.set(connLabel, Promise.resolve({})); + return Promise.resolve({}); + } + try { + if (selectedConnection?.meta?.payload.assembly.length === 0) { + throw new Error(); } + meta = Promise.resolve(selectedConnection?.meta?.payload); + + this.cache.set(connLabel, meta); + } catch (error) { + window.showErrorMessage( + "No database running in this Insights connection.", + ); + meta = Promise.resolve({}); + this.cache.set(connLabel, meta); + //TODO ADD ERROR TO CONSOLE HERE } return meta || Promise.resolve({}); } @@ -129,18 +152,17 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { ); break; case DataSourceCommand.Refresh: - await activateConnectionForServer(msg.selectedServer); + const connMngService = new ConnectionManagementService(); + await connMngService.refreshGetMetas(); const selectedServer = getServerForUri(document.uri) || ""; this.cache.delete(selectedServer); updateWebview(); break; case DataSourceCommand.Run: - await activateConnectionForServer(msg.selectedServer); - await runDataSource(msg.dataSourceFile); + await runDataSource(msg.dataSourceFile, msg.selectedServer); break; case DataSourceCommand.Populate: - await activateConnectionForServer(msg.selectedServer); - await populateScratchpad(msg.dataSourceFile); + await populateScratchpad(msg.dataSourceFile, msg.selectedServer); break; } }); diff --git a/test/suite/commands.test.ts b/test/suite/commands.test.ts index 42c0e220..28d2559a 100644 --- a/test/suite/commands.test.ts +++ b/test/suite/commands.test.ts @@ -74,167 +74,6 @@ describe("dataSourceCommand", () => { await assert.doesNotReject(dataSourceCommand.addDataSource()); }); - - it("should rename a data source", async () => { - mock({ - "/temp": { - ".kdb-datasources": { - "datasource-0.ds": '{"name": "datasource-0"}', - }, - }, - }); - - ext.context = {} as vscode.ExtensionContext; - sinon.stub(ext, "context").value({ - globalStorageUri: { - fsPath: "/temp/", - }, - }); - - await assert.doesNotReject( - dataSourceCommand.renameDataSource("datasource-0", "datasource-1"), - ); - }); - - it("should save a data source", async () => { - mock({ - "/temp": { - ".kdb-datasources": { - "datasource-0.ds": '{"name": "datasource-0"}', - }, - }, - }); - - ext.context = {} as vscode.ExtensionContext; - sinon.stub(ext, "context").value({ - globalStorageUri: { - fsPath: "/temp/", - }, - }); - - const ds = createDefaultDataSourceFile(); - ds.name = "datasource-0"; - - await assert.doesNotReject(dataSourceCommand.saveDataSource(ds)); - }); - - it("should save a data source with a different name", async () => { - mock({ - "/temp": { - ".kdb-datasources": { - "datasource-0.ds": '{"name": "datasource-0"}', - }, - }, - }); - - ext.context = {} as vscode.ExtensionContext; - sinon.stub(ext, "context").value({ - globalStorageUri: { - fsPath: "/temp/", - }, - }); - - const ds = createDefaultDataSourceFile(); - ds.name = "datasource-1"; - ds.originalName = "datasource-0"; - - await assert.doesNotReject(dataSourceCommand.saveDataSource(ds)); - }); - - it("should delete a data source", async () => { - mock({ - "/temp": { - ".kdb-datasources": { - "datasource-0.ds": '{"name": "datasource-0"}', - }, - }, - }); - - ext.context = {} as vscode.ExtensionContext; - sinon.stub(ext, "context").value({ - globalStorageUri: { - fsPath: "/temp/", - }, - }); - - const item = new KdbDataSourceTreeItem( - "datasource-0", - vscode.TreeItemCollapsibleState.Collapsed, - [], - ); - - await assert.doesNotReject(dataSourceCommand.deleteDataSource(item)); - }); - - it("should open a data source", async () => { - mock({ - "/temp": { - ".kdb-datasources": { - "datasource-0.ds": '{"name": "datasource-0"}', - }, - }, - }); - - ext.context = {} as vscode.ExtensionContext; - sinon.stub(ext, "context").value({ - globalStorageUri: { - fsPath: "/temp/", - }, - }); - - const item = new KdbDataSourceTreeItem( - "datasource-0", - vscode.TreeItemCollapsibleState.Collapsed, - [], - ); - - const uri = vscode.Uri.file("/temp/.kdb-datasources/datasource-0.ds"); - - await assert.doesNotReject(dataSourceCommand.openDataSource(item, uri)); - }); - - it("should open datasource", async () => { - const insightsNode = new InsightsNode( - [], - "insightsnode1", - { - server: "https://insightsservername.com/", - alias: "insightsserveralias", - auth: true, - }, - TreeItemCollapsibleState.None, - ); - - ext.activeConnection = new InsightsConnection( - insightsNode.label, - insightsNode, - ); - - mock({ - "/temp": { - ".kdb-datasources": { - "datasource-0.ds": '{"name": "datasource-0"}', - }, - }, - }); - - ext.context = {} as vscode.ExtensionContext; - sinon.stub(ext, "context").value({ - globalStorageUri: { - fsPath: "/temp/", - }, - }); - - const item = new KdbDataSourceTreeItem( - "datasource-0", - vscode.TreeItemCollapsibleState.Collapsed, - [], - ); - - const uri = vscode.Uri.file("/temp/.kdb-datasources/datasource-0.ds"); - - await assert.doesNotReject(dataSourceCommand.openDataSource(item, uri)); - }); }); describe("dataSourceCommand2", () => { From 51880df1ff90550f8b1c49a4d6447c02d204f246 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 10:08:29 +0100 Subject: [PATCH 07/15] fix ds and workbook icons --- src/commands/dataSourceCommand.ts | 27 ++++------------ src/commands/serverCommand.ts | 6 +++- src/services/dataSourceEditorProvider.ts | 8 ++++- src/services/workspaceTreeProvider.ts | 4 +-- src/utils/core.ts | 39 ++++++++---------------- 5 files changed, 32 insertions(+), 52 deletions(-) diff --git a/src/commands/dataSourceCommand.ts b/src/commands/dataSourceCommand.ts index 4cad27e7..fabc0ab9 100644 --- a/src/commands/dataSourceCommand.ts +++ b/src/commands/dataSourceCommand.ts @@ -111,12 +111,12 @@ export async function populateScratchpad( export async function runDataSource( dataSourceForm: DataSourceFiles, connLabel: string, + executorName: string, ): Promise { if (DataSourcesPanel.running) { return; } DataSourcesPanel.running = true; - const executorName = ext.activeTextEditor?.document.fileName.split("/").pop(); const connMngService = new ConnectionManagementService(); const selectedConnection = connMngService.retrieveConnectedConnection(connLabel); @@ -165,27 +165,17 @@ export async function runDataSource( ext.isDatasourceExecution = false; if (res.error) { window.showErrorMessage(res.error); - addDStoQueryHistory( - dataSourceForm, - false, - connLabel, - executorName ? executorName : "", - ); + addDStoQueryHistory(dataSourceForm, false, connLabel, executorName); } else if (ext.resultsViewProvider.isVisible()) { ext.outputChannel.appendLine( `Results: ${typeof res === "string" ? "0" : res.rows.length} rows`, ); - addDStoQueryHistory( - dataSourceForm, - true, - connLabel, - executorName ? executorName : "", - ); + addDStoQueryHistory(dataSourceForm, true, connLabel, executorName); writeQueryResultsToView( res, getQuery(fileContent, selectedType), connLabel, - executorName ? executorName : "", + executorName, true, selectedType, ); @@ -193,17 +183,12 @@ export async function runDataSource( ext.outputChannel.appendLine( `Results is a string with length: ${res.length}`, ); - addDStoQueryHistory( - dataSourceForm, - true, - connLabel, - executorName ? executorName : "", - ); + addDStoQueryHistory(dataSourceForm, true, connLabel, executorName); writeQueryResultsToConsole( res, getQuery(fileContent, selectedType), connLabel, - executorName ? executorName : "", + executorName, true, selectedType, ); diff --git a/src/commands/serverCommand.ts b/src/commands/serverCommand.ts index 6095ccea..7d73a969 100644 --- a/src/commands/serverCommand.ts +++ b/src/commands/serverCommand.ts @@ -521,7 +521,11 @@ export function rerunQuery(rerunQueryElement: QueryHistory) { ); } else { const dsFile = rerunQueryElement.query as DataSourceFiles; - runDataSource(dsFile, rerunQueryElement.connectionName); + runDataSource( + dsFile, + rerunQueryElement.connectionName, + rerunQueryElement.executorName, + ); } } diff --git a/src/services/dataSourceEditorProvider.ts b/src/services/dataSourceEditorProvider.ts index 6912601f..a51269ec 100644 --- a/src/services/dataSourceEditorProvider.ts +++ b/src/services/dataSourceEditorProvider.ts @@ -42,6 +42,7 @@ import { MetaObjectPayload } from "../models/meta"; import { ConnectionManagementService } from "./connectionManagerService"; export class DataSourceEditorProvider implements CustomTextEditorProvider { + public filenname = ""; static readonly viewType = "kdb.dataSourceEditor"; public static register(context: ExtensionContext): Disposable { @@ -97,6 +98,7 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { document: TextDocument, webviewPanel: WebviewPanel, ): Promise { + this.filenname = document.fileName.split("/").pop() || ""; const webview = webviewPanel.webview; webview.options = { enableScripts: true }; webview.html = this.getWebviewContent(webview); @@ -159,7 +161,11 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { updateWebview(); break; case DataSourceCommand.Run: - await runDataSource(msg.dataSourceFile, msg.selectedServer); + await runDataSource( + msg.dataSourceFile, + msg.selectedServer, + this.filenname, + ); break; case DataSourceCommand.Populate: await populateScratchpad(msg.dataSourceFile, msg.selectedServer); diff --git a/src/services/workspaceTreeProvider.ts b/src/services/workspaceTreeProvider.ts index 46e18f32..422b6726 100644 --- a/src/services/workspaceTreeProvider.ts +++ b/src/services/workspaceTreeProvider.ts @@ -22,7 +22,7 @@ import { workspace, } from "vscode"; import Path from "path"; -import { getServerIconState } from "../utils/core"; +import { getWorkspaceIconsState } from "../utils/core"; import { getConnectionForUri } from "../commands/workspaceCommand"; import { ext } from "../extensionVariables"; @@ -92,7 +92,7 @@ export class FileTreeItem extends TreeItem { if (this.resourceUri) { const connection = getConnectionForUri(this.resourceUri); if (connection) { - state = getServerIconState(connection.label); + state = getWorkspaceIconsState(connection.label); } } this.iconPath = Path.join( diff --git a/src/utils/core.ts b/src/utils/core.ts index c3b08b94..80248166 100644 --- a/src/utils/core.ts +++ b/src/utils/core.ts @@ -256,17 +256,26 @@ export function getInsightsAlias(insightsList: InsightDetails[]): void { }); } -export function getServerIconState(label: string): string { - if (ext.activeConnection?.connLabel === label) { +export function getServerIconState(connLabel: string): string { + if (ext.activeConnection?.connLabel === connLabel) { return "-active"; } else if ( - ext.connectedConnectionList?.some((conn) => conn.connLabel === label) + ext.connectedConnectionList?.some((conn) => conn.connLabel === connLabel) ) { return "-connected"; } return ""; } +export function getWorkspaceIconsState(connLabel: string): string { + if ( + ext.connectedConnectionList?.some((conn) => conn.connLabel === connLabel) + ) { + return "-active"; + } + return ""; +} + export function getStatus(label: string): string { if (ext.activeConnection?.connLabel === label) { return "- active"; @@ -282,30 +291,6 @@ export function delay(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } -export function getScratchpadStatusIcon(label: string) { - if ( - ext.activeScratchPadList?.some((scratchpad) => scratchpad.name === label) - ) { - return "-active"; - } else if ( - ext.connectedScratchPadList?.some((scratchpad) => scratchpad.name === label) - ) { - return "-connected"; - } else { - return ""; - } -} - -export function getDatasourceStatusIcon(label: string) { - if (ext.activeDatasourceList?.some((ds) => ds.name === label)) { - return "-active"; - } else if (ext.connectedDatasourceList?.some((ds) => ds.name === label)) { - return "-connected"; - } else { - return ""; - } -} - export async function checkLocalInstall(): Promise { const QHOME = workspace.getConfiguration().get("kdb.qHomeDirectory"); if (QHOME || env.QHOME) { From 92695c3ed6d272b3bc1ed21355b858ccfe375a40 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 10:34:01 +0100 Subject: [PATCH 08/15] optimize the code --- src/commands/dataSourceCommand.ts | 18 +++++++++--------- src/services/dataSourceEditorProvider.ts | 21 +++++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/commands/dataSourceCommand.ts b/src/commands/dataSourceCommand.ts index fabc0ab9..f106c0c5 100644 --- a/src/commands/dataSourceCommand.ts +++ b/src/commands/dataSourceCommand.ts @@ -121,15 +121,11 @@ export async function runDataSource( const selectedConnection = connMngService.retrieveConnectedConnection(connLabel); - if (selectedConnection && selectedConnection instanceof LocalConnection) { - window.showErrorMessage("No Insights active connection found"); - DataSourcesPanel.running = false; - //TODO ADD ERROR TO CONSOLE HERE - return; - } - try { - selectedConnection?.getMeta(); + if (selectedConnection instanceof LocalConnection || !selectedConnection) { + throw new Error("No Insights active connection found"); + } + selectedConnection.getMeta(); if (!selectedConnection?.meta?.payload.assembly) { ext.outputChannel.appendLine( `To run a datasource you need to be connected to an Insights server`, @@ -137,7 +133,7 @@ export async function runDataSource( window.showErrorMessage( "To run a datasource you need to be connected to an Insights server", ); - //TODO ADD ERROR TO CONSOLE HERE + return; } @@ -193,6 +189,10 @@ export async function runDataSource( selectedType, ); } + } catch (error) { + window.showErrorMessage((error as Error).message); + DataSourcesPanel.running = false; + //TODO ADD ERROR TO CONSOLE HERE } finally { DataSourcesPanel.running = false; } diff --git a/src/services/dataSourceEditorProvider.ts b/src/services/dataSourceEditorProvider.ts index a51269ec..15f49f67 100644 --- a/src/services/dataSourceEditorProvider.ts +++ b/src/services/dataSourceEditorProvider.ts @@ -67,17 +67,18 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { } const selectedConnection = connMngService.retrieveConnectedConnection(connLabel); - if ( - selectedConnection && - !(selectedConnection instanceof InsightsConnection) - ) { - window.showErrorMessage("The connection selected is not Insights"); - //TODO ADD ERROR TO CONSOLE HERE - this.cache.set(connLabel, Promise.resolve({})); - return Promise.resolve({}); - } + try { - if (selectedConnection?.meta?.payload.assembly.length === 0) { + if ( + !(selectedConnection instanceof InsightsConnection) || + !selectedConnection + ) { + throw new Error("The connection selected is not Insights"); + } + if ( + !selectedConnection.meta || + selectedConnection.meta.payload.assembly.length === 0 + ) { throw new Error(); } meta = Promise.resolve(selectedConnection?.meta?.payload); From 8c91c4a786041768adfc4ac088b9ee61d8c711fc Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 12:20:20 +0100 Subject: [PATCH 09/15] fix tests --- src/commands/dataSourceCommand.ts | 9 +- src/services/connectionManagerService.ts | 1 - test/suite/commands.test.ts | 484 +++++++++++------------ test/suite/panels.test.ts | 4 +- test/suite/services.test.ts | 8 +- test/suite/utils.test.ts | 149 +++---- 6 files changed, 299 insertions(+), 356 deletions(-) diff --git a/src/commands/dataSourceCommand.ts b/src/commands/dataSourceCommand.ts index f106c0c5..9c08bd6d 100644 --- a/src/commands/dataSourceCommand.ts +++ b/src/commands/dataSourceCommand.ts @@ -127,14 +127,7 @@ export async function runDataSource( } selectedConnection.getMeta(); if (!selectedConnection?.meta?.payload.assembly) { - ext.outputChannel.appendLine( - `To run a datasource you need to be connected to an Insights server`, - ); - window.showErrorMessage( - "To run a datasource you need to be connected to an Insights server", - ); - - return; + throw new Error("No database running in the Insights connection"); } dataSourceForm.insightsNode = getConnectedInsightsNode(); diff --git a/src/services/connectionManagerService.ts b/src/services/connectionManagerService.ts index 459de4a3..6bdd05e9 100644 --- a/src/services/connectionManagerService.ts +++ b/src/services/connectionManagerService.ts @@ -12,7 +12,6 @@ */ import { LocalConnection } from "../classes/localConnection"; -import * as os from "os"; import { window, commands } from "vscode"; import { ext } from "../extensionVariables"; import { InsightsNode, KdbNode } from "./kdbTreeProvider"; diff --git a/test/suite/commands.test.ts b/test/suite/commands.test.ts index 28d2559a..c14cc1bf 100644 --- a/test/suite/commands.test.ts +++ b/test/suite/commands.test.ts @@ -30,7 +30,6 @@ import { import { ExecutionTypes } from "../../src/models/execution"; import { InsightDetails } from "../../src/models/insights"; import { ScratchpadResult } from "../../src/models/scratchpadResult"; -import { KdbDataSourceTreeItem } from "../../src/services/dataSourceTreeProvider"; import { InsightsNode, KdbNode, @@ -49,6 +48,7 @@ import { LocalConnection } from "../../src/classes/localConnection"; import { ConnectionManagementService } from "../../src/services/connectionManagerService"; import { InsightsConnection } from "../../src/classes/insightsConnection"; import * as workspaceCommand from "../../src/commands/workspaceCommand"; +import { MetaObject } from "../../src/models/meta"; describe("dataSourceCommand", () => { afterEach(() => { @@ -79,6 +79,17 @@ describe("dataSourceCommand", () => { describe("dataSourceCommand2", () => { let dummyDataSourceFiles: DataSourceFiles; const localConn = new LocalConnection("localhost:5001", "test"); + const insightsNode = new InsightsNode( + [], + "insightsnode1", + { + server: "https://insightsservername.com/", + alias: "insightsserveralias", + auth: true, + }, + TreeItemCollapsibleState.None, + ); + const insightsConn = new InsightsConnection(insightsNode.label, insightsNode); const uriTest: vscode.Uri = vscode.Uri.parse("test"); let resultsPanel: KdbResultsViewProvider; ext.outputChannel = vscode.window.createOutputChannel("kdb"); @@ -324,29 +335,15 @@ describe("dataSourceCommand2", () => { let getDataInsightsStub: sinon.SinonStub; let handleWSResultsStub: sinon.SinonStub; let handleScratchpadTableRes: sinon.SinonStub; - const insightsNode = new InsightsNode( - [], - "insightsnode1", - { - server: "https://insightsservername.com/", - alias: "insightsserveralias", - auth: true, - }, - TreeItemCollapsibleState.None, - ); beforeEach(() => { windowMock = sinon.mock(vscode.window); - ext.activeConnection = new InsightsConnection( - insightsNode.label, - insightsNode, - ); getApiBodyStub = sinon.stub(dataSourceCommand, "getApiBody"); checkIfTimeParamIsCorrectStub = sinon.stub( dataSourceUtils, "checkIfTimeParamIsCorrect", ); - getDataInsightsStub = sinon.stub(ext.activeConnection, "getDataInsights"); + getDataInsightsStub = sinon.stub(insightsConn, "getDataInsights"); handleWSResultsStub = sinon.stub(queryUtils, "handleWSResults"); handleScratchpadTableRes = sinon.stub( queryUtils, @@ -359,35 +356,14 @@ describe("dataSourceCommand2", () => { sinon.restore(); }); - it("should show an error message if not active connection is undefined", async () => { - ext.activeConnection = undefined; - await dataSourceCommand.runApiDataSource(dummyDataSourceFiles); - windowMock - .expects("showErrorMessage") - .once() - .withArgs("No Insights active connection found"); - sinon.assert.notCalled(getApiBodyStub); - sinon.assert.notCalled(getDataInsightsStub); - sinon.assert.notCalled(handleWSResultsStub); - }); - - it("should show an error message if not active to an Insights server", async () => { - ext.activeConnection = localConn; - await dataSourceCommand.runApiDataSource(dummyDataSourceFiles); - windowMock - .expects("showErrorMessage") - .once() - .withArgs("No Insights active connection found"); - sinon.assert.notCalled(getApiBodyStub); - sinon.assert.notCalled(getDataInsightsStub); - sinon.assert.notCalled(handleWSResultsStub); - }); - it("should show an error message if the time parameters are incorrect", async () => { const windowMock = sinon.mock(vscode.window); checkIfTimeParamIsCorrectStub.returns(false); - await dataSourceCommand.runApiDataSource(dummyDataSourceFiles); + await dataSourceCommand.runApiDataSource( + dummyDataSourceFiles, + insightsConn, + ); windowMock .expects("showErrorMessage") .once() @@ -414,8 +390,10 @@ describe("dataSourceCommand2", () => { { a: "6", b: "9" }, ]); - const result = - await dataSourceCommand.runApiDataSource(dummyDataSourceFiles); + const result = await dataSourceCommand.runApiDataSource( + dummyDataSourceFiles, + insightsConn, + ); sinon.assert.calledOnce(getDataInsightsStub); sinon.assert.calledOnce(handleWSResultsStub); @@ -432,24 +410,10 @@ describe("dataSourceCommand2", () => { let getDataInsightsStub: sinon.SinonStub; let handleWSResultsStub: sinon.SinonStub; let handleScratchpadTableRes: sinon.SinonStub; - const insightsNode = new InsightsNode( - [], - "insightsnode1", - { - server: "https://insightsservername.com/", - alias: "insightsserveralias", - auth: true, - }, - TreeItemCollapsibleState.None, - ); beforeEach(() => { windowMock = sinon.mock(vscode.window); - ext.activeConnection = new InsightsConnection( - insightsNode.label, - insightsNode, - ); - getDataInsightsStub = sinon.stub(ext.activeConnection, "getDataInsights"); + getDataInsightsStub = sinon.stub(insightsConn, "getDataInsights"); handleWSResultsStub = sinon.stub(queryUtils, "handleWSResults"); handleScratchpadTableRes = sinon.stub( queryUtils, @@ -458,28 +422,9 @@ describe("dataSourceCommand2", () => { }); afterEach(() => { - ext.activeConnection = undefined; sinon.restore(); }); - it("should show an error message if active connection is undefined", async () => { - ext.activeConnection = undefined; - await dataSourceCommand.runQsqlDataSource(dummyDataSourceFiles); - windowMock - .expects("showErrorMessage") - .once() - .withArgs("No Insights active connection found"); - }); - - it("should show an error message if not active to an Insights server", async () => { - ext.activeConnection = localConn; - await dataSourceCommand.runQsqlDataSource(dummyDataSourceFiles); - windowMock - .expects("showErrorMessage") - .once() - .withArgs("No Insights active connection found"); - }); - it("should call the API and handle the results", async () => { getDataInsightsStub.resolves({ arrayBuffer: true }); handleWSResultsStub.resolves([ @@ -493,8 +438,10 @@ describe("dataSourceCommand2", () => { { a: "6", b: "9" }, ]); - const result = - await dataSourceCommand.runQsqlDataSource(dummyDataSourceFiles); + const result = await dataSourceCommand.runQsqlDataSource( + dummyDataSourceFiles, + insightsConn, + ); sinon.assert.calledOnce(getDataInsightsStub); sinon.assert.calledOnce(handleWSResultsStub); @@ -511,24 +458,10 @@ describe("dataSourceCommand2", () => { let getDataInsightsStub: sinon.SinonStub; let handleWSResultsStub: sinon.SinonStub; let handleScratchpadTableRes: sinon.SinonStub; - const insightsNode = new InsightsNode( - [], - "insightsnode1", - { - server: "https://insightsservername.com/", - alias: "insightsserveralias", - auth: true, - }, - TreeItemCollapsibleState.None, - ); beforeEach(() => { windowMock = sinon.mock(vscode.window); - ext.activeConnection = new InsightsConnection( - insightsNode.label, - insightsNode, - ); - getDataInsightsStub = sinon.stub(ext.activeConnection, "getDataInsights"); + getDataInsightsStub = sinon.stub(insightsConn, "getDataInsights"); handleWSResultsStub = sinon.stub(queryUtils, "handleWSResults"); handleScratchpadTableRes = sinon.stub( queryUtils, @@ -537,28 +470,9 @@ describe("dataSourceCommand2", () => { }); afterEach(() => { - ext.activeConnection = undefined; sinon.restore(); }); - it("should show an error message if active connection is undefined", async () => { - ext.activeConnection = undefined; - await dataSourceCommand.runSqlDataSource(dummyDataSourceFiles); - windowMock - .expects("showErrorMessage") - .once() - .withArgs("No Insights active connection found"); - }); - - it("should show an error message if not active to an Insights server", async () => { - ext.activeConnection = localConn; - await dataSourceCommand.runSqlDataSource(dummyDataSourceFiles); - windowMock - .expects("showErrorMessage") - .once() - .withArgs("No Insights active connection found"); - }); - it("should call the API and handle the results", async () => { getDataInsightsStub.resolves({ arrayBuffer: true }); handleWSResultsStub.resolves([ @@ -572,8 +486,10 @@ describe("dataSourceCommand2", () => { { a: "6", b: "9" }, ]); - const result = - await dataSourceCommand.runSqlDataSource(dummyDataSourceFiles); + const result = await dataSourceCommand.runSqlDataSource( + dummyDataSourceFiles, + insightsConn, + ); sinon.assert.calledOnce(getDataInsightsStub); sinon.assert.calledOnce(handleWSResultsStub); @@ -586,107 +502,61 @@ describe("dataSourceCommand2", () => { }); describe("runDataSource", () => { - const dummyMeta = { - rc: [ - { - api: 3, - agg: 1, - assembly: 1, - schema: 1, - rc: "dummy-rc", - labels: [{ kxname: "dummy-assembly" }], - started: "2023-10-04T17:20:57.659088747", - }, - ], - dap: [ - { - assembly: "dummy-assembly", - instance: "idb", - startTS: "2023-10-25T01:40:03.000000000", - endTS: "2023-10-25T14:00:03.000000000", - }, - ], - api: [ - { - api: ".kxi.getData", - kxname: ["dummy-assembly"], - aggFn: ".sgagg.getData", - custom: false, - full: true, - metadata: { - description: "dummy desc.", - params: [ - { - name: "table", - type: -11, - isReq: true, - description: "dummy desc.", - }, - ], - return: { - type: 0, - description: "dummy desc.", - }, - misc: { safe: true }, - aggReturn: { - type: 98, + const dummyMeta: MetaObject = { + header: { + ac: "0", + agg: ":127.0.0.1:5070", + ai: "", + api: ".kxi.getMeta", + client: ":127.0.0.1:5050", + corr: "CorrHash", + http: "json", + logCorr: "logCorrHash", + protocol: "gw", + rc: "0", + rcvTS: "2099-05-22T11:06:33.650000000", + retryCount: "0", + to: "2099-05-22T11:07:33.650000000", + userID: "dummyID", + userName: "testUser", + }, + payload: { + rc: [ + { + api: 3, + agg: 1, + assembly: 1, + schema: 1, + rc: "dummy-rc", + labels: [{ kxname: "dummy-assembly" }], + started: "2023-10-04T17:20:57.659088747", + }, + ], + dap: [], + api: [], + agg: [ + { + aggFn: ".sgagg.aggFnDflt", + custom: false, + full: true, + metadata: { description: "dummy desc.", + params: [{ description: "dummy desc." }], + return: { description: "dummy desc." }, + misc: {}, }, + procs: [], }, - procs: [], - }, - ], - agg: [ - { - aggFn: ".sgagg.aggFnDflt", - custom: false, - full: true, - metadata: { - description: "dummy desc.", - params: [{ description: "dummy desc." }], - return: { description: "dummy desc." }, - misc: {}, + ], + assembly: [ + { + assembly: "dummy-assembly", + kxname: "dummy-assembly", + tbls: ["dummyTbl"], }, - procs: [], - }, - ], - assembly: [ - { - assembly: "dummy-assembly", - kxname: "dummy-assembly", - tbls: ["dummyTbl"], - }, - ], - schema: [ - { - table: "dummyTbl", - assembly: ["dummy-assembly"], - typ: "partitioned", - pkCols: [], - prtnCol: "srcTime", - sortColsMem: [], - sortColsIDisk: [], - sortColsDisk: [], - isSplayed: true, - isPartitioned: true, - isSharded: false, - columns: [ - { - column: "sym", - typ: 10, - description: "dummy desc.", - oldName: "", - attrMem: "", - attrIDisk: "", - attrDisk: "", - isSerialized: false, - foreign: "", - anymap: false, - backfill: "", - }, - ], - }, - ], + ], + schema: [], + }, }; const dummyFileContent: DataSourceFiles = { name: "dummy-DS", @@ -715,6 +585,7 @@ describe("dataSourceCommand2", () => { }, insightsNode: "dummyNode", }; + const connMngService = new ConnectionManagementService(); const uriTest: vscode.Uri = vscode.Uri.parse("test"); const ab = new ArrayBuffer(26); ext.resultsViewProvider = new KdbResultsViewProvider(uriTest); @@ -722,30 +593,21 @@ describe("dataSourceCommand2", () => { getMetaStub, handleWSResultsStub, handleScratchpadTableRes, + retrieveConnStub, getDataInsightsStub, writeQueryResultsToViewStub, writeQueryResultsToConsoleStub: sinon.SinonStub; let windowMock: sinon.SinonMock; - const insightsNode = new InsightsNode( - [], - "insightsnode1", - { - server: "https://insightsservername.com/", - alias: "insightsserveralias", - auth: true, - }, - TreeItemCollapsibleState.None, - ); ext.outputChannel = vscode.window.createOutputChannel("kdb"); beforeEach(() => { - windowMock = sinon.mock(vscode.window); - ext.activeConnection = new InsightsConnection( - insightsNode.label, - insightsNode, + retrieveConnStub = sinon.stub( + connMngService, + "retrieveConnectedConnection", ); - getMetaStub = sinon.stub(ext.activeConnection, "getMeta"); + windowMock = sinon.mock(vscode.window); + getMetaStub = sinon.stub(insightsConn, "getMeta"); isVisibleStub = sinon.stub(ext.resultsViewProvider, "isVisible"); handleWSResultsStub = sinon .stub(queryUtils, "handleWSResults") @@ -753,7 +615,7 @@ describe("dataSourceCommand2", () => { handleScratchpadTableRes = sinon .stub(queryUtils, "handleScratchpadTableRes") .returns("dummy results"); - getDataInsightsStub = sinon.stub(ext.activeConnection, "getDataInsights"); + getDataInsightsStub = sinon.stub(insightsConn, "getDataInsights"); writeQueryResultsToViewStub = sinon.stub( serverCommand, "writeQueryResultsToView", @@ -765,14 +627,17 @@ describe("dataSourceCommand2", () => { }); afterEach(() => { - ext.activeConnection = undefined; sinon.restore(); }); it("should show an error message if not connected to an Insights server", async () => { ext.activeConnection = undefined; getMetaStub.resolves({}); - await dataSourceCommand.runDataSource({} as DataSourceFiles); + await dataSourceCommand.runDataSource( + {} as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", + ); windowMock .expects("showErrorMessage") .once() @@ -782,7 +647,11 @@ describe("dataSourceCommand2", () => { it("should show an error message if not active to an Insights server", async () => { ext.activeConnection = localConn; getMetaStub.resolves({}); - await dataSourceCommand.runDataSource({} as DataSourceFiles); + await dataSourceCommand.runDataSource( + {} as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", + ); windowMock .expects("showErrorMessage") .once() @@ -790,38 +659,59 @@ describe("dataSourceCommand2", () => { }); it("should return QSQL results", async () => { + ext.connectedConnectionList.push(insightsConn); + retrieveConnStub.resolves(insightsConn); + insightsConn.meta = dummyMeta; getMetaStub.resolves(dummyMeta); getDataInsightsStub.resolves({ arrayBuffer: ab, error: "" }); isVisibleStub.returns(true); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToConsoleStub); sinon.assert.calledOnce(writeQueryResultsToViewStub); + + ext.connectedConnectionList.length = 0; }); it("should return API results", async () => { + ext.connectedConnectionList.push(insightsConn); + retrieveConnStub.resolves(insightsConn); + insightsConn.meta = dummyMeta; dummyFileContent.dataSource.selectedType = DataSourceTypes.API; getMetaStub.resolves(dummyMeta); getDataInsightsStub.resolves({ arrayBuffer: ab, error: "" }); isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.calledOnce(writeQueryResultsToConsoleStub); + + ext.connectedConnectionList.length = 0; }); it("should return SQL results", async () => { + ext.connectedConnectionList.push(insightsConn); + retrieveConnStub.resolves(insightsConn); + insightsConn.meta = dummyMeta; dummyFileContent.dataSource.selectedType = DataSourceTypes.SQL; getMetaStub.resolves(dummyMeta); getDataInsightsStub.resolves({ arrayBuffer: ab, error: "" }); isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.calledOnce(writeQueryResultsToConsoleStub); + + ext.connectedConnectionList.length = 0; }); it("should return error message QSQL", async () => { @@ -831,6 +721,8 @@ describe("dataSourceCommand2", () => { isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.neverCalledWith(writeQueryResultsToConsoleStub); @@ -843,6 +735,8 @@ describe("dataSourceCommand2", () => { isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.neverCalledWith(writeQueryResultsToConsoleStub); @@ -855,6 +749,8 @@ describe("dataSourceCommand2", () => { isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.neverCalledWith(writeQueryResultsToConsoleStub); @@ -867,6 +763,8 @@ describe("dataSourceCommand2", () => { isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.neverCalledWith(writeQueryResultsToConsoleStub); @@ -879,6 +777,8 @@ describe("dataSourceCommand2", () => { isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.neverCalledWith(writeQueryResultsToConsoleStub); @@ -891,6 +791,8 @@ describe("dataSourceCommand2", () => { isVisibleStub.returns(false); await dataSourceCommand.runDataSource( dummyFileContent as DataSourceFiles, + insightsConn.connLabel, + "test-file.kdb.json", ); sinon.assert.neverCalledWith(writeQueryResultsToViewStub); sinon.assert.neverCalledWith(writeQueryResultsToConsoleStub); @@ -935,8 +837,10 @@ describe("dataSourceCommand2", () => { sinon.restore(); }); it("should show error msg", async () => { - ext.activeConnection = localConn; - await dataSourceCommand.populateScratchpad(dummyFileContent); + await dataSourceCommand.populateScratchpad( + dummyFileContent, + localConn.connLabel, + ); windowMock .expects("showErrorMessage") .once() @@ -1159,13 +1063,23 @@ describe("serverCommand", () => { const result = { data: [1, 2, 3] }; const executeCommandStub = sinon.stub(vscode.commands, "executeCommand"); - serverCommand.writeQueryResultsToView(result, ""); + serverCommand.writeQueryResultsToView( + result, + "", + "testConn", + "testFile.kdb.q", + false, + "WORKBOOK", + false, + "2", + ); sinon.assert.calledWith( executeCommandStub.firstCall, "kdb.resultsPanel.update", result, - undefined, + false, + "WORKBOOK", ); executeCommandStub.restore(); @@ -1302,7 +1216,11 @@ describe("serverCommand", () => { serverCommand.writeScratchpadResult( scratchpadResult, "dummy query", - "123", + "connLabel", + "testFile.kdb.q", + false, + true, + "2", ); sinon.assert.notCalled(writeQueryResultsToViewStub); sinon.assert.notCalled(writeQueryResultsToConsoleStub); @@ -1314,7 +1232,11 @@ describe("serverCommand", () => { serverCommand.writeScratchpadResult( scratchpadResult, "dummy query", - "123", + "connLabel", + "testFile.kdb.py", + true, + true, + "2", ); sinon.assert.notCalled(writeQueryResultsToConsoleStub); sinon.assert.notCalled(queryConsoleErrorStub); @@ -1326,7 +1248,11 @@ describe("serverCommand", () => { serverCommand.writeScratchpadResult( scratchpadResult, "dummy query", - "123", + "connLabel", + "testFile.kdb.py", + true, + true, + "2", ); sinon.assert.notCalled(writeQueryResultsToViewStub); }); @@ -1379,13 +1305,23 @@ describe("serverCommand", () => { it("runQuery with undefined editor ", () => { ext.activeTextEditor = undefined; - const result = serverCommand.runQuery(ExecutionTypes.PythonQueryFile); + const result = serverCommand.runQuery( + ExecutionTypes.PythonQueryFile, + "", + "", + false, + ); assert.equal(result, false); }); it("runQuery with QuerySelection", () => { ext.connectionNode = undefined; - const result = serverCommand.runQuery(ExecutionTypes.QuerySelection); + const result = serverCommand.runQuery( + ExecutionTypes.QuerySelection, + "", + "", + false, + ); assert.equal(result, undefined); }); @@ -1393,6 +1329,9 @@ describe("serverCommand", () => { ext.connectionNode = undefined; const result = serverCommand.runQuery( ExecutionTypes.PythonQuerySelection, + "", + "", + false, ); assert.equal(result, undefined); }); @@ -1401,13 +1340,21 @@ describe("serverCommand", () => { ext.connectionNode = insightsNode; const result = serverCommand.runQuery( ExecutionTypes.PythonQuerySelection, + "", + "", + false, ); assert.equal(result, undefined); }); it("runQuery with QueryFile", () => { ext.connectionNode = undefined; - const result = serverCommand.runQuery(ExecutionTypes.QueryFile); + const result = serverCommand.runQuery( + ExecutionTypes.QueryFile, + "", + "", + false, + ); assert.equal(result, undefined); }); @@ -1415,6 +1362,9 @@ describe("serverCommand", () => { ext.connectionNode = undefined; const result = serverCommand.runQuery( ExecutionTypes.ReRunQuery, + "", + "", + false, "rerun query", ); assert.equal(result, undefined); @@ -1422,13 +1372,23 @@ describe("serverCommand", () => { it("runQuery with PythonQueryFile", () => { ext.connectionNode = undefined; - const result = serverCommand.runQuery(ExecutionTypes.PythonQueryFile); + const result = serverCommand.runQuery( + ExecutionTypes.PythonQueryFile, + "", + "", + false, + ); assert.equal(result, undefined); }); it("runQuery with PythonQueryFile", () => { ext.connectionNode = insightsNode; - const result = serverCommand.runQuery(ExecutionTypes.PythonQueryFile); + const result = serverCommand.runQuery( + ExecutionTypes.PythonQueryFile, + "", + "", + false, + ); assert.equal(result, undefined); }); }); @@ -1470,7 +1430,14 @@ describe("serverCommand", () => { ext.connectionNode = kdbNode; isVisibleStub.returns(true); executeQueryStub.resolves({ data: "data" }); - serverCommand.executeQuery("SELECT * FROM table"); + serverCommand.executeQuery( + "SELECT * FROM table", + "testeConn", + "testFile.kdb.q", + ".", + true, + true, + ); sinon.assert.notCalled(writeResultsConsoleStub); sinon.assert.notCalled(writeScratchpadResultStub); }); @@ -1479,7 +1446,14 @@ describe("serverCommand", () => { ext.connectionNode = kdbNode; isVisibleStub.returns(false); executeQueryStub.resolves("dummy test"); - serverCommand.executeQuery("SELECT * FROM table"); + serverCommand.executeQuery( + "SELECT * FROM table", + "testeConn", + "testFile.kdb.q", + ".", + true, + true, + ); sinon.assert.notCalled(writeResultsViewStub); sinon.assert.notCalled(writeScratchpadResultStub); }); @@ -1488,14 +1462,28 @@ describe("serverCommand", () => { ext.connectionNode = insightsNode; isVisibleStub.returns(true); executeQueryStub.resolves("dummy test"); - serverCommand.executeQuery("SELECT * FROM table"); + serverCommand.executeQuery( + "SELECT * FROM table", + "testeConn", + "testFile.kdb.q", + ".", + true, + true, + ); sinon.assert.notCalled(writeResultsConsoleStub); }); it("should get error", async () => { ext.activeConnection = localConn; ext.connectionNode = kdbNode; - const res = await serverCommand.executeQuery(""); + const res = await serverCommand.executeQuery( + "", + "testeConn", + "testFile.kdb.q", + ".", + true, + true, + ); assert.equal(res, undefined); }); }); @@ -1538,6 +1526,7 @@ describe("serverCommand", () => { }); it("should execute query for non-datasource query", async function () { const rerunQueryElement: QueryHistory = { + executorName: "test", isDatasource: false, query: "SELECT * FROM table", language: "q", @@ -1554,6 +1543,7 @@ describe("serverCommand", () => { it("should run datasource for datasource query", async function () { const ds = createDefaultDataSourceFile(); const rerunQueryElement: QueryHistory = { + executorName: "test", isDatasource: true, datasourceType: DataSourceTypes.QSQL, query: ds, diff --git a/test/suite/panels.test.ts b/test/suite/panels.test.ts index 1d89a4a4..554ed111 100644 --- a/test/suite/panels.test.ts +++ b/test/suite/panels.test.ts @@ -226,7 +226,7 @@ describe("WebPanels", () => { const stub = sinon.stub(ext, "activeConnection"); stub.get(() => insightsConn); - const output = resultsPanel.convertToGrid(results); + const output = resultsPanel.convertToGrid(results, true); assert.equal(output, expectedOutput); // Restore the stub @@ -276,7 +276,7 @@ describe("WebPanels", () => { const stub = sinon.stub(ext, "activeConnection"); stub.get(() => insightsConn); - const output = resultsPanel.convertToGrid(results); + const output = resultsPanel.convertToGrid(results, true); assert.equal(output, expectedOutput); // Restore the stub diff --git a/test/suite/services.test.ts b/test/suite/services.test.ts index fe16c610..3ca7c3d7 100644 --- a/test/suite/services.test.ts +++ b/test/suite/services.test.ts @@ -609,6 +609,7 @@ describe("queryHistoryProvider", () => { const dummyDS = createDefaultDataSourceFile(); const dummyQueryHistory: QueryHistory[] = [ { + executorName: "testExecutorName", connectionName: "testConnectionName", time: "testTime", query: "testQuery", @@ -616,6 +617,7 @@ describe("queryHistoryProvider", () => { connectionType: ServerType.INSIGHTS, }, { + executorName: "testExecutorName2", connectionName: "testConnectionName2", time: "testTime2", query: "testQuery2", @@ -624,6 +626,7 @@ describe("queryHistoryProvider", () => { duration: "500", }, { + executorName: "testExecutorName3", connectionName: "testConnectionName3", time: "testTime3", query: dummyDS, @@ -754,7 +757,7 @@ describe("connectionManagerService", () => { ); const insightNode = new InsightsNode( ["child1"], - "testLabel", + "testInsightsAlias", insights["testInsight"], TreeItemCollapsibleState.None, ); @@ -906,6 +909,7 @@ describe("connectionManagerService", () => { ext.activeConnection = undefined; const result = await connectionManagerService.executeQuery( command, + "connTest", context, stringfy, ); @@ -917,6 +921,7 @@ describe("connectionManagerService", () => { executeQueryStub.returns("test results"); const result = await connectionManagerService.executeQuery( command, + undefined, context, stringfy, ); @@ -928,6 +933,7 @@ describe("connectionManagerService", () => { getScratchpadQueryStub.returns("test query"); const result = await connectionManagerService.executeQuery( command, + undefined, context, stringfy, ); diff --git a/test/suite/utils.test.ts b/test/suite/utils.test.ts index c41b4241..667c5711 100644 --- a/test/suite/utils.test.ts +++ b/test/suite/utils.test.ts @@ -14,7 +14,6 @@ import * as assert from "assert"; import * as sinon from "sinon"; import * as vscode from "vscode"; -import * as fs from "fs"; import mock from "mock-fs"; import { TreeItemCollapsibleState } from "vscode"; import { ext } from "../../src/extensionVariables"; @@ -48,10 +47,9 @@ import { DDateTimeClass, DTimestampClass, } from "../../src/ipc/cClasses"; -import { DataSourceFiles, DataSourceTypes } from "../../src/models/dataSource"; +import { DataSourceTypes } from "../../src/models/dataSource"; import { InsightDetails } from "../../src/models/insights"; import { LocalConnection } from "../../src/classes/localConnection"; -import { ScratchpadFile } from "../../src/models/scratchpad"; interface ITestItem extends vscode.QuickPickItem { id: number; @@ -179,91 +177,6 @@ describe("Utils", () => { }); }); - describe("getScratchpadStatusIcon", () => { - const scratchpadDummy: ScratchpadFile = { - name: "test", - code: "", - }; - beforeEach(() => { - ext.activeScratchPadList.length = 0; - ext.connectedScratchPadList.length = 0; - }); - afterEach(() => { - ext.activeScratchPadList.length = 0; - ext.connectedScratchPadList.length = 0; - }); - it("should return active if scratchpad label is on the active list", () => { - ext.activeScratchPadList.push(scratchpadDummy); - ext.connectedScratchPadList.push(scratchpadDummy); - const result = coreUtils.getScratchpadStatusIcon("test"); - assert.strictEqual(result, "-active"); - }); - it("should return connected if scratchpad label is on the connected list", () => { - ext.connectedScratchPadList.push(scratchpadDummy); - const result = coreUtils.getScratchpadStatusIcon("test"); - assert.strictEqual(result, "-connected"); - }); - - it("should return empty string if scratchpad label is not on the active or connected list", () => { - const result = coreUtils.getScratchpadStatusIcon("test"); - assert.strictEqual(result, ""); - }); - }); - - describe("getDatasourceStatusIcon", () => { - const dsFileDummy: DataSourceFiles = { - name: "test", - dataSource: { - selectedType: DataSourceTypes.API, - api: { - selectedApi: "", - table: "", - startTS: "", - endTS: "", - fill: "zero", - temporality: "snapshot", - filter: [], - groupBy: [], - agg: [], - sortCols: [], - slice: [], - labels: [], - }, - qsql: { - query: "", - selectedTarget: "", - }, - sql: { - query: "", - }, - }, - }; - beforeEach(() => { - ext.activeDatasourceList.length = 0; - ext.connectedDatasourceList.length = 0; - }); - afterEach(() => { - ext.activeDatasourceList.length = 0; - ext.connectedDatasourceList.length = 0; - }); - it("should return active if scratchpad label is on the active list", () => { - ext.activeDatasourceList.push(dsFileDummy); - ext.connectedDatasourceList.push(dsFileDummy); - const result = coreUtils.getDatasourceStatusIcon("test"); - assert.strictEqual(result, "-active"); - }); - it("should return connected if scratchpad label is on the connected list", () => { - ext.connectedDatasourceList.push(dsFileDummy); - const result = coreUtils.getDatasourceStatusIcon("test"); - assert.strictEqual(result, "-connected"); - }); - - it("should return empty string if scratchpad label is not on the active or connected list", () => { - const result = coreUtils.getDatasourceStatusIcon("test"); - assert.strictEqual(result, ""); - }); - }); - describe("getServerIconState", () => { const localConn = new LocalConnection("127.0.0.1:5001", "testLabel"); afterEach(() => { @@ -681,7 +594,7 @@ describe("Utils", () => { ext.connectionNode = kdbNode; - queryConsole.append(output, query, serverName); + queryConsole.append(output, query, "fileName", serverName); assert.strictEqual(ext.kdbQueryHistoryList.length, 1); assert.strictEqual(ext.kdbQueryHistoryList[0].success, true); assert.strictEqual( @@ -704,7 +617,7 @@ describe("Utils", () => { ext.connectionNode = kdbNode; - queryConsole.append(output, query, serverName); + queryConsole.append(output, query, "fileName", serverName); assert.strictEqual(ext.kdbQueryHistoryList.length, 1); assert.strictEqual(ext.kdbQueryHistoryList[0].success, true); assert.strictEqual( @@ -721,7 +634,16 @@ describe("Utils", () => { ext.connectionNode = insightsNode; - queryConsole.append(output, query, serverName); + queryConsole.append( + output, + query, + "fileName", + serverName, + true, + "WORKBOOK", + true, + "2", + ); assert.strictEqual(ext.kdbQueryHistoryList.length, 1); assert.strictEqual(ext.kdbQueryHistoryList[0].success, true); assert.strictEqual( @@ -737,7 +659,18 @@ describe("Utils", () => { ext.connectionNode = kdbNode; - queryConsole.appendQueryError(query, output, true, serverName, true); + queryConsole.appendQueryError( + query, + output, + serverName, + "fileName", + true, + false, + "WORKBOOK", + true, + false, + "2", + ); assert.strictEqual(ext.kdbQueryHistoryList.length, 1); assert.strictEqual(ext.kdbQueryHistoryList[0].success, false); assert.strictEqual( @@ -751,9 +684,18 @@ describe("Utils", () => { const output = "test"; const serverName = "testServer"; - ext.connectionNode = insightsNode; - - queryConsole.appendQueryError(query, output, true, serverName); + queryConsole.appendQueryError( + query, + output, + serverName, + "filename", + true, + true, + "WORKBOOK", + true, + false, + "2", + ); assert.strictEqual(ext.kdbQueryHistoryList.length, 1); assert.strictEqual(ext.kdbQueryHistoryList[0].success, false); assert.strictEqual( @@ -769,7 +711,13 @@ describe("Utils", () => { ext.connectionNode = insightsNode; - queryConsole.appendQueryError(query, output, false, serverName); + queryConsole.appendQueryError( + query, + output, + serverName, + "filename", + false, + ); assert.strictEqual(ext.kdbQueryHistoryList.length, 1); assert.strictEqual(ext.kdbQueryHistoryList[0].success, false); assert.strictEqual( @@ -786,7 +734,13 @@ describe("Utils", () => { ext.kdbQueryHistoryList.length = 0; - queryUtils.addQueryHistory(query, connectionName, connectionType, true); + queryUtils.addQueryHistory( + query, + "fileName", + connectionName, + connectionType, + true, + ); assert.strictEqual(ext.kdbQueryHistoryList.length, 1); }); @@ -800,6 +754,7 @@ describe("Utils", () => { queryUtils.addQueryHistory( query, connectionName, + "fileName", connectionType, true, true, From 052004bc3a0114a788d2a77a3cc28f6ad9c5304d Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 12:31:55 +0100 Subject: [PATCH 10/15] add tests --- test/suite/utils.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/suite/utils.test.ts b/test/suite/utils.test.ts index 667c5711..4ebbc944 100644 --- a/test/suite/utils.test.ts +++ b/test/suite/utils.test.ts @@ -231,6 +231,25 @@ describe("Utils", () => { assert.strictEqual(result, "- disconnected"); }); }); + + describe("getWorkspaceIconsState", () => { + const localConn = new LocalConnection("127.0.0.1:5001", "testLabel"); + afterEach(() => { + ext.connectedConnectionList.length = 0; + }); + + it("should return active state", () => { + ext.connectedConnectionList.push(localConn); + const result = coreUtils.getWorkspaceIconsState(localConn.connLabel); + assert.strictEqual(result, "-active"); + }); + + it("should return disconnected state", () => { + ext.activeConnection = undefined; + const result = coreUtils.getWorkspaceIconsState(localConn.connLabel); + assert.strictEqual(result, ""); + }); + }); }); describe("dataSource", () => { From a5f0585f3b5de9a10906da80f4a548456e937519 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 13:56:22 +0100 Subject: [PATCH 11/15] getmeta tests for ds --- src/services/dataSourceEditorProvider.ts | 4 +- test/suite/services.test.ts | 189 +++++++++++++++++++++++ 2 files changed, 191 insertions(+), 2 deletions(-) diff --git a/src/services/dataSourceEditorProvider.ts b/src/services/dataSourceEditorProvider.ts index 15f49f67..42bcaf80 100644 --- a/src/services/dataSourceEditorProvider.ts +++ b/src/services/dataSourceEditorProvider.ts @@ -57,7 +57,7 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { constructor(private readonly context: ExtensionContext) {} - getMeta(connLabel: string) { + async getMeta(connLabel: string) { let meta = this.cache.get(connLabel); const connMngService = new ConnectionManagementService(); const isConnected = connMngService.isConnected(connLabel); @@ -92,7 +92,7 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { this.cache.set(connLabel, meta); //TODO ADD ERROR TO CONSOLE HERE } - return meta || Promise.resolve({}); + return (await meta) || Promise.resolve({}); } async resolveCustomTextEditor( diff --git a/test/suite/services.test.ts b/test/suite/services.test.ts index 3ca7c3d7..03bd0ec3 100644 --- a/test/suite/services.test.ts +++ b/test/suite/services.test.ts @@ -58,6 +58,7 @@ import { } from "../../src/services/workspaceTreeProvider"; import Path from "path"; import * as utils from "../../src/utils/getUri"; +import { MetaObject } from "../../src/models/meta"; // eslint-disable-next-line @typescript-eslint/no-var-requires const codeFlow = require("../../src/services/kdbInsights/codeFlowLogin"); @@ -1119,6 +1120,194 @@ describe("dataSourceEditorProvider", () => { panel.listeners.onDidChangeViewState(); panel.listeners.onDidDispose(); }); + + describe("getMeta", () => { + const dummyMeta: MetaObject = { + header: { + ac: "0", + agg: ":127.0.0.1:5070", + ai: "", + api: ".kxi.getMeta", + client: ":127.0.0.1:5050", + corr: "CorrHash", + http: "json", + logCorr: "logCorrHash", + protocol: "gw", + rc: "0", + rcvTS: "2099-05-22T11:06:33.650000000", + retryCount: "0", + to: "2099-05-22T11:07:33.650000000", + userID: "dummyID", + userName: "testUser", + }, + payload: { + rc: [ + { + api: 3, + agg: 1, + assembly: 1, + schema: 1, + rc: "dummy-rc", + labels: [{ kxname: "dummy-assembly" }], + started: "2023-10-04T17:20:57.659088747", + }, + ], + dap: [], + api: [], + agg: [ + { + aggFn: ".sgagg.aggFnDflt", + custom: false, + full: true, + metadata: { + description: "dummy desc.", + params: [{ description: "dummy desc." }], + return: { description: "dummy desc." }, + misc: {}, + }, + procs: [], + }, + ], + assembly: [ + { + assembly: "dummy-assembly", + kxname: "dummy-assembly", + tbls: ["dummyTbl"], + }, + ], + schema: [], + }, + }; + + const dummyMetaNoAssembly: MetaObject = { + header: { + ac: "0", + agg: ":127.0.0.1:5070", + ai: "", + api: ".kxi.getMeta", + client: ":127.0.0.1:5050", + corr: "CorrHash", + http: "json", + logCorr: "logCorrHash", + protocol: "gw", + rc: "0", + rcvTS: "2099-05-22T11:06:33.650000000", + retryCount: "0", + to: "2099-05-22T11:07:33.650000000", + userID: "dummyID", + userName: "testUser", + }, + payload: { + rc: [ + { + api: 3, + agg: 1, + assembly: 1, + schema: 1, + rc: "dummy-rc", + labels: [{ kxname: "dummy-assembly" }], + started: "2023-10-04T17:20:57.659088747", + }, + ], + dap: [], + api: [], + agg: [ + { + aggFn: ".sgagg.aggFnDflt", + custom: false, + full: true, + metadata: { + description: "dummy desc.", + params: [{ description: "dummy desc." }], + return: { description: "dummy desc." }, + misc: {}, + }, + procs: [], + }, + ], + assembly: [], + schema: [], + }, + }; + const insightsNode = new InsightsNode( + [], + "insightsnode1", + { + server: "https://insightsservername.com/", + alias: "insightsserveralias", + auth: true, + }, + TreeItemCollapsibleState.None, + ); + const insightsConn = new InsightsConnection( + insightsNode.label, + insightsNode, + ); + const localConn = new LocalConnection("127.0.0.1:5001", "testLabel"); + const connMngService = new ConnectionManagementService(); + let isConnetedStub, retrieveConnectedConnectionStub: sinon.SinonStub; + beforeEach(() => { + isConnetedStub = sinon.stub(connMngService, "isConnected"); + retrieveConnectedConnectionStub = sinon.stub( + connMngService, + "retrieveConnectedConnection", + ); + }); + afterEach(() => { + ext.connectedConnectionList.length = 0; + ext.connectedContextStrings.length = 0; + }); + + it("Should return empty object if the connection selected is not connected", async () => { + isConnetedStub.returns(false); + const provider = new DataSourceEditorProvider(context); + const result = await provider.getMeta(insightsConn.connLabel); + assert.deepStrictEqual(result, {}); + }); + + it("Should return empty object if the connection selected is undefined", async () => { + ext.connectedContextStrings.push(insightsConn.connLabel); + isConnetedStub.resolves(true); + const provider = new DataSourceEditorProvider(context); + const result = await provider.getMeta(insightsConn.connLabel); + assert.deepStrictEqual(result, {}); + }); + + it("Should return empty object if the connection selected is a LocalConnection", async () => { + ext.connectedContextStrings.push(localConn.connLabel); + ext.connectedConnectionList.push(localConn); + isConnetedStub.resolves(true); + const provider = new DataSourceEditorProvider(context); + const result = await provider.getMeta(localConn.connLabel); + assert.deepStrictEqual(result, {}); + }); + it("Should return empty object if the meta is undefined", async () => { + ext.connectedContextStrings.push(insightsConn.connLabel); + ext.connectedConnectionList.push(insightsConn); + isConnetedStub.resolves(true); + const provider = new DataSourceEditorProvider(context); + const result = await provider.getMeta(insightsConn.connLabel); + assert.deepStrictEqual(result, {}); + }); + it("Should return empty object if the meta has no assembly", async () => { + ext.connectedContextStrings.push(insightsConn.connLabel); + ext.connectedConnectionList.push(insightsConn); + isConnetedStub.resolves(true); + insightsConn.meta = dummyMetaNoAssembly; + const provider = new DataSourceEditorProvider(context); + const result = await provider.getMeta(insightsConn.connLabel); + assert.deepStrictEqual(result, {}); + }); + it("Should return empty object if the meta has no assembly", async () => { + ext.connectedContextStrings.push(insightsConn.connLabel); + ext.connectedConnectionList.push(insightsConn); + isConnetedStub.resolves(true); + insightsConn.meta = dummyMeta; + const provider = new DataSourceEditorProvider(context); + const result = await provider.getMeta(insightsConn.connLabel); + assert.deepStrictEqual(result, dummyMeta.payload); + }); + }); }); }); From a5c68b975f2d0256cd29e03f2bcee0d047dcb329 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 14:09:52 +0100 Subject: [PATCH 12/15] add executequery tests --- test/suite/commands.test.ts | 67 ++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/test/suite/commands.test.ts b/test/suite/commands.test.ts index c14cc1bf..fa310e8d 100644 --- a/test/suite/commands.test.ts +++ b/test/suite/commands.test.ts @@ -1423,16 +1423,65 @@ describe("serverCommand", () => { }); afterEach(() => { ext.activeConnection = undefined; + ext.connectedConnectionList.length = 0; + ext.connectedContextStrings.length = 0; sinon.restore(); }); - it("should execute query and write results to view", async () => { + it("should fail if connLabel is empty and activeConnection is undefined", async () => { + serverCommand.executeQuery( + "SELECT * FROM table", + "", + "testFile.kdb.q", + ".", + true, + true, + ); + sinon.assert.notCalled(writeResultsConsoleStub); + sinon.assert.notCalled(writeResultsViewStub); + sinon.assert.notCalled(writeScratchpadResultStub); + }); + + it("should proceed if connLabel is empty and activeConnection is not undefined", async () => { ext.activeConnection = localConn; - ext.connectionNode = kdbNode; + ext.connectedConnectionList.push(localConn); + ext.connectedContextStrings.push(localConn.connLabel); isVisibleStub.returns(true); executeQueryStub.resolves({ data: "data" }); serverCommand.executeQuery( "SELECT * FROM table", - "testeConn", + "", + "testFile.kdb.q", + ".", + true, + true, + ); + sinon.assert.notCalled(writeResultsConsoleStub); + sinon.assert.notCalled(writeScratchpadResultStub); + }); + it("should fail if the connection selected is not connected", async () => { + ext.connectedConnectionList.push(localConn); + isVisibleStub.returns(true); + executeQueryStub.resolves({ data: "data" }); + serverCommand.executeQuery( + "SELECT * FROM table", + localConn.connLabel, + "testFile.kdb.q", + ".", + true, + true, + ); + sinon.assert.notCalled(writeResultsConsoleStub); + sinon.assert.notCalled(writeResultsViewStub); + sinon.assert.notCalled(writeScratchpadResultStub); + }); + it("should execute query and write results to view", async () => { + ext.connectedConnectionList.push(localConn); + ext.connectedContextStrings.push(localConn.connLabel); + isVisibleStub.returns(true); + executeQueryStub.resolves({ data: "data" }); + serverCommand.executeQuery( + "SELECT * FROM table", + localConn.connLabel, "testFile.kdb.q", ".", true, @@ -1442,13 +1491,13 @@ describe("serverCommand", () => { sinon.assert.notCalled(writeScratchpadResultStub); }); it("should execute query and write results to console", async () => { - ext.activeConnection = localConn; - ext.connectionNode = kdbNode; + ext.connectedConnectionList.push(localConn); + ext.connectedContextStrings.push(localConn.connLabel); isVisibleStub.returns(false); executeQueryStub.resolves("dummy test"); serverCommand.executeQuery( "SELECT * FROM table", - "testeConn", + localConn.connLabel, "testFile.kdb.q", ".", true, @@ -1458,13 +1507,13 @@ describe("serverCommand", () => { sinon.assert.notCalled(writeScratchpadResultStub); }); it("should execute query and write error to console", async () => { - ext.activeConnection = insightsConn; - ext.connectionNode = insightsNode; + ext.connectedConnectionList.push(insightsConn); + ext.connectedContextStrings.push(insightsConn.connLabel); isVisibleStub.returns(true); executeQueryStub.resolves("dummy test"); serverCommand.executeQuery( "SELECT * FROM table", - "testeConn", + insightsConn.connLabel, "testFile.kdb.q", ".", true, From a3395616c72aef060e850658b098323faf047697 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 14:25:14 +0100 Subject: [PATCH 13/15] refresh getmeta tests --- test/suite/services.test.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/suite/services.test.ts b/test/suite/services.test.ts index 03bd0ec3..ce5f9a00 100644 --- a/test/suite/services.test.ts +++ b/test/suite/services.test.ts @@ -1051,6 +1051,28 @@ describe("connectionManagerService", () => { sinon.assert.notCalled(resetScratchpadStub); }); }); + + describe("refreshGetMetas", () => { + let getMetaStub: sinon.SinonStub; + beforeEach(() => { + getMetaStub = sinon.stub(insightsConn, "getMeta"); + }); + afterEach(() => { + sinon.restore(); + ext.connectedConnectionList.length = 0; + }); + + it("Should not refresh getMetas if connection is not InsightsConnection", async () => { + await connectionManagerService.refreshGetMetas(); + sinon.assert.notCalled(getMetaStub); + }); + + it("Should refresh getMetas if connection is InsightsConnection", async () => { + ext.connectedConnectionList.push(insightsConn); + await connectionManagerService.refreshGetMetas(); + sinon.assert.calledOnce(getMetaStub); + }); + }); }); describe("dataSourceEditorProvider", () => { From 0c9346b6978b9db14e9ada1b05015dc06540b679 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 14:48:08 +0100 Subject: [PATCH 14/15] fix ds error msg --- src/commands/dataSourceCommand.ts | 4 ++-- src/commands/serverCommand.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/dataSourceCommand.ts b/src/commands/dataSourceCommand.ts index 9c08bd6d..2a3c3418 100644 --- a/src/commands/dataSourceCommand.ts +++ b/src/commands/dataSourceCommand.ts @@ -81,7 +81,7 @@ export async function populateScratchpad( validateInput: (value: string | undefined) => validateScratchpadOutputVariableName(value), }; - + /* istanbul ignore next */ window.showInputBox(scratchpadVariable).then(async (outputVariable) => { if (outputVariable !== undefined && outputVariable !== "") { const connMngService = new ConnectionManagementService(); @@ -123,7 +123,7 @@ export async function runDataSource( try { if (selectedConnection instanceof LocalConnection || !selectedConnection) { - throw new Error("No Insights active connection found"); + throw new Error("The selected Insights Connection is not connected"); } selectedConnection.getMeta(); if (!selectedConnection?.meta?.payload.assembly) { diff --git a/src/commands/serverCommand.ts b/src/commands/serverCommand.ts index 7d73a969..274e65b7 100644 --- a/src/commands/serverCommand.ts +++ b/src/commands/serverCommand.ts @@ -333,7 +333,7 @@ export async function executeQuery( const queryConsole = ExecutionConsole.start(); if (connLabel === "") { if (ext.activeConnection === undefined) { - window.showInformationMessage( + window.showErrorMessage( "No active connection founded. Connect to one connection.", ); //TODO ADD ERROR TO CONSOLE HERE From b06055663c1b67e5c9bbeee0f280cca3dd76d7e6 Mon Sep 17 00:00:00 2001 From: Philip Carneiro Date: Wed, 22 May 2024 14:50:18 +0100 Subject: [PATCH 15/15] add tests for tooltip queryhistory --- test/suite/services.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/suite/services.test.ts b/test/suite/services.test.ts index ce5f9a00..eb03773e 100644 --- a/test/suite/services.test.ts +++ b/test/suite/services.test.ts @@ -623,6 +623,7 @@ describe("queryHistoryProvider", () => { time: "testTime2", query: "testQuery2", success: true, + isWorkbook: true, connectionType: ServerType.KDB, duration: "500", },