Skip to content

Commit e4406f4

Browse files
Merge branch 'main' into elena/yer-a-wizard-query
2 parents 460da1e + b0940e6 commit e4406f4

File tree

3 files changed

+185
-55
lines changed

3 files changed

+185
-55
lines changed

extensions/ql-vscode/src/distribution.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ export class DistributionManager implements DistributionProvider {
215215
minSecondsSinceLastUpdateCheck: number,
216216
): Promise<DistributionUpdateCheckResult> {
217217
const distribution = await this.getDistributionWithoutVersionCheck();
218+
if (distribution === undefined) {
219+
minSecondsSinceLastUpdateCheck = 0;
220+
}
218221
const extensionManagedCodeQlPath =
219222
await this.extensionSpecificDistributionManager.getCodeQlPathWithoutVersionCheck();
220223
if (distribution?.codeQlPath !== extensionManagedCodeQlPath) {

extensions/ql-vscode/src/view/results/__tests__/results.spec.tsx

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from "react";
2-
import { render as reactRender, screen } from "@testing-library/react";
2+
import { act, render as reactRender, screen } from "@testing-library/react";
33
import { ResultsApp } from "../results";
44
import {
55
Interpretation,
@@ -20,18 +20,20 @@ const exampleSarif = fs.readJSONSync(
2020
describe(ResultsApp.name, () => {
2121
const render = () => reactRender(<ResultsApp />);
2222
const postMessage = async (msg: IntoResultsViewMsg) => {
23-
// window.postMessage doesn't set the origin correctly, see
24-
// https://github.com/jsdom/jsdom/issues/2745
25-
window.dispatchEvent(
26-
new MessageEvent("message", {
27-
source: window,
28-
origin: window.location.origin,
29-
data: msg,
30-
}),
31-
);
23+
await act(async () => {
24+
// window.postMessage doesn't set the origin correctly, see
25+
// https://github.com/jsdom/jsdom/issues/2745
26+
window.dispatchEvent(
27+
new MessageEvent("message", {
28+
source: window,
29+
origin: window.location.origin,
30+
data: msg,
31+
}),
32+
);
3233

33-
// The event is dispatched asynchronously, so we need to wait for it to be handled.
34-
await new Promise((resolve) => setTimeout(resolve, 0));
34+
// The event is dispatched asynchronously, so we need to wait for it to be handled.
35+
await new Promise((resolve) => setTimeout(resolve, 0));
36+
});
3537
};
3638

3739
it("renders results", async () => {
@@ -95,6 +97,7 @@ describe(ResultsApp.name, () => {
9597
},
9698
},
9799
};
100+
98101
await postMessage(message);
99102

100103
expect(
@@ -117,4 +120,84 @@ describe(ResultsApp.name, () => {
117120
screen.getByText("'x' is assigned a value but never used."),
118121
).toBeInTheDocument();
119122
});
123+
124+
it("renders results when switching between queries with different result set names", async () => {
125+
render();
126+
127+
await postMessage({
128+
t: "setState",
129+
interpretation: undefined,
130+
origResultsPaths: {
131+
resultsPath: "/a/b/c/results.bqrs",
132+
interpretedResultsPath: "/a/b/c/interpretedResults.sarif",
133+
},
134+
resultsPath: "/a/b/c/results.bqrs",
135+
parsedResultSets: {
136+
pageNumber: 0,
137+
pageSize: 200,
138+
numPages: 1,
139+
numInterpretedPages: 0,
140+
resultSet: {
141+
schema: {
142+
name: "#select",
143+
rows: 1,
144+
columns: [{ kind: "s" }],
145+
pagination: { "step-size": 200, offsets: [13] },
146+
},
147+
rows: [["foobar1"]],
148+
t: "RawResultSet",
149+
},
150+
resultSetNames: ["#select"],
151+
},
152+
sortedResultsMap: {},
153+
database: {
154+
name: "test-db",
155+
databaseUri: "test-db-uri",
156+
},
157+
shouldKeepOldResultsWhileRendering: false,
158+
metadata: {},
159+
queryName: "empty.ql",
160+
queryPath: "/a/b/c/empty.ql",
161+
});
162+
163+
expect(screen.getByText("foobar1")).toBeInTheDocument();
164+
165+
await postMessage({
166+
t: "setState",
167+
interpretation: undefined,
168+
origResultsPaths: {
169+
resultsPath: "/a/b/c/results.bqrs",
170+
interpretedResultsPath: "/a/b/c/interpretedResults.sarif",
171+
},
172+
resultsPath: "/a/b/c/results.bqrs",
173+
parsedResultSets: {
174+
pageNumber: 0,
175+
pageSize: 200,
176+
numPages: 1,
177+
numInterpretedPages: 0,
178+
resultSet: {
179+
schema: {
180+
name: "#Quick_evaluation_of_expression",
181+
rows: 1,
182+
columns: [{ name: "#expr_result", kind: "s" }],
183+
pagination: { "step-size": 200, offsets: [49] },
184+
},
185+
rows: [["foobar2"]],
186+
t: "RawResultSet",
187+
},
188+
resultSetNames: ["#Quick_evaluation_of_expression"],
189+
},
190+
sortedResultsMap: {},
191+
database: {
192+
name: "test-db",
193+
databaseUri: "test-db-uri",
194+
},
195+
shouldKeepOldResultsWhileRendering: false,
196+
metadata: {},
197+
queryName: "Quick evaluation of empty.ql:1",
198+
queryPath: "/a/b/c/empty.ql",
199+
});
200+
201+
expect(screen.getByText("foobar2")).toBeInTheDocument();
202+
});
120203
});

extensions/ql-vscode/src/view/results/result-tables.tsx

Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,52 @@ function renderResultCountString(resultSet: ResultSet): JSX.Element {
7878
);
7979
}
8080

81+
function getInterpretedTableName(interpretation: Interpretation): string {
82+
return interpretation.data.t === "GraphInterpretationData"
83+
? GRAPH_TABLE_NAME
84+
: ALERTS_TABLE_NAME;
85+
}
86+
87+
function getResultSetNames(
88+
interpretation: Interpretation | undefined,
89+
parsedResultSets: ParsedResultSets,
90+
): string[] {
91+
return interpretation
92+
? parsedResultSets.resultSetNames.concat([
93+
getInterpretedTableName(interpretation),
94+
])
95+
: parsedResultSets.resultSetNames;
96+
}
97+
98+
function getResultSets(
99+
rawResultSets: readonly ResultSet[],
100+
interpretation: Interpretation | undefined,
101+
): ResultSet[] {
102+
const resultSets: ResultSet[] =
103+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
104+
// @ts-ignore 2783 Avoid compilation error for overwriting the t property
105+
rawResultSets.map((rs) => ({ t: "RawResultSet", ...rs }));
106+
107+
if (interpretation !== undefined) {
108+
const tableName = getInterpretedTableName(interpretation);
109+
resultSets.push({
110+
t: "InterpretedResultSet",
111+
// FIXME: The values of version, columns, tupleCount are
112+
// unused stubs because a InterpretedResultSet schema isn't used the
113+
// same way as a RawResultSet. Probably should pull `name` field
114+
// out.
115+
schema: {
116+
name: tableName,
117+
rows: 1,
118+
columns: [],
119+
},
120+
name: tableName,
121+
interpretation,
122+
});
123+
}
124+
return resultSets;
125+
}
126+
81127
/**
82128
* Displays multiple `ResultTable` tables, where the table to be displayed is selected by a
83129
* dropdown.
@@ -86,51 +132,13 @@ export class ResultTables extends React.Component<
86132
ResultTablesProps,
87133
ResultTablesState
88134
> {
89-
private getResultSets(): ResultSet[] {
90-
const resultSets: ResultSet[] =
91-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
92-
// @ts-ignore 2783
93-
this.props.rawResultSets.map((rs) => ({ t: "RawResultSet", ...rs }));
94-
95-
if (this.props.interpretation !== undefined) {
96-
const tableName = this.getInterpretedTableName();
97-
resultSets.push({
98-
t: "InterpretedResultSet",
99-
// FIXME: The values of version, columns, tupleCount are
100-
// unused stubs because a InterpretedResultSet schema isn't used the
101-
// same way as a RawResultSet. Probably should pull `name` field
102-
// out.
103-
schema: {
104-
name: tableName,
105-
rows: 1,
106-
columns: [],
107-
},
108-
name: tableName,
109-
interpretation: this.props.interpretation,
110-
});
111-
}
112-
return resultSets;
113-
}
114-
115-
private getInterpretedTableName(): string {
116-
return this.props.interpretation?.data.t === "GraphInterpretationData"
117-
? GRAPH_TABLE_NAME
118-
: ALERTS_TABLE_NAME;
119-
}
120-
121-
private getResultSetNames(): string[] {
122-
return this.props.interpretation
123-
? this.props.parsedResultSets.resultSetNames.concat([
124-
this.getInterpretedTableName(),
125-
])
126-
: this.props.parsedResultSets.resultSetNames;
127-
}
128-
129135
constructor(props: ResultTablesProps) {
130136
super(props);
131137
const selectedTable =
132138
props.parsedResultSets.selectedTable ||
133-
getDefaultResultSet(this.getResultSets());
139+
getDefaultResultSet(
140+
getResultSets(props.rawResultSets, props.interpretation),
141+
);
134142
const selectedPage = `${props.parsedResultSets.pageNumber + 1}`;
135143
this.state = {
136144
selectedTable,
@@ -139,6 +147,36 @@ export class ResultTables extends React.Component<
139147
};
140148
}
141149

150+
componentDidUpdate(
151+
prevProps: Readonly<ResultTablesProps>,
152+
prevState: Readonly<ResultTablesState>,
153+
snapshot?: any,
154+
) {
155+
const resultSetExists =
156+
this.props.parsedResultSets.resultSetNames.some(
157+
(v) => this.state.selectedTable === v,
158+
) ||
159+
getResultSets(this.props.rawResultSets, this.props.interpretation).some(
160+
(v) => this.state.selectedTable === v.schema.name,
161+
);
162+
163+
// If the selected result set does not exist, select the default result set.
164+
if (!resultSetExists) {
165+
this.setState((state, props) => {
166+
const selectedTable =
167+
props.parsedResultSets.selectedTable ||
168+
getDefaultResultSet(
169+
getResultSets(props.rawResultSets, props.interpretation),
170+
);
171+
172+
return {
173+
selectedTable,
174+
selectedPage: `${props.parsedResultSets.pageNumber + 1}`,
175+
};
176+
});
177+
}
178+
}
179+
142180
untoggleProblemsView() {
143181
this.setState({
144182
problemsViewSelected: false,
@@ -303,8 +341,14 @@ export class ResultTables extends React.Component<
303341

304342
render(): React.ReactNode {
305343
const { selectedTable } = this.state;
306-
const resultSets = this.getResultSets();
307-
const resultSetNames = this.getResultSetNames();
344+
const resultSets = getResultSets(
345+
this.props.rawResultSets,
346+
this.props.interpretation,
347+
);
348+
const resultSetNames = getResultSetNames(
349+
this.props.interpretation,
350+
this.props.parsedResultSets,
351+
);
308352

309353
const resultSet = resultSets.find(
310354
(resultSet) => resultSet.schema.name === selectedTable,

0 commit comments

Comments
 (0)