Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(gate): make __typename returns the variant name on unions #838

Merged
merged 1 commit into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
252 changes: 29 additions & 223 deletions .ghjk/deno.lock

Large diffs are not rendered by default.

582 changes: 271 additions & 311 deletions .ghjk/lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/typegate/src/engine/planner/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ export class Planner {
}),
);
const unselectedVariants = new Set(selectableVariants.keys());

if (unselectedVariants.size === 0 && selectionSet.selections.length > 0) {
const path = this.formatPath(node.path);
throw new Error(`at ${path}: Unexpected selections`);
Expand Down Expand Up @@ -238,6 +237,7 @@ export class Planner {
...node,
path: parentPath,
typeIdx: idx,
parentStage: stage,
},
outputType.properties,
stage,
Expand Down
18 changes: 16 additions & 2 deletions src/typegate/src/engine/planner/parameter_transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import type { TypeGraph } from "../../typegraph/mod.ts";
import { Type } from "../../typegraph/type_node.ts";
import type { ParameterTransformNode } from "../../typegraph/types.ts";
import { type ValidationContext, validationContext } from "../typecheck/common.ts";
import {
type ValidationContext,
validationContext,
} from "../typecheck/common.ts";
import { generateListValidator } from "../typecheck/inline_validators/list.ts";
import { generateNumberValidator } from "../typecheck/inline_validators/number.ts";
import {
Expand Down Expand Up @@ -174,9 +177,11 @@
return this.#compileSecretsInjection(typeIdx, nodeData.key);
case "parent":
return this.#compileParentInjection(typeIdx, nodeData.parentIdx);
case "static":
return this.#compileStaticInjection(typeIdx, nodeData.valueJson);
default:
throw new Error(
`Unknown source: ${nodeData.source} at ${this.#path}`,
`Unknown source: ${(nodeData as any).source} at ${this.#path}`,

Check warning on line 184 in src/typegate/src/engine/planner/parameter_transformer.ts

View check run for this annotation

Codecov / codecov/patch

src/typegate/src/engine/planner/parameter_transformer.ts#L184

Added line #L184 was not covered by tests
);
}
}
Expand Down Expand Up @@ -347,6 +352,15 @@
return varName;
}

#compileStaticInjection(_typeIdx: number, valueJson: string) {
// VALIDATION
// - the value is validated AOT with the typegraph

const varName = this.#createVarName();
this.#collector.push(`const ${varName} = ${valueJson};`);
return varName;
}

#createVarName() {
return `_var${++this.#latestVarIndex}`;
}
Expand Down
23 changes: 16 additions & 7 deletions src/typegate/src/runtimes/deno/deno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,9 @@ export class DenoRuntime extends Runtime {
verbose: boolean,
): ComputeStage[] {
if (stage.props.node === "__typename") {
return [
stage.withResolver(() => {
const { parent: parentStage } = stage.props;
if (parentStage != null) {
return parentStage.props.outType.title;
}
const getTypename = () => {
const parentStage = stage.props.parent;
if (parentStage == null) {
switch (stage.props.operationType) {
case ast.OperationTypeNode.QUERY:
return "Query";
Expand All @@ -182,7 +179,19 @@ export class DenoRuntime extends Runtime {
`Unsupported operation type '${stage.props.operationType}'`,
);
}
}),
}

const idSlice = stage.id().slice(parentStage.id().length);
if (idSlice.startsWith("$")) {
return idSlice.split(".")[0].slice(1);
}
return parentStage.props.outType.title;
};

const typename = getTypename();

return [
stage.withResolver(() => typename),
];
}

Expand Down
2 changes: 1 addition & 1 deletion src/typegraph/python/typegraph/t.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ def serialize_apply_param_node(node: ApplyParamNode) -> Any:
if isinstance(node, ApplyFromArg):
return {"source": "arg", "name": node.name}
if isinstance(node, ApplyFromStatic):
return {"source": "static", "value": JsonLib.dumps(node.value)}
return {"source": "static", "value_json": JsonLib.dumps(node.value)}
if isinstance(node, ApplyFromContext):
return {"source": "context", "key": node.key}
if isinstance(node, ApplyFromSecret):
Expand Down
23 changes: 23 additions & 0 deletions tests/typename/typename.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ def typename(g: Graph):
code="() => ({ id: 12 })",
).with_policy(public)

u8 = t.integer(min=0, max=255, name="U8")

color = t.either(
[
t.enum(["red", "green", "blue"]).rename("NamedColor"),
t.string(pattern=r"^#[0-9a-f]{6}$").rename("HexColor"),
t.struct({"r": u8, "g": u8, "b": u8}).rename("RgbColor"),
]
)

g.expose(
denoUser=deno_user,
randomUser=randomUser,
Expand All @@ -31,4 +41,17 @@ def typename(g: Graph):
effect=effects.delete(),
).with_policy(public),
createUser=prisma.create(prisma_user).with_policy(public),
getRgbColor=deno.identity(t.struct({"color": color}))
.apply(
{
"color": g.set(
{
"r": 255,
"g": 0,
"b": 0,
}
)
}
)
.with_policy(public),
)
56 changes: 32 additions & 24 deletions tests/typename/typename_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import { recreateMigrations } from "../utils/migrations.ts";
import { gql, Meta } from "../utils/mod.ts";

const secrets = {
POSTGRES: "postgresql://postgres:password@localhost:5432/db?schema=typename",
};

Meta.test("Typename", async (t) => {
const e = await t.engine("typename/typename.py", {
secrets: {
POSTGRES:
"postgresql://postgres:password@localhost:5432/db?schema=typename",
},
});
const e = await t.engine("typename/typename.py", { secrets });

await t.should("allow querying typename at root level", async () => {
await gql`
Expand All @@ -26,12 +25,7 @@ Meta.test("Typename", async (t) => {
});

Meta.test("Typename in deno runtime", async (t) => {
const e = await t.engine("typename/typename.py", {
secrets: {
POSTGRES:
"postgresql://postgres:password@localhost:5432/db?schema=typename",
},
});
const e = await t.engine("typename/typename.py", { secrets });

await t.should("allow querying typename in an object", async () => {
await gql`
Expand All @@ -51,12 +45,7 @@ Meta.test("Typename in deno runtime", async (t) => {
});

Meta.test("Typename in random runtime", async (t) => {
const e = await t.engine("typename/typename.py", {
secrets: {
POSTGRES:
"postgresql://postgres:password@localhost:5432/db?schema=typename",
},
});
const e = await t.engine("typename/typename.py", { secrets });

await t.should("allow querying typename in an object", async () => {
await gql`
Expand All @@ -76,12 +65,7 @@ Meta.test("Typename in random runtime", async (t) => {
});

Meta.test("Typename in prisma runtime", async (t) => {
const e = await t.engine("typename/typename.py", {
secrets: {
POSTGRES:
"postgresql://postgres:password@localhost:5432/db?schema=typename",
},
});
const e = await t.engine("typename/typename.py", { secrets });

await gql`
mutation a {
Expand Down Expand Up @@ -112,3 +96,27 @@ Meta.test("Typename in prisma runtime", async (t) => {
.on(e);
});
});

Meta.test("Typename on union", async (t) => {
const e = await t.engine("typename/typename.py", { secrets });

await t.should("get variant type name", async () => {
await gql`
query {
getRgbColor {
color {
... on RgbColor {
r g b __typename
Natoandro marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
`
.expectData({
getRgbColor: {
color: { r: 255, g: 0, b: 0, __typename: "RgbColor" },
},
})
.on(e);
});
});
Loading