graphile-contrib / postgraphile-plugin-connection-filter

Filtering on PostGraphile connections
MIT License
283 stars 32 forks source link

Question on `notDistinctFrom` operation #183

Open zacherkkila opened 1 year ago

zacherkkila commented 1 year ago

Thank you for all the work on this library! We use it quite extensively but have a few questions regarding null variables.

From the readme

To allow null and {} in inputs, use the connectionFilterAllowNullInput and connectionFilterAllowEmptyObjectInput options documented under Plugin Options. Please note that even with connectionFilterAllowNullInput enabled, null is never interpreted as a SQL NULL; fields with null values are simply ignored when resolving the query.

So if the fields are ignored, how is this intended to work with the distinctFrom, notDistinctFrom options? The operators readme in the docs appear to show support for this

image

These functions would be extremely useful for us as we often pass in null and would prefer no results, rather than every single item in the table like you see in the table below. Curious if we may be doing something wrong or if there is a way to support this functionality.

image
mattbretl commented 1 year ago

Interesting! I agree that the docs could be clearer; "treating null like an ordinary value" refers only to null values in the DB, and not null fields in the GraphQL query.

(Perhaps related, see https://github.com/graphile-contrib/postgraphile-plugin-connection-filter/issues/58 for the history of the null and {} design decision.)

As far as getting the result you're after, could you just replace { notDistinctFrom: null } with { isNull: true} and { distinctFrom: null } with { isNull: false }, or would that significantly complicate your client code?

zacherkkila commented 1 year ago

Thank you for the response!

As far as getting the result you're after, could you just replace { notDistinctFrom: null } with { isNull: true} and { distinctFrom: null } with { isNull: false }, or would that significantly complicate your client code?

I am realizing now my screenshot isn't all that useful but an example we run into is filtering a list of items that meet any of multiple conditions and/or when null is one of many possible valid search items. is not distinct from in this case works fine in the db which is a bit confusing until you realize what is happening on the graphql side.

query FindAll($id: Int, $name: String) {
  allPartNumbers(
    filter: {
      or: [
        { id: { notDistinctFrom: $id }}, 
        { name: { notDistinctFrom: $name }} 
      ]
    }
  ) {
    nodes {
      id
      name
    }
  }
}

For cases where null is not a valid search value, what we ended up doing is just passing empty arrays rather than null.

query FindAll($id: [Int!] = [], $name: [String!] = []) {
  allPartNumbers(
    filter: {
      or: [
        { id: { in: $id }}, 
        { name: { in: $name }} 
      ]
    }
  ) {
    nodes {
      id
      name
    }
  }
}

However, this doesn’t cover the case of null being valid, for that we would need to pass in a second variable to handle the null case which does complicate the UI code with a lot of filters.

Given #58 I understand why the decision was made, probably just a documentation update would be useful here so feel free to close as needed.

Thanks again for the work on the plugin!