Skip to content

Commit

Permalink
Merge pull request #223 from KxSystems/KXI-33265
Browse files Browse the repository at this point in the history
KXI-33265 - Fix Results tab for local connections
  • Loading branch information
Philip-Carneiro-KX authored Jan 5, 2024
2 parents 43d7c66 + 586364f commit a0644f1
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/commands/serverCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ export async function executeQuery(
query = sanitizeQuery(query);

if (ext.resultsViewProvider.isVisible()) {
const queryRes = await ext.connection.executeQuery(query, context, false);
const queryRes = await ext.connection.executeQuery(query, context, true);
writeQueryResultsToView(queryRes, query);
} else {
const queryRes = await ext.connection.executeQuery(query, context, true);
Expand Down
71 changes: 44 additions & 27 deletions src/models/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ import * as nodeq from "node-q";
import { commands, window } from "vscode";
import { ext } from "../extensionVariables";
import { delay } from "../utils/core";
import {
convertArrayOfArraysToObjects,
handleQueryResults,
} from "../utils/execution";
import { convertStringToArray, handleQueryResults } from "../utils/execution";
import { queryWrapper } from "../utils/queryUtils";
import { QueryResult, QueryResultType } from "./queryResult";

export class Connection {
private options: nodeq.ConnectionParameters;
private connection?: nodeq.Connection;
public connected: boolean;
private result?: string;

constructor(connectionString: string, creds?: string[], tls?: boolean) {
const params = connectionString.split(":");
Expand Down Expand Up @@ -98,16 +96,11 @@ export class Connection {
context?: string,
stringify?: boolean
): Promise<any> {
let result;
let retryCount = 0;
while (this.connection === undefined) {
if (retryCount > ext.maxRetryCount) {
return "timeout";
}
await delay(500);
retryCount++;
}
await this.waitForConnection();

if (!this.connection) {
return "timeout";
}
const wrapper = queryWrapper();
this.connection.k(
wrapper,
Expand All @@ -116,29 +109,53 @@ export class Connection {
!!stringify,
(err: Error, res: QueryResult) => {
if (err) {
result = handleQueryResults(err.toString(), QueryResultType.Error);
} else if (res) {
if (res.errored) {
result = handleQueryResults(
res.error + (res.backtrace ? "\n" + res.backtrace : ""),
QueryResultType.Error
);
} else {
result = res.result;
}
this.result = handleQueryResults(
err.toString(),
QueryResultType.Error
);
}
if (res) {
this.handleQueryResult(res);
}
}
);

while (result === undefined || result === null) {
const result = await this.waitForResult();

if (ext.resultsViewProvider.isVisible()) {
return convertStringToArray(result);
}

return result;
}

private async waitForConnection(): Promise<void> {
let retryCount = 0;
while (this.connection === undefined) {
if (retryCount > ext.maxRetryCount) {
throw new Error("timeout");
}
await delay(500);
retryCount++;
}
}

if (!stringify) {
result = convertArrayOfArraysToObjects(result);
private handleQueryResult = (res: QueryResult): void => {
if (res.errored) {
this.result = handleQueryResults(
res.error + (res.backtrace ? "\n" + res.backtrace : ""),
QueryResultType.Error
);
} else {
this.result = res.result;
}
};

return result;
private async waitForResult(): Promise<any> {
while (this.result === undefined || this.result === null) {
await delay(500);
}
return this.result;
}

public async executeQueryRaw(command: string): Promise<string> {
Expand Down
66 changes: 66 additions & 0 deletions src/utils/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,69 @@ export function convertArrayOfArraysToObjects(arr: any): any[] {

return result;
}

function processLineWithSeparator(line: string, index: number): object {
const parts = line.split("|").map((part) => part.trim());
return { Index: index + 1, Key: parts[0], Value: parts[1] };
}

function processLineWithoutSeparator(line: string, index: number): object[] {
if (!line.startsWith('"') && line.includes(" ")) {
// Split the line into parts by spaces and map each part to an object
return line.split(" ").map((part, i) => {
return { Index: index + i + 1, Value: part };
});
} else {
return [{ Index: index + 1, Value: line.trim() }];
}
}

function processLine(
line: string,
index: number,
fieldLengths: number[],
fieldNames: string[]
): object {
let start = 0;
const obj: { [key: string]: any } = { Index: index + 1 };
fieldLengths.forEach((length, i) => {
obj[fieldNames[i]] = line.substring(start, start + length).trim();
start += length;
});
return obj;
}

export function convertStringToArray(str: string): any[] {
const lines = str.split("\n").filter((line) => line.trim() !== "");
if (lines.length > 2 && lines[1].startsWith("---")) {
const fieldNames = lines[0].split(" ").filter((part) => part !== "");
lines.splice(1, 1);
let total = 0;
const fieldLengths = fieldNames.map((name, i) => {
if (i === fieldNames.length - 1) {
return lines[0].length - total;
}
const elementLength =
lines[0].indexOf(fieldNames[i + 1] ?? "") - lines[0].indexOf(name);
total += elementLength;
return elementLength;
});
lines.shift();
return lines.flatMap((line, index) =>
fieldLengths.length > 0
? processLine(line, index, fieldLengths, fieldNames)
: []
);
}

return lines
.flatMap((line, index) => {
const parts = line.split("|").map((part) => part.trim());
return parts.length === 2
? processLineWithSeparator(line, index)
: processLineWithoutSeparator(line, index);
})
.filter(
(obj) => !("Value" in obj && (obj.Value as string).startsWith("-"))
);
}
63 changes: 63 additions & 0 deletions test/suite/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,69 @@ describe("Utils", () => {
assert.deepStrictEqual(result, expectedOutput);
});
});

describe("convertArrayOfObjectsToArrays", () => {
it("convertStringToArray handles string with separator", () => {
const input = "key1 | value1\nkey2 | value2";
const expectedOutput = [
{ Index: 1, Key: "key1", Value: "value1" },
{ Index: 2, Key: "key2", Value: "value2" },
];
const output = executionUtils.convertStringToArray(input);
assert.deepStrictEqual(output, expectedOutput);
});

it("convertStringToArray handles string without separator", () => {
const input = "value1\nvalue2";
const expectedOutput = [
{ Index: 1, Value: "value1" },
{ Index: 2, Value: "value2" },
];
const output = executionUtils.convertStringToArray(input);
assert.deepStrictEqual(output, expectedOutput);
});

it("convertStringToArray handles string with field names and lengths", () => {
const input = "name age\n---\nJohn 25\nDoe 30";
const expectedOutput = [
{ Index: 1, name: "John", age: "25" },
{ Index: 2, name: "Doe", age: "30" },
];
const output = executionUtils.convertStringToArray(input);
assert.deepStrictEqual(output, expectedOutput);
});

it("convertStringToArray filters out lines starting with '-'", () => {
const input = "key1 | value1\nkey2 | value2\nkey3 | value3";
const expectedOutput = [
{ Index: 1, Key: "key1", Value: "value1" },
{ Index: 2, Key: "key2", Value: "value2" },
{ Index: 3, Key: "key3", Value: "value3" },
];
const output = executionUtils.convertStringToArray(input);
assert.deepStrictEqual(output, expectedOutput);
});

it("convertStringToArray handles single value results", () => {
const input = "2001.01.01D12:00:00.000000000\n";
const expectedOutput = [
{ Index: 1, Value: "2001.01.01D12:00:00.000000000" },
];
const output = executionUtils.convertStringToArray(input);
assert.deepStrictEqual(output, expectedOutput);
});

it("convertStringToArray handles single line with multiple value results", () => {
const input =
"2001.01.01D12:00:00.000000000 2001.01.01D12:00:00.000000001\n";
const expectedOutput = [
{ Index: 1, Value: "2001.01.01D12:00:00.000000000" },
{ Index: 2, Value: "2001.01.01D12:00:00.000000001" },
];
const output = executionUtils.convertStringToArray(input);
assert.deepStrictEqual(output, expectedOutput);
});
});
});

describe("executionConsole", () => {
Expand Down

0 comments on commit a0644f1

Please sign in to comment.