-
Notifications
You must be signed in to change notification settings - Fork 5
Directive @selection
The @selection directive provides an ability to move optional arguments of GraphQL field to a lambda block in
generated projection interface. Let define a GraphQL schema:
type Query {
films(
genre: Genre!,
title: String,
offset: Int! = 0,
limit: Int! = 30
): [Film!]!
}
type Film {
id: ID!
genre: Genre!
title: String!
}
enum Genre {
DRAMA
COMEDY
THRILLER
HORROR
}This schema allows us to write a query using the generated DSL that looks like this:
val context: ExampleContext = exampleContextOf(createMyAdapter())
val response = context.query {
films(Genre.DRAMA, title = "*Dream*", offset = 100, limit = 100) {
id()
genre()
title()
}
}
response.films.forEach { film ->
println("Film [${film.id}]: ${film.title} (${film.genre})")
}The films projection function has 3 optional arguments:
- The
titleis optional because it is nullable. - The
offsetis optional because it has a default value. - The
limitis optional because it has a default value.
We can move these arguments to the lambda block of the films projection function using the @selection directive.
Let's modify our schema:
directive @selection on FIELD_DEFINITION
type Query {
films(
genre: Genre!,
title: String,
offset: Int! = 0,
limit: Int! = 30
): [Film!]! @selection
}
type Film {
id: ID!
genre: Genre!
title: String!
}
enum Genre {
DRAMA
COMEDY
THRILLER
HORROR
}Now we can write our query like this:
val context: ExampleContext = exampleContextOf(createMyAdapter())
val response = context.query {
films(Genre.DRAMA) {
title = "*Dream*"
offset = 100
limit = 100
id()
genre()
title()
}
}
response.films.forEach { film ->
println("Film [${film.id}]: ${film.title} (${film.genre})")
}The @selection directive improves readability of DSL queries in case the GraphQL field contains many optional
arguments.
Without @selection directive for the GraphQL type Query, Kobby generates
a projection interface that looks like this:
@ExampleDSL
interface QueryProjection {
/**
* @param offset Default: 0
* @param limit Default: 30
*/
fun films(
genre: Genre,
title: String? = null,
offset: Int? = null,
limit: Int? = null,
__projection: FilmProjection.() -> Unit
): Unit
}After applying @selection directive, the generated interface will change as follows:
@ExampleDSL
interface QueryProjection {
fun films(genre: Genre, __query: QueryFilmsQuery.() -> Unit): Unit
}
@ExampleDSL
interface QueryFilmsSelection {
var title: String?
/**
* Default: 0
*/
var offset: Int?
/**
* Default: 30
*/
var limit: Int?
}
@ExampleDSL
interface QueryFilmsQuery : QueryFilmsSelection, FilmProjectionFor the films field marked with the @selection directive, Kobby generates an additional QueryFilmsSelection
interface that contains all the optional arguments. Since the films field returns a list of films, its lambda must
also contain the projection of the Film type. To do this, Kobby generates a third interface, QueryFilmsQuery, which
is simply QueryFilmsSelection + FilmProjection (naming convention is simple: "selection" + "projection" = "query").
And the QueryFilmsQuery interface is used as a receiver of the QueryProjection.films lambda expression.
- The
@selectiondirective can only be applied to a field that contains optional arguments - nullable arguments or arguments with default value. - The
@selectiondirective cannot be applied to overridden fields. In this case, apply the directive to the base interface field.
In case of violation of any restriction, the directive will be ignored.