Gauthier Peel
Gauthier Peel

Reputation: 1518

QueryDSL and SQL Function from Postgres

I would like to use Postgres FullText search with QueryDsl JPA.

Generated in SQL:

select * 
from film 
where to_tsquery ('tarzan') @@ to_tsvector('french',film.title) = true

to get all film containing tarzan in their title.

In JPA I define a custom function 'ftsMatch' which I could use like that:

String jpql = "select film from Film film where ftsMatch(:queryString, film.titre) = true";

I QueryDSL I would like to have an opportunity to define a predicate on String type :

QFilm.film.titre.ftsMatch('tarzan')

I haven't found any solution

Upvotes: 4

Views: 4646

Answers (1)

Gauthier Peel
Gauthier Peel

Reputation: 1518

What I would like to do is to extends the com.querydsl.core.types.dsl.StringExpression.class and add a custom function fullTextMatch() which could be used like :

BooleanBuilder booleanBuilder = new BooleanBuilder(QFilm.film.titre.fullTextMatch(_titre, "french"));

it would turn into SQL :

select film0_.id as id1_2_ .. from film film0_ 
where  to_tsquery (?) @@   to_tsvector('pg_catalog.french',film0_.titre)=true

I haven't found how to get the QueryDSL syntax above, but found the following solution:

1/ define Custom Dialect for Postgres and register the Customm function on this dialect :

public class CustomFullTextPostgresDialect extends PostgreSQL94Dialect {

    public CustomFullTextPostgresDialect() {
        registerFunction("ftsMatch", new PostgreSQLFullTextSearchFunction());
    }

}

2/ Code the custom function PostgreSQLFullTextSearchFunction implementing org.hibernate.dialect.function.SQLFunction This function 'ftsMacth' will generate the SQL :

String fragment = " to_tsquery (" + value + ") @@   to_tsvector(" + ftsConfig + "," + field + ")";

This step give me access to Posgres FullText in JPA :

String jpql = "select film from Film film "
        + "where FUNCTION( 'ftsMatch', :titre,'pg_catalog.french', film.titre) = true";
TypedQuery<Film> typedQuery = em.createQuery(jpql, Film.class);
typedQuery.setParameter("titre", _titre);
List<Film> list = typedQuery.getResultList();

3/Use QueryDsl to relay to the custom function defined on the extended postgres Dialect :

BooleanTemplate predicate = Expressions
        .booleanTemplate("FUNCTION('ftsMatch', {0},'pg_catalog.french', film.titre) = true ", _titre);

Page<Film> page = filmRepository.findAll(predicate, _pageable);

But with this QueryDSL solution, I still need the Hibernate customization. And the syntax is no longer DSL oriented

Upvotes: 2

Related Questions