Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
package org.springframework.data.couchbase.core;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;

import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.support.OneAndAllId;
import org.springframework.data.couchbase.core.support.InCollection;
import org.springframework.data.couchbase.core.support.WithGetOptions;
Expand All @@ -33,6 +35,7 @@
*
* @author Christoph Strobl
* @author Tigran Babloyan
* @author Emilien Bevierre
* @since 2.0
*/
public interface ExecutableFindByIdOperation {
Expand Down Expand Up @@ -122,6 +125,17 @@ interface FindByIdWithProjection<T> extends FindByIdInScope<T>, WithProjectionId
*/
@Override
FindByIdInScope<T> project(String... fields);

/**
* Type-safe variant of {@link #project(String...)} using property paths.
*
* @param fields the property paths to project.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default FindByIdInScope<T> project(TypedPropertyPath<T, ?>... fields) {
return project(Arrays.stream(fields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
}

interface FindByIdWithExpiry<T> extends FindByIdWithProjection<T>, WithExpiry<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
package org.springframework.data.couchbase.core;

import java.util.List;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;

import org.springframework.dao.IncorrectResultSizeDataAccessException;

import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.QueryCriteriaDefinition;
import org.springframework.data.couchbase.core.support.InCollection;
Expand All @@ -38,6 +41,7 @@
* Query Operations
*
* @author Christoph Strobl
* @author Emilien Bevierre
* @since 2.0
*/
public interface ExecutableFindByQueryOperation {
Expand Down Expand Up @@ -270,6 +274,17 @@ interface FindByQueryWithProjecting<T> extends FindByQueryWithProjection<T> {
* @throws IllegalArgumentException if returnType is {@literal null}.
*/
FindByQueryWithProjection<T> project(String[] fields);

/**
* Type-safe variant of {@link #project(String[])} using property paths.
*
* @param fields the property paths to project.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default FindByQueryWithProjection<T> project(TypedPropertyPath<T, ?>... fields) {
return project(Arrays.stream(fields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
}

/**
Expand All @@ -288,6 +303,17 @@ interface FindByQueryWithDistinct<T> extends FindByQueryWithProjecting<T>, WithD
*/
@Override
FindByQueryWithProjection<T> distinct(String[] distinctFields);

/**
* Type-safe variant of {@link #distinct(String[])} using property paths.
*
* @param distinctFields the property paths for distinct fields.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default FindByQueryWithProjection<T> distinct(TypedPropertyPath<T, ?>... distinctFields) {
return distinct(Arrays.stream(distinctFields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
Comment on lines 284 to +316
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project(TypedPropertyPath...) and distinct(TypedPropertyPath...) overloads use TypedPropertyPath<?, ?>..., which allows passing paths unrelated to the queried entity type T. Consider changing them to TypedPropertyPath<T, ?>... so these overloads actually enforce type-safe paths for this fluent API.

Copilot uses AI. Check for mistakes.
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.stream.Stream;

import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.support.InCollection;
import org.springframework.data.couchbase.core.support.InScope;
import org.springframework.data.couchbase.core.support.WithSearchConsistency;
Expand Down Expand Up @@ -167,6 +168,9 @@ interface FindBySearchWithSkip<T> extends FindBySearchWithLimit<T> {

interface FindBySearchWithSort<T> extends FindBySearchWithSkip<T> {
FindBySearchWithSkip<T> withSort(SearchSort... sort);

<P> FindBySearchWithSkip<T> withSort(TypedPropertyPath<P, ?> property,
TypedPropertyPath<P, ?>... additionalProperties);
}

interface FindBySearchWithHighlight<T> extends FindBySearchWithSort<T> {
Expand All @@ -175,6 +179,14 @@ interface FindBySearchWithHighlight<T> extends FindBySearchWithSort<T> {
default FindBySearchWithSort<T> withHighlight(String... fields) {
return withHighlight(HighlightStyle.SERVER_DEFAULT, fields);
}

<P> FindBySearchWithSort<T> withHighlight(HighlightStyle style, TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields);

default <P> FindBySearchWithSort<T> withHighlight(TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields) {
return withHighlight(HighlightStyle.SERVER_DEFAULT, field, additionalFields);
}
}

interface FindBySearchWithFacets<T> extends FindBySearchWithHighlight<T> {
Expand All @@ -183,6 +195,9 @@ interface FindBySearchWithFacets<T> extends FindBySearchWithHighlight<T> {

interface FindBySearchWithFields<T> extends FindBySearchWithFacets<T> {
FindBySearchWithFacets<T> withFields(String... fields);

<P> FindBySearchWithFacets<T> withFields(TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields);
Comment on lines 169 to +200
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new overloads declare their own type parameter <P> instead of reusing the fluent API's entity type <T>, which allows callers to pass property paths unrelated to the searched entity. Consider changing these signatures to TypedPropertyPath<T, ?> (and corresponding varargs) to make the overloads actually type-safe for the operation.

Copilot uses AI. Check for mistakes.
}

interface FindBySearchWithProjection<T> extends FindBySearchWithFields<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Map;
import java.util.stream.Stream;

import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.ReactiveFindBySearchOperationSupport.ReactiveFindBySearchSupport;
import org.springframework.data.couchbase.core.query.OptionsBuilder;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -186,8 +187,8 @@ public FindBySearchWithOptions<T> inCollection(final String collection) {
@Override
public FindBySearchWithQuery<T> withOptions(final SearchOptions options) {
return new ExecutableFindBySearchSupport<>(template, domainType, returnType, indexName, searchRequest,
scanConsistency, scope, collection, options != null ? options : this.options, sort,
highlightStyle, highlightFields, facets, fields, limitSkip);
scanConsistency, scope, collection, options != null ? options : this.options, sort, highlightStyle,
highlightFields, facets, fields, limitSkip);
}

@Override
Expand Down Expand Up @@ -215,11 +216,23 @@ public FindBySearchWithSkip<T> withSort(SearchSort... sort) {
fields, limitSkip);
}

@Override
public <P> FindBySearchWithSkip<T> withSort(TypedPropertyPath<P, ?> property,
TypedPropertyPath<P, ?>... additionalProperties) {
return withSort(SearchPropertyPathSupport.toSearchSorts(template.getConverter(), property, additionalProperties));
}
Comment on lines +219 to +223
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These implementations mirror the interface issue: the overload introduces a fresh <P> type parameter instead of tying the path root to the searched entity type <T>, so callers can pass property paths for unrelated classes. Update the signature to accept TypedPropertyPath<T, ?> (and varargs) so it is truly type-safe for this operation.

Copilot uses AI. Check for mistakes.

@Override
public FindBySearchWithSort<T> withHighlight(HighlightStyle style, String... fields) {
return new ExecutableFindBySearchSupport<>(template, domainType, returnType, indexName, searchRequest,
scanConsistency, scope, collection, options, sort, style, fields, facets,
this.fields, limitSkip);
scanConsistency, scope, collection, options, sort, style, fields, facets, this.fields, limitSkip);
}

@Override
public <P> FindBySearchWithSort<T> withHighlight(HighlightStyle style, TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields) {
return withHighlight(style,
SearchPropertyPathSupport.getMappedFieldPaths(template.getConverter(), field, additionalFields));
}

@Override
Expand All @@ -235,5 +248,11 @@ public FindBySearchWithFacets<T> withFields(String... fields) {
scanConsistency, scope, collection, options, sort, highlightStyle, highlightFields, facets,
fields, limitSkip);
}

@Override
public <P> FindBySearchWithFacets<T> withFields(TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields) {
return withFields(SearchPropertyPathSupport.getMappedFieldPaths(template.getConverter(), field, additionalFields));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@
import com.couchbase.client.java.kv.MutateInOptions;
import com.couchbase.client.java.kv.PersistTo;
import com.couchbase.client.java.kv.ReplicateTo;
import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.support.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;

/**
* Mutate In Operations
*
* @author Tigran Babloyan
* @author Emilien Bevierre
* @since 5.1
*/
public interface ExecutableMutateInByIdOperation {
Expand Down Expand Up @@ -98,6 +101,42 @@ interface MutateInByIdWithPaths<T> extends TerminatingMutateInById<T>, WithMutat
* By default the CAS value is not provided.
*/
MutateInByIdWithPaths<T> withCasProvided();

/**
* Type-safe variant of {@link #withRemovePaths(String...)} using property paths.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default MutateInByIdWithPaths<T> withRemovePaths(TypedPropertyPath<T, ?>... removePaths) {
return withRemovePaths(Arrays.stream(removePaths).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}

/**
* Type-safe variant of {@link #withInsertPaths(String...)} using property paths.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default MutateInByIdWithPaths<T> withInsertPaths(TypedPropertyPath<T, ?>... insertPaths) {
return withInsertPaths(Arrays.stream(insertPaths).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}

/**
* Type-safe variant of {@link #withUpsertPaths(String...)} using property paths.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default MutateInByIdWithPaths<T> withUpsertPaths(TypedPropertyPath<T, ?>... upsertPaths) {
return withUpsertPaths(Arrays.stream(upsertPaths).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}

/**
* Type-safe variant of {@link #withReplacePaths(String...)} using property paths.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default MutateInByIdWithPaths<T> withReplacePaths(TypedPropertyPath<T, ?>... replacePaths) {
return withReplacePaths(Arrays.stream(replacePaths).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
Comment on lines +105 to +139
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new overloads accept TypedPropertyPath<?, ?>... even though the fluent API is parameterized with <T>, which allows passing paths unrelated to the mutated entity type. Consider changing them to TypedPropertyPath<T, ?>... to keep the API genuinely type-safe.

Copilot uses AI. Check for mistakes.
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;

import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.support.InCollection;
import org.springframework.data.couchbase.core.support.InScope;
import org.springframework.data.couchbase.core.support.OneAndAllIdReactive;
Expand All @@ -36,6 +38,7 @@
*
* @author Christoph Strobl
* @author Tigran Babloyan
* @author Emilien Bevierre
* @since 2.0
*/
public interface ReactiveFindByIdOperation {
Expand Down Expand Up @@ -126,6 +129,17 @@ interface FindByIdWithProjection<T> extends FindByIdInScope<T>, WithProjectionId
*/
FindByIdInCollection<T> project(String... fields);

/**
* Type-safe variant of {@link #project(String...)} using property paths.
*
* @param fields the property paths to project.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default FindByIdInCollection<T> project(TypedPropertyPath<T, ?>... fields) {
return project(Arrays.stream(fields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}

}

interface FindByIdWithExpiry<T> extends FindByIdWithProjection<T>, WithExpiry<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Arrays;

import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.QueryCriteriaDefinition;
import org.springframework.data.couchbase.core.support.InCollection;
Expand All @@ -38,6 +41,7 @@
*
* @author Michael Nitschinger
* @author Michael Reiche
* @author Emilien Bevierre
*/
public interface ReactiveFindByQueryOperation {

Expand Down Expand Up @@ -217,6 +221,17 @@ interface FindByQueryWithProjecting<T> extends FindByQueryWithProjection<T> {
* @throws IllegalArgumentException if returnType is {@literal null}.
*/
FindByQueryWithProjection<T> project(String[] fields);

/**
* Type-safe variant of {@link #project(String[])} using property paths.
*
* @param fields the property paths to project.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default FindByQueryWithProjection<T> project(TypedPropertyPath<T, ?>... fields) {
return project(Arrays.stream(fields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
}

/**
Expand All @@ -234,6 +249,17 @@ interface FindByQueryWithDistinct<T> extends FindByQueryWithProjecting<T>, WithD
* @throws IllegalArgumentException if field is {@literal null}.
*/
FindByQueryWithProjection<T> distinct(String[] distinctFields);

/**
* Type-safe variant of {@link #distinct(String[])} using property paths.
*
* @param distinctFields the property paths for distinct fields.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default FindByQueryWithProjection<T> distinct(TypedPropertyPath<T, ?>... distinctFields) {
return distinct(Arrays.stream(distinctFields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
Comment on lines 225 to +262
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new project(TypedPropertyPath...)/distinct(TypedPropertyPath...) overloads use TypedPropertyPath<?, ?>... which allows paths unrelated to the queried entity type T. Consider changing them to TypedPropertyPath<T, ?>... to preserve type-safety across this fluent API.

Copilot uses AI. Check for mistakes.
Comment on lines 225 to +262
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These TypedPropertyPath<?, ?>... varargs overloads will emit "unchecked/heap pollution" warnings unless suppressed. Add an appropriate suppression (or refactor to avoid parameterized varargs) to keep the build warning-free.

Copilot uses AI. Check for mistakes.
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Map;

import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.support.InCollection;
import org.springframework.data.couchbase.core.support.InScope;
import org.springframework.data.couchbase.core.support.WithSearchConsistency;
Expand Down Expand Up @@ -192,6 +193,9 @@ interface FindBySearchWithSort<T> extends FindBySearchWithSkip<T> {
* @param sort the sort specifications.
*/
FindBySearchWithSkip<T> withSort(SearchSort... sort);

<P> FindBySearchWithSkip<T> withSort(TypedPropertyPath<P, ?> property,
TypedPropertyPath<P, ?>... additionalProperties);
}

/**
Expand All @@ -214,6 +218,14 @@ interface FindBySearchWithHighlight<T> extends FindBySearchWithSort<T> {
default FindBySearchWithSort<T> withHighlight(String... fields) {
return withHighlight(HighlightStyle.SERVER_DEFAULT, fields);
}

<P> FindBySearchWithSort<T> withHighlight(HighlightStyle style, TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields);

default <P> FindBySearchWithSort<T> withHighlight(TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields) {
return withHighlight(HighlightStyle.SERVER_DEFAULT, field, additionalFields);
}
}

/**
Expand All @@ -238,6 +250,9 @@ interface FindBySearchWithFields<T> extends FindBySearchWithFacets<T> {
* @param fields the field names.
*/
FindBySearchWithFacets<T> withFields(String... fields);

<P> FindBySearchWithFacets<T> withFields(TypedPropertyPath<P, ?> field,
TypedPropertyPath<P, ?>... additionalFields);
}

/**
Expand Down
Loading
Loading