spring-graphql icon indicating copy to clipboard operation
spring-graphql copied to clipboard

Query by Example doesn't have a binding customization mechanism

Open danvega opened this issue 1 year ago • 1 comments

I have a GraphQLRepository that extends QueryByExampleExectutor

@GraphQlRepository
public interface BookRepository extends JpaRepository<Book, Long>, QueryByExampleExecutor<Book> {}

If I try to do a partial match on the book title no results come back. If I enter the full book title the results come back as expected.

// Find books by partial title match
query {
  books(book: { title: "Spring Boot" }) {
    id
    title
    author
    publishedYear
  }
}

I realize I can write a data fetcher for this but this:

@Controller
public class BookController {

    private final BookRepository repository;

    public BookController(BookRepository repository) {
        this.repository = repository;
    }

    @QueryMapping
    public List<Book> booksContaining(@Argument(name = "book") Book filterBook) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
                .withIgnoreCase()
                .withIgnoreNullValues();

        Example<Book> example = Example.of(filterBook, matcher);
        return repository.findAll(example);
    }
}

But I would like a way to customize this so I can use a StringMatcher.CONTAINING and match on part of the book title.

danvega avatar Nov 07 '24 13:11 danvega

Customizing ExampleMatcher is a reasonable request. Introducing a strategy interface that creates ExampleMatcher would be my initial approach. I'm not quite sure about the context that we should provide to the method. I think something along the lines for an initial cut:

interface ExampleMatcherProvider<T> {

  ExampleMatcher getExampleMatcher(T probe, DataFetchingEnvironment environment);
}

Such a signature would provide the most meaningful context.

For auto-registration, I think a programming model to let repositories implement the interface through a default method would be neat:

@GraphQlRepository
public interface BookRepository extends JpaRepository<Book, Long>, 
                                        QueryByExampleExecutor<Book>, ExampleMatcherProvider<Book> {
    
  default ExampleMatcher getExampleMatcher(Book probe, DataFetchingEnvironment environment) {
    return …;
  }
}

Alternatively, defining a @Bean ExampleMatcherProvider<Book> and using ResolvableType to correlate the strategy object could work too.

mp911de avatar Nov 07 '24 14:11 mp911de

We've been regularly trying to come up with a good model to express customization approaches. Query by Example is much more constrained than Querydsl and so a reduced functionality scope could allow a more declarative approach.

However, there is very little demand and so we do not have a good amount of usecases to determine commonalities. Therefore, we're closing this ticket for the time being. We want to come back to it once there is more substance we can learn from to come up with an approach that is useful to users.

mp911de avatar Jul 17 '25 08:07 mp911de