Skip to main content

Parameter Transformations

Use cases

might consider using parameter transformations if:

  • you want a simple interface for your function but you cannot change the input type;
  • if you want to re-use your function with a different set of parameters.

Parameter transformations are a way to refine the input type of your function to adapt to your need. They enable you to use injection to predefined input type without manually rewriting the type to add injections. It is most usefull for input types generated by runtimes, especially the PrismaRuntime which generates complex input types.

Related concept: Injection

note

In the following sections a plain object means:

  • in JavaScript/TypeScript: an object (literal)
  • in Python: a dictionary

func::reduce(tree)

The reduce method allows you to only enable some paths in the graph of the input type of the function.

The only required parameter to func::reduce is the reduce tree.

Reduce tree

A reduce tree (reduce sub-tree) is plain object whose property values are either a reduce sub-tree or a g.inherit() expression.

Each plain object represents a t.struct() in the input type subgraph.

All the nodes that are missing from the reduce tree will set the argument to its default value. Therefore they must be optional.

Consider the following typegraph:

const post = t.struct({
id: t.uuid(),
title: t.string(),
content: t.string(),
});

const user = t.struct({
id: t.uuid(),
email: t.email(),
posts: t.list(post),
});

const filter = t.struct({
id: t.uuid().optional(),
email: t.email().optional(),
posts: t.struct({
count: t.struct({
gt: t.integer({ min: 1 }).optional(),
lt: t.integer({ min: 1 }).optional(),
}),
tag: t.list(t.string()),
}),
});

const deno = DenoRuntime();
const findUsers = deno.func(filter, t.list(user), { code: "..." });

g.expose({
findUserById: findUsers.reduce({
id: g.inherit(),
}),
findUsersByPostCount: findUsers.reduce({
posts: {
count: g.inherit(),
},
}),
currentUser: findUsers.reduce({
id: g.inherit().fromContext("profile.userId"),
}),
});

The following queries are valid:

query FindUsersById($id: String!) {
findUserById(id: $id) {
id
email
}
}

query FindUsersByPostCount($min: Int!) {
findUsersByPostCount(posts: { count: { gt: $min } }) {
id
email
}
}

However the following query is invalid:

query Q {
findUserById(email: "[email protected]") {
id
email
}
}

The currentUser function will not accept any parameter.

Notes:

  • The only fully supported non-leaf node is t.struct().
  • Support for t.either() and t.union() is experimental.
  • t.list() is not supported.
  • Each non-leaf node may be optional or not.

func::apply(tree)

The apply method allows you to rewrite the input type of the function, enabling flat input type whatever is the level of nesting in the original input type.

The only required parameter to func::apply is the apply tree.

Apply tree

LexiconDefinition
Apply nodeObject node, list node or leaf-node
Apply treeObject node
Object nodeA plain object whose property values are nodes. It represents a t.struct().
List nodeAn array or list whose items are nodes. It represents a t.list().
Leaf nodeAn apply expression. See below.

From the code blocks in previouse section, let's make the following changes.

g.expose(
findUsersByPostCount: findUsers.apply({
posts: {
count: {
lt: g.as_arg(),
gt: g.as_arg(),
}
}
}),
findTechWriters: findUsers.apply({
posts: {
tags: [g.set("tech")]
}
}),
)

In this case, the matching queries are the following:

query FindUsersByPostCount($lt: Int, $gt: Int) {
findUsersByPostCount(lt: $lt, gt: $gt) {
id
email
}
}

query FindTechWriters {
findTechWriters {
id
email
}
}

Those queries will be translated to the following:

query FindUsersByPostCount($lt: Int, $gt: Int) {
findUsers({ posts: { count: { lt: $lt, gt: $gt } } }) {
id
email
}
}

query FindTechWriters {
findUsers({ posts: { tags: ["tech"] } }) {
id
email
}
}

Apply expressions

An apply expression indicates the source of the value for a specific leaf node in the apply tree.

Apply expressionSource
g.as_arg([name])The value will be provided as a parameter, under the name name. It is optional for object properties where the default is the property key.
g.from_parent(type_name)The node will have the same value as the field of the parent t.struct (of the t.func) that has the type name type_name.
g.from_context(path)The node will have the value of the context field accessible by the path path.
g.from_secret(key)The node will have the value of the secret named key on the current typegraph.
g.set(literal_value)The passed literal_value will be used.