Skip to content

Add type-safe property paths overloads (#2126)#2128

Open
emilienbev wants to merge 2 commits intoAddFTSfrom
AddTypeSafetyPropertyReferences
Open

Add type-safe property paths overloads (#2126)#2128
emilienbev wants to merge 2 commits intoAddFTSfrom
AddTypeSafetyPropertyReferences

Conversation

@emilienbev
Copy link
Copy Markdown
Collaborator

Fixes #2126

  • You have read the Spring Data contribution guidelines.
  • There is a ticket in the bug tracker for the project in our JIRA.
  • You use the code formatters provided here and have them applied to your changes. Don’t submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.
  • You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).

Fixes #2085

Signed-off-by: Emilien Bevierre <emilien.bevierre@couchbase.com>
Fixes #2126

Signed-off-by: Emilien Bevierre <emilien.bevierre@couchbase.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces type-safe (method-reference based) property path overloads across Couchbase query/search fluent APIs, reducing reliance on string-based field names and adding mapping support for FTS field paths.

Changes:

  • Added TypedPropertyPath overloads for projection, distinct, mutate-in paths, query criteria chaining, and FTS search configuration (sort/highlight/fields).
  • Introduced SearchPropertyPathSupport to map TypedPropertyPath to stored field names (including @Field aliases) for FTS operations.
  • Added new unit tests covering typed property references and mapped FTS field path resolution.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 21 comments.

Show a summary per file
File Description
src/main/java/org/springframework/data/couchbase/core/ExecutableFindByIdOperation.java Adds type-safe project(TypedPropertyPath...) overload.
src/main/java/org/springframework/data/couchbase/core/ReactiveFindByIdOperation.java Adds type-safe project(TypedPropertyPath...) overload (reactive).
src/main/java/org/springframework/data/couchbase/core/ExecutableFindByQueryOperation.java Adds type-safe project/distinct(TypedPropertyPath...) overloads (blocking).
src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperation.java Adds type-safe project/distinct(TypedPropertyPath...) overloads (reactive).
src/main/java/org/springframework/data/couchbase/core/query/QueryCriteria.java Adds where/and/or(TypedPropertyPath...) overloads.
src/main/java/org/springframework/data/couchbase/core/query/Query.java Adds distinct(TypedPropertyPath...) overload.
src/main/java/org/springframework/data/couchbase/core/ExecutableMutateInByIdOperation.java Adds type-safe mutate-in path overloads (blocking).
src/main/java/org/springframework/data/couchbase/core/ReactiveMutateInByIdOperation.java Adds type-safe mutate-in path overloads (reactive).
src/main/java/org/springframework/data/couchbase/core/support/WithProjectionId.java Adds common type-safe project(TypedPropertyPath...) default method.
src/main/java/org/springframework/data/couchbase/core/support/WithProjecting.java Adds common type-safe project(TypedPropertyPath...) default method.
src/main/java/org/springframework/data/couchbase/core/support/WithDistinct.java Adds common type-safe distinct(TypedPropertyPath...) default method.
src/main/java/org/springframework/data/couchbase/core/support/WithMutateInPaths.java Adds common type-safe mutate-in path default methods.
src/main/java/org/springframework/data/couchbase/core/ExecutableFindBySearchOperation.java Adds type-safe FTS overloads for sort/highlight/fields (blocking).
src/main/java/org/springframework/data/couchbase/core/ReactiveFindBySearchOperation.java Adds type-safe FTS overloads for sort/highlight/fields (reactive).
src/main/java/org/springframework/data/couchbase/core/ExecutableFindBySearchOperationSupport.java Implements new typed FTS overloads (blocking).
src/main/java/org/springframework/data/couchbase/core/ReactiveFindBySearchOperationSupport.java Implements new typed FTS overloads (reactive).
src/main/java/org/springframework/data/couchbase/core/SearchPropertyPathSupport.java New helper to map typed property paths to stored field names and FTS sorts.
src/main/java/org/springframework/data/couchbase/repository/query/SearchBasedCouchbaseQuery.java Minor whitespace cleanup.
src/main/java/org/springframework/data/couchbase/repository/query/ReactiveSearchBasedCouchbaseQuery.java Minor whitespace cleanup.
src/test/java/org/springframework/data/couchbase/core/SearchPropertyPathSupportTests.java New tests for mapped field path resolution (incl. @Field alias + nesting).
src/test/java/org/springframework/data/couchbase/core/query/TypeSafePropertyReferenceTests.java New tests for typed paths in QueryCriteria, Query.distinct, and Sort.
src/test/java/org/springframework/data/couchbase/core/ExecutableFindBySearchOperationTests.java Reflection-based checks ensuring typed overloads exist on interfaces.
src/test/java/org/springframework/data/couchbase/repository/query/SearchBasedCouchbaseQueryTests.java Test scaffolding updated to compile with new typed overloads.
src/test/java/org/springframework/data/couchbase/repository/query/ReactiveSearchBasedCouchbaseQueryTests.java Test scaffolding updated to compile with new typed overloads.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 18 to 26
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import org.springframework.dao.IncorrectResultSizeDataAccessException;
import java.util.Arrays;

import org.springframework.data.core.TypedPropertyPath;
import org.springframework.data.couchbase.core.query.Query;
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.

Import ordering is inconsistent: java.util.Arrays is placed after org.springframework... imports. Reorder imports into the usual groups (java/javax → org.springframework → third-party) to match the project's formatting and avoid checkstyle/formatter diffs.

Copilot uses AI. Check for mistakes.
* @param fields the property paths to project.
* @since 6.1
*/
default Object project(TypedPropertyPath<?, ?>... fields) {
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 overload uses TypedPropertyPath<?, ?>... which weakens type-safety and allows passing paths unrelated to R. Consider changing the signature to TypedPropertyPath<R, ?>... so projected fields are constrained to the operation's entity type.

Suggested change
default Object project(TypedPropertyPath<?, ?>... fields) {
default Object project(TypedPropertyPath<R, ?>... fields) {

Copilot uses AI. Check for mistakes.
*
* @param fields the property paths to project.
* @since 6.1
*/
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.

This TypedPropertyPath<?, ?>... varargs method will trigger an "unchecked/heap pollution" compiler warning unless suppressed (similar methods in other files use @SuppressWarnings("unchecked")). Add an appropriate suppression (or refactor to avoid parameterized varargs) to keep the build warning-free.

Suggested change
*/
*/
@SuppressWarnings("unchecked")

Copilot uses AI. Check for mistakes.
* @param fields the property paths to project.
* @since 6.1
*/
default Object project(TypedPropertyPath<?, ?>... fields) {
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 overload uses TypedPropertyPath<?, ?>... which weakens type-safety and allows passing paths unrelated to R. Consider changing the signature to TypedPropertyPath<R, ?>... so projected fields are constrained to the operation's entity type.

Suggested change
default Object project(TypedPropertyPath<?, ?>... fields) {
default Object project(TypedPropertyPath<R, ?>... fields) {

Copilot uses AI. Check for mistakes.
*
* @param fields the property paths to project.
* @since 6.1
*/
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.

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

Suggested change
*/
*/
@SuppressWarnings("unchecked")

Copilot uses AI. Check for mistakes.
Comment on lines 225 to +260
@@ -234,6 +248,16 @@ 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
*/
default FindByQueryWithProjection<T> distinct(TypedPropertyPath<?, ?>... distinctFields) {
return distinct(Arrays.stream(distinctFields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
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.
Comment on lines 284 to +316
@@ -288,6 +303,17 @@
*/
@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<?, ?>... distinctFields) {
return distinct(Arrays.stream(distinctFields).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
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.
Comment on lines +105 to +139
/**
* Type-safe variant of {@link #withRemovePaths(String...)} using property paths.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default MutateInByIdWithPaths<T> withRemovePaths(TypedPropertyPath<?, ?>... 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<?, ?>... 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<?, ?>... 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<?, ?>... replacePaths) {
return withReplacePaths(Arrays.stream(replacePaths).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
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.
Comment on lines +135 to +136
@SuppressWarnings("unchecked")
default FindByIdInScope<T> project(TypedPropertyPath<?, ?>... fields) {
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.

This new overload uses TypedPropertyPath<?, ?>..., which allows passing paths unrelated to the entity type T. Consider changing it to TypedPropertyPath<T, ?>... so the projection paths are constrained to the entity being loaded.

Suggested change
@SuppressWarnings("unchecked")
default FindByIdInScope<T> project(TypedPropertyPath<?, ?>... fields) {
default FindByIdInScope<T> project(TypedPropertyPath<T, ?>... fields) {

Copilot uses AI. Check for mistakes.
* @since 6.1
*/
@SuppressWarnings("unchecked")
default FindByIdInCollection<T> project(TypedPropertyPath<?, ?>... fields) {
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.

This new overload uses TypedPropertyPath<?, ?>..., which allows passing paths unrelated to the entity type T. Consider changing it to TypedPropertyPath<T, ?>... so projection paths are constrained to the entity being loaded (matching the intent of type-safe property paths).

Suggested change
default FindByIdInCollection<T> project(TypedPropertyPath<?, ?>... fields) {
default FindByIdInCollection<T> project(TypedPropertyPath<T, ?>... fields) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants