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

Filtering on the basis of child entities #2960

Closed
azf20 opened this issue Nov 8, 2021 · 13 comments · Fixed by #3184
Closed

Filtering on the basis of child entities #2960

azf20 opened this issue Nov 8, 2021 · 13 comments · Fixed by #3184
Assignees

Comments

@azf20
Copy link
Contributor

azf20 commented Nov 8, 2021

Subgraph consumers can currently only filter and sort on the basis of top-level entity fields. As a consumer, I want to be able to filter and sort on the basis of child entity fields.

Schema:

type Author @entity {
  id: ID!
  genre: Genre
  userProfile: User @derived(field: "id")
}

type User @entity {
  id: ID!
  dateOfBirth: String
  country: String
}

Query:

query {
  authors(where: {userProfile: { dateOfBirth_eq: "1987-04-03" } }) {
    id
  }
}
  • Will there need to be a limit on how many layers deep a filter can be applied? Restrict at one level, at least to begin with
  • Are there any considerations around arrays of child entities, vs. single child entities?
  • How will this work with interfaces?
  • Will there be a conflict between userProfile: "12345" and the nested filter? Will need to be a union of a String and an object, or make a breaking change

Meta-task: compare with syntax from other projects

@azf20 azf20 added this to GraphQL API Nov 8, 2021
@azf20 azf20 moved this to Todo in GraphQL API Nov 8, 2021
@Jannis
Copy link
Contributor

Jannis commented Nov 11, 2021

From https://www.apollographql.com/docs/apollo-server/schema/unions-interfaces/#union-type:

All of a union's included types must be object types (not scalars, input types, etc.). Included types do not need to share any fields.

So that means we can't support both

where: { userProfile: "foo" }

and

where: { userProfile: { id: "foo" } }

at the same time. 😢

@dotansimha
Copy link
Contributor

All of a union's included types must be object types (not scalars, input types, etc.). Included types do not need to share any fields

Yeah, because union and interfaces need to be resolved using resolveType or isTypeOf, while scalars / input types doesn't have the ability to do that, so we can't do UserFilter | String.

So ideally, we can introduce a new form of generating field arguments, that is more flexible and takes child entities into consideration, and gradually deprecate the existing one?
We can also experiment with @oneOf implementation (graphql/graphql-spec#825) to validate the input types.

@kamilkisiela
Copy link
Contributor

kamilkisiela commented Nov 16, 2021

Will there need to be a limit on how many layers deep a filter can be applied? Restrict at one level, at least to begin with

I guess it depends on how the data is fetched. All these filters could be applied as one or as many depending on the data fetching implementation. If some of them are super heavy for the database, we could define a score for them and calculate the complexity/heaviness of the query (score of 1200, where the limit is 250 will block the query from running).

Are there any considerations around arrays of child entities, vs. single child entities?

I'm not sure what do you mean here.

How will this work with interfaces?

All the arguments defined within an interface has to be defined in types implementing this interface, no extra arguments in these types. https://stackblitz.com/edit/typescript-mjzhzw

Will there be a conflict between userProfile: "12345" and the nested filter? Will need to be a union of a String and an object, or make a breaking change

Exactly what Dotan and Jannis said.

@Jannis
Copy link
Contributor

Jannis commented Nov 16, 2021

How will this work with interfaces?

All the arguments defined within an interface has to be defined in types implementing this interface, no extra arguments in these types. https://stackblitz.com/edit/typescript-mjzhzw

What @azf20 meant was that for any interface defined in the subgraph's GraphQL schema, the generated GraphQL API will have fields such as bicycle(id: "...") and bicycles(where: { ... }, ...). Queries against these interfaces will query across all concrete types implementing the interface. So the question was how we'd generate child filters when interfaces are involved.

I think the answer is fairly straight-forward: we should only generate child filter arguments for the fields in the interface, not in the concrete types that implement it.

@azf20
Copy link
Contributor Author

azf20 commented Nov 16, 2021

Are there any considerations around arrays of child entities, vs. single child entities?

Given:

author @entity {
  id: ID!
  name: String!
  books: [Book]
}

If I query for:

authors(where: books { genre_eq: "Horror" } ) {
  id
  name
  books { 
    id
  }
}

Presumably I get authors where any of their books have the Horror genre. Though is there a use case for selecting only horror (this might be a broader question about filtering on the basis of arrays). But also highlighting that the implementation of this filtering would presumably be different.

@azf20
Copy link
Contributor Author

azf20 commented Nov 24, 2021

As discussed yesterday:

  • We will not break the generated API at this time, so we can't use fieldName to filter child entities
  • I propose fieldName_, i.e.
authors(where: books_: { genre: "Horror" } ) {
  id
}

Though this might be a bit opaque / not "graphQL-y", so open to suggestions. Other ideas:

  • books_child
  • books_entity

I think this does highlight the need to (at some point) release a v2 with breaking changes.

cc @lutter @Jannis @dotansimha @kamilkisiela

@dotansimha
Copy link
Contributor

As discussed yesterday:

  • We will not break the generated API at this time, so we can't use fieldName to filter child entities
  • I propose fieldName_, i.e.
authors(where: books_: { genre: "Horror" } ) {
  id
}

Though this might be a bit opaque / not "graphQL-y", so open to suggestions. Other ideas:

  • books_child
  • books_entity

Sounds good, we can start with that and see how it looks like. Other suggestions are totally valid as well.

I think this does highlight the need to (at some point) release a v2 with breaking changes.

Makes a lot of sense, it's a good thing that we tackle some of these now, it will be easier to plan v2 of the GraphQL API.

@dotansimha dotansimha removed their assignment Nov 24, 2021
@leoyvens
Copy link
Collaborator

We could start with supporting only the form books_genre: "Horror"

@azf20
Copy link
Contributor Author

azf20 commented Nov 24, 2021

We could start with supporting only the form books_genre: "Horror"

That is interesting, though won't that lead to quite explosive Filter types?

@leoyvens
Copy link
Collaborator

That's a good point. Ok, I guess I don't mind the trailing _.

@azf20 azf20 moved this from Todo to In Progress in GraphQL API Dec 10, 2021
@dotansimha dotansimha linked a pull request Dec 19, 2021 that will close this issue
@elhaix
Copy link

elhaix commented Dec 26, 2021

I hope I am getting the gist of this issue, if so, it also depends in how your data is structured.

In this query, I am applying a filter to a child entity. Again, it depends if your data model supports this. The Graph also offers you the ability to create your own graphs where I'm sure you could massage the model to your liking:

# get a list of token pools for "WETH"
# WETH/USDT poolID (500 feeTier): 0x11b815efb8f581194ae79006d24e0d814b7697f6
{
tokens(where:{symbol:"WETH"}) {
    name
    symbolID: id
    whitelistPools(where: {feeTier: "500"}) {   # child entity filter
      poolID: id
      feeTier
      liquidity
      token0Price
      token1Price
      token0 {
        id
        symbol
        name	
        volumeUSD
        decimals
      }
      token1 {
        id
        symbol
        name
        volumeUSD
        decimals
      }
    }
  }
}

@azf20 azf20 moved this from In Progress to Awaiting release in GraphQL API Jan 31, 2022
@dotansimha dotansimha moved this from Awaiting release to Ready for review in GraphQL API Mar 9, 2022
@dotansimha dotansimha moved this from In review to In Progress in GraphQL API Apr 25, 2022
@dotansimha dotansimha moved this from In Progress to In review in GraphQL API Apr 27, 2022
@dotansimha dotansimha linked a pull request May 2, 2022 that will close this issue
Repository owner moved this from In review to Done in GraphQL API Jun 27, 2022
@mihoward21
Copy link

Super excited for this update! Thank you all for working on this feature. Do you all know when this will be live for us to use? And does this update include sorting as well, or just filtering?

@azf20 azf20 changed the title Filtering and sorting on the basis of child entities Filtering on the basis of child entities Jul 14, 2022
@azf20
Copy link
Contributor Author

azf20 commented Jul 14, 2022

Hi @mihoward21 this is currently in testing, will ping this thread! The initial feature is just filtering, with sorting to come (follow #3737 for more!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
7 participants