Merge pull request #3048 from github/koesie10/type-model
Add `type` as modeled method type
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
SinkModeledMethod,
|
||||
SourceModeledMethod,
|
||||
SummaryModeledMethod,
|
||||
TypeModeledMethod,
|
||||
} from "../modeled-method";
|
||||
import { DataTuple } from "../model-extension-file";
|
||||
import { Mode } from "../shared/mode";
|
||||
@@ -17,7 +18,7 @@ type ReadModeledMethod = (row: DataTuple[]) => ModeledMethod;
|
||||
|
||||
export type ModelsAsDataLanguagePredicate<T> = {
|
||||
extensiblePredicate: string;
|
||||
supportedKinds: string[];
|
||||
supportedKinds?: string[];
|
||||
generateMethodDefinition: GenerateMethodDefinition<T>;
|
||||
readModeledMethod: ReadModeledMethod;
|
||||
};
|
||||
@@ -43,6 +44,7 @@ export type ModelsAsDataLanguagePredicates = {
|
||||
sink?: ModelsAsDataLanguagePredicate<SinkModeledMethod>;
|
||||
summary?: ModelsAsDataLanguagePredicate<SummaryModeledMethod>;
|
||||
neutral?: ModelsAsDataLanguagePredicate<NeutralModeledMethod>;
|
||||
type?: ModelsAsDataLanguagePredicate<TypeModeledMethod>;
|
||||
};
|
||||
|
||||
export type MethodArgumentOptions = {
|
||||
|
||||
@@ -151,6 +151,30 @@ export const ruby: ModelsAsDataLanguage = {
|
||||
};
|
||||
},
|
||||
},
|
||||
type: {
|
||||
extensiblePredicate: "typeModel",
|
||||
// extensible predicate typeModel(string type1, string type2, string path);
|
||||
generateMethodDefinition: (method) => [
|
||||
method.relatedTypeName,
|
||||
method.typeName,
|
||||
`Method[${method.methodName}].${method.path}`,
|
||||
],
|
||||
readModeledMethod: (row) => {
|
||||
const typeName = row[1] as string;
|
||||
const { methodName, path } = parseRubyAccessPath(row[2] as string);
|
||||
|
||||
return {
|
||||
type: "type",
|
||||
relatedTypeName: row[0] as string,
|
||||
path,
|
||||
signature: rubyMethodSignature(typeName, methodName),
|
||||
packageName: "",
|
||||
typeName,
|
||||
methodName,
|
||||
methodParameters: "",
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
modelGeneration: {
|
||||
queryConstraints: {
|
||||
|
||||
@@ -25,6 +25,8 @@ export function createEmptyModeledMethod(
|
||||
return createEmptySummaryModeledMethod(canonicalMethodSignature);
|
||||
case "neutral":
|
||||
return createEmptyNeutralModeledMethod(canonicalMethodSignature);
|
||||
case "type":
|
||||
return createEmptyTypeModeledMethod(canonicalMethodSignature);
|
||||
default:
|
||||
assertNever(type);
|
||||
}
|
||||
@@ -86,3 +88,14 @@ function createEmptyNeutralModeledMethod(
|
||||
provenance: "manual",
|
||||
};
|
||||
}
|
||||
|
||||
function createEmptyTypeModeledMethod(
|
||||
methodSignature: MethodSignature,
|
||||
): ModeledMethod {
|
||||
return {
|
||||
...methodSignature,
|
||||
type: "type",
|
||||
relatedTypeName: "",
|
||||
path: "",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ export type ModeledMethodType =
|
||||
| "source"
|
||||
| "sink"
|
||||
| "summary"
|
||||
| "type"
|
||||
| "neutral";
|
||||
|
||||
export type Provenance =
|
||||
@@ -51,12 +52,19 @@ export interface NeutralModeledMethod extends MethodSignature {
|
||||
readonly provenance: Provenance;
|
||||
}
|
||||
|
||||
export interface TypeModeledMethod extends MethodSignature {
|
||||
readonly type: "type";
|
||||
readonly relatedTypeName: string;
|
||||
readonly path: string;
|
||||
}
|
||||
|
||||
export type ModeledMethod =
|
||||
| NoneModeledMethod
|
||||
| SourceModeledMethod
|
||||
| SinkModeledMethod
|
||||
| SummaryModeledMethod
|
||||
| NeutralModeledMethod;
|
||||
| NeutralModeledMethod
|
||||
| TypeModeledMethod;
|
||||
|
||||
export type ModeledMethodKind = string;
|
||||
|
||||
|
||||
@@ -70,6 +70,13 @@ function canonicalizeModeledMethod(
|
||||
kind: modeledMethod.kind,
|
||||
provenance: "manual",
|
||||
};
|
||||
case "type":
|
||||
return {
|
||||
...methodSignature,
|
||||
type: "type",
|
||||
relatedTypeName: modeledMethod.relatedTypeName,
|
||||
path: modeledMethod.path,
|
||||
};
|
||||
default:
|
||||
assertNever(modeledMethod);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SinkModeledMethod,
|
||||
SourceModeledMethod,
|
||||
SummaryModeledMethod,
|
||||
TypeModeledMethod,
|
||||
} from "./modeled-method";
|
||||
import {
|
||||
getModelsAsDataLanguage,
|
||||
@@ -68,6 +69,7 @@ export function createDataExtensionYaml(
|
||||
sink: [] as SinkModeledMethod[],
|
||||
summary: [] as SummaryModeledMethod[],
|
||||
neutral: [] as NeutralModeledMethod[],
|
||||
type: [] as TypeModeledMethod[],
|
||||
} satisfies Record<keyof ModelsAsDataLanguagePredicates, ModeledMethod[]>;
|
||||
|
||||
for (const modeledMethod of modeledMethods) {
|
||||
@@ -88,6 +90,9 @@ export function createDataExtensionYaml(
|
||||
case "neutral":
|
||||
methodsByType.neutral.push(modeledMethod);
|
||||
break;
|
||||
case "type":
|
||||
methodsByType.type.push(modeledMethod);
|
||||
break;
|
||||
default:
|
||||
assertNever(modeledMethod);
|
||||
}
|
||||
@@ -122,6 +127,12 @@ export function createDataExtensionYaml(
|
||||
methodsByType.neutral,
|
||||
modelsAsDataLanguage.predicates.neutral,
|
||||
);
|
||||
case "type":
|
||||
return createExtensions(
|
||||
language,
|
||||
methodsByType.type,
|
||||
modelsAsDataLanguage.predicates.type,
|
||||
);
|
||||
default:
|
||||
assertNever(type);
|
||||
}
|
||||
|
||||
31
extensions/ql-vscode/src/view/common/ReadonlyDropdown.tsx
Normal file
31
extensions/ql-vscode/src/view/common/ReadonlyDropdown.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as React from "react";
|
||||
import { useMemo } from "react";
|
||||
import { Dropdown } from "./Dropdown";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
className?: string;
|
||||
|
||||
"aria-label"?: string;
|
||||
};
|
||||
|
||||
export function ReadonlyDropdown({ value, ...props }: Props) {
|
||||
const options = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
value,
|
||||
label: value,
|
||||
},
|
||||
];
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
value={value}
|
||||
disabledPlaceholder={value}
|
||||
disabled={true}
|
||||
options={options}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
modeledMethodSupportsInput,
|
||||
} from "../../model-editor/modeled-method";
|
||||
import { Method } from "../../model-editor/method";
|
||||
import { ReadonlyDropdown } from "../common/ReadonlyDropdown";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
import { getModelsAsDataLanguage } from "../../model-editor/languages";
|
||||
|
||||
@@ -59,6 +60,10 @@ export const ModelInputDropdown = ({
|
||||
? modeledMethod.input
|
||||
: undefined;
|
||||
|
||||
if (modeledMethod?.type === "type") {
|
||||
return <ReadonlyDropdown value={modeledMethod.path} aria-label="Path" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
value={value}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
modeledMethodSupportsOutput,
|
||||
} from "../../model-editor/modeled-method";
|
||||
import { Method } from "../../model-editor/method";
|
||||
import { ReadonlyDropdown } from "../common/ReadonlyDropdown";
|
||||
import { getModelsAsDataLanguage } from "../../model-editor/languages";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
|
||||
@@ -60,6 +61,15 @@ export const ModelOutputDropdown = ({
|
||||
? modeledMethod.output
|
||||
: undefined;
|
||||
|
||||
if (modeledMethod?.type === "type") {
|
||||
return (
|
||||
<ReadonlyDropdown
|
||||
value={modeledMethod.relatedTypeName}
|
||||
aria-label="Related type name"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
value={value}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { Method } from "../../model-editor/method";
|
||||
import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empty";
|
||||
import { Mutable } from "../../common/mutable";
|
||||
import { ReadonlyDropdown } from "../common/ReadonlyDropdown";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
import { getModelsAsDataLanguage } from "../../model-editor/languages";
|
||||
|
||||
@@ -73,6 +74,20 @@ export const ModelTypeDropdown = ({
|
||||
[onChange, method, modeledMethod, language],
|
||||
);
|
||||
|
||||
const value = modeledMethod?.type ?? "none";
|
||||
|
||||
const isShownOption = options.some((option) => option.value === value);
|
||||
|
||||
if (!isShownOption) {
|
||||
return (
|
||||
<ReadonlyDropdown
|
||||
// Try to show this like a normal type with uppercased first letter
|
||||
value={value.charAt(0).toUpperCase() + value.slice(1)}
|
||||
aria-label="Model type"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
value={modeledMethod?.type ?? "none"}
|
||||
|
||||
@@ -75,33 +75,71 @@ describe("parseGenerateModelResults", () => {
|
||||
ruby,
|
||||
createMockLogger(),
|
||||
);
|
||||
expect(result.sort()).toEqual(
|
||||
[
|
||||
{
|
||||
input: "Argument[self]",
|
||||
kind: "value",
|
||||
methodName: "create_function",
|
||||
methodParameters: "",
|
||||
output: "ReturnValue",
|
||||
packageName: "",
|
||||
provenance: "manual",
|
||||
signature: "SQLite3::Database#create_function",
|
||||
type: "summary",
|
||||
typeName: "SQLite3::Database",
|
||||
},
|
||||
{
|
||||
input: "Argument[1]",
|
||||
kind: "value",
|
||||
methodName: "new",
|
||||
methodParameters: "",
|
||||
output: "ReturnValue",
|
||||
packageName: "",
|
||||
provenance: "manual",
|
||||
signature: "SQLite3::Value!#new",
|
||||
type: "summary",
|
||||
typeName: "SQLite3::Value!",
|
||||
},
|
||||
].sort(),
|
||||
);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
methodName: "types",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::ResultSet#types",
|
||||
type: "type",
|
||||
typeName: "SQLite3::ResultSet",
|
||||
},
|
||||
{
|
||||
methodName: "columns",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::ResultSet#columns",
|
||||
type: "type",
|
||||
typeName: "SQLite3::ResultSet",
|
||||
},
|
||||
{
|
||||
methodName: "types",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::Statement#types",
|
||||
type: "type",
|
||||
typeName: "SQLite3::Statement",
|
||||
},
|
||||
{
|
||||
methodName: "columns",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::Statement#columns",
|
||||
type: "type",
|
||||
typeName: "SQLite3::Statement",
|
||||
},
|
||||
{
|
||||
input: "Argument[self]",
|
||||
kind: "value",
|
||||
methodName: "create_function",
|
||||
methodParameters: "",
|
||||
output: "ReturnValue",
|
||||
packageName: "",
|
||||
provenance: "manual",
|
||||
signature: "SQLite3::Database#create_function",
|
||||
type: "summary",
|
||||
typeName: "SQLite3::Database",
|
||||
},
|
||||
{
|
||||
input: "Argument[1]",
|
||||
kind: "value",
|
||||
methodName: "new",
|
||||
methodParameters: "",
|
||||
output: "ReturnValue",
|
||||
packageName: "",
|
||||
provenance: "manual",
|
||||
signature: "SQLite3::Value!#new",
|
||||
type: "summary",
|
||||
typeName: "SQLite3::Value!",
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -138,6 +138,46 @@ describe("runGenerateQueries", () => {
|
||||
...options,
|
||||
});
|
||||
expect(onResults).toHaveBeenCalledWith([
|
||||
{
|
||||
methodName: "types",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::ResultSet#types",
|
||||
type: "type",
|
||||
typeName: "SQLite3::ResultSet",
|
||||
},
|
||||
{
|
||||
methodName: "columns",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::ResultSet#columns",
|
||||
type: "type",
|
||||
typeName: "SQLite3::ResultSet",
|
||||
},
|
||||
{
|
||||
methodName: "types",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::Statement#types",
|
||||
type: "type",
|
||||
typeName: "SQLite3::Statement",
|
||||
},
|
||||
{
|
||||
methodName: "columns",
|
||||
methodParameters: "",
|
||||
packageName: "",
|
||||
path: "ReturnValue",
|
||||
relatedTypeName: "Array",
|
||||
signature: "SQLite3::Statement#columns",
|
||||
type: "type",
|
||||
typeName: "SQLite3::Statement",
|
||||
},
|
||||
{
|
||||
input: "Argument[self]",
|
||||
kind: "value",
|
||||
|
||||
Reference in New Issue
Block a user