@@ -39,11 +39,13 @@ import com.querydsl.core.types.PathType;
|
|||||||
import com.querydsl.core.types.SubQueryExpression;
|
import com.querydsl.core.types.SubQueryExpression;
|
||||||
import com.querydsl.core.types.TemplateExpression;
|
import com.querydsl.core.types.TemplateExpression;
|
||||||
import com.querydsl.core.types.Visitor;
|
import com.querydsl.core.types.Visitor;
|
||||||
|
import com.querydsl.core.types.Order;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes the given Querydsl query to a Document query for Couchbase.
|
* Serializes the given Querydsl query to a Document query for Couchbase.
|
||||||
*
|
*
|
||||||
* @author Michael Reiche
|
* @author Michael Reiche
|
||||||
|
* @author Tigran Babloyan
|
||||||
*/
|
*/
|
||||||
public abstract class CouchbaseDocumentSerializer implements Visitor<Object, Void> {
|
public abstract class CouchbaseDocumentSerializer implements Visitor<Object, Void> {
|
||||||
|
|
||||||
@@ -55,8 +57,15 @@ public abstract class CouchbaseDocumentSerializer implements Visitor<Object, Voi
|
|||||||
Sort sort = Sort.unsorted();
|
Sort sort = Sort.unsorted();
|
||||||
for (OrderSpecifier<?> orderBy : orderBys) {
|
for (OrderSpecifier<?> orderBy : orderBys) {
|
||||||
Object key = orderBy.getTarget().accept(this, null);
|
Object key = orderBy.getTarget().accept(this, null);
|
||||||
// sort.and(Sort.by(orderBy));
|
String keyAsString = key.toString();
|
||||||
// sort.append(key.toString(), orderBy.getOrder() == Order.ASC ? 1 : -1);
|
Sort.NullHandling sortNullHandling = switch (orderBy.getNullHandling()) {
|
||||||
|
case NullsFirst -> Sort.NullHandling.NULLS_FIRST;
|
||||||
|
case NullsLast -> Sort.NullHandling.NULLS_LAST;
|
||||||
|
default -> Sort.NullHandling.NATIVE;
|
||||||
|
};
|
||||||
|
Sort.Direction sortDirection = orderBy.getOrder() == Order.ASC ? Sort.Direction.ASC : Sort.Direction.DESC;
|
||||||
|
Sort.Order sortOrder = new Sort.Order(sortDirection, keyAsString, sortNullHandling);
|
||||||
|
sort = sort.and(Sort.by(sortOrder));
|
||||||
}
|
}
|
||||||
return sort;
|
return sort;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.springframework.util.Assert;
|
|||||||
* BasicQuery for Querydsl
|
* BasicQuery for Querydsl
|
||||||
*
|
*
|
||||||
* @author Michael Reiche
|
* @author Michael Reiche
|
||||||
|
* @author Tigran Babloyan
|
||||||
*/
|
*/
|
||||||
public class BasicQuery extends Query {
|
public class BasicQuery extends Query {
|
||||||
|
|
||||||
@@ -40,12 +41,11 @@ public class BasicQuery extends Query {
|
|||||||
* {@link CouchbaseDocument}.
|
* {@link CouchbaseDocument}.
|
||||||
*
|
*
|
||||||
* @param query must not be {@literal null}.
|
* @param query must not be {@literal null}.
|
||||||
* @param projectionFields must not be {@literal null}.
|
* @param projectionFields can be {@literal null}.
|
||||||
* @throws IllegalArgumentException when {@code sortObject} or {@code fieldsObject} is {@literal null}.
|
* @throws IllegalArgumentException when {@code sortObject} or {@code fieldsObject} is {@literal null}.
|
||||||
*/
|
*/
|
||||||
public BasicQuery(Query query, Map<String, String> projectionFields) {
|
public BasicQuery(Query query, Map<String, String> projectionFields) {
|
||||||
super(query);
|
super(query);
|
||||||
Assert.notNull(projectionFields, "Field document must not be null");
|
|
||||||
this.projectionFields = projectionFields;
|
this.projectionFields = projectionFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||||
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation;
|
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation;
|
||||||
|
import org.springframework.data.couchbase.core.query.Query;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageImpl;
|
import org.springframework.data.domain.PageImpl;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
@@ -250,7 +251,7 @@ public class SpringDataCouchbaseQuery<T> extends SpringDataCouchbaseQuerySupport
|
|||||||
@Nullable Expression<?> projection, QueryModifiers modifiers, List<OrderSpecifier<?>> orderBy) {
|
@Nullable Expression<?> projection, QueryModifiers modifiers, List<OrderSpecifier<?>> orderBy) {
|
||||||
|
|
||||||
Map<String, String> fields = createProjection(projection);
|
Map<String, String> fields = createProjection(projection);
|
||||||
BasicQuery basicQuery = new BasicQuery(createCriteria(filter), fields);
|
BasicQuery basicQuery = filter == null ? new BasicQuery(new Query(), fields) : new BasicQuery(createCriteria(filter), fields);
|
||||||
|
|
||||||
Integer limit = modifiers.getLimitAsInteger();
|
Integer limit = modifiers.getLimitAsInteger();
|
||||||
Integer offset = modifiers.getOffsetAsInteger();
|
Integer offset = modifiers.getOffsetAsInteger();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.querydsl.couchbase.document.CouchbaseDocumentSerializer;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Michael Reiche
|
* @author Michael Reiche
|
||||||
|
* @author Tigran Babloyan
|
||||||
*/
|
*/
|
||||||
abstract class SpringDataCouchbaseQuerySupport<Q extends SpringDataCouchbaseQuerySupport<Q>>
|
abstract class SpringDataCouchbaseQuerySupport<Q extends SpringDataCouchbaseQuerySupport<Q>>
|
||||||
extends AbstractCouchbaseQueryDSL<Q> {
|
extends AbstractCouchbaseQueryDSL<Q> {
|
||||||
@@ -84,10 +85,9 @@ abstract class SpringDataCouchbaseQuerySupport<Q extends SpringDataCouchbaseQuer
|
|||||||
// sb.append(", ").append(projection.toJson(JSON_WRITER_SETTINGS, codec));
|
// sb.append(", ").append(projection.toJson(JSON_WRITER_SETTINGS, codec));
|
||||||
// }
|
// }
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
// TODO
|
if (!sort.isEmpty()) {
|
||||||
// if (!sort.isEmpty()) {
|
sb.append(".sort(").append(sort).append(")");
|
||||||
// sb.append(".sort(").append(sort.toJson(JSON_WRITER_SETTINGS, codec)).append(")");
|
}
|
||||||
// }
|
|
||||||
if (getQueryMixin().getMetadata().getModifiers().getOffset() != null) {
|
if (getQueryMixin().getMetadata().getModifiers().getOffset() != null) {
|
||||||
sb.append(".skip(").append(getQueryMixin().getMetadata().getModifiers().getOffset()).append(")");
|
sb.append(".skip(").append(getQueryMixin().getMetadata().getModifiers().getOffset()).append(")");
|
||||||
}
|
}
|
||||||
@@ -128,6 +128,6 @@ abstract class SpringDataCouchbaseQuerySupport<Q extends SpringDataCouchbaseQuer
|
|||||||
* CouchbaseDocumentSerializer#toSort(List)
|
* CouchbaseDocumentSerializer#toSort(List)
|
||||||
*/
|
*/
|
||||||
protected Sort createSort(List<OrderSpecifier<?>> orderSpecifiers) {
|
protected Sort createSort(List<OrderSpecifier<?>> orderSpecifiers) {
|
||||||
return null; // TODO serializer.toSort(orderSpecifiers);
|
return serializer.toSort(orderSpecifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,15 @@ package org.springframework.data.couchbase.repository.query;
|
|||||||
import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS;
|
import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.springframework.data.couchbase.util.Util.comprises;
|
import static org.springframework.data.couchbase.util.Util.comprises;
|
||||||
import static org.springframework.data.couchbase.util.Util.exactly;
|
import static org.springframework.data.couchbase.util.Util.exactly;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
@@ -53,6 +56,7 @@ import org.springframework.data.couchbase.util.Capabilities;
|
|||||||
import org.springframework.data.couchbase.util.ClusterType;
|
import org.springframework.data.couchbase.util.ClusterType;
|
||||||
import org.springframework.data.couchbase.util.IgnoreWhen;
|
import org.springframework.data.couchbase.util.IgnoreWhen;
|
||||||
import org.springframework.data.couchbase.util.JavaIntegrationTests;
|
import org.springframework.data.couchbase.util.JavaIntegrationTests;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||||
|
|
||||||
@@ -67,6 +71,7 @@ import com.querydsl.core.types.dsl.BooleanExpression;
|
|||||||
* Repository tests
|
* Repository tests
|
||||||
*
|
*
|
||||||
* @author Michael Reiche
|
* @author Michael Reiche
|
||||||
|
* @author Tigran Babloyan
|
||||||
*/
|
*/
|
||||||
@SpringJUnitConfig(CouchbaseRepositoryQuerydslIntegrationTests.Config.class)
|
@SpringJUnitConfig(CouchbaseRepositoryQuerydslIntegrationTests.Config.class)
|
||||||
@IgnoreWhen(missesCapabilities = Capabilities.QUERY, clusterTypes = ClusterType.MOCKED)
|
@IgnoreWhen(missesCapabilities = Capabilities.QUERY, clusterTypes = ClusterType.MOCKED)
|
||||||
@@ -410,6 +415,72 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
|
|||||||
assertEquals(" WHERE name in $1", bq(predicate));
|
assertEquals(" WHERE name in $1", bq(predicate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSort(){
|
||||||
|
{
|
||||||
|
BooleanExpression predicate = airline.name.in(Arrays.stream(saved).map(Airline::getName).toList());
|
||||||
|
Iterable<Airline> result = airlineRepository.findAll(predicate, Sort.by("name").ascending());
|
||||||
|
assertArrayEquals(StreamSupport.stream(result.spliterator(), false).toArray(Airline[]::new),
|
||||||
|
Arrays.stream(saved)
|
||||||
|
.sorted(Comparator.comparing(Airline::getName))
|
||||||
|
.toArray(Airline[]::new),
|
||||||
|
"Order of airlines does not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BooleanExpression predicate = airline.name.in(Arrays.stream(saved).map(Airline::getName).toList());
|
||||||
|
Iterable<Airline> result = airlineRepository.findAll(predicate, Sort.by("name").descending());
|
||||||
|
assertArrayEquals(StreamSupport.stream(result.spliterator(), false).toArray(Airline[]::new),
|
||||||
|
Arrays.stream(saved)
|
||||||
|
.sorted(Comparator.comparing(Airline::getName).reversed())
|
||||||
|
.toArray(Airline[]::new),
|
||||||
|
"Order of airlines does not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BooleanExpression predicate = airline.name.in(Arrays.stream(saved).map(Airline::getName).toList());
|
||||||
|
Iterable<Airline> result = airlineRepository.findAll(predicate, airline.name.asc());
|
||||||
|
assertArrayEquals(StreamSupport.stream(result.spliterator(), false).toArray(Airline[]::new),
|
||||||
|
Arrays.stream(saved)
|
||||||
|
.sorted(Comparator.comparing(Airline::getName))
|
||||||
|
.toArray(Airline[]::new),
|
||||||
|
"Order of airlines does not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BooleanExpression predicate = airline.name.in(Arrays.stream(saved).map(Airline::getName).toList());
|
||||||
|
Iterable<Airline> result = airlineRepository.findAll(predicate, airline.name.desc());
|
||||||
|
assertArrayEquals(StreamSupport.stream(result.spliterator(), false).toArray(Airline[]::new),
|
||||||
|
Arrays.stream(saved)
|
||||||
|
.sorted(Comparator.comparing(Airline::getName).reversed())
|
||||||
|
.toArray(Airline[]::new),
|
||||||
|
"Order of airlines does not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Comparator<String> nullSafeStringComparator = Comparator
|
||||||
|
.nullsFirst(String::compareTo);
|
||||||
|
Iterable<Airline> result = airlineRepository.findAll(airline.hqCountry.asc().nullsFirst());
|
||||||
|
assertArrayEquals(StreamSupport.stream(result.spliterator(), false).toArray(Airline[]::new),
|
||||||
|
Arrays.stream(saved)
|
||||||
|
.sorted(Comparator.comparing(Airline::getHqCountry, nullSafeStringComparator))
|
||||||
|
.toArray(Airline[]::new),
|
||||||
|
"Order of airlines does not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Comparator<String> nullSafeStringComparator = Comparator
|
||||||
|
.nullsFirst(String::compareTo);
|
||||||
|
Iterable<Airline> result = airlineRepository.findAll(airline.hqCountry.desc().nullsLast());
|
||||||
|
assertArrayEquals(StreamSupport.stream(result.spliterator(), false).toArray(Airline[]::new),
|
||||||
|
Arrays.stream(saved)
|
||||||
|
.sorted(Comparator.comparing(Airline::getHqCountry, nullSafeStringComparator).reversed())
|
||||||
|
.toArray(Airline[]::new),
|
||||||
|
"Order of airlines does not match");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNotIn() {
|
void testNotIn() {
|
||||||
|
|||||||
Reference in New Issue
Block a user