Skip to content

Commit 4e2ea61

Browse files
committed
Split up query running, upgrade running, and operations on queries post run.
1 parent 4ebad72 commit 4e2ea61

File tree

10 files changed

+400
-326
lines changed

10 files changed

+400
-326
lines changed

extensions/ql-vscode/src/databases-ui.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { commands, Event, EventEmitter, ExtensionContext, ProviderResult, TreeDa
44
import * as cli from './cli';
55
import { DatabaseItem, DatabaseManager, getUpgradesDirectories } from "./databases";
66
import { logger } from "./logging";
7-
import { clearCacheInDatabase, upgradeDatabase, UserCancellationException } from "./queries";
7+
import { clearCacheInDatabase, UserCancellationException } from "./run-queries";
88
import * as qsClient from './queryserver-client';
99
import { getOnDiskWorkspaceFolders } from "./helpers";
10+
import { upgradeDatabase } from './upgrades';
1011

1112
type ThemableIconPath = { light: string, dark: string } | string;
1213

extensions/ql-vscode/src/extension.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import * as helpers from './helpers';
1010
import { spawnIdeServer } from './ide-server';
1111
import { InterfaceManager, WebviewReveal } from './interface';
1212
import { ideServerLogger, logger, queryServerLogger } from './logging';
13-
import { compileAndRunQueryAgainstDatabase, EvaluationInfo, tmpDirDisposal, UserCancellationException } from './queries';
14-
import { QueryHistoryItem, QueryHistoryManager } from './query-history';
15-
import * as qsClient from './queryserver-client';
13+
import { compileAndRunQueryAgainstDatabase, tmpDirDisposal, UserCancellationException } from './run-queries';
14+
import { QueryHistoryManager } from './query-history';
1615
import { CodeQLCliServer } from './cli';
1716
import { assertNever } from './helpers-pure';
17+
import * as qsClient from './queryserver-client';
18+
import { CompletedQuery } from './query-results';
1819

1920
/**
2021
* extension.ts
@@ -244,13 +245,13 @@ async function activateWithInstalledDistribution(ctx: ExtensionContext, distribu
244245
const databaseUI = new DatabaseUI(ctx, cliServer, dbm, qs);
245246
ctx.subscriptions.push(databaseUI);
246247

247-
const qhm = new QueryHistoryManager(ctx, async item => showResultsForInfo(item.info, WebviewReveal.Forced));
248+
const qhm = new QueryHistoryManager(ctx, async item => showResultsForCompletedQuery(item, WebviewReveal.Forced));
248249
const intm = new InterfaceManager(ctx, dbm, cliServer, queryServerLogger);
249250
ctx.subscriptions.push(intm);
250251
archiveFilesystemProvider.activate(ctx);
251252

252-
async function showResultsForInfo(info: EvaluationInfo, forceReveal: WebviewReveal): Promise<void> {
253-
await intm.showResults(info, forceReveal, false);
253+
async function showResultsForCompletedQuery(query: CompletedQuery, forceReveal: WebviewReveal): Promise<void> {
254+
await intm.showResults(query, forceReveal, false);
254255
}
255256

256257
async function compileAndRunQuery(quickEval: boolean, selectedQuery: Uri | undefined) {
@@ -261,8 +262,8 @@ async function activateWithInstalledDistribution(ctx: ExtensionContext, distribu
261262
throw new Error('Can\'t run query without a selected database');
262263
}
263264
const info = await compileAndRunQueryAgainstDatabase(cliServer, qs, dbItem, quickEval, selectedQuery);
264-
await showResultsForInfo(info, WebviewReveal.NotForced);
265-
qhm.push(new QueryHistoryItem(info));
265+
const item = qhm.addQuery(info);
266+
await showResultsForCompletedQuery(item, WebviewReveal.NotForced);
266267
}
267268
catch (e) {
268269
if (e instanceof UserCancellationException) {

extensions/ql-vscode/src/helpers.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as path from 'path';
22
import { CancellationToken, ProgressOptions, window as Window, workspace } from 'vscode';
33
import { logger } from './logging';
4-
import { EvaluationInfo } from './queries';
4+
import { QueryInfo } from './run-queries';
55

66
export interface ProgressUpdate {
77
/**
@@ -121,16 +121,16 @@ export function getOnDiskWorkspaceFolders() {
121121
* Gets a human-readable name for an evaluated query.
122122
* Uses metadata if it exists, and defaults to the query file name.
123123
*/
124-
export function getQueryName(info: EvaluationInfo) {
124+
export function getQueryName(query: QueryInfo) {
125125
// Queries run through quick evaluation are not usually the entire query file.
126126
// Label them differently and include the line numbers.
127-
if (info.query.quickEvalPosition !== undefined) {
128-
const { line, endLine, fileName } = info.query.quickEvalPosition;
127+
if (query.quickEvalPosition !== undefined) {
128+
const { line, endLine, fileName } = query.quickEvalPosition;
129129
const lineInfo = line === endLine ? `${line}` : `${line}-${endLine}`;
130130
return `Quick evaluation of ${path.basename(fileName)}:${lineInfo}`;
131-
} else if (info.query.metadata && info.query.metadata.name) {
132-
return info.query.metadata.name;
131+
} else if (query.metadata && query.metadata.name) {
132+
return query.metadata.name;
133133
} else {
134-
return path.basename(info.query.program.queryPath);
134+
return path.basename(query.program.queryPath);
135135
}
136136
}

extensions/ql-vscode/src/interface-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface Interpretation {
3434

3535
export interface ResultsInfo {
3636
resultsPath: string;
37+
interpretedResultsPath: string;
3738
}
3839

3940
export interface SortedResultSetInfo {

extensions/ql-vscode/src/interface.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import { assertNever } from './helpers-pure';
1515
import { FromResultsViewMsg, Interpretation, IntoResultsViewMsg, ResultsInfo, SortedResultSetInfo, SortedResultsMap, INTERPRETED_RESULTS_PER_RUN_LIMIT, QueryMetadata } from './interface-types';
1616
import { Logger } from './logging';
1717
import * as messages from './messages';
18-
import { EvaluationInfo, interpretResults, QueryInfo, tmpDir } from './queries';
18+
import { tmpDir, QueryInfo } from './run-queries';
19+
import { CompletedQuery, interpretResults } from './query-results';
1920

2021
/**
2122
* interface.ts
@@ -87,7 +88,7 @@ export function webviewUriToFileUri(webviewUri: string): Uri {
8788
}
8889

8990
export class InterfaceManager extends DisposableObject {
90-
private _displayedEvaluationInfo?: EvaluationInfo;
91+
private _displayedQuery?: CompletedQuery;
9192
private _panel: vscode.WebviewPanel | undefined;
9293
private _panelLoaded = false;
9394
private _panelLoadedCallBacks: (() => void)[] = [];
@@ -180,14 +181,14 @@ export class InterfaceManager extends DisposableObject {
180181
this._panelLoadedCallBacks = [];
181182
break;
182183
case 'changeSort': {
183-
if (this._displayedEvaluationInfo === undefined) {
184+
if (this._displayedQuery === undefined) {
184185
showAndLogErrorMessage("Failed to sort results since evaluation info was unknown.");
185186
break;
186187
}
187188
// Notify the webview that it should expect new results.
188189
await this.postMessage({ t: 'resultsUpdating' });
189-
await this._displayedEvaluationInfo.query.updateSortState(this.cliServer, msg.resultSetName, msg.sortState);
190-
await this.showResults(this._displayedEvaluationInfo, WebviewReveal.NotForced, true);
190+
await this._displayedQuery.updateSortState(this.cliServer, msg.resultSetName, msg.sortState);
191+
await this.showResults(this._displayedQuery, WebviewReveal.NotForced, true);
191192
break;
192193
}
193194
default:
@@ -218,18 +219,18 @@ export class InterfaceManager extends DisposableObject {
218219
* UI interaction requesting results, e.g. clicking on a query
219220
* history entry.
220221
*/
221-
public async showResults(info: EvaluationInfo, forceReveal: WebviewReveal, shouldKeepOldResultsWhileRendering: boolean = false): Promise<void> {
222-
if (info.result.resultType !== messages.QueryResultType.SUCCESS) {
222+
public async showResults(results: CompletedQuery, forceReveal: WebviewReveal, shouldKeepOldResultsWhileRendering: boolean = false): Promise<void> {
223+
if (results.result.resultType !== messages.QueryResultType.SUCCESS) {
223224
return;
224225
}
225226

226-
const interpretation = await this.interpretResultsInfo(info.query, info.query.resultsInfo);
227+
const interpretation = await this.interpretResultsInfo(results.query);
227228

228229
const sortedResultsMap: SortedResultsMap = {};
229-
info.query.sortedResultsInfo.forEach((v, k) =>
230+
results.sortedResultsInfo.forEach((v, k) =>
230231
sortedResultsMap[k] = this.convertPathPropertiesToWebviewUris(v));
231232

232-
this._displayedEvaluationInfo = info;
233+
this._displayedQuery = results;
233234

234235
const panel = this.getPanel();
235236
await this.waitForPanelLoaded();
@@ -242,7 +243,7 @@ export class InterfaceManager extends DisposableObject {
242243
// more asynchronous message to not so abruptly interrupt
243244
// user's workflow by immediately revealing the panel.
244245
const showButton = 'View Results';
245-
const queryName = helpers.getQueryName(info);
246+
const queryName = results.queryName;
246247
const resultPromise = vscode.window.showInformationMessage(
247248
`Finished running query ${(queryName.length > 0) ? ` “${queryName}”` : ''}.`,
248249
showButton
@@ -259,11 +260,11 @@ export class InterfaceManager extends DisposableObject {
259260
await this.postMessage({
260261
t: 'setState',
261262
interpretation,
262-
resultsPath: this.convertPathToWebviewUri(info.query.resultsInfo.resultsPath),
263+
resultsPath: this.convertPathToWebviewUri(results.query.resultsInfo.resultsPath),
263264
sortedResultsMap,
264-
database: info.database,
265+
database: results.database,
265266
shouldKeepOldResultsWhileRendering,
266-
metadata: info.query.metadata
267+
metadata: results.query.metadata
267268
});
268269
}
269270

@@ -288,7 +289,7 @@ private async getTruncatedResults(metadata : QueryMetadata | undefined ,resultsP
288289
;
289290
}
290291

291-
private async interpretResultsInfo(query: QueryInfo, resultsInfo: ResultsInfo): Promise<Interpretation | undefined> {
292+
private async interpretResultsInfo(query: QueryInfo): Promise<Interpretation | undefined> {
292293
let interpretation: Interpretation | undefined = undefined;
293294
if (query.hasInterpretedResults()
294295
&& query.quickEvalPosition === undefined // never do results interpretation if quickEval
@@ -299,7 +300,7 @@ private async getTruncatedResults(metadata : QueryMetadata | undefined ,resultsP
299300
const sourceInfo = sourceArchiveUri === undefined ?
300301
undefined :
301302
{ sourceArchive: sourceArchiveUri.fsPath, sourceLocationPrefix };
302-
interpretation = await this.getTruncatedResults(query.metadata, resultsInfo.resultsPath, sourceInfo, sourceLocationPrefix);
303+
interpretation = await this.getTruncatedResults(query.metadata, query.resultsInfo.resultsPath, sourceInfo, sourceLocationPrefix);
303304
}
304305
catch (e) {
305306
// If interpretation fails, accept the error and continue
Lines changed: 29 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import * as vscode from 'vscode';
22
import { ExtensionContext, window as Window } from 'vscode';
3-
import { EvaluationInfo, QueryInfo } from './queries';
4-
import * as helpers from './helpers';
5-
import * as messages from './messages';
3+
import { CompletedQuery } from './query-results';
4+
import { QueryWithResults } from './run-queries';
65
/**
76
* query-history.ts
87
* ------------
@@ -12,72 +11,32 @@ import * as messages from './messages';
1211
* `TreeDataProvider` subclass below.
1312
*/
1413

15-
/**
16-
* One item in the user-displayed list of queries that have been run.
17-
*/
18-
export class QueryHistoryItem {
19-
queryName: string;
20-
time: string;
21-
databaseName: string;
22-
info: EvaluationInfo;
23-
24-
constructor(info: EvaluationInfo) {
25-
this.queryName = helpers.getQueryName(info);
26-
this.databaseName = info.database.name;
27-
this.info = info;
28-
this.time = new Date().toLocaleString();
29-
}
30-
31-
get statusString(): string {
32-
switch (this.info.result.resultType) {
33-
case messages.QueryResultType.CANCELLATION:
34-
return `cancelled after ${this.info.result.evaluationTime / 1000} seconds`;
35-
case messages.QueryResultType.OOM:
36-
return `out of memory`;
37-
case messages.QueryResultType.SUCCESS:
38-
return `finished in ${this.info.result.evaluationTime / 1000} seconds`;
39-
case messages.QueryResultType.TIMEOUT:
40-
return `timed out after ${this.info.result.evaluationTime / 1000} seconds`;
41-
case messages.QueryResultType.OTHER_ERROR:
42-
default:
43-
return `failed`;
44-
}
45-
}
46-
47-
toString(): string {
48-
const { databaseName, queryName, time } = this;
49-
return `[${time}] ${queryName} on ${databaseName} - ${this.statusString}`;
50-
}
51-
}
52-
5314
/**
5415
* Tree data provider for the query history view.
5516
*/
56-
class HistoryTreeDataProvider implements vscode.TreeDataProvider<QueryHistoryItem> {
17+
class HistoryTreeDataProvider implements vscode.TreeDataProvider<CompletedQuery> {
5718

5819
/**
5920
* XXX: This idiom for how to get a `.fire()`-able event emitter was
6021
* cargo culted from another vscode extension. It seems rather
6122
* involved and I hope there's something better that can be done
6223
* instead.
6324
*/
64-
private _onDidChangeTreeData: vscode.EventEmitter<QueryHistoryItem | undefined> = new vscode.EventEmitter<QueryHistoryItem | undefined>();
65-
readonly onDidChangeTreeData: vscode.Event<QueryHistoryItem | undefined> = this._onDidChangeTreeData.event;
25+
private _onDidChangeTreeData: vscode.EventEmitter<CompletedQuery | undefined> = new vscode.EventEmitter<CompletedQuery | undefined>();
26+
readonly onDidChangeTreeData: vscode.Event<CompletedQuery | undefined> = this._onDidChangeTreeData.event;
6627

67-
private ctx: ExtensionContext;
68-
private history: QueryHistoryItem[] = [];
28+
private history: CompletedQuery[] = [];
6929

7030
/**
7131
* When not undefined, must be reference-equal to an item in `this.databases`.
7232
*/
73-
private current: QueryHistoryItem | undefined;
33+
private current: CompletedQuery | undefined;
7434

75-
constructor(ctx: ExtensionContext) {
76-
this.ctx = ctx;
35+
constructor() {
7736
this.history = [];
7837
}
7938

80-
getTreeItem(element: QueryHistoryItem): vscode.TreeItem {
39+
getTreeItem(element: CompletedQuery): vscode.TreeItem {
8140
const it = new vscode.TreeItem(element.toString());
8241

8342
it.command = {
@@ -89,7 +48,7 @@ class HistoryTreeDataProvider implements vscode.TreeDataProvider<QueryHistoryIte
8948
return it;
9049
}
9150

92-
getChildren(element?: QueryHistoryItem): vscode.ProviderResult<QueryHistoryItem[]> {
51+
getChildren(element?: CompletedQuery): vscode.ProviderResult<CompletedQuery[]> {
9352
if (element == undefined) {
9453
return this.history;
9554
}
@@ -98,25 +57,25 @@ class HistoryTreeDataProvider implements vscode.TreeDataProvider<QueryHistoryIte
9857
}
9958
}
10059

101-
getParent(element: QueryHistoryItem): vscode.ProviderResult<QueryHistoryItem> {
60+
getParent(element: CompletedQuery): vscode.ProviderResult<CompletedQuery> {
10261
return null;
10362
}
10463

105-
getCurrent(): QueryHistoryItem | undefined {
64+
getCurrent(): CompletedQuery | undefined {
10665
return this.current;
10766
}
10867

109-
push(item: QueryHistoryItem): void {
68+
push(item: CompletedQuery): void {
11069
this.current = item;
11170
this.history.push(item);
11271
this._onDidChangeTreeData.fire();
11372
}
11473

115-
setCurrentItem(item: QueryHistoryItem) {
74+
setCurrentItem(item: CompletedQuery) {
11675
this.current = item;
11776
}
11877

119-
remove(item: QueryHistoryItem) {
78+
remove(item: CompletedQuery) {
12079
if (this.current === item)
12180
this.current = undefined;
12281
const index = this.history.findIndex(i => i === item);
@@ -141,23 +100,24 @@ const DOUBLE_CLICK_TIME = 500;
141100
export class QueryHistoryManager {
142101
treeDataProvider: HistoryTreeDataProvider;
143102
ctx: ExtensionContext;
144-
treeView: vscode.TreeView<QueryHistoryItem>;
145-
selectedCallback: ((item: QueryHistoryItem) => void) | undefined;
146-
lastItemClick: { time: Date, item: QueryHistoryItem } | undefined;
103+
treeView: vscode.TreeView<CompletedQuery>;
104+
selectedCallback: ((item: CompletedQuery) => void) | undefined;
105+
lastItemClick: { time: Date, item: CompletedQuery } | undefined;
106+
147107

148-
async invokeCallbackOn(queryHistoryItem: QueryHistoryItem) {
108+
async invokeCallbackOn(queryHistoryItem: CompletedQuery) {
149109
if (this.selectedCallback !== undefined) {
150110
const sc = this.selectedCallback;
151111
await sc(queryHistoryItem);
152112
}
153113
}
154114

155-
async handleOpenQuery(queryHistoryItem: QueryHistoryItem) {
156-
const textDocument = await vscode.workspace.openTextDocument(vscode.Uri.file(queryHistoryItem.info.query.program.queryPath));
115+
async handleOpenQuery(queryHistoryItem: CompletedQuery) {
116+
const textDocument = await vscode.workspace.openTextDocument(vscode.Uri.file(queryHistoryItem.query.program.queryPath));
157117
await vscode.window.showTextDocument(textDocument, vscode.ViewColumn.One);
158118
}
159119

160-
async handleRemoveHistoryItem(queryHistoryItem: QueryHistoryItem) {
120+
async handleRemoveHistoryItem(queryHistoryItem: CompletedQuery) {
161121
this.treeDataProvider.remove(queryHistoryItem);
162122
const current = this.treeDataProvider.getCurrent();
163123
if (current !== undefined) {
@@ -166,7 +126,7 @@ export class QueryHistoryManager {
166126
}
167127
}
168128

169-
async handleItemClicked(queryHistoryItem: QueryHistoryItem) {
129+
async handleItemClicked(queryHistoryItem: CompletedQuery) {
170130
this.treeDataProvider.setCurrentItem(queryHistoryItem);
171131

172132
const now = new Date();
@@ -185,10 +145,10 @@ export class QueryHistoryManager {
185145
}
186146
}
187147

188-
constructor(ctx: ExtensionContext, selectedCallback?: (item: QueryHistoryItem) => Promise<void>) {
148+
constructor(ctx: ExtensionContext, selectedCallback?: (item: CompletedQuery) => Promise<void>) {
189149
this.ctx = ctx;
190150
this.selectedCallback = selectedCallback;
191-
const treeDataProvider = this.treeDataProvider = new HistoryTreeDataProvider(ctx);
151+
const treeDataProvider = this.treeDataProvider = new HistoryTreeDataProvider();
192152
this.treeView = Window.createTreeView('codeQLQueryHistory', { treeDataProvider });
193153
this.treeView.onDidChangeSelection(async ev => {
194154
if (ev.selection.length == 0) {
@@ -204,8 +164,10 @@ export class QueryHistoryManager {
204164
}));
205165
}
206166

207-
push(item: QueryHistoryItem) {
167+
addQuery(info: QueryWithResults): CompletedQuery {
168+
const item = new CompletedQuery(info);
208169
this.treeDataProvider.push(item);
209170
this.treeView.reveal(item, { select: true });
171+
return item;
210172
}
211173
}

0 commit comments

Comments
 (0)