Search code examples
hasura

How to apply a Hasura `where` filter only if a variable is not null?


I have a query like this:

query getUsers ($setId: Int) {
  user(where: { user_sets: { set_id: { _in: [$setId] } } }) {
    id
    name
    status
    user_sets {
      set {
        name
      }
    }
    # more fields...
  }
}

What I'm looking for, is a way to not apply the where filter and give all entries if $setId is null. I'd like to avoid dynamically writing the query - it'd be easy to do something like this, but we want queries in static .graphql files:

const query = `
query getUsers (${ setId ? '$setId: Int' : ''}) {
  user(${ setId ? 'where: { user_sets: { set_id: { _in: [$setId] } } }' : '' }) {
`

Some things I've tried:

  • Using GraphQL directives like @skip and @include, but it seems these only apply to fields returned, not to any part of a where filter
  • Using Hasura boolExps like _is_null and _or, but it seems these can't test variables directly, they can only compare variables to columns contents

Solution

  • This behaviour changed somewhere between v1.3.4. Therefore there are two correct answers.

    You can read more about this change in the hasura repository.

    Before Version 1.3.4

    This answer describes it.

    After Version 1.3.4

    Using null in comparisons is dangerous when defaulting to true because an accidentally unset variable could result in a dropped table. The maintainers removed this behaviour but made it accessible by setting the variable HASURA_GRAPHQL_V1_BOOLEAN_NULL_COLLAPSE.

    When comparing with {_eq: null}, Hasura will throw an error because it is assumed that this is a mistake.

    If you want to compare to a value and evaluate to true when the value is null, you need to handle the case on the client side and pass the whole boolean expression to Hasura.

    query getUsers ($userSetsWhere: user_sets_bool_exp) {
      user(where: { user_sets: { $userSetsWhere } }) {
        id
        name
        status
        user_sets {
          set {
            name
          }
        }
        # more fields...
      }
    }
    
    const userSetsWhere = setId ? { set_id: { _eq: $setId } } : {};
    

    What it does, is that only in case the value is not null or undefined a non-empty expression gets passed to Hasura.