Skip to content

Commit 319a54c

Browse files
authored
Merge pull request #2906 from github/koesie10/convert-remaining-multiple-models
Convert remaining extension host code to handle multiple models
2 parents 4dcfa8b + 385b0e8 commit 319a54c

File tree

11 files changed

+158
-102
lines changed

11 files changed

+158
-102
lines changed

extensions/ql-vscode/src/model-editor/auto-model.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import { groupMethods, sortGroupNames, sortMethods } from "./shared/sorting";
1414
* the order in the UI.
1515
* @param mode Whether it is application or framework mode.
1616
* @param methods all methods.
17-
* @param modeledMethods the currently modeled methods.
17+
* @param modeledMethodsBySignature the currently modeled methods.
1818
* @returns list of modeled methods that are candidates for modeling.
1919
*/
2020
export function getCandidates(
2121
mode: Mode,
2222
methods: Method[],
23-
modeledMethods: Record<string, ModeledMethod>,
23+
modeledMethodsBySignature: Record<string, ModeledMethod[]>,
2424
): MethodSignature[] {
2525
// Sort the same way as the UI so we send the first ones listed in the UI first
2626
const grouped = groupMethods(methods, mode);
@@ -32,12 +32,11 @@ export function getCandidates(
3232
const candidates: MethodSignature[] = [];
3333

3434
for (const method of sortedMethods) {
35-
const modeledMethod: ModeledMethod = modeledMethods[method.signature] ?? {
36-
type: "none",
37-
};
35+
const modeledMethods: ModeledMethod[] =
36+
modeledMethodsBySignature[method.signature] ?? [];
3837

3938
// Anything that is modeled is not a candidate
40-
if (modeledMethod.type !== "none") {
39+
if (modeledMethods.some((m) => m.type !== "none")) {
4140
continue;
4241
}
4342

extensions/ql-vscode/src/model-editor/auto-modeler.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { QueryRunner } from "../query-server";
1616
import { DatabaseItem } from "../databases/local-databases";
1717
import { Mode } from "./shared/mode";
1818
import { CancellationTokenSource } from "vscode";
19-
import { convertToLegacyModeledMethods } from "./modeled-methods-legacy";
2019

2120
// Limit the number of candidates we send to the model in each request
2221
// to avoid long requests.
@@ -43,7 +42,7 @@ export class AutoModeler {
4342
inProgressMethods: string[],
4443
) => Promise<void>,
4544
private readonly addModeledMethods: (
46-
modeledMethods: Record<string, ModeledMethod>,
45+
modeledMethods: Record<string, ModeledMethod[]>,
4746
) => Promise<void>,
4847
) {
4948
this.jobs = new Map<string, CancellationTokenSource>();
@@ -60,7 +59,7 @@ export class AutoModeler {
6059
public async startModeling(
6160
packageName: string,
6261
methods: Method[],
63-
modeledMethods: Record<string, ModeledMethod>,
62+
modeledMethods: Record<string, ModeledMethod[]>,
6463
mode: Mode,
6564
): Promise<void> {
6665
if (this.jobs.has(packageName)) {
@@ -107,7 +106,7 @@ export class AutoModeler {
107106
private async modelPackage(
108107
packageName: string,
109108
methods: Method[],
110-
modeledMethods: Record<string, ModeledMethod>,
109+
modeledMethods: Record<string, ModeledMethod[]>,
111110
mode: Mode,
112111
cancellationTokenSource: CancellationTokenSource,
113112
): Promise<void> {
@@ -193,31 +192,31 @@ export class AutoModeler {
193192
filename: "auto-model.yml",
194193
});
195194

196-
const rawLoadedMethods = loadDataExtensionYaml(models);
197-
if (!rawLoadedMethods) {
195+
const loadedMethods = loadDataExtensionYaml(models);
196+
if (!loadedMethods) {
198197
return;
199198
}
200199

201-
const loadedMethods = convertToLegacyModeledMethods(rawLoadedMethods);
202-
203200
// Any candidate that was part of the response is a negative result
204201
// meaning that the canidate is not a sink for the kinds that the LLM is checking for.
205202
// For now we model this as a sink neutral method, however this is subject
206203
// to discussion.
207204
for (const candidate of candidateMethods) {
208205
if (!(candidate.signature in loadedMethods)) {
209-
loadedMethods[candidate.signature] = {
210-
type: "neutral",
211-
kind: "sink",
212-
input: "",
213-
output: "",
214-
provenance: "ai-generated",
215-
signature: candidate.signature,
216-
packageName: candidate.packageName,
217-
typeName: candidate.typeName,
218-
methodName: candidate.methodName,
219-
methodParameters: candidate.methodParameters,
220-
};
206+
loadedMethods[candidate.signature] = [
207+
{
208+
type: "neutral",
209+
kind: "sink",
210+
input: "",
211+
output: "",
212+
provenance: "ai-generated",
213+
signature: candidate.signature,
214+
packageName: candidate.packageName,
215+
typeName: candidate.typeName,
216+
methodName: candidate.methodName,
217+
methodParameters: candidate.methodParameters,
218+
},
219+
];
221220
}
222221
}
223222

extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-view-provider.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import { assertNever } from "../../common/helpers-pure";
1414
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
1515
import { ModelConfigListener } from "../../config";
1616
import { DatabaseItem } from "../../databases/local-databases";
17+
import {
18+
convertFromLegacyModeledMethod,
19+
convertToLegacyModeledMethod,
20+
} from "../modeled-methods-legacy";
1721

1822
export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
1923
ToMethodModelingMessage,
@@ -70,7 +74,9 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
7074
await this.postMessage({
7175
t: "setSelectedMethod",
7276
method: selectedMethod.method,
73-
modeledMethod: selectedMethod.modeledMethod,
77+
modeledMethod: convertToLegacyModeledMethod(
78+
selectedMethod.modeledMethods,
79+
),
7480
isModified: selectedMethod.isModified,
7581
});
7682
}
@@ -107,9 +113,10 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
107113
case "setModeledMethod": {
108114
const activeState = this.ensureActiveState();
109115

110-
this.modelingStore.updateModeledMethod(
116+
this.modelingStore.updateModeledMethods(
111117
activeState.databaseItem,
112-
msg.method,
118+
msg.method.signature,
119+
convertFromLegacyModeledMethod(msg.method),
113120
);
114121
this.modelingStore.addModifiedMethod(
115122
activeState.databaseItem,
@@ -158,12 +165,15 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
158165
this.push(
159166
this.modelingStore.onModeledMethodsChanged(async (e) => {
160167
if (this.webviewView && e.isActiveDb) {
161-
const modeledMethod = e.modeledMethods[this.method?.signature ?? ""];
162-
if (modeledMethod) {
163-
await this.postMessage({
164-
t: "setModeledMethod",
165-
method: modeledMethod,
166-
});
168+
const modeledMethods = e.modeledMethods[this.method?.signature ?? ""];
169+
if (modeledMethods) {
170+
const modeledMethod = convertToLegacyModeledMethod(modeledMethods);
171+
if (modeledMethod) {
172+
await this.postMessage({
173+
t: "setModeledMethod",
174+
method: modeledMethod,
175+
});
176+
}
167177
}
168178
}
169179
}),
@@ -190,7 +200,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
190200
await this.postMessage({
191201
t: "setSelectedMethod",
192202
method: e.method,
193-
modeledMethod: e.modeledMethod,
203+
modeledMethod: convertToLegacyModeledMethod(e.modeledMethods),
194204
isModified: e.isModified,
195205
});
196206
}

extensions/ql-vscode/src/model-editor/methods-usage/methods-usage-data-provider.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class MethodsUsageDataProvider
2626
private databaseItem: DatabaseItem | undefined = undefined;
2727
private sourceLocationPrefix: string | undefined = undefined;
2828
private hideModeledMethods: boolean = INITIAL_HIDE_MODELED_METHODS_VALUE;
29-
private modeledMethods: Record<string, ModeledMethod> = {};
29+
private modeledMethods: Record<string, ModeledMethod[]> = {};
3030
private modifiedMethodSignatures: Set<string> = new Set();
3131

3232
private readonly onDidChangeTreeDataEmitter = this.push(
@@ -52,7 +52,7 @@ export class MethodsUsageDataProvider
5252
methods: Method[],
5353
databaseItem: DatabaseItem,
5454
hideModeledMethods: boolean,
55-
modeledMethods: Record<string, ModeledMethod>,
55+
modeledMethods: Record<string, ModeledMethod[]>,
5656
modifiedMethodSignatures: Set<string>,
5757
): Promise<void> {
5858
if (
@@ -99,13 +99,10 @@ export class MethodsUsageDataProvider
9999
}
100100

101101
private getModelingStatusIcon(method: Method): ThemeIcon {
102-
const modeledMethod = this.modeledMethods[method.signature];
102+
const modeledMethods = this.modeledMethods[method.signature];
103103
const modifiedMethod = this.modifiedMethodSignatures.has(method.signature);
104104

105-
const status = getModelingStatus(
106-
modeledMethod ? [modeledMethod] : [],
107-
modifiedMethod,
108-
);
105+
const status = getModelingStatus(modeledMethods, modifiedMethod);
109106
switch (status) {
110107
case "unmodeled":
111108
return new ThemeIcon("error", new ThemeColor("errorForeground"));

extensions/ql-vscode/src/model-editor/methods-usage/methods-usage-panel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class MethodsUsagePanel extends DisposableObject {
3434
methods: Method[],
3535
databaseItem: DatabaseItem,
3636
hideModeledMethods: boolean,
37-
modeledMethods: Record<string, ModeledMethod>,
37+
modeledMethods: Record<string, ModeledMethod[]>,
3838
modifiedMethodSignatures: Set<string>,
3939
): Promise<void> {
4040
await this.dataProvider.setState(

extensions/ql-vscode/src/model-editor/model-editor-view.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import { telemetryListener } from "../common/vscode/telemetry";
4444
import { ModelingStore } from "./modeling-store";
4545
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
4646
import {
47-
convertFromLegacyModeledMethods,
47+
convertFromLegacyModeledMethod,
4848
convertToLegacyModeledMethods,
4949
} from "./modeled-methods-legacy";
5050

@@ -224,7 +224,7 @@ export class ModelEditorView extends AbstractWebview<
224224
this.extensionPack,
225225
this.databaseItem.language,
226226
methods,
227-
convertFromLegacyModeledMethods(modeledMethods),
227+
modeledMethods,
228228
this.mode,
229229
this.cliServer,
230230
this.app.logger,
@@ -311,7 +311,10 @@ export class ModelEditorView extends AbstractWebview<
311311
);
312312
break;
313313
case "setModeledMethod": {
314-
this.setModeledMethod(msg.method);
314+
this.setModeledMethods(
315+
msg.method.signature,
316+
convertFromLegacyModeledMethod(msg.method),
317+
);
315318
break;
316319
}
317320
default:
@@ -371,10 +374,7 @@ export class ModelEditorView extends AbstractWebview<
371374
this.cliServer,
372375
this.app.logger,
373376
);
374-
this.modelingStore.setModeledMethods(
375-
this.databaseItem,
376-
convertToLegacyModeledMethods(modeledMethods),
377-
);
377+
this.modelingStore.setModeledMethods(this.databaseItem, modeledMethods);
378378
} catch (e: unknown) {
379379
void showAndLogErrorMessage(
380380
this.app.logger,
@@ -446,10 +446,16 @@ export class ModelEditorView extends AbstractWebview<
446446
queryStorageDir: this.queryStorageDir,
447447
databaseItem: addedDatabase ?? this.databaseItem,
448448
onResults: async (modeledMethods) => {
449-
const modeledMethodsByName: Record<string, ModeledMethod> = {};
449+
const modeledMethodsByName: Record<string, ModeledMethod[]> = {};
450450

451451
for (const modeledMethod of modeledMethods) {
452-
modeledMethodsByName[modeledMethod.signature] = modeledMethod;
452+
if (!(modeledMethod.signature in modeledMethodsByName)) {
453+
modeledMethodsByName[modeledMethod.signature] = [];
454+
}
455+
456+
modeledMethodsByName[modeledMethod.signature].push(
457+
modeledMethod,
458+
);
453459
}
454460

455461
this.addModeledMethods(modeledMethodsByName);
@@ -620,7 +626,7 @@ export class ModelEditorView extends AbstractWebview<
620626
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
621627
await this.postMessage({
622628
t: "setModeledMethods",
623-
methods: event.modeledMethods,
629+
methods: convertToLegacyModeledMethods(event.modeledMethods),
624630
});
625631
}
626632
}),
@@ -646,7 +652,7 @@ export class ModelEditorView extends AbstractWebview<
646652
);
647653
}
648654

649-
private addModeledMethods(modeledMethods: Record<string, ModeledMethod>) {
655+
private addModeledMethods(modeledMethods: Record<string, ModeledMethod[]>) {
650656
this.modelingStore.addModeledMethods(this.databaseItem, modeledMethods);
651657

652658
this.modelingStore.addModifiedMethods(
@@ -655,13 +661,17 @@ export class ModelEditorView extends AbstractWebview<
655661
);
656662
}
657663

658-
private setModeledMethod(method: ModeledMethod) {
664+
private setModeledMethods(signature: string, methods: ModeledMethod[]) {
659665
const state = this.modelingStore.getStateForActiveDb();
660666
if (!state) {
661667
throw new Error("Attempting to set modeled method without active db");
662668
}
663669

664-
this.modelingStore.updateModeledMethod(state.databaseItem, method);
665-
this.modelingStore.addModifiedMethod(state.databaseItem, method.signature);
670+
this.modelingStore.updateModeledMethods(
671+
state.databaseItem,
672+
signature,
673+
methods,
674+
);
675+
this.modelingStore.addModifiedMethod(state.databaseItem, signature);
666676
}
667677
}
Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,57 @@
11
import { ModeledMethod } from "./modeled-method";
22

3-
export function convertFromLegacyModeledMethods(
4-
modeledMethods: Record<string, ModeledMethod>,
5-
): Record<string, ModeledMethod[]> {
6-
// Convert a single ModeledMethod to an array of ModeledMethods
7-
return Object.fromEntries(
8-
Object.entries(modeledMethods).map(([signature, modeledMethod]) => {
9-
return [signature, [modeledMethod]];
10-
}),
11-
);
12-
}
13-
3+
/**
4+
* Converts a record of a single ModeledMethod indexed by signature to a record of ModeledMethod[] indexed by signature
5+
* for legacy usage. This function should always be used instead of the trivial conversion to track usages of this
6+
* conversion.
7+
*
8+
* This method should only be called inside a `postMessage` call. If it's used anywhere else, consider whether the
9+
* boundary is correct: the boundary should as close as possible to the extension host -> webview boundary.
10+
*
11+
* @param modeledMethods The record of a single ModeledMethod indexed by signature
12+
*/
1413
export function convertToLegacyModeledMethods(
1514
modeledMethods: Record<string, ModeledMethod[]>,
1615
): Record<string, ModeledMethod> {
1716
// Always take the first modeled method in the array
1817
return Object.fromEntries(
19-
Object.entries(modeledMethods).map(([signature, modeledMethods]) => {
20-
return [signature, modeledMethods[0]];
21-
}),
18+
Object.entries(modeledMethods)
19+
.map(([signature, modeledMethods]) => {
20+
const modeledMethod = convertToLegacyModeledMethod(modeledMethods);
21+
if (!modeledMethod) {
22+
return null;
23+
}
24+
return [signature, modeledMethod];
25+
})
26+
.filter((entry): entry is [string, ModeledMethod] => entry !== null),
2227
);
2328
}
29+
30+
/**
31+
* Converts a single ModeledMethod to a ModeledMethod[] for legacy usage. This function should always be used instead
32+
* of the trivial conversion to track usages of this conversion.
33+
*
34+
* This method should only be called inside a `onMessage` function (or its equivalent). If it's used anywhere else,
35+
* consider whether the boundary is correct: the boundary should as close as possible to the webview -> extension host
36+
* boundary.
37+
*
38+
* @param modeledMethod The single ModeledMethod
39+
*/
40+
export function convertFromLegacyModeledMethod(modeledMethod: ModeledMethod) {
41+
return [modeledMethod];
42+
}
43+
44+
/**
45+
* Converts a ModeledMethod[] to a single ModeledMethod for legacy usage. This function should always be used instead
46+
* of the trivial conversion to track usages of this conversion.
47+
*
48+
* This method should only be called inside a `postMessage` call. If it's used anywhere else, consider whether the
49+
* boundary is correct: the boundary should as close as possible to the extension host -> webview boundary.
50+
*
51+
* @param modeledMethods The ModeledMethod[]
52+
*/
53+
export function convertToLegacyModeledMethod(
54+
modeledMethods: ModeledMethod[],
55+
): ModeledMethod | undefined {
56+
return modeledMethods[0];
57+
}

0 commit comments

Comments
 (0)