yahoo / elide

Elide is a Java library that lets you stand up a GraphQL/JSON-API web service with minimal effort.
https://elide.io
Other
1k stars 227 forks source link

How to define a filter by ManyToMany relationship? #667

Closed olOwOlo closed 6 years ago

olOwOlo commented 6 years ago

I have a Topic and a Category entity as shown below:

public class Topic {
  // ...

  @ManyToMany
  public Set<Category> getCategories() {
    return categories;
  }
}
public class Category {
  // ...

  @ManyToMany(mappedBy = "categories")
  public List<Topic> getTopics() {
    return topics;
  }
}

Can I get topics under a category through filter? What I want has the same result as this:

http://localhost:8080/api/category/1/topics

I tried the following way, but I got a InvalidPredicateException: Invalid query parameter: filter[topic]\nInvalid association categories.id.

http://localhost:8080/api/topic?filter[topic]=categories.id==1
aklish commented 6 years ago

By default, the RSQL dialect does not allow filters to cross toMany associations:

https://github.com/yahoo/elide/blob/master/elide-core/src/main/java/com/yahoo/elide/core/filter/dialect/RSQLFilterDialect.java#L263

There is a flag that can turn this behavior on, but this feature has limited support: https://github.com/yahoo/elide/blob/master/elide-core/src/main/java/com/yahoo/elide/core/filter/dialect/RSQLFilterDialect.java#L190

Crossing a to-many relationship in a filter requires a join between two related entities where the number of rows returned from the join can exceed the size of the original collection the client is requesting.

There is limited support for this kind of filter for root collections only. Also, pagination will not work (if you both filter in this way and paginate in the same query) - the client will get a 400 error. Finally, the syntax is a bit different. Here is an example of the syntax in a test:

https://github.com/yahoo/elide/blob/c40bda7a259e29065ebdf3cb130e22bd3bc3782e/elide-integration-tests/src/test/groovy/com/yahoo/elide/tests/FilterIT.groovy#L1511

You can search for more examples in the FilterIT.groovy test file looking for "RSQL global". Because this kind of filter is not fully supported, I don't believe the documentation describes this capability.

The best I can offer is to suggest trying it out and seeing if this is useful for you or not. Hope that helps. Let me know if you have questions on the filter syntax since I don't believe it is documented anymore.

olOwOlo commented 6 years ago

@aklish , thank you for your reply.

I didn't know the two filter dialects have some different behaviours, I didn't even try another way :(

It seems that "RSQL Global" support it but "RSQL Typed" not.

Finally, I got what I want by :

http://localhost:8080/api/topic?filter=categories.id==1

The pagination also works well 😄

http://localhost:8080/api/topic?filter=categories.id==1&page[number]=1&page[size]=2&page[totals]

Thank you very much again for your help !