Skip to content

Commit c71739d

Browse files
Merge pull request #61 from gjsjohnmurray/fix-22
Handle duplicate column names in query results when using 2023.1+
2 parents 2ac5fea + 44f4784 commit c71739d

File tree

4 files changed

+58
-15
lines changed

4 files changed

+58
-15
lines changed

package-lock.json

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@
6868
"devDependencies": {
6969
"@babel/preset-env": "^7.14.2",
7070
"@intersystems-community/intersystems-servermanager": "^3.8.0",
71+
"@types/lodash": "^4.17.15",
7172
"@types/node": "^14.17.0",
7273
"@types/vscode": "^1.93.0",
7374
"@vscode/vsce": "^2.19.0",
75+
"lodash": "^4.17.21",
7476
"rimraf": "^3.0.2",
7577
"ts-loader": "^9.2.1",
7678
"typescript": "^4.9.5",

src/ls/driver.ts

+37-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { IConnectionDriver, MConnectionExplorer, NSDatabase, ContextValue, Arg0
44
import { v4 as generateId } from 'uuid';
55
import IRISdb, { IRISDirect, IQueries } from './irisdb';
66
import keywordsCompletion from './keywords';
7+
import zipObject from 'lodash/zipObject';
78

89
const toBool = (v: any) => v && (v.toString() === '1' || v.toString().toLowerCase() === 'true' || v.toString().toLowerCase() === 'yes');
910

@@ -55,21 +56,48 @@ export default class IRISDriver extends AbstractDriver<IRISdb, DriverOptions> im
5556
return queries.split(/;\s*(\n|$)/gm).filter(query => query.trim().length);
5657
}
5758

59+
// Handle duplicate column names by appending counter
60+
private getColumnNames(columns: { name: string, type: string }[]): string[] {
61+
return columns.reduce((names, { name }) => {
62+
const count = names.filter((n) => n === name).length;
63+
return names.concat(count > 0 ? `${name} (${count})` : name);
64+
}, []);
65+
}
66+
67+
// Modify to take account of deduplicated column names
68+
private mapRows(rows: any[], columns: string[]): any[] {
69+
return rows.map((r) => zipObject(columns, r));
70+
}
71+
5872
public query: (typeof AbstractDriver)['prototype']['query'] = async (queries, opt = {}) => {
5973
const irisdb = await this.open();
6074
const listQueries = this.splitQueries(queries.toString());
6175
const queriesResults = await Promise.all(listQueries.map(query => irisdb.query(query, [])));
6276
const resultsAgg: NSDatabase.IResult[] = [];
6377
queriesResults.forEach(queryResult => {
64-
resultsAgg.push({
65-
cols: queryResult.length ? Object.keys(queryResult[0]) : [],
66-
connId: this.getId(),
67-
messages: [{ date: new Date(), message: `Query ok with ${queryResult.length} results` }],
68-
results: queryResult,
69-
query: queries.toString(),
70-
requestId: opt.requestId,
71-
resultId: generateId(),
72-
});
78+
if (irisdb.apiVersion < 6) {
79+
resultsAgg.push({
80+
cols: queryResult.content.length ? Object.keys(queryResult.content[0]) : [],
81+
connId: this.getId(),
82+
messages: [{ date: new Date(), message: `Query ok with ${queryResult.content.length} results` }],
83+
results: queryResult.content,
84+
query: queries.toString(),
85+
requestId: opt.requestId,
86+
resultId: generateId(),
87+
});
88+
}
89+
else {
90+
const cols = this.getColumnNames(queryResult[0].columns || []);
91+
resultsAgg.push({
92+
cols,
93+
connId: this.getId(),
94+
messages: [{ date: new Date(), message: `Query ok with ${queryResult[0]?.content.length ?? 'no'} results` }],
95+
results: this.mapRows(queryResult[0]?.content, cols),
96+
query: queries.toString(),
97+
requestId: opt.requestId,
98+
resultId: generateId(),
99+
});
100+
}
73101
});
74102

75103
return resultsAgg;

src/ls/irisdb.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ export default class IRISdb {
2727

2828
private config: IRISDirect;
2929
private cookies: string[] = [];
30-
private apiVersion = 1;
30+
private _apiVersion = 1;
31+
32+
public get apiVersion() {
33+
return this._apiVersion;
34+
}
3135

3236
public constructor(config: IRISDirect) {
3337
this.config = config;
@@ -57,11 +61,11 @@ export default class IRISdb {
5761
headers?: any
5862
): Promise<any> {
5963
const { https, host, port, pathPrefix, username, password } = this.config;
60-
if (minVersion > this.apiVersion) {
61-
return Promise.reject(`${path} not supported by API version ${this.apiVersion}`);
64+
if (minVersion > this._apiVersion) {
65+
return Promise.reject(`${path} not supported by API version ${this._apiVersion}`);
6266
}
6367
if (minVersion && minVersion > 0) {
64-
path = `v${this.apiVersion}/${path}`;
68+
path = `v${this._apiVersion}/${path}`;
6569
}
6670

6771
headers = {
@@ -169,7 +173,7 @@ export default class IRISdb {
169173
You must select one of the following: ${data.namespaces.join(", ")}.`,
170174
};
171175
}
172-
this.apiVersion = data.api;
176+
this._apiVersion = data.api;
173177
return info;
174178
}
175179
});
@@ -183,7 +187,7 @@ export default class IRISdb {
183187
return this.request(1, "POST", `${this.config.namespace}/action/query`, {
184188
parameters,
185189
query,
186-
}).then(data => data.result.content)
190+
}, this._apiVersion >= 6 ? { positional: true } : {}).then(data => data.result)
187191
}
188192

189193

0 commit comments

Comments
 (0)