Skip to content

Commit 57eb593

Browse files
committed
Merge branch 'main' into sdk-long-running-discovery
2 parents 0aaaf88 + e0521ea commit 57eb593

File tree

15 files changed

+483
-148
lines changed

15 files changed

+483
-148
lines changed

typegate/src/engine/planner/parameter_transformer.ts

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import { QueryFn, QueryFunction } from "../../libs/jsonpath.ts";
55
import { TypeGraph } from "../../typegraph/mod.ts";
66
import { Type } from "../../typegraph/type_node.ts";
77
import { ParameterTransformNode } from "../../typegraph/types.ts";
8-
import { generateBooleanValidator } from "../typecheck/inline_validators/boolean.ts";
8+
import { ValidationContext, validationContext } from "../typecheck/common.ts";
99
import { generateListValidator } from "../typecheck/inline_validators/list.ts";
1010
import { generateNumberValidator } from "../typecheck/inline_validators/number.ts";
1111
import {
1212
generateObjectValidator,
1313
getKeys,
1414
} from "../typecheck/inline_validators/object.ts";
1515
import { generateStringValidator } from "../typecheck/inline_validators/string.ts";
16+
import { InputValidationCompiler } from "../typecheck/input.ts";
1617

1718
export type TransformParamsInput = {
1819
args: Record<string, any>;
@@ -35,7 +36,10 @@ type CompiledTransformerInput = {
3536
};
3637

3738
type CompiledTransformer = {
38-
(input: CompiledTransformerInput): Record<string, any>;
39+
(
40+
input: CompiledTransformerInput,
41+
contxt: ValidationContext,
42+
): Record<string, any>;
3943
};
4044

4145
export function compileParameterTransformer(
@@ -45,10 +49,10 @@ export function compileParameterTransformer(
4549
): TransformParams {
4650
const ctx = new TransformerCompilationContext(typegraph, parentProps);
4751
const { fnBody, deps } = ctx.compile(transformerTreeRoot);
48-
const fn = new Function("input", fnBody) as CompiledTransformer;
52+
const fn = new Function("input", "context", fnBody) as CompiledTransformer;
4953
return ({ args, context, parent }) => {
5054
const getContext = compileContextQueries(deps.contexts)(context);
51-
const res = fn({ args, getContext, parent });
55+
const res = fn({ args, getContext, parent }, validationContext);
5256
return res;
5357
};
5458
}
@@ -105,10 +109,16 @@ class TransformerCompilationContext {
105109
nonStrictMode: new Set(),
106110
},
107111
};
112+
#inputValidatorCompiler: InputValidationCompiler;
113+
#typesWithCustomValidator: Set<number> = new Set();
108114

109115
constructor(typegraph: TypeGraph, parentProps: Record<string, number>) {
110116
this.#tg = typegraph;
111117
this.#parentProps = parentProps;
118+
this.#inputValidatorCompiler = new InputValidationCompiler(
119+
typegraph,
120+
(idx) => `validate_${idx}`,
121+
);
112122
}
113123

114124
#reset() {
@@ -127,8 +137,11 @@ class TransformerCompilationContext {
127137
this.#reset();
128138
const varName = this.#compileNode(rootNode);
129139
this.#collector.push(`return ${varName};`);
140+
const customValidators = [...this.#typesWithCustomValidator]
141+
.map((idx) => this.#inputValidatorCompiler.codes.get(idx))
142+
.join("\n");
130143
const res = {
131-
fnBody: this.#collector.join("\n"),
144+
fnBody: customValidators + this.#collector.join("\n"),
132145
deps: this.#dependencies,
133146
};
134147

@@ -232,7 +245,7 @@ class TransformerCompilationContext {
232245
const varName = this.#createVarName();
233246
let typeNode = this.#tg.type(typeIdx);
234247
let optional = false;
235-
if (typeNode.type === Type.OPTIONAL) {
248+
while (typeNode.type === Type.OPTIONAL) {
236249
typeNode = this.#tg.type(typeNode.item);
237250
optional = true;
238251
}
@@ -248,45 +261,24 @@ class TransformerCompilationContext {
248261

249262
this.#collector.push(`if (${varName} != null) {`);
250263

251-
switch (typeNode.type) {
252-
case Type.OPTIONAL:
253-
throw new Error(`At "${path}": nested optional not supported`);
254-
case Type.INTEGER: {
255-
const parsedVar = this.#createVarName();
256-
this.#collector.push(
257-
`const ${parsedVar} = parseInt(${varName}, 10);`,
258-
...generateNumberValidator(typeNode, parsedVar, path),
259-
);
260-
break;
261-
}
262-
case Type.FLOAT: {
263-
const parsedVar = this.#createVarName();
264-
this.#collector.push(
265-
`const ${parsedVar} = parseFloat(${varName});`,
266-
...generateNumberValidator(typeNode, parsedVar, path),
267-
);
268-
break;
269-
}
270-
case Type.STRING:
271-
this.#collector.push(
272-
...generateStringValidator(typeNode, varName, path),
273-
);
274-
break;
275-
case Type.BOOLEAN: {
276-
const parsedVar = this.#createVarName();
277-
278-
this.#collector.push(
279-
`const ${varName} = Boolean(${varName});`,
280-
...generateBooleanValidator(typeNode, parsedVar, path),
281-
);
282-
break;
283-
}
284-
285-
default:
286-
throw new Error(
287-
`At "${path}": Unsupported type "${typeNode.type}" for context injection`,
288-
);
264+
const types = this.#inputValidatorCompiler.generateValidators(typeIdx);
265+
for (const idx of types) {
266+
this.#typesWithCustomValidator.add(idx);
289267
}
268+
const errorVar = this.#createVarName();
269+
this.#collector.push(`const ${errorVar} = [];`);
270+
const args = [varName, JSON.stringify(path), errorVar, "context"];
271+
this.#collector.push(` validate_${typeIdx}(${args.join(", ")});`);
272+
this.#collector.push(` if (${errorVar}.length > 0) {`);
273+
const errorStrVar = this.#createVarName();
274+
const errMap = `([path, msg]) => \` - at \${path}: \${msg}\``;
275+
this.#collector.push(
276+
` const ${errorStrVar} = ${errorVar}.map(${errMap}).join("\\n");`,
277+
);
278+
this.#collector.push(
279+
` throw new Error(\`Context validation failed:\\n\${${errorStrVar}}\`);`,
280+
);
281+
this.#collector.push(` }`);
290282

291283
this.#collector.push("}");
292284
if (!optional) {
@@ -316,14 +308,23 @@ class TransformerCompilationContext {
316308
...generateStringValidator(typeNode, varName, path),
317309
);
318310
break;
319-
case Type.INTEGER:
320-
case Type.FLOAT:
311+
case Type.INTEGER: {
312+
const parsedVar = this.#createVarName();
313+
this.#collector.push(
314+
`const ${parsedVar} = parseInt(${varName}, 10);`,
315+
...generateNumberValidator(typeNode, parsedVar, path),
316+
);
317+
break;
318+
}
319+
case Type.FLOAT: {
320+
const parsedVar = this.#createVarName();
321321
this.#collector.push(
322-
...generateNumberValidator(typeNode, varName, path),
322+
`const ${parsedVar} = parseFloat(${varName});`,
323+
...generateNumberValidator(typeNode, parsedVar, path),
323324
);
324325
break;
326+
}
325327
default:
326-
// TODO optional??
327328
throw new Error(
328329
`At "${path}": Unsupported type "${typeNode.type}" for secret injection`,
329330
);

typegate/src/engine/typecheck/input.ts

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414

1515
export function generateValidator(tg: TypeGraph, typeIdx: number): Validator {
1616
const validator = new Function(
17-
new InputValidationCompiler(tg).generate(typeIdx),
17+
new InputValidationCompiler(tg, (typeIdx) => `validate_${typeIdx}`)
18+
.generate(typeIdx),
1819
)() as ValidatorFn;
1920
return (value: unknown) => {
2021
const errors: ErrorEntry[] = [];
@@ -103,16 +104,15 @@ function filterDeclaredFields(
103104
}
104105
}
105106

106-
function functionName(typeIdx: number) {
107-
return `validate_${typeIdx}`;
108-
}
109-
110107
export class InputValidationCompiler {
111108
codes: Map<number, string> = new Map();
109+
#getFunctionName: (idx: number) => string;
112110

113-
constructor(private tg: TypeGraph) {}
111+
constructor(private tg: TypeGraph, getFunctionName: (idx: number) => string) {
112+
this.#getFunctionName = getFunctionName;
113+
}
114114

115-
generate(rootTypeIdx: number): string {
115+
generateValidators(rootTypeIdx: number) {
116116
const cg = new CodeGenerator();
117117
const queue = [rootTypeIdx];
118118
const refs = new Set([rootTypeIdx]);
@@ -145,31 +145,37 @@ export class InputValidationCompiler {
145145
cg.generateFileValidator(typeNode);
146146
break;
147147
case "optional":
148-
cg.generateOptionalValidator(typeNode, functionName(typeNode.item));
148+
cg.generateOptionalValidator(
149+
typeNode,
150+
this.#getFunctionName(typeNode.item),
151+
);
149152
queue.push(typeNode.item);
150153
break;
151154
case "list":
152-
cg.generateArrayValidator(typeNode, functionName(typeNode.items));
155+
cg.generateArrayValidator(
156+
typeNode,
157+
this.#getFunctionName(typeNode.items),
158+
);
153159
queue.push(typeNode.items);
154160
break;
155161
case "object":
156162
cg.generateObjectValidator(
157163
typeNode,
158-
mapValues(typeNode.properties, functionName),
164+
mapValues(typeNode.properties, this.#getFunctionName),
159165
);
160166
queue.push(...Object.values(typeNode.properties));
161167
break;
162168
case "union":
163169
cg.generateUnionValidator(
164170
typeNode,
165-
typeNode.anyOf.map(functionName),
171+
typeNode.anyOf.map(this.#getFunctionName),
166172
);
167173
queue.push(...typeNode.anyOf);
168174
break;
169175
case "either":
170176
cg.generateEitherValidator(
171177
typeNode,
172-
typeNode.oneOf.map(functionName),
178+
typeNode.oneOf.map(this.#getFunctionName),
173179
);
174180
queue.push(...typeNode.oneOf);
175181
break;
@@ -178,18 +184,23 @@ export class InputValidationCompiler {
178184
}
179185
}
180186

181-
const fnName = functionName(typeIdx);
187+
const fnName = this.#getFunctionName(typeIdx);
182188
const fnBody = cg.reset().join("\n");
183189
this.codes.set(
184190
typeIdx,
185191
`function ${fnName}(value, path, errors, context) {\n${fnBody}\n}`,
186192
);
187193
}
188194

189-
const rootValidatorName = functionName(rootTypeIdx);
190-
const rootValidator = `\nreturn ${rootValidatorName}`;
195+
return refs;
196+
}
197+
198+
generate(rootTypeIdx: number): string {
199+
const fns = this.generateValidators(rootTypeIdx);
200+
const rootValidatorName = this.#getFunctionName(rootTypeIdx);
201+
const codes = [...fns].map((idx) => this.codes.get(idx));
202+
codes.push(`\nreturn ${rootValidatorName}`);
191203

192-
return [...refs].map((idx) => this.codes.get(idx))
193-
.join("\n") + rootValidator;
204+
return codes.join("\n");
194205
}
195206
}

typegate/src/runtimes/python_wasi/python_wasi.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ import * as ast from "graphql/ast";
1515

1616
const logger = getLogger(import.meta);
1717

18-
function generateVmIdentifier(mat: Materializer) {
18+
function generateVmIdentifier(mat: Materializer, uuid: string) {
1919
const { mod } = mat.data ?? {};
20+
let identifier = "";
2021
if (mod !== undefined) {
21-
return `pymod_${mod}`;
22+
identifier = `pymod_${mod}`;
23+
} else {
24+
identifier = `default`;
2225
}
23-
return "default";
26+
identifier = `${identifier}_${uuid}`;
27+
return identifier;
2428
}
2529

2630
export class PythonWasiRuntime extends Runtime {
@@ -30,7 +34,9 @@ export class PythonWasiRuntime extends Runtime {
3034
private w: PythonWasmMessenger,
3135
) {
3236
super(typegraphName, uuid);
37+
this.uuid = uuid;
3338
}
39+
uuid: string;
3440

3541
static async init(params: RuntimeInitParams): Promise<Runtime> {
3642
const { materializers, typegraph, typegraphName } = params;
@@ -39,10 +45,10 @@ export class PythonWasiRuntime extends Runtime {
3945
logger.info(`initializing default vm: ${typegraphName}`);
4046

4147
// add default vm for lambda/def
42-
const defaultVm = new PythonVirtualMachine();
43-
await defaultVm.setup("default");
44-
w.vmMap.set("default", defaultVm);
4548
const uuid = crypto.randomUUID();
49+
const defaultVm = new PythonVirtualMachine();
50+
await defaultVm.setup(`default_${uuid}`);
51+
w.vmMap.set(`default_${uuid}`, defaultVm);
4652

4753
for (const m of materializers) {
4854
switch (m.name) {
@@ -67,7 +73,7 @@ export class PythonWasiRuntime extends Runtime {
6773
const code = pyModMat.data.code as string;
6874

6975
const repr = await structureRepr(code);
70-
const vmId = generateVmIdentifier(m);
76+
const vmId = generateVmIdentifier(m, uuid);
7177
const basePath = path.join(
7278
"tmp",
7379
"scripts",
@@ -165,7 +171,7 @@ export class PythonWasiRuntime extends Runtime {
165171

166172
delegate(mat: Materializer): Resolver {
167173
const { name } = mat.data ?? {};
168-
const vmId = generateVmIdentifier(mat);
174+
const vmId = generateVmIdentifier(mat, this.uuid);
169175
return (args: unknown) => this.w.execute(name as string, { vmId, args });
170176
}
171177
}

0 commit comments

Comments
 (0)