Move query derivation infrastructure to Spring Data Relational. Adapt to newly introduced ValueFunction for deferred value mapping. Use query derivation in integration tests.
Tweak javadoc, add since and author tags, reformat code.
Related ticket: https://jira.spring.io/browse/DATAJDBC-514
Original pull request: #295.
We now accept StatementFilterFunction and ExecuteFunction via DatabaseClient to filter Statement execution. StatementFilterFunctions can be used to pre-process the statement or post-process Result objects.
databaseClient.execute(…)
.filter((s, next) -> next.execute(s.returnGeneratedValues("my_id")))
.filter((s, next) -> next.execute(s.fetchSize(25)))
databaseClient.execute(…)
.filter(s -> s.returnGeneratedValues("my_id"))
.filter(s -> s.fetchSize(25))
Original pull request: #308.
Refactored DefaultDatabaseClientUnitTests in order to make the relevant differences in setup easier to spot.
Formatting and nullability annotations.
Original pull request: #307.
We now support composition of Criteria objects to create a Criteria from one or more top-level criteria and to compose nested AND/OR Criteria objects:
Criteria.where("name").is("Foo")).and(Criteria.where("name").is("Bar").or("age")
.lessThan(49).or(Criteria.where("name").not("Bar").and("age").greaterThan(49))
Original pull request: #307.
We now support SpEL expressions in string-based queries to bind parameters for more dynamic queries. SpEL expressions are enclosed in :#{…} and rendered as synthetic named parameter so their values are substituted with bound parameters to avoid SQL injection attach vectors.
interface PersonRepository extends Repository<Person, String> {
@Query("SELECT * FROM person WHERE lastname = :#{'hello'}")
Mono<Person> findHello();
@Query("SELECT * FROM person WHERE lastname = :#{[0]} and firstname = :firstname")
Mono<Person> findByLastnameAndFirstname(@Param("value") String value, @Param("firstname") String firstname);
@Query("SELECT * FROM person WHERE lastname = :#{#person.name}")
Mono<Person> findByExample(@Param("person") Person person);
}
We now correctly reuse bind markers for named parameter substitution when using collection arguments to create dynamic argument lists. Previously, we allocated a new bind marker for each item in the collection which left the parameters intended for reuse unbound.
Use limit/offset instead of Page and accept Expression objects to declare a select list. Use SqlIdentifier in Update, Query, Criteria and fluent API.
Original pull request: #287.
We now provide a Template API that exposes entity-centric methods. It complements DatabaseClient's simple object mapper methods.
Original pull request: #287.
We now use SqlIdentifier to encapsulate the table and column name across the API. The fluent DatabaseClient API accepts the table name and select column projections as SqlIdentifier. The Criteria API remains String-based as names for Query and Update objects may reference either column names or property names.
QueryMapper and UpdateMapper require now a R2DBC dialect object to be constructed. R2dbcMappingContext is configured in a way to not require quoting to preserve backwards compatibility.
We now use the Id property name when using the converter to map property names to column names. In other places, where we don't use the converter, we stick with the Id column name.
We now support interface projections when using as(Class) through ProjectionFactory. Simple, type-less queries (execute, select from table) are backed by Map implementations and require the projection type to return a similar type than the expected value. Simple types (such as numeric types) are converted between the backing result and the projection. Conversion of complex types requires a source with type information such as a typed select (select().from(Person.class).as(PersonProjection.class)) to apply registered converters on property-level.