Hasura: How to pass a dynamic expression/condition using GraphQl
We had a case in our app where we wanted to give the user ability filter questions by "answered" or "not_answered" or "all".
We have a flag in the questions table called "is_answered", it's pretty easy to use it like this
query getQuestions($subjectId: bigint, $is_answered: Boolean = true) {
questions(
where: {
subject_id: { _eq: $subjectId }
is_answered: { _eq: $is_answered }
}
) {
title
}
}
by passing $is_answered
we can retrieve either the answered or not answered questions. But what if want to retrieve both?
We thought we can just by passing null
or undefined
instrad of a boolean then Hasura will understand and will ignore the whole expression and retieve both, but Hasura throws an error if you do this.
Solutions we have:
Solution (1): Multiple queries
You can have multiple queries, one that has the $is_answered
parameter, and the other doesn't have it.. this might be okay for small queries or edge cases only, but if you have big queries and you do this, it will be hard to maintain those queries.
Solution (2): Use boolean expression AndExp
Hasura has several boolean expressions that you can use them.
One of them is AndExp
we used it to fix this issue by passing the query a dynamic expression as bellow:
We updated our query to be:
query getQuestions(
$subjectId: bigint
$isAnsweredExpression: questions_bool_exp!
) {
questions(
where: { subject_id: { _eq: $subjectId }, _and: [$isAnsweredExpression] }
) {
title
}
}
We changed $is_answered
param to $isAnsweredExpression
with type: questions_bool_exp!
where questions
is our table name, you need to update it
Now this is how passed the expression to the query:
await client.query({
fetchPolicy: "no-cache",
query,
variables: {
subjectId: 1,
isAnsweredExpression:
display == "all" ? {} : { is_answered: { _eq: display == "answered" } }
}
});
display
is the selected option by user it can be "all", "answered" or "not_answered".
if the user chooses "all", then we just need send {}
and Hasura will ignore your expression and you will get both answered and not answered questions, if the user chooses "answered" or "not_answered", then you need to send the full expression like this { is_answered: { _eq: true }
Hope this fixes your issue!