Skip to content

Commit 0894112

Browse files
committed
Add support for FTS
Fixes #2085 Signed-off-by: Emilien Bevierre <emilien.bevierre@couchbase.com>
1 parent c4c3cfb commit 0894112

29 files changed

Lines changed: 3399 additions & 8 deletions

src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
* @author Michael Reiche
5050
* @author Jorge Rodriguez Martin
5151
* @author Tigran Babloyan
52+
* @author Emilien Bevierre
5253
* @since 3.0
5354
*/
5455
public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContextAware {
@@ -188,6 +189,11 @@ public <T> ExecutableFindByAnalytics<T> findByAnalytics(Class<T> domainType) {
188189
return new ExecutableFindByAnalyticsOperationSupport(this).findByAnalytics(domainType);
189190
}
190191

192+
@Override
193+
public <T> ExecutableFindBySearch<T> findBySearch(Class<T> domainType) {
194+
return new ExecutableFindBySearchOperationSupport(this).findBySearch(domainType);
195+
}
196+
191197
@Override
192198
@Deprecated
193199
public ExecutableRemoveById removeById() {
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Copyright 2025-present the original author or authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.couchbase.core;
17+
18+
import java.util.List;
19+
import java.util.Map;
20+
import java.util.Optional;
21+
import java.util.stream.Stream;
22+
23+
import org.springframework.dao.IncorrectResultSizeDataAccessException;
24+
import org.springframework.data.couchbase.core.support.InCollection;
25+
import org.springframework.data.couchbase.core.support.InScope;
26+
import org.springframework.data.couchbase.core.support.WithSearchConsistency;
27+
import org.springframework.data.couchbase.core.support.WithSearchOptions;
28+
import org.springframework.data.couchbase.core.support.WithSearchQuery;
29+
import org.jspecify.annotations.Nullable;
30+
31+
import com.couchbase.client.java.search.HighlightStyle;
32+
import com.couchbase.client.java.search.SearchOptions;
33+
import com.couchbase.client.java.search.SearchRequest;
34+
import com.couchbase.client.java.search.SearchScanConsistency;
35+
import com.couchbase.client.java.search.facet.SearchFacet;
36+
import com.couchbase.client.java.search.result.SearchRow;
37+
import com.couchbase.client.java.search.sort.SearchSort;
38+
39+
/**
40+
* Full-Text Search (FTS) Operations (Blocking)
41+
*
42+
* @author Emilien Bevierre
43+
* @since 6.2
44+
*/
45+
public interface ExecutableFindBySearchOperation {
46+
47+
/**
48+
* Queries the Full-Text Search (FTS) service.
49+
*
50+
* @param domainType the entity type to use for the results.
51+
*/
52+
<T> ExecutableFindBySearch<T> findBySearch(Class<T> domainType);
53+
54+
interface TerminatingFindBySearch<T> {
55+
56+
/**
57+
* Get exactly zero or one result.
58+
*
59+
* @return {@link Optional#empty()} if no match found.
60+
* @throws IncorrectResultSizeDataAccessException if more than one match found.
61+
*/
62+
default Optional<T> one() {
63+
return Optional.ofNullable(oneValue());
64+
}
65+
66+
/**
67+
* Get exactly zero or one result.
68+
*
69+
* @return {@literal null} if no match found.
70+
* @throws IncorrectResultSizeDataAccessException if more than one match found.
71+
*/
72+
@Nullable
73+
T oneValue();
74+
75+
/**
76+
* Get the first or no result.
77+
*
78+
* @return {@link Optional#empty()} if no match found.
79+
*/
80+
default Optional<T> first() {
81+
return Optional.ofNullable(firstValue());
82+
}
83+
84+
/**
85+
* Get the first or no result.
86+
*
87+
* @return {@literal null} if no match found.
88+
*/
89+
@Nullable
90+
T firstValue();
91+
92+
/**
93+
* Get all matching elements, hydrated as entities via KV GET.
94+
*
95+
* @return never {@literal null}.
96+
*/
97+
List<T> all();
98+
99+
/**
100+
* Stream all matching elements.
101+
*
102+
* @return a {@link Stream} of results. Never {@literal null}.
103+
*/
104+
Stream<T> stream();
105+
106+
/**
107+
* Get the number of matching elements.
108+
*
109+
* @return total number of matching elements.
110+
*/
111+
long count();
112+
113+
/**
114+
* Check for the presence of matching elements.
115+
*
116+
* @return {@literal true} if at least one matching element exists.
117+
*/
118+
boolean exists();
119+
120+
/**
121+
* Get raw FTS search rows (without entity hydration).
122+
*
123+
* @return never {@literal null}.
124+
*/
125+
List<SearchRow> rows();
126+
127+
/**
128+
* Get a combined result including hydrated entities, raw rows, metadata, and facet results.
129+
*
130+
* @return a {@link SearchResult} containing the full response.
131+
*/
132+
SearchResult<T> result();
133+
}
134+
135+
interface FindBySearchWithQuery<T> extends TerminatingFindBySearch<T>, WithSearchQuery<T> {
136+
@Override
137+
TerminatingFindBySearch<T> matching(SearchRequest searchRequest);
138+
}
139+
140+
interface FindBySearchWithOptions<T> extends FindBySearchWithQuery<T>, WithSearchOptions<T> {
141+
@Override
142+
FindBySearchWithQuery<T> withOptions(SearchOptions options);
143+
}
144+
145+
interface FindBySearchInCollection<T> extends FindBySearchWithOptions<T>, InCollection<T> {
146+
@Override
147+
FindBySearchWithOptions<T> inCollection(String collection);
148+
}
149+
150+
interface FindBySearchInScope<T> extends FindBySearchInCollection<T>, InScope<T> {
151+
@Override
152+
FindBySearchInCollection<T> inScope(String scope);
153+
}
154+
155+
interface FindBySearchWithConsistency<T> extends FindBySearchInScope<T>, WithSearchConsistency<T> {
156+
@Override
157+
FindBySearchInScope<T> withConsistency(SearchScanConsistency scanConsistency);
158+
}
159+
160+
interface FindBySearchWithLimit<T> extends FindBySearchWithConsistency<T> {
161+
FindBySearchWithConsistency<T> withLimit(int limit);
162+
}
163+
164+
interface FindBySearchWithSkip<T> extends FindBySearchWithLimit<T> {
165+
FindBySearchWithLimit<T> withSkip(int skip);
166+
}
167+
168+
interface FindBySearchWithSort<T> extends FindBySearchWithSkip<T> {
169+
FindBySearchWithSkip<T> withSort(SearchSort... sort);
170+
}
171+
172+
interface FindBySearchWithHighlight<T> extends FindBySearchWithSort<T> {
173+
FindBySearchWithSort<T> withHighlight(HighlightStyle style, String... fields);
174+
175+
default FindBySearchWithSort<T> withHighlight(String... fields) {
176+
return withHighlight(HighlightStyle.SERVER_DEFAULT, fields);
177+
}
178+
}
179+
180+
interface FindBySearchWithFacets<T> extends FindBySearchWithHighlight<T> {
181+
FindBySearchWithHighlight<T> withFacets(Map<String, SearchFacet> facets);
182+
}
183+
184+
interface FindBySearchWithFields<T> extends FindBySearchWithFacets<T> {
185+
FindBySearchWithFacets<T> withFields(String... fields);
186+
}
187+
188+
interface FindBySearchWithProjection<T> extends FindBySearchWithFields<T> {
189+
<R> FindBySearchWithFields<R> as(Class<R> returnType);
190+
}
191+
192+
interface FindBySearchWithIndex<T> extends FindBySearchWithProjection<T> {
193+
FindBySearchWithProjection<T> withIndex(String indexName);
194+
}
195+
196+
interface ExecutableFindBySearch<T> extends FindBySearchWithIndex<T> {}
197+
}

0 commit comments

Comments
 (0)