rsql-jpa-specification

repository·master·Indexed 43 days ago

https://github.com/perplexhub/rsql-jpa-specification

A library that translates RSQL (RESTful Service Query Language) queries into Spring Data JPA Specifications or QueryDSL Predicates. It supports entity association queries, property path remapping, custom operators, and PostgreSQL jsonb field querying. It provides starters for Spring Boot 2, 3, and 4+, and supports calling whitelisted stored procedures for searching and sorting.

Tokens
5.3K
Snippets
20
Records
21
Agent score
55%

What's inside rsql-jpa-specification

  1. Query JSONB fields in PostgreSQL

    master

    The library supports querying PostgreSQL jsonb fields using dot notation to traverse the JSON structure. It utilizes the PostgreSQL jsonb_path_exists function under the hood.

    Supported JSON primitive types:

    • string
    • number
    • boolean
    • array

    Temporal Values: Since PostgreSQL 13, jsonb supports temporal values via the datetime() function. When querying date-time values stored in JSONB, you must use the ISO 8601 format. If the request conforms to a timezone pattern, the library will use jsonb_path_exists_tz.

    // Example: querying a nested field in a jsonb column named 'data'
    String rsql = "data.user.id==1";
    List<User> users = userRepository.findAll(toSpecification(rsql));
  2. Prepare JPA Repositories for RSQL

    master

    For your JPA repository to support RSQL-based queries, it must extend both JpaSpecificationExecutor (for Spring Data JPA Specifications) and QuerydslPredicateExecutor (for QueryDSL Predicates).

    package com.perplexhub.repository;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import org.springframework.data.querydsl.QuerydslPredicateExecutor;
    
    import com.perplexhub.model.User;
    
    public interface UserRepository extends JpaRepository<User, String>, JpaSpecificationExecutor<User>, QuerydslPredicateExecutor<User> {
    }
  3. Install rsql-jpa-spring-boot-starter for Spring JPA translation

    master

    To translate RSQL queries into Spring Data JPA Specification objects, add the rsql-jpa-spring-boot-starter dependency to your Maven project.

    Compatibility Note:

    • SpringBoot 4+: Use version 7.x or higher.
    • SpringBoot 3: Use version 6.x.
    • SpringBoot 2: Use version 5.x.
    <dependency>
      <groupId>io.github.perplexhub</groupId>
      <artifactId>rsql-jpa-spring-boot-starter</artifactId>
      <version>X.X.X</version>
    </dependency>
  4. Configure JPA Repository for QueryDSL

    master

    To enable RSQL to QueryDSL translation, your repository interface must extend QuerydslPredicateExecutor (alongside JpaRepository and JpaSpecificationExecutor).

    package com.perplexhub.repository;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import org.springframework.data.querydsl.QuerydslPredicateExecutor;
    import com.perplexhub.model.User;
    
    public interface UserRepository extends JpaRepository<User, String>, JpaSpecificationExecutor<User>, QuerydslPredicateExecutor<User> {
    }
  5. Configure JPA Repository for RSQL

    master

    To enable RSQL support in your JPA repositories, your repository interface must extend JpaSpecificationExecutor.

    Example implementation:

    public interface UserRepository extends JpaRepository<User, String>, JpaSpecificationExecutor<User> {
    }
    package com.perplexhub.repository;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import com.perplexhub.model.User;
    
    public interface UserRepository extends JpaRepository<User, String>, JpaSpecificationExecutor<User> {
    }
  6. Install rsql-jpa-specification dependencies

    master

    To use this library, you must include spring-data-jpa in your Maven configuration. If you intend to use RSQLSupport.toPredicate for QueryDSL translation, you must also include querydsl-core.

    <!-- Add spring-data-jpa to your pom.xml -->
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>x.y.z</version>
    </dependency>
    
    <!-- Add querydsl-core to your pom.xml if you plan to use RSQLSupport.toPredicate -->
    <dependency>
      <groupId>com.querydsl</groupId>
      <artifactId>querydsl-core</artifactId>
      <version>x.y.z</version>
    </dependency>
  7. Install rsql-querydsl-spring-boot-starter for QueryDSL translation

    master

    To translate RSQL queries into QueryDSL Predicate objects, add the rsql-querydsl-spring-boot-starter dependency.

    Configuration: Your repository interface must extend both JpaSpecificationExecutor and QuerydslPredicateExecutor to support both translation types.

    <dependency>
      <groupId>io.github.perplexhub</groupId>
      <artifactId>rsql-querydsl-spring-boot-starter</artifactId>
      <version>X.X.X</version>
    </dependency>
  8. Escape Special Characters in LIKE Predicates

    master

    When using the LIKE operator in RSQL, you may need to escape special characters (like % or _) to search for them literally. To do this, use QuerySupport.builder() to specify a likeEscapeCharacter.

    Example: To search for a string containing an underscore (_) using $ as the escape character, your RSQL query should look like name=like='$_' and you must configure the builder with the escape character.

    char escapeChar = '$';
    QuerySupport query = QuerySupport.builder()
        .rsqlQuery("name=like='" + escapeChar + "%'")
        .likeEscapeCharacter(escapeChar)
        .build();
    List<Company> users = companyRepository.findAll(toSpecification(query));
  9. Translate RSQL to QueryDSL Predicate

    master

    Use RSQLSupport.toPredicate(filter, path) to convert an RSQL string into a QueryDSL Predicate (specifically a BooleanExpression). This requires a QueryDSL generated path object (e.g., QUser.user).

    Features:

    • Pagination: Pass a Pageable object to findAll.
    • Property Path Remapping: Use a Map<String, String> to map external RSQL property names to your internal domain model paths.
    // Basic usage with QueryDSL path
    repository.findAll(RSQLSupport.toPredicate(filter, QUser.user));
    
    // With pagination
    Pageable pageable = PageRequest.of(0, 5);
    repository.findAll(RSQLSupport.toPredicate(filter, QUser.user), pageable);
    
    // With property path remapping
    Map<String, String> propertyPathMapper = new HashMap<>();
    propertyPathMapper.put("compId", "company.id");
    repository.findAll(RSQLSupport.toPredicate(filter, QUser.user, propertyPathMapper));
  10. Call Stored Procedures in RSQL

    master

    RSQL supports calling stored procedures for both searching and sorting.

    Syntax: Procedures must be prefixed with @ and arguments are enclosed in [], separated by |. @procedure_name[arg1|arg2|...]

    Arguments:

    • Constants: Prefixed with # (e.g., #123, #true, #null).
    • Columns: Use the column name directly.
    • Nested Calls: You can pass the result of another procedure call as an argument.
    • Text: Since spaces are not supported in RSQL, use \t to represent spaces in text values.

    Security (Whitelisting): To prevent unauthorized execution, stored procedures must be explicitly whitelisted using QuerySupport (for searches) or SortSupport (for sorts). You can use regex-like expressions for whitelisting/blacklisting.

    String rsql = "@concat[greetings|#123]=='HELLO123'";
    QuerySupport querySupport = QuerySupport.builder()
            .rsqlQuery(rsql)
            .procedureWhiteList(List.of("concat", "upper"))
            .build();
    List<Item> companies = itemRepository.findAll(toSpecification(querySupport));
  11. Use RSQL with QueryDSL Predicates

    master

    To generate QueryDSL BooleanExpression objects, use RSQLSupport.toPredicate(filter, path).

    Features:

    • Path Mapping: Supports remapping property paths via a Map.
    • Per-query Conversion: You can provide a specific Spring ConversionService for a single query using the four-argument overload.
    // Basic usage with QueryDSL path
    repository.findAll(RSQLSupport.toPredicate(filter, QUser.user));
    
    // With property path remapping
    Map<String, String> propertyPathMapper = new HashMap<>();
    propertyPathMapper.put("compId", "company.id");
    repository.findAll(toPredicate(filter, QUser.user, propertyPathMapper));
    
    // With a specific ConversionService
    repository.findAll(toPredicate(filter, QUser.user, propertyPathMapper, applicationConversionService));