Skip to content

Commit df96993

Browse files
committed
Added a feature for opening a new query editor with the query active in the inspector. #25
1 parent d343f7e commit df96993

10 files changed

Lines changed: 318 additions & 110 deletions

File tree

src/controllers/visualization.controller.ts

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@ interface IOutgoingMessage {
5050
filterObjectsSchema?: string;
5151
}
5252

53-
export const VisualizationController = async (webview: vscode.Webview, connectionContext: ConnectionContext) => {
54-
await renderWebviewContent(webview, connectionContext);
53+
export const VisualizationController = async (
54+
webview: vscode.Webview,
55+
connectionContext: ConnectionContext,
56+
connectionProfile: azdata.IConnectionProfile
57+
) => {
58+
await renderWebviewContent(webview, connectionContext, connectionProfile);
5559
};
5660

5761

@@ -60,7 +64,11 @@ const postMessage = (webview: azdata.DashboardWebview | vscode.Webview, message:
6064
};
6165

6266

63-
const renderWebviewContent = async (webview: vscode.Webview, connectionContext: ConnectionContext) => {
67+
const renderWebviewContent = async (
68+
webview: vscode.Webview,
69+
connectionContext: ConnectionContext,
70+
connectionProfile: azdata.IConnectionProfile
71+
) => {
6472
webview.html = loadWebView();
6573
if (connectionContext.connectionId) {
6674

@@ -167,6 +175,77 @@ const renderWebviewContent = async (webview: vscode.Webview, connectionContext:
167175
await loadRows(data.commandSessionId, repository, webview, viewModel);
168176
}
169177
}
178+
case 'openNewQueryEditor': {
179+
if (viewModel.selectedObject === undefined) {
180+
return;
181+
}
182+
183+
const object = viewModel.selectedObject;
184+
185+
if (
186+
viewModel.columnsRelativeToObject?.Name !== object.Name
187+
|| viewModel.columnsRelativeToObject?.Schema !== object.Schema
188+
)
189+
{
190+
return;
191+
}
192+
193+
let orderByColumns: string[] | undefined;
194+
let sortAscending: boolean[] | undefined;
195+
196+
if (viewModel.sortRowsByColumnName) {
197+
orderByColumns = [viewModel.sortRowsByColumnName];
198+
if (viewModel.sortRowsByColumnAscending !== undefined) {
199+
sortAscending = [viewModel.sortRowsByColumnAscending];
200+
}
201+
else {
202+
sortAscending = [true];
203+
}
204+
}
205+
else {
206+
const primaryKey = viewModel.columns?.filter(c => c.IsPrimaryKey)
207+
.sort((c1, c2) => c1.KeyOrdinal <= c2.KeyOrdinal ? -1 : 1)
208+
.map(c => c.Name);
209+
orderByColumns = primaryKey;
210+
sortAscending = primaryKey?.map(p => true);
211+
}
212+
213+
const query = repository.getDbTableRowsQuery(object, viewModel.columns, viewModel.filter!, orderByColumns, sortAscending, viewModel.rowsPageIndex, viewModel.rowsPageSize);
214+
215+
try {
216+
const doc = await azdata.queryeditor.openQueryDocument({
217+
content: query,
218+
});
219+
220+
const connProfile: azdata.connection.ConnectionProfile = {
221+
authenticationType: connectionProfile.authenticationType,
222+
connectionId: connectionContext.connectionId,
223+
connectionName: connectionProfile.connectionName!,
224+
databaseName: connectionProfile.databaseName!,
225+
groupFullName: connectionProfile.groupFullName!,
226+
groupId: connectionProfile.groupId!,
227+
options: {
228+
...connectionProfile.options,
229+
database: connectionProfile.databaseName!,
230+
},
231+
password: "",
232+
providerId: connectionProfile.providerName,
233+
savePassword: connectionProfile.savePassword,
234+
saveProfile: connectionProfile.saveProfile,
235+
serverName: connectionProfile.serverName!,
236+
userName: "",
237+
};
238+
239+
await doc.connect(connProfile);
240+
241+
} catch (e) {
242+
vscode.window.showErrorMessage(
243+
`Error opening new query editor: ${(<Error>e).message}`
244+
);
245+
}
246+
247+
break;
248+
}
170249
}
171250
}
172251
});

src/extension.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ const loadVisualizationFromExplorer = async (context: azdata.ObjectExplorerConte
6060
// And set its HTML content
6161
await VisualizationController(
6262
panel.webview,
63-
connectionContext
63+
connectionContext,
64+
iConnProfile
6465
);
6566
}
6667
catch (e) {
@@ -109,7 +110,8 @@ const loadVisualizationFromEditor = async (context: azdata.ObjectExplorerContext
109110
// And set its HTML content
110111
await VisualizationController(
111112
panel.webview,
112-
connectionContext
113+
connectionContext,
114+
context.connectionProfile!
113115
);
114116
}
115117
catch (e) {

src/repositories/db.repository.mssql.ts

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,17 @@ export class DbRepositoryMSSQL implements IDbRepository{
331331
pageSize: number = 20
332332
): Promise<QueryResults<{ rows: any[]; count: number; }>> {
333333

334-
if (table === undefined || table === null
335-
|| DbRepository.hasPotentialSqlInjection(filter)
336-
) {
334+
const queryRows = this.getDbTableRowsQuery(
335+
table,
336+
columns,
337+
filter,
338+
orderByColumns,
339+
sortAscending,
340+
pageIndex,
341+
pageSize
342+
);
343+
344+
if (queryRows === undefined) {
337345
return {
338346
sessionId,
339347
data: {
@@ -342,44 +350,9 @@ export class DbRepositoryMSSQL implements IDbRepository{
342350
}
343351
};
344352
}
345-
346-
if (pageIndex < 1) { pageIndex = 1; }
347-
if (pageSize < 0) { pageSize = 20; }
348-
349-
const hasOrderingColumns: boolean = orderByColumns !== undefined && orderByColumns.length > 0;
350-
if (hasOrderingColumns && sortAscending !== undefined) {
351-
orderByColumns = orderByColumns?.map((col, index) => sortAscending[index] ? col : col + ' DESC');
352-
}
353-
353+
354354
const whereExpression = filter ? 'WHERE ' + filter : '';
355-
const orderBy = hasOrderingColumns ? `
356-
ORDER BY ${orderByColumns?.join(',')}
357-
OFFSET ${(pageIndex - 1) * pageSize} ROWS FETCH NEXT ${pageSize} ROWS ONLY
358-
` : '';
359-
360-
const top = !hasOrderingColumns ? `TOP(${pageSize})` : '';
361-
362-
let columnsExpression = '';
363-
if (columns !== undefined && columns !== null && columns.length > 0) {
364-
columnsExpression = columns.map(col => {
365-
let statement = `[${col.Name}]`;
366-
let colType = getBaseType(col.Type);
367-
if (colType === 'geography' || colType === 'geometry') {
368-
statement = `CONVERT(varchar(max), [${col.Name}].ToString()) as [${col.Name}]`;
369-
}
370-
return statement;
371-
}).join(',');
372-
}
373-
else {
374-
columnsExpression = '*';
375-
}
376-
377-
const queryRows = `
378-
SELECT ${top} ${columnsExpression}
379-
FROM [${table.Schema}].[${table.Name}]
380-
${whereExpression}
381-
${orderBy}`;
382-
355+
383356
const queryCount = `
384357
SELECT COUNT(*) as count
385358
FROM [${table.Schema}].[${table.Name}]
@@ -431,4 +404,63 @@ export class DbRepositoryMSSQL implements IDbRepository{
431404
}
432405
};
433406
}
407+
408+
409+
getDbTableRowsQuery(
410+
table: DatabaseObject,
411+
columns: DatabaseColumn[] | undefined,
412+
filter: string,
413+
orderByColumns?: string[],
414+
sortAscending?: boolean[],
415+
pageIndex: number = 1,
416+
pageSize: number = 20
417+
): string | undefined {
418+
419+
if (table === undefined || table === null
420+
|| DbRepository.hasPotentialSqlInjection(filter)
421+
) {
422+
return undefined;
423+
}
424+
425+
if (pageIndex < 1) { pageIndex = 1; }
426+
if (pageSize < 0) { pageSize = 20; }
427+
428+
const hasOrderingColumns: boolean = orderByColumns !== undefined && orderByColumns.length > 0;
429+
if (hasOrderingColumns && sortAscending !== undefined) {
430+
orderByColumns = orderByColumns?.map((col, index) => sortAscending[index] ? col : col + ' DESC');
431+
}
432+
433+
const whereExpression = filter ? `\nWHERE\n ${filter}` : '';
434+
const orderBy = hasOrderingColumns ?
435+
`\nORDER BY\n ${orderByColumns?.join(',')}` +
436+
`\nOFFSET ${(pageIndex - 1) * pageSize} ROWS FETCH NEXT ${pageSize} ROWS ONLY`
437+
: '';
438+
439+
const top = !hasOrderingColumns ? `TOP(${pageSize})` : '';
440+
441+
let columnsExpression = '';
442+
if (columns !== undefined && columns !== null && columns.length > 0) {
443+
columnsExpression = columns.map(col => {
444+
let statement: string;
445+
let colType = getBaseType(col.Type);
446+
if (colType === 'geography' || colType === 'geometry') {
447+
statement = `\n CONVERT(varchar(max), [${col.Name}].ToString()) as [${col.Name}]`;
448+
}
449+
else {
450+
statement = `\n [${col.Name}]`;
451+
}
452+
return statement;
453+
}).join(',');
454+
}
455+
else {
456+
columnsExpression = '*';
457+
}
458+
459+
const queryRows = `SELECT ${top} ${columnsExpression}` +
460+
`\nFROM\n [${table.Schema}].[${table.Name}]` +
461+
whereExpression +
462+
orderBy;
463+
464+
return queryRows;
465+
}
434466
}

src/repositories/db.repository.mysql.ts

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,17 @@ export class DbRepositoryMySQL implements IDbRepository{
293293
pageSize: number = 20
294294
): Promise<QueryResults<{ rows: any[]; count: number; }>> {
295295

296-
if (table === undefined || table === null
297-
|| DbRepository.hasPotentialSqlInjection(filter)
298-
) {
296+
const queryRows = this.getDbTableRowsQuery(
297+
table,
298+
columns,
299+
filter,
300+
orderByColumns,
301+
sortAscending,
302+
pageIndex,
303+
pageSize
304+
);
305+
306+
if (queryRows === undefined) {
299307
return {
300308
sessionId,
301309
data: {
@@ -304,36 +312,9 @@ export class DbRepositoryMySQL implements IDbRepository{
304312
}
305313
};
306314
}
307-
308-
if (pageIndex < 1) { pageIndex = 1; }
309-
if (pageSize < 0) { pageSize = 20; }
310-
311-
const hasOrderingColumns: boolean = orderByColumns !== undefined && orderByColumns.length > 0;
312-
if (hasOrderingColumns && sortAscending !== undefined) {
313-
orderByColumns = orderByColumns?.map((col, index) => sortAscending[index] ? `\`${col}\`` : `\`${col}\`` + ' DESC');
314-
}
315-
315+
316316
const whereExpression = filter ? 'WHERE ' + filter : '';
317-
const orderBy = hasOrderingColumns ? `ORDER BY ${orderByColumns?.join(',')}` : '';
318-
319-
let columnsExpression = '';
320-
if (columns !== undefined && columns !== null && columns.length > 0) {
321-
columnsExpression = columns.map(col => {
322-
let statement = `\`${col.Name}\``;
323-
return statement;
324-
}).join(',');
325-
}
326-
else {
327-
columnsExpression = '*';
328-
}
329-
330-
const queryRows = `
331-
SELECT ${columnsExpression}
332-
FROM \`${table.Schema}\`.\`${table.Name}\`
333-
${whereExpression}
334-
${orderBy}
335-
LIMIT ${(pageIndex - 1) * pageSize}, ${pageSize}`;
336-
317+
337318
const queryCount = `
338319
SELECT COUNT(*) as count
339320
FROM \`${table.Schema}\`.\`${table.Name}\`
@@ -385,4 +366,52 @@ export class DbRepositoryMySQL implements IDbRepository{
385366
}
386367
};
387368
}
369+
370+
371+
getDbTableRowsQuery(
372+
table: DatabaseObject,
373+
columns: DatabaseColumn[] | undefined,
374+
filter: string,
375+
orderByColumns?: string[],
376+
sortAscending?: boolean[],
377+
pageIndex: number = 1,
378+
pageSize: number = 20
379+
): string | undefined {
380+
381+
if (table === undefined || table === null
382+
|| DbRepository.hasPotentialSqlInjection(filter)
383+
) {
384+
return undefined;
385+
}
386+
387+
if (pageIndex < 1) { pageIndex = 1; }
388+
if (pageSize < 0) { pageSize = 20; }
389+
390+
const hasOrderingColumns: boolean = orderByColumns !== undefined && orderByColumns.length > 0;
391+
if (hasOrderingColumns && sortAscending !== undefined) {
392+
orderByColumns = orderByColumns?.map((col, index) => sortAscending[index] ? `\`${col}\`` : `\`${col}\`` + ' DESC');
393+
}
394+
395+
const whereExpression = filter ? `\nWHERE\n ${filter}` : '';
396+
const orderBy = hasOrderingColumns ? `\nORDER BY\n ${orderByColumns?.join(',')}` : '';
397+
398+
let columnsExpression = '';
399+
if (columns !== undefined && columns !== null && columns.length > 0) {
400+
columnsExpression = columns.map(col => {
401+
let statement = `\n \`${col.Name}\``;
402+
return statement;
403+
}).join(',');
404+
}
405+
else {
406+
columnsExpression = '*';
407+
}
408+
409+
const queryRows = `SELECT ${columnsExpression}` +
410+
`\nFROM\n \`${table.Schema}\`.\`${table.Name}\`` +
411+
whereExpression +
412+
orderBy +
413+
`\nLIMIT ${(pageIndex - 1) * pageSize}, ${pageSize}`;
414+
415+
return queryRows;
416+
}
388417
}

0 commit comments

Comments
 (0)