Skip to content

Commit c53378e

Browse files
committed
Add support for scopes and collections for repositories.
Adds DynamicProxyable and DynamicInvocationHandler to set scope/collection/options on PseudoArgs when calling operations via repository interfaces. Closes #963.
1 parent d172f39 commit c53378e

18 files changed

+628
-86
lines changed

src/main/java/org/springframework/data/couchbase/SimpleCouchbaseClientFactory.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors
2+
* Copyright 2012-2021 the original author or authors
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package org.springframework.data.couchbase;
1817

1918
import java.util.function.Supplier;
@@ -33,6 +32,9 @@
3332

3433
/**
3534
* The default implementation of a {@link CouchbaseClientFactory}.
35+
*
36+
* @author Michael Nitschinger
37+
* @author Michael Reiche
3638
*/
3739
public class SimpleCouchbaseClientFactory implements CouchbaseClientFactory {
3840

@@ -74,7 +76,7 @@ private SimpleCouchbaseClientFactory(final Supplier<Cluster> cluster, final Stri
7476

7577
@Override
7678
public CouchbaseClientFactory withScope(final String scopeName) {
77-
return new SimpleCouchbaseClientFactory(cluster, bucket.name(), scopeName);
79+
return new SimpleCouchbaseClientFactory(cluster, bucket.name(), scopeName != null ? scopeName : getScope().name());
7880
}
7981

8082
@Override

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package org.springframework.data.couchbase.core;
1817

1918
import org.springframework.data.couchbase.CouchbaseClientFactory;
2019
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
21-
import org.springframework.data.couchbase.core.support.PseudoArgs;
2220

2321
/**
2422
* Defines common operations on the Couchbase data source, most commonly implemented by
2523
* {@link ReactiveCouchbaseTemplate}.
24+
*
25+
* @author Michael Nitschinger
26+
* @author Michael Reiche
2627
*/
2728
public interface ReactiveCouchbaseOperations extends ReactiveFluentCouchbaseOperations {
2829

@@ -46,9 +47,4 @@ public interface ReactiveCouchbaseOperations extends ReactiveFluentCouchbaseOper
4647
*/
4748
CouchbaseClientFactory getCouchbaseClientFactory();
4849

49-
/**
50-
* @@return the pseudoArgs from the ThreadLocal field of the CouchbaseOperations
51-
*/
52-
PseudoArgs<?> getPseudoArgs();
53-
5450
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,17 @@ public void setApplicationContext(final ApplicationContext applicationContext) t
158158
}
159159

160160
/**
161-
* {@inheritDoc}
161+
* @return the pseudoArgs from the ThreadLocal field
162162
*/
163-
@Override
164163
public PseudoArgs<?> getPseudoArgs() {
165164
return threadLocalArgs == null ? null : threadLocalArgs.get();
166165
}
167166

167+
/**
168+
* set the ThreadLocal field
169+
*/
170+
public void setPseudoArgs(PseudoArgs<?> threadLocalArgs) {
171+
this.threadLocalArgs.set(threadLocalArgs);
172+
}
173+
168174
}

src/main/java/org/springframework/data/couchbase/core/support/PseudoArgs.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,42 +74,42 @@ public PseudoArgs(ReactiveCouchbaseTemplate template, String scope, String colle
7474
}
7575

7676
/**
77-
* @@return the options
77+
* @return the options
7878
*/
7979
public OPTS getOptions() {
8080
return this.options;
8181
}
8282

8383
/**
84-
* @@return the scope name
84+
* @return the scope name
8585
*/
8686
public String getScope() {
8787
return this.scopeName;
8888
}
8989

9090
/**
91-
* @@return the collection name
91+
* @return the collection name
9292
*/
9393
public String getCollection() {
9494
return this.collectionName;
9595
}
9696

9797
/**
98-
* @@return the options from the ThreadLocal field of the template
98+
* @return the options from the ThreadLocal field of the template
9999
*/
100100
private OPTS getThreadLocalOptions(ReactiveCouchbaseTemplate template) {
101101
return template.getPseudoArgs() == null ? null : (OPTS) (template.getPseudoArgs().getOptions());
102102
}
103103

104104
/**
105-
* @@return the scope name from the ThreadLocal field of the template
105+
* @return the scope name from the ThreadLocal field of the template
106106
*/
107107
private String getThreadLocalScopeName(ReactiveCouchbaseTemplate template) {
108108
return template.getPseudoArgs() == null ? null : template.getPseudoArgs().getScope();
109109
}
110110

111111
/**
112-
* @@return the collection name from the ThreadLocal field of the template
112+
* @return the collection name from the ThreadLocal field of the template
113113
*/
114114
private String getThreadLocalCollectionName(ReactiveCouchbaseTemplate template) {
115115
return template.getPseudoArgs() == null ? null : template.getPseudoArgs().getCollection();

src/main/java/org/springframework/data/couchbase/repository/CouchbaseRepository.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2020 the original author or authors.
2+
* Copyright 2013-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,16 +18,20 @@
1818

1919
import java.util.List;
2020

21-
import com.couchbase.client.java.query.QueryScanConsistency;
21+
import org.springframework.data.couchbase.core.CouchbaseOperations;
22+
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
2223
import org.springframework.data.domain.Sort;
2324
import org.springframework.data.repository.NoRepositoryBean;
2425
import org.springframework.data.repository.PagingAndSortingRepository;
2526
import org.springframework.data.repository.Repository;
2627

28+
import com.couchbase.client.java.query.QueryScanConsistency;
29+
2730
/**
2831
* Couchbase specific {@link Repository} interface.
2932
*
3033
* @author Michael Nitschinger
34+
* @author Michael Reiche
3135
*/
3236
@NoRepositoryBean
3337
public interface CouchbaseRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
@@ -43,4 +47,7 @@ public interface CouchbaseRepository<T, ID> extends PagingAndSortingRepository<T
4347
@Override
4448
List<T> findAllById(Iterable<ID> iterable);
4549

50+
CouchbaseEntityInformation<T, String> getEntityInformation();
51+
52+
CouchbaseOperations getOperations();
4653
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2017-2021 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+
17+
package org.springframework.data.couchbase.repository;
18+
19+
import java.lang.reflect.Proxy;
20+
21+
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
22+
import org.springframework.data.couchbase.repository.support.DynamicInvocationHandler;
23+
24+
import com.couchbase.client.java.CommonOptions;
25+
26+
/**
27+
* The generic parameter needs to be REPO which is either a CouchbaseRepository parameterized on T,ID or a
28+
* ReactiveCouchbaseRepository parameterized on T,ID. i.e.: interface AirportRepository extends
29+
* CouchbaseRepository<Airport, String>, DynamicProxyable<AirportRepository>
30+
*
31+
* @param <REPO>
32+
*
33+
* @author Michael Reiche
34+
*
35+
*/
36+
public interface DynamicProxyable<REPO> {
37+
38+
CouchbaseEntityInformation getEntityInformation();
39+
40+
Object getOperations();
41+
42+
/**
43+
* Support for Couchbase-specific options, scope and collections The three "with" methods will return a new proxy
44+
* instance with the specified options, scope, or collections set. The setters are called with the corresponding
45+
* options, scope and collection to set the ThreadLocal fields on the CouchbaseOperations of the repository just
46+
* before the call is made to the repository, and called again with 'null' just after the call is made. The repository
47+
* method will fetch those values to use in the call.
48+
*/
49+
50+
/**
51+
* @param options - the options to set on the returned repository object
52+
*/
53+
@SuppressWarnings("unchecked")
54+
default REPO withOptions(CommonOptions<?> options) {
55+
REPO proxyInstance = (REPO) Proxy.newProxyInstance(this.getClass().getClassLoader(),
56+
this.getClass().getInterfaces(), new DynamicInvocationHandler(this, options, null, (String) null));
57+
return proxyInstance;
58+
}
59+
60+
/**
61+
* @param scope - the scope to set on the returned repository object
62+
*/
63+
@SuppressWarnings("unchecked")
64+
default REPO withScope(String scope) {
65+
REPO proxyInstance = (REPO) Proxy.newProxyInstance(this.getClass().getClassLoader(),
66+
this.getClass().getInterfaces(), new DynamicInvocationHandler<>(this, null, null, scope));
67+
return proxyInstance;
68+
}
69+
70+
/**
71+
* @param collection - the collection to set on the returned repository object
72+
*/
73+
@SuppressWarnings("unchecked")
74+
default REPO withCollection(String collection) {
75+
REPO proxyInstance = (REPO) Proxy.newProxyInstance(this.getClass().getClassLoader(),
76+
this.getClass().getInterfaces(), new DynamicInvocationHandler<>(this, null, collection, null));
77+
return proxyInstance;
78+
}
79+
80+
}

src/main/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepository.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2020 the original author or authors.
2+
* Copyright 2017-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,16 +15,21 @@
1515
*/
1616
package org.springframework.data.couchbase.repository;
1717

18+
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
19+
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
1820
import org.springframework.data.repository.NoRepositoryBean;
1921
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
2022

2123
/**
2224
* Couchbase-specific {@link ReactiveSortingRepository} implementation.
2325
*
2426
* @author Subhashni Balakrishnan
27+
* @author Michael Reiche
2528
* @since 3.0
2629
*/
2730
@NoRepositoryBean
2831
public interface ReactiveCouchbaseRepository<T, ID> extends ReactiveSortingRepository<T, ID> {
32+
ReactiveCouchbaseOperations getOperations();
2933

34+
<T1> CouchbaseEntityInformation<T1, String> getEntityInformation();
3035
}

src/main/java/org/springframework/data/couchbase/repository/ScanConsistency.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors
2+
* Copyright 2012-2021 the original author or authors
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,8 +24,14 @@
2424
import com.couchbase.client.java.analytics.AnalyticsScanConsistency;
2525
import com.couchbase.client.java.query.QueryScanConsistency;
2626

27+
/**
28+
* Scan Consistency Annotation
29+
*
30+
* @author Michael Reiche
31+
*
32+
*/
2733
@Retention(RetentionPolicy.RUNTIME)
28-
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
34+
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE })
2935
@Documented
3036
public @interface ScanConsistency {
3137

src/main/java/org/springframework/data/couchbase/repository/query/AbstractCouchbaseQuery.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors
2+
* Copyright 2020-2021 the original author or authors
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
1515
*/
1616
package org.springframework.data.couchbase.repository.query;
1717

18-
import com.couchbase.client.core.io.CollectionIdentifier;
1918
import org.springframework.core.convert.converter.Converter;
2019
import org.springframework.data.couchbase.core.CouchbaseOperations;
2120
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.ExecutableFindByQuery;
@@ -84,14 +83,11 @@ protected Object doExecute(CouchbaseQueryMethod method, ResultProcessor processo
8483
query = applyAnnotatedConsistencyIfPresent(query);
8584
// query = applyAnnotatedCollationIfPresent(query, accessor); // not yet implemented
8685

87-
ExecutableFindByQuery<?> find = typeToRead == null ? findOperationWithProjection //
88-
: findOperationWithProjection; // not yet implemented in core .as(typeToRead);
89-
90-
String collection = null;
86+
ExecutableFindByQuery<?> find = findOperationWithProjection;
9187

9288
CouchbaseQueryExecution execution = getExecution(accessor,
9389
new ResultProcessingConverter<>(processor, getOperations(), getInstantiators()), find);
94-
return execution.execute(query, processor.getReturnedType().getDomainType(), collection);
90+
return execution.execute(query, processor.getReturnedType().getDomainType(), null);
9591
}
9692

9793
/**
@@ -114,8 +110,7 @@ private CouchbaseQueryExecution getExecution(ParameterAccessor accessor, Convert
114110
* @param operation must not be {@literal null}.
115111
* @return
116112
*/
117-
private CouchbaseQueryExecution getExecutionToWrap(ParameterAccessor accessor,
118-
ExecutableFindByQuery<?> operation) {
113+
private CouchbaseQueryExecution getExecutionToWrap(ParameterAccessor accessor, ExecutableFindByQuery<?> operation) {
119114

120115
if (isDeleteQuery()) {
121116
return new DeleteExecution(getOperations(), getQueryMethod());

src/main/java/org/springframework/data/couchbase/repository/query/AbstractReactiveCouchbaseQuery.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
1515
*/
1616
package org.springframework.data.couchbase.repository.query;
1717

18-
import com.couchbase.client.core.io.CollectionIdentifier;
1918
import org.springframework.core.convert.converter.Converter;
2019
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
2120
import org.springframework.data.couchbase.core.ReactiveFindByQueryOperation;
@@ -82,15 +81,11 @@ protected Object doExecute(CouchbaseQueryMethod method, ResultProcessor processo
8281
query = applyAnnotatedConsistencyIfPresent(query);
8382
// query = applyAnnotatedCollationIfPresent(query, accessor); // not yet implemented
8483

85-
ReactiveFindByQuery<?> find = typeToRead == null //
86-
? findOperationWithProjection //
87-
: findOperationWithProjection; // note yet implemented in core .as(typeToRead);
88-
89-
String collection = null;
84+
ReactiveFindByQuery<?> find = findOperationWithProjection;
9085

9186
ReactiveCouchbaseQueryExecution execution = getExecution(accessor,
9287
new ResultProcessingConverter<>(processor, getOperations(), getInstantiators()), find);
93-
return execution.execute(query, processor.getReturnedType().getDomainType(), collection);
88+
return execution.execute(query, processor.getReturnedType().getDomainType(), null);
9489
}
9590

9691
/**

0 commit comments

Comments
 (0)