projectionFields) {
+ Assert.notNull(projectionFields, "Field document must not be null");
+ this.projectionFields = projectionFields;
+ }
+
+ /*
+ * (non-Javadoc)
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof BasicQuery)) {
+ return false;
+ }
+ BasicQuery that = (BasicQuery) o;
+ return querySettingsEquals(that) && //
+ nullSafeEquals(projectionFields, that.projectionFields) && //
+ nullSafeEquals(sort, that.sort);
+ }
+
+ private boolean querySettingsEquals(BasicQuery that) {
+ return super.equals(that);
+ }
+
+ /*
+ * (non-Javadoc)
+ */
+ @Override
+ public int hashCode() {
+
+ int result = super.hashCode();
+ result = 31 * result + nullSafeHashCode(getCriteriaList());
+ result = 31 * result + nullSafeHashCode(projectionFields);
+ result = 31 * result + nullSafeHashCode(sort);
+
+ return result;
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseAnnotationProcessor.java b/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseAnnotationProcessor.java
new file mode 100644
index 000000000..059931d98
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseAnnotationProcessor.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.couchbase.repository.support;
+
+import java.util.Collections;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.tools.Diagnostic;
+
+import org.springframework.data.couchbase.core.mapping.Document;
+import org.springframework.lang.Nullable;
+
+import com.querydsl.apt.AbstractQuerydslProcessor;
+import com.querydsl.apt.Configuration;
+import com.querydsl.apt.DefaultConfiguration;
+import com.querydsl.core.annotations.QueryEmbeddable;
+import com.querydsl.core.annotations.QueryEmbedded;
+import com.querydsl.core.annotations.QueryEntities;
+import com.querydsl.core.annotations.QuerySupertype;
+import com.querydsl.core.annotations.QueryTransient;
+
+/**
+ * Annotation processor to create Querydsl query types for QueryDsl annotated classes.
+ *
+ * @author Michael Reiche
+ */
+@SupportedAnnotationTypes({ "com.querydsl.core.annotations.*", "org.springframework.data.couchbase.core.mapping.*" })
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+public class CouchbaseAnnotationProcessor extends AbstractQuerydslProcessor {
+
+ /*
+ * (non-Javadoc)
+ * @see com.querydsl.apt.AbstractQuerydslProcessor#createConfiguration(javax.annotation.processing.RoundEnvironment)
+ */
+ @Override
+ protected Configuration createConfiguration(@Nullable RoundEnvironment roundEnv) {
+
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Running " + getClass().getSimpleName());
+
+ DefaultConfiguration configuration = new DefaultConfiguration(processingEnv, roundEnv, Collections.emptySet(),
+ QueryEntities.class, Document.class, QuerySupertype.class, QueryEmbeddable.class, QueryEmbedded.class,
+ QueryTransient.class);
+ configuration.setUnknownAsEmbedded(true);
+
+ return configuration;
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java b/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java
index d8bff2d00..bc05c5f60 100644
--- a/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java
+++ b/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2020 the original author or authors.
+ * Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +16,13 @@
package org.springframework.data.couchbase.repository.support;
+import static org.springframework.data.querydsl.QuerydslUtils.QUERY_DSL_PRESENT;
+
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Optional;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
@@ -30,9 +33,11 @@
import org.springframework.data.couchbase.repository.query.StringBasedCouchbaseQuery;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.projection.ProjectionFactory;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
+import org.springframework.data.repository.core.support.RepositoryComposition;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
@@ -53,6 +58,8 @@ public class CouchbaseRepositoryFactory extends RepositoryFactorySupport {
private static final SpelExpressionParser SPEL_PARSER = new SpelExpressionParser();
+ private final CouchbaseOperations operations;
+
/**
* Holds the reference to the template.
*/
@@ -76,7 +83,7 @@ public CouchbaseRepositoryFactory(final RepositoryOperationsMapping couchbaseOpe
this.couchbaseOperationsMapping = couchbaseOperationsMapping;
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
mappingContext = this.couchbaseOperationsMapping.getMappingContext();
-
+ operations = this.couchbaseOperationsMapping.getDefault();
addRepositoryProxyPostProcessor(crudMethodMetadataPostProcessor);
}
@@ -168,4 +175,44 @@ public RepositoryQuery resolveQuery(final Method method, final RepositoryMetadat
}
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryFragments(org.springframework.data.repository.core.RepositoryMetadata)
+ */
+ @Override
+ protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
+ return getRepositoryFragments(metadata, operations);
+ }
+
+ /**
+ * Creates {@link RepositoryComposition.RepositoryFragments} based on {@link RepositoryMetadata} to add
+ * Couchbase-specific extensions. Typically adds a {@link QuerydslCouchbasePredicateExecutor} if the repository
+ * interface uses Querydsl.
+ *
+ * Can be overridden by subclasses to customize {@link RepositoryComposition.RepositoryFragments}.
+ *
+ * @param metadata repository metadata.
+ * @param operations the Couchbase operations manager.
+ * @return
+ */
+ protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata,
+ CouchbaseOperations operations) {
+
+ boolean isQueryDslRepository = QUERY_DSL_PRESENT
+ && QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
+
+ if (isQueryDslRepository) {
+
+ if (metadata.isReactiveRepository()) {
+ throw new InvalidDataAccessApiUsageException(
+ "Cannot combine Querydsl and reactive repository support in a single interface");
+ }
+
+ return RepositoryComposition.RepositoryFragments
+ .just(new QuerydslCouchbasePredicateExecutor<>(getEntityInformation(metadata.getDomainType()), operations));
+ }
+
+ return RepositoryComposition.RepositoryFragments.empty();
+ }
+
}
diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/DBRef.java b/src/main/java/org/springframework/data/couchbase/repository/support/DBRef.java
new file mode 100644
index 000000000..c2ab85942
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/repository/support/DBRef.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-2022 the original author or authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.couchbase.repository.support;
+
+/**
+ * DB references
+ *
+ * @author Michael Reiche
+ */
+public class DBRef {
+ Object id;
+
+ public Object getId() {
+ return id;
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/FetchableFluentQuerySupport.java b/src/main/java/org/springframework/data/couchbase/repository/support/FetchableFluentQuerySupport.java
new file mode 100644
index 000000000..2ec692bd8
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/repository/support/FetchableFluentQuerySupport.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012-2022 the original author or authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.couchbase.repository.support;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.repository.query.FluentQuery;
+
+/**
+ * Querydsl fluent api
+ *
+ * @author Michael Reiche
+ */
+abstract class FetchableFluentQuerySupport
implements FluentQuery.FetchableFluentQuery {
+
+ private final P predicate;
+ private final Sort sort;
+ private final Class resultType;
+ private final List fieldsToInclude;
+
+ FetchableFluentQuerySupport(P predicate, Sort sort, Class resultType, List fieldsToInclude) {
+ this.predicate = predicate;
+ this.sort = sort;
+ this.resultType = resultType;
+ this.fieldsToInclude = fieldsToInclude;
+ }
+
+ protected abstract FetchableFluentQuerySupport create(P predicate, Sort sort, Class resultType,
+ List fieldsToInclude);
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
+ */
+ public abstract T oneValue();
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
+ */
+ public abstract T firstValue();
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
+ */
+ public abstract List all();
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
+ */
+ public abstract Page page(Pageable pageable);
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
+ */
+ public abstract Stream stream();
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
+ */
+ public abstract long count();
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
+ */
+ public abstract boolean exists();
+
+ P getPredicate() {
+ return predicate;
+ }
+
+ Sort getSort() {
+ return sort;
+ }
+
+ Class getResultType() {
+ return resultType;
+ }
+
+ List getFieldsToInclude() {
+ return fieldsToInclude;
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/QuerydslCouchbasePredicateExecutor.java b/src/main/java/org/springframework/data/couchbase/repository/support/QuerydslCouchbasePredicateExecutor.java
new file mode 100644
index 000000000..2048db9ef
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/repository/support/QuerydslCouchbasePredicateExecutor.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2017-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.couchbase.repository.support;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.data.couchbase.core.CouchbaseOperations;
+import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.querydsl.EntityPathResolver;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+import org.springframework.data.querydsl.SimpleEntityPathResolver;
+import org.springframework.data.repository.query.FluentQuery;
+import org.springframework.data.support.PageableExecutionUtils;
+import org.springframework.util.Assert;
+
+import com.querydsl.core.NonUniqueResultException;
+import com.querydsl.core.types.EntityPath;
+import com.querydsl.core.types.OrderSpecifier;
+import com.querydsl.core.types.Predicate;
+
+/**
+ * Couchbase-specific {@link QuerydslPredicateExecutor} that allows execution {@link Predicate}s in various forms.
+ *
+ * @author Michael Reiche
+ * @since 5.0
+ */
+public class QuerydslCouchbasePredicateExecutor extends QuerydslPredicateExecutorSupport
+ implements QuerydslPredicateExecutor {
+
+ private final CouchbaseOperations couchbaseOperations;
+
+ /**
+ * Creates a new {@link QuerydslCouchbasePredicateExecutor} for the given {@link CouchbaseEntityInformation} and
+ * {@link CouchbaseOperations}. Uses the {@link SimpleEntityPathResolver} to create an {@link EntityPath} for the
+ * given domain class.
+ *
+ * @param entityInformation must not be {@literal null}.
+ * @param couchbaseOperations must not be {@literal null}.
+ */
+ public QuerydslCouchbasePredicateExecutor(CouchbaseEntityInformation entityInformation,
+ CouchbaseOperations couchbaseOperations) {
+ this(entityInformation, couchbaseOperations, SimpleEntityPathResolver.INSTANCE);
+ }
+
+ /**
+ * Creates a new {@link QuerydslCouchbasePredicateExecutor} for the given {@link CouchbaseEntityInformation},
+ * {@linkCouchbaseOperations} and {@link EntityPathResolver}.
+ *
+ * @param entityInformation must not be {@literal null}.
+ * @param couchbaseOperations must not be {@literal null}.
+ * @param resolver must not be {@literal null}.
+ */
+ public QuerydslCouchbasePredicateExecutor(CouchbaseEntityInformation entityInformation,
+ CouchbaseOperations couchbaseOperations, EntityPathResolver resolver) {
+ super(couchbaseOperations.getConverter(), pathBuilderFor(resolver.createPath(entityInformation.getJavaType())),
+ entityInformation);
+ this.couchbaseOperations = couchbaseOperations;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findById(com.querydsl.core.types.Predicate)
+ */
+ @Override
+ public Optional findOne(Predicate predicate) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ try {
+ return Optional.ofNullable(createQueryFor(predicate).fetchOne());
+ } catch (NonUniqueResultException ex) {
+ throw new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.querydsl.core.types.Predicate)
+ */
+ @Override
+ public List findAll(Predicate predicate) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ return createQueryFor(predicate).fetch();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, com.querydsl.core.types.OrderSpecifier>[])
+ */
+ @Override
+ public List findAll(Predicate predicate, OrderSpecifier>... orders) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ Assert.notNull(orders, "Order specifiers must not be null!");
+ return createQueryFor(predicate).orderBy(orders).fetch();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Sort)
+ */
+ @Override
+ public List findAll(Predicate predicate, Sort sort) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ Assert.notNull(sort, "Sort must not be null!");
+ return applySorting(createQueryFor(predicate), sort).fetch();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.querydsl.core.types.OrderSpecifier[])
+ */
+ @Override
+ public Iterable findAll(OrderSpecifier>... orders) {
+ Assert.notNull(orders, "Order specifiers must not be null!");
+ return createQuery().orderBy(orders).fetch();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Pageable)
+ */
+ @Override
+ public Page findAll(Predicate predicate, Pageable pageable) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ Assert.notNull(pageable, "Pageable must not be null!");
+ SpringDataCouchbaseQuery query = createQueryFor(predicate);
+ return PageableExecutionUtils.getPage(applyPagination(query, pageable).fetch(), pageable, query::fetchCount);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#count(com.querydsl.core.types.Predicate)
+ */
+ @Override
+ public long count(Predicate predicate) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ return createQueryFor(predicate).fetchCount();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#exists(com.querydsl.core.types.Predicate)
+ */
+ @Override
+ public boolean exists(Predicate predicate) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ return createQueryFor(predicate).fetchCount() > 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findBy(com.querydsl.core.types.Predicate, java.util.function.Function)
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public R findBy(Predicate predicate,
+ Function, R> queryFunction) {
+ Assert.notNull(predicate, "Predicate must not be null!");
+ Assert.notNull(queryFunction, "Query function must not be null!");
+ return queryFunction.apply(new FluentQuerydsl<>(predicate, (Class) typeInformation().getJavaType()));
+ }
+
+ /**
+ * Creates a {@link SpringDataCouchbaseQuery} for the given {@link Predicate}.
+ *
+ * @param predicate
+ * @return
+ */
+ private SpringDataCouchbaseQuery createQueryFor(Predicate predicate) {
+ return createQuery().where(predicate);
+ }
+
+ /**
+ * Creates a {@link SpringDataCouchbaseQuery}.
+ *
+ * @return
+ */
+ private SpringDataCouchbaseQuery createQuery() {
+ return new SpringDataCouchbaseQuery<>(couchbaseOperations, typeInformation().getJavaType());
+ }
+
+ /**
+ * Applies the given {@link Pageable} to the given {@link SpringDataCouchbaseQuery}.
+ *
+ * @param query
+ * @param pageable
+ * @return
+ */
+ private SpringDataCouchbaseQuery applyPagination(SpringDataCouchbaseQuery query, Pageable pageable) {
+ if (pageable.isUnpaged()) {
+ return query;
+ }
+ query = query.offset(pageable.getOffset()).limit(pageable.getPageSize());
+ return applySorting(query, pageable.getSort());
+ }
+
+ /**
+ * Applies the given {@link Sort} to the given {@link SpringDataCouchbaseQuery}.
+ *
+ * @param query
+ * @param sort
+ * @return
+ */
+ private SpringDataCouchbaseQuery applySorting(SpringDataCouchbaseQuery query, Sort sort) {
+ toOrderSpecifiers(sort).forEach(query::orderBy);
+ return query;
+ }
+
+ /**
+ * {@link org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery} using Querydsl
+ * {@link Predicate}.
+ *
+ * @author Mark Paluch
+ * @since 3.3
+ */
+ class FluentQuerydsl extends FetchableFluentQuerySupport {
+
+ FluentQuerydsl(Predicate predicate, Class resultType) {
+ this(predicate, Sort.unsorted(), resultType, Collections.emptyList());
+ }
+
+ FluentQuerydsl(Predicate predicate, Sort sort, Class resultType, List fieldsToInclude) {
+ super(predicate, sort, resultType, fieldsToInclude);
+ }
+
+ @Override
+ protected FluentQuerydsl create(Predicate predicate, Sort sort, Class resultType,
+ List fieldsToInclude) {
+ return new FluentQuerydsl<>(predicate, sort, resultType, fieldsToInclude);
+ }
+
+ @Override
+ public FetchableFluentQuery sortBy(Sort sort) {
+ return null;
+ }
+
+ @Override
+ public FetchableFluentQuery project(Collection properties) {
+ return null;
+ }
+
+ @Override
+ public FetchableFluentQuery as(Class resultType) {
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
+ */
+ @Override
+ public T oneValue() {
+ return createQuery().fetchOne();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
+ */
+ @Override
+ public T firstValue() {
+ return createQuery().fetchFirst();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
+ */
+ @Override
+ public List all() {
+ return createQuery().fetch();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
+ */
+ @Override
+ public Page page(Pageable pageable) {
+
+ Assert.notNull(pageable, "Pageable must not be null!");
+
+ return createQuery().fetchPage(pageable);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
+ */
+ @Override
+ public Stream stream() {
+ return createQuery().stream();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
+ */
+ @Override
+ public long count() {
+ return createQuery().fetchCount();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
+ */
+ @Override
+ public boolean exists() {
+ return count() > 0;
+ }
+
+ private SpringDataCouchbaseQuery createQuery() {
+ return new SpringDataCouchbaseQuery<>(couchbaseOperations, typeInformation().getJavaType(), getResultType(),
+ "collection", this::customize).where(getPredicate());
+ }
+
+ private void customize(BasicQuery query) {
+
+ List fieldsToInclude = getFieldsToInclude();
+ if (!fieldsToInclude.isEmpty()) {
+ Map fields = new HashMap();
+ fieldsToInclude.forEach(field -> fields.put(field, field));
+ query.setProjectionFields(fields);
+ }
+
+ if (getSort().isSorted()) {
+ query.with(getSort());
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/QuerydslPredicateExecutorSupport.java b/src/main/java/org/springframework/data/couchbase/repository/support/QuerydslPredicateExecutorSupport.java
new file mode 100644
index 000000000..88685db55
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/repository/support/QuerydslPredicateExecutorSupport.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012-2022 the original author or authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.couchbase.repository.support;
+
+import com.querydsl.core.types.EntityPath;
+import com.querydsl.core.types.Expression;
+import com.querydsl.core.types.OrderSpecifier;
+import com.querydsl.core.types.dsl.PathBuilder;
+import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.querydsl.QSort;
+import org.springframework.data.repository.core.EntityInformation;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Michael Reiche
+ */
+public class QuerydslPredicateExecutorSupport {
+
+ private final SpringDataCouchbaseSerializer serializer;
+ private final PathBuilder builder;
+ private final EntityInformation entityInformation;
+
+ QuerydslPredicateExecutorSupport(CouchbaseConverter converter, PathBuilder builder,
+ EntityInformation entityInformation) {
+
+ this.serializer = new SpringDataCouchbaseSerializer(converter);
+ this.builder = builder;
+ this.entityInformation = entityInformation;
+ }
+
+ protected static PathBuilder pathBuilderFor(EntityPath path) {
+ return new PathBuilder<>(path.getType(), path.getMetadata());
+ }
+
+ protected EntityInformation typeInformation() {
+ return entityInformation;
+ }
+
+ protected SpringDataCouchbaseSerializer cuchbaseSerializer() {
+ return serializer;
+ }
+
+ /**
+ * Transforms a plain {@link Sort.Order} into a Querydsl specific {@link OrderSpecifier}.
+ *
+ * @param order
+ * @return
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected OrderSpecifier> toOrder(Sort.Order order) {
+
+ Expression