graphql-provider/Add arguments to query
You can add parameters to the query.
Since the underlying kimmer-sql itself is designed for dynamic query, here we make all parameters nullable, thus realizing dynamic query.
package com.example.demo.query
import org.springframework.stereotype.Service
import org.babyfish.graphql.provider.Query
import org.babyfish.kimmer.sql.ast.ilike
import org.babyfish.kimmer.sql.ast.valueIn
import org.babyfish.kimmer.sql.ast.valueNotIn
import com.example.demo.model.* // α
@Service
class BookQuery: Query() {
suspend fun books(
name: String?,
storeName: String?,
authorFirstName: String?,
authorLastName: String?
): List<Book> =
runtime.queryList {
db {
name?.let {
where(table.name ilike it) // β
}
storeName?.let {
where(table.store.name ilike it) // γ
}
if (authorFirstName !== null || authorLastName !== null) {
where {
table.id valueIn subQuery(Author::class) { // δ
authorFirstName?.let {
where(table.firstName ilike it) // ε
}
authorLastName?.let {
where(table.lastName ilike it)
}
select(table.books.id) // ζ
}
}
}
orderBy(table.name)
}
}
}
-
α:
We used to add the ksp plugin to build.gralde.kts to automatically generate source code required for strongly typed SQL based on user-defined entity types. Now, we import the auto-generated code.
In the above code, we have used some expressions: table.name, table.store.name, table.firstName, table.lastName, table.books.id. In fact, they are all extension properties defined in the automatically generated code.
-
β:
table is an implicit variable provided by the query's lambda expression, representing the main table of the current query(Book)
-
γ
table.store means inner join, that's dynamic join of kimmer-sql, please click here to see more information about dynamic join.
-
δ
We used to write configuration like this in build.gradle.kts
ksp { ... arg("kimmer.table.collection-join-only-for-sub-query", "true") }
This configuration is very important, it means that table joins based on collection associations are prohibited from being created in top-level queries.
In the previous code, we can create joins based on many-to-one associations through table.store generated by ksp. But here is different, ksp will deliberately generate less code, we cannot create joins based on one-to-many associations through some code like table.authors.
In this way, the compiler can guarantee that we cannot create joins through one-to-many or many-to-many associations. This ensures that there will not be any bugs caused by query results containing duplicate data.
Since the query arguments related to Author cannot be implemented by table join, subquery becomes the only option.
-
ε
Here table is the implicit variable provided by the lamda expression of the subquery, which represents the main table of the subquery.
It is worth noting that the table of the subquery overrides the table of the parent query. Therefore, the table here is the AUTHOR table of the subquery, not the BOOK table of the parent query.
-
ζ
-
table.books represents table join through many-to-many associations, doing this in a subquery has no side effects (ksp argument "kimmer.table.collection-join-only-for-sub-query" only disallow this in top-level queries)
-
In fact, this is half join of kimmer-sql, please click here to see more information about half join.
-
Start the app, access http://localhost:8080/graphiql
Execute
query {
books(name: "GraphQL") {
name
store {
name
}
authors {
firstName
lastName
}
}
}
The response is
{
"data": {
"books": [
{
"name": "GraphQL in Action",
"store": {
"name": "MANNING"
},
"authors": [
{
"firstName": "Samer",
"lastName": "Buna"
}
]
},
{
"name": "Learning GraphQL",
"store": {
"name": "O'REILLY"
},
"authors": [
{
"firstName": "Eve",
"lastName": "Procello"
},
{
"firstName": "Alex",
"lastName": "Banks"
}
]
}
]
}
}
< Previous: Configure batch size | Home | Next: Add arguments to association >