Extract external API usage query to separate file

This commit is contained in:
Koen Vlaswinkel
2023-04-05 12:36:44 +02:00
parent d9b362ddff
commit c245f338f5
2 changed files with 122 additions and 92 deletions

View File

@@ -5,21 +5,14 @@ import {
ToDataExtensionsEditorMessage,
} from "../pure/interface-types";
import { ProgressUpdate } from "../progress";
import { extLogger, TeeLogger } from "../common";
import { CoreCompletedQuery, QueryRunner } from "../queryRunner";
import { qlpackOfDatabase } from "../contextual/queryResolver";
import { file } from "tmp-promise";
import { writeFile } from "fs-extra";
import { dump } from "js-yaml";
import {
getOnDiskWorkspaceFolders,
showAndLogExceptionWithTelemetry,
} from "../helpers";
import { QueryRunner } from "../queryRunner";
import { showAndLogExceptionWithTelemetry } from "../helpers";
import { DatabaseItem } from "../local-databases";
import { CodeQLCliServer } from "../cli";
import { decodeBqrsToExternalApiUsages } from "./bqrs";
import { redactableError } from "../pure/errors";
import { asError, getErrorMessage } from "../pure/helpers-pure";
import { getResults, runQuery } from "./external-api-usage-query";
export class DataExtensionsEditorView extends AbstractWebview<
ToDataExtensionsEditorMessage,
@@ -76,22 +69,34 @@ export class DataExtensionsEditorView extends AbstractWebview<
}
protected async loadExternalApiUsages(): Promise<void> {
const cancellationTokenSource = new CancellationTokenSource();
try {
const queryResult = await this.runQuery();
const queryResult = await runQuery({
cliServer: this.cliServer,
queryRunner: this.queryRunner,
databaseItem: this.databaseItem,
queryStorageDir: this.queryStorageDir,
progress: (progressUpdate: ProgressUpdate) => {
void this.showProgress(progressUpdate, 1500);
},
token: cancellationTokenSource.token,
});
if (!queryResult) {
await this.clearProgress();
return;
}
await this.showProgress({
message: "Loading results",
message: "Decoding results",
step: 1100,
maxStep: 1500,
});
const bqrsPath = queryResult.outputDir.bqrsPath;
const bqrsChunk = await this.getResults(bqrsPath);
const bqrsChunk = await getResults({
cliServer: this.cliServer,
bqrsPath: queryResult.outputDir.bqrsPath,
});
if (!bqrsChunk) {
await this.clearProgress();
return;
@@ -120,83 +125,6 @@ export class DataExtensionsEditorView extends AbstractWebview<
}
}
private async runQuery(): Promise<CoreCompletedQuery | undefined> {
const qlpacks = await qlpackOfDatabase(this.cliServer, this.databaseItem);
const packsToSearch = [qlpacks.dbschemePack];
if (qlpacks.queryPack) {
packsToSearch.push(qlpacks.queryPack);
}
const suiteFile = (
await file({
postfix: ".qls",
})
).path;
const suiteYaml = [];
for (const qlpack of packsToSearch) {
suiteYaml.push({
from: qlpack,
queries: ".",
include: {
id: `${this.databaseItem.language}/telemetry/fetch-external-apis`,
},
});
}
await writeFile(suiteFile, dump(suiteYaml), "utf8");
const queries = await this.cliServer.resolveQueriesInSuite(
suiteFile,
getOnDiskWorkspaceFolders(),
);
if (queries.length !== 1) {
void extLogger.log(`Expected exactly one query, got ${queries.length}`);
return;
}
const query = queries[0];
const tokenSource = new CancellationTokenSource();
const queryRun = this.queryRunner.createQueryRun(
this.databaseItem.databaseUri.fsPath,
{ queryPath: query, quickEvalPosition: undefined },
false,
getOnDiskWorkspaceFolders(),
undefined,
this.queryStorageDir,
undefined,
undefined,
);
return queryRun.evaluate(
(update) => this.showProgress(update, 1500),
tokenSource.token,
new TeeLogger(this.queryRunner.logger, queryRun.outputDir.logPath),
);
}
private async getResults(bqrsPath: string) {
const bqrsInfo = await this.cliServer.bqrsInfo(bqrsPath);
if (bqrsInfo["result-sets"].length !== 1) {
void extLogger.log(
`Expected exactly one result set, got ${bqrsInfo["result-sets"].length}`,
);
return undefined;
}
const resultSet = bqrsInfo["result-sets"][0];
await this.showProgress({
message: "Decoding results",
step: 1200,
maxStep: 1500,
});
return this.cliServer.bqrsDecode(bqrsPath, resultSet.name);
}
private async showProgress(update: ProgressUpdate, maxStep?: number) {
await this.postMessage({
t: "showProgress",

View File

@@ -0,0 +1,102 @@
import { CoreCompletedQuery, QueryRunner } from "../queryRunner";
import { qlpackOfDatabase } from "../contextual/queryResolver";
import { file } from "tmp-promise";
import { writeFile } from "fs-extra";
import { dump } from "js-yaml";
import { getOnDiskWorkspaceFolders } from "../helpers";
import { extLogger, TeeLogger } from "../common";
import { CancellationToken } from "vscode";
import { CodeQLCliServer } from "../cli";
import { DatabaseItem } from "../local-databases";
import { ProgressCallback } from "../progress";
export type RunQueryOptions = {
cliServer: CodeQLCliServer;
queryRunner: QueryRunner;
databaseItem: DatabaseItem;
queryStorageDir: string;
progress: ProgressCallback;
token: CancellationToken;
};
export async function runQuery({
cliServer,
queryRunner,
databaseItem,
queryStorageDir,
progress,
token,
}: RunQueryOptions): Promise<CoreCompletedQuery | undefined> {
const qlpacks = await qlpackOfDatabase(cliServer, databaseItem);
const packsToSearch = [qlpacks.dbschemePack];
if (qlpacks.queryPack) {
packsToSearch.push(qlpacks.queryPack);
}
const suiteFile = (
await file({
postfix: ".qls",
})
).path;
const suiteYaml = [];
for (const qlpack of packsToSearch) {
suiteYaml.push({
from: qlpack,
queries: ".",
include: {
id: `${databaseItem.language}/telemetry/fetch-external-apis`,
},
});
}
await writeFile(suiteFile, dump(suiteYaml), "utf8");
const queries = await cliServer.resolveQueriesInSuite(
suiteFile,
getOnDiskWorkspaceFolders(),
);
if (queries.length !== 1) {
void extLogger.log(`Expected exactly one query, got ${queries.length}`);
return;
}
const query = queries[0];
const queryRun = queryRunner.createQueryRun(
databaseItem.databaseUri.fsPath,
{ queryPath: query, quickEvalPosition: undefined },
false,
getOnDiskWorkspaceFolders(),
undefined,
queryStorageDir,
undefined,
undefined,
);
return queryRun.evaluate(
progress,
token,
new TeeLogger(queryRunner.logger, queryRun.outputDir.logPath),
);
}
export type GetResultsOptions = {
cliServer: CodeQLCliServer;
bqrsPath: string;
};
export async function getResults({ cliServer, bqrsPath }: GetResultsOptions) {
const bqrsInfo = await cliServer.bqrsInfo(bqrsPath);
if (bqrsInfo["result-sets"].length !== 1) {
void extLogger.log(
`Expected exactly one result set, got ${bqrsInfo["result-sets"].length}`,
);
return undefined;
}
const resultSet = bqrsInfo["result-sets"][0];
return cliServer.bqrsDecode(bqrsPath, resultSet.name);
}