GraphQl hasFilter usage

Hi dgraph Team,
I noticed in my schema the hasFilter from the #11944 v20.11.0 update.
I’d like to know how the usage of multiple hasFilters works, as the example just point out a single value.

This is the example:

queryStudent(filter: { has : name } ){
   tid
   age
   name
}

I personally would expect the hasFilter to work with a List like [Filter] in and/or, or a regular Filter in not, where one could set the hasFilter by boolean, so I could also easily filter that a field should be null.

Example 1 - List

queryStudent(filter: { has : [name, age] } ){
   tid
   age
   name
}

Example 2 - filter

queryStudent(filter: { has : {name: true, age: false} } ){
   tid
   age
   name
}

If the implementation is by design, nvm my question and I just missed an explanation in the docs :blush:

You can combine multiple has statements inside and/or/not logic to accomplish your same queries.

and: [{ has: name },{ has: age }]

has: name, not: { has: age }

@verneleem that is indeed a solution for the problem, but makes it by design more complicated for generic filter generations.
Thus my question if it wouldn’t be better to have has as a list.

I believe the goal was to map more of the DQL functionality to the GraphQL generated schema. The has filter was first available in DQL (has function docs). So when this filter was brought into GraphQL, it was introduced with very similar syntax, e.g. every has function only accepts a single parameter and multiple has functions could be connected with AND, OR, and NOT logic. This provides a simpler GraphQL to DQL rewriting script.

You could somewhat easily create a script to rewrite your two examples into acceptable syntax:

const hasArrayFormatter = (fields) => {
  if (!Array.isArray(fields) || fields.length < 1) return {}
  fields =  fields.map(field => {
    return { has: field }
  })
  return {
    and: fields
  }
}
const hasArray = ["name","age"]
const formattedHas = hasArrayFormatter(hasArray)

response: { and: [ { has: "name" }, { has: "age" } ] }

const hasPropsFormatter = (fields) => {
  if (typeof fields !== 'object' || fields === null || Object.keys(fields).length === 0) return {}
  const filters = []
  for(const [field, required] of Object.entries(fields)) {
    if (required) {
      filters.push({ has: field })
    } else {
      filters.push({ not: { has: field } })
    }
  }
  return { and: filters }
}
const hasProps = { name: true, age: false }
const formattedHas = hasPropsFormatter(hasProps)

response: { and: [ { has: "name" }, { not: { has: "age" } } ] }

You could then plug these straight into your query:

const query = gql`
  query Students($filter: StudentFilter) {
    queryStudent(filter: $filter) {
      tid
      age
      name
    }
  }
`
// ...
const {data} = useQuery(query, { variables: { filter: formattedHas } })
// ...
2 Likes

@verneleem thank you for your really elaborate answer, it was way more than I expected :smiley:.

I now recon my error, as I viewed the and/or filter as junctions for separate entities, but of couse, one can look at it more like SQL AND expression, too.