Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

graphql: AND/OR filter #4080

Merged
merged 3 commits into from
Nov 10, 2022
Merged

graphql: AND/OR filter #4080

merged 3 commits into from
Nov 10, 2022

Conversation

saihaj
Copy link
Member

@saihaj saihaj commented Oct 20, 2022

introduces alternative syntax for doing AND/OR filters.

Generated filter will have these new types

input Proposal_fitler {
  id: ID
  # ... other variants of `id` like we do today
  collection: String
  # ... other variants of `collection` like we do today
  and: [Proposal_filter]
  or: [Proposal_filter]
}

Example queries

  1. using multiple AND filters
query {
  proposals(
    where: { and: [{ id_in: "111" }, { collection_contains_nocase: "a" }] }
  ) {
    id
  }
}
  1. Using multiple OR filters
query {
  proposals(
    where: { or: [{ id_in: "111" }, { collection_contains_nocase: "a" }] }
  ) {
    id
  }
}
  1. Using AND/OR combined
query {
  proposals(
    where: {
      or: [{ id_in: "111" }, { collection_contains_nocase: "a" }]
      and: [{ owner_contains: "0x2" }]
    }
  ) {
    id
  }
}

Downside with this approach is users can still have nested AND/OR which can be quite expensive example

query {
  proposals(
    where: {
      or: [
        { id_in: "111" }
        {
          collection_contains_nocase: "a"
          and: [{ owner_contains: "0x2" }, { id_in: "22" }]
        }
      ]
      and: [{ owner_contains: "0x2" }]
    }
  ) {
    id
  }
}

@lutter
Copy link
Collaborator

lutter commented Oct 20, 2022

I am still trying to wrap my head around what this all means - the notation that GraphQL imposes on us makes this all pretty confusing.

If I have predicates a, b, c, etc. where each predicate is something like name: "Truss", where: { a, b, c } and where: { and: [a, b, c] } mean the same thing. It gets more murky with

where: {
  and: [a, b],
  or: [c, d]
}

because we need to define precedence rules. I would expect the above to mean (a and b) or c or d. That, I think, could also be written as where: { or: [ {and: [a, b]}, c, d] }.

I wonder if we should enforce the latter notation by making it illegal to have and and or at the same level, since the more explicit notation of where: { or: [ {and: [a, b]}, c, d] } is much clearer.

There's also the mixed case of where: { a, b, or: [c, d] } which would mean a and b and (c or d) and also useless cases like where: {a, b, and: [c, d] } which is the same as where: {a, b, c, d}

As for this being expensive: if people start using or a lot, especially with no additional constraints, that can become very expensive; I haven't tried it but something like where: { or: [{token_0: "ABC"}, {token_1: "ABC"}] } OTOH, we already have plenty of ways to write expensive queries.

@azf20
Copy link
Contributor

azf20 commented Oct 21, 2022

Thanks so much @saihaj! I think this is close.. I wonder if we can address some of @lutter's concerns by making the approaches exclusive, i.e. the filter can only be one of the following:

Retained for backwards compatibility & simplicity (this is effectively a simple AND):

input Proposal_original_filter {
  id: ID
  # ... other variants of `id` like we do today
  collection: String
}

Allows for "or conditions":

input Proposal_and_filter {
  or: [Proposal_filter]
}

Allows for more nuanced AND filtering, sub-filters with OR etc:

input Proposal_or_filter {
  and: [Proposal_filter]
}

So in summary:

input Proposal_filter = Proposal_original_filter | Proposal_and_filter | Proposal_or_filter

@azf20
Copy link
Contributor

azf20 commented Oct 24, 2022

Per @saihaj's note in Slack, we can't do a Union here, so we have to have the combined type.

One point of clarification:

where: {
  and: [a, b],
  or: [c, d]
}

I read this as a and b and (c or d), which I think is different to your assumption @lutter ((a and b) or c or d). The reason I read it like that is that different arguments at the top level are treated as one big and, rather than an or. @saihaj can you confirm which would be applied?

@azf20
Copy link
Contributor

azf20 commented Oct 24, 2022

@saihaj assuming yes, @lutter and I just caught up and this syntax looks good to go, but I think we will just want to add a check to prevent and and or filters at the same level, if that makes sense? Otherwise I think this is ready for review

@azf20
Copy link
Contributor

azf20 commented Oct 27, 2022

@saihaj as this is still in draft, just let us know when this is ready to take a look!

@lutter
Copy link
Collaborator

lutter commented Nov 8, 2022

One thing: it would be good if there was an (undocumented) feature flag GRAPH_GRAPHQL_DISABLE_BOOL_FILTERS to turn off boolean filters. I am not sure how hard it will be to get that in, but if we could control at least whether or can be used would be very good as that has the highest potential to create slow queries. Turning off or should happen at the point where we parse filters and just result in a QueryExecutionError::NotSupported or some such. The flag should default to false (i.e., we accept filters by default)

@saihaj saihaj changed the base branch from saihaj/579 to master November 8, 2022 19:04
@saihaj saihaj marked this pull request as ready for review November 8, 2022 19:04
@saihaj saihaj changed the title graphql: alternative sytnax for AND/OR graphql: AND/OR filter Nov 8, 2022
Co-authored-by: Kamil Kisiela <[email protected]>
Copy link
Collaborator

@lutter lutter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all looks good, you just need to add the environment variable that allows disabling boolean filters

graphql/src/store/query.rs Outdated Show resolved Hide resolved
graphql/src/schema/api.rs Show resolved Hide resolved
@saihaj saihaj requested a review from lutter November 9, 2022 15:41
Copy link
Collaborator

@lutter lutter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Looks great now!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants