1616package org .springframework .data .couchbase .core ;
1717
1818import static com .couchbase .client .java .kv .GetAndTouchOptions .getAndTouchOptions ;
19+ import static com .couchbase .client .java .kv .GetAndLockOptions .getAndLockOptions ;
1920import static com .couchbase .client .java .transactions .internal .ConverterUtil .makeCollectionIdentifier ;
2021
22+ import com .couchbase .client .java .kv .GetAndLockOptions ;
2123import reactor .core .publisher .Flux ;
2224import reactor .core .publisher .Mono ;
2325
2628import java .util .Arrays ;
2729import java .util .Collection ;
2830import java .util .List ;
31+ import java .util .Optional ;
2932
3033import org .slf4j .Logger ;
3134import org .slf4j .LoggerFactory ;
4548 * {@link ReactiveFindByIdOperation} implementations for Couchbase.
4649 *
4750 * @author Michael Reiche
51+ * @author Tigran Babloyan
4852 */
4953public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperation {
5054
@@ -58,7 +62,7 @@ public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperati
5862 @ Override
5963 public <T > ReactiveFindById <T > findById (Class <T > domainType ) {
6064 return new ReactiveFindByIdSupport <>(template , domainType , OptionsBuilder .getScopeFrom (domainType ),
61- OptionsBuilder .getCollectionFrom (domainType ), null , null , null , template .support ());
65+ OptionsBuilder .getCollectionFrom (domainType ), null , null , null , null , template .support ());
6266 }
6367
6468 static class ReactiveFindByIdSupport <T > implements ReactiveFindById <T > {
@@ -71,11 +75,12 @@ static class ReactiveFindByIdSupport<T> implements ReactiveFindById<T> {
7175 private final List <String > fields ;
7276 private final ReactiveTemplateSupport support ;
7377 private final Duration expiry ;
78+ private final Duration lockDuration ;
7479
7580 private Duration expiryToUse ;
7681
7782 ReactiveFindByIdSupport (ReactiveCouchbaseTemplate template , Class <T > domainType , String scope , String collection ,
78- CommonOptions <?> options , List <String > fields , Duration expiry , ReactiveTemplateSupport support ) {
83+ CommonOptions <?> options , List <String > fields , Duration expiry , Duration lockDuration , ReactiveTemplateSupport support ) {
7984 this .template = template ;
8085 this .domainType = domainType ;
8186 this .scope = scope ;
@@ -84,6 +89,7 @@ static class ReactiveFindByIdSupport<T> implements ReactiveFindById<T> {
8489 this .fields = fields ;
8590 this .expiry = expiry ;
8691 this .support = support ;
92+ this .lockDuration = lockDuration ;
8793 }
8894
8995 @ Override
@@ -99,8 +105,12 @@ public Mono<T> one(final Object id) {
99105
100106 Mono <T > reactiveEntity = TransactionalSupport .checkForTransactionInThreadLocalStorage ().flatMap (ctxOpt -> {
101107 if (!ctxOpt .isPresent ()) {
102- if (pArgs .getOptions () instanceof GetAndTouchOptions ) {
103- return rc .getAndTouch (id .toString (), expiryToUse , (GetAndTouchOptions ) pArgs .getOptions ())
108+ if (pArgs .getOptions () instanceof GetAndTouchOptions options ) {
109+ return rc .getAndTouch (id .toString (), expiryToUse , options )
110+ .flatMap (result -> support .decodeEntity (id , result .contentAs (String .class ), result .cas (), domainType ,
111+ pArgs .getScope (), pArgs .getCollection (), null , null ));
112+ } else if (pArgs .getOptions () instanceof GetAndLockOptions options ) {
113+ return rc .getAndLock (id .toString (), Optional .of (lockDuration ).orElse (Duration .ZERO ), options )
104114 .flatMap (result -> support .decodeEntity (id , result .contentAs (String .class ), result .cas (), domainType ,
105115 pArgs .getScope (), pArgs .getCollection (), null , null ));
106116 } else {
@@ -132,6 +142,9 @@ public Mono<T> one(final Object id) {
132142 }
133143
134144 private void rejectInvalidTransactionalOptions () {
145+ if (this .lockDuration != null ) {
146+ throw new IllegalArgumentException ("withLock is not supported in a transaction" );
147+ }
135148 if (this .expiry != null ) {
136149 throw new IllegalArgumentException ("withExpiry is not supported in a transaction" );
137150 }
@@ -151,39 +164,53 @@ public Flux<? extends T> all(final Collection<String> ids) {
151164 @ Override
152165 public FindByIdInScope <T > withOptions (final GetOptions options ) {
153166 Assert .notNull (options , "Options must not be null." );
154- return new ReactiveFindByIdSupport <>(template , domainType , scope , collection , options , fields , expiry , support );
167+ return new ReactiveFindByIdSupport <>(template , domainType , scope , collection , options , fields , expiry ,
168+ lockDuration , support );
155169 }
156170
157171 @ Override
158172 public FindByIdWithOptions <T > inCollection (final String collection ) {
159173 return new ReactiveFindByIdSupport <>(template , domainType , scope ,
160- collection != null ? collection : this .collection , options , fields , expiry , support );
174+ collection != null ? collection : this .collection , options , fields , expiry , lockDuration , support );
161175 }
162176
163177 @ Override
164178 public FindByIdInCollection <T > inScope (final String scope ) {
165179 return new ReactiveFindByIdSupport <>(template , domainType , scope != null ? scope : this .scope , collection ,
166- options , fields , expiry , support );
180+ options , fields , expiry , lockDuration , support );
167181 }
168182
169183 @ Override
170184 public FindByIdInCollection <T > project (String ... fields ) {
171185 Assert .notNull (fields , "Fields must not be null" );
172186 return new ReactiveFindByIdSupport <>(template , domainType , scope , collection , options , Arrays .asList (fields ),
173- expiry , support );
187+ expiry , lockDuration , support );
174188 }
175189
176190 @ Override
177191 public FindByIdWithProjection <T > withExpiry (final Duration expiry ) {
178- return new ReactiveFindByIdSupport <>(template , domainType , scope , collection , options , fields , expiry , support );
192+ return new ReactiveFindByIdSupport <>(template , domainType , scope , collection , options , fields , expiry ,
193+ lockDuration , support );
194+ }
195+
196+ @ Override
197+ public FindByIdWithExpiry <T > withLock (final Duration lockDuration ) {
198+ return new ReactiveFindByIdSupport <>(template , domainType , scope , collection , options , fields , expiry ,
199+ lockDuration , support );
179200 }
180201
181202 private CommonOptions <?> initGetOptions () {
182203 CommonOptions <?> getOptions ;
183204 final CouchbasePersistentEntity <?> entity = template .getConverter ().getMappingContext ()
184205 .getRequiredPersistentEntity (domainType );
185206 Boolean isTouchOnRead = entity .isTouchOnRead ();
186- if (expiry != null || isTouchOnRead || options instanceof GetAndTouchOptions ) {
207+ if (lockDuration != null || options instanceof GetAndLockOptions ) {
208+ GetAndLockOptions gOptions = options != null ? (GetAndLockOptions ) options : getAndLockOptions ();
209+ if (gOptions .build ().transcoder () == null ) {
210+ gOptions .transcoder (RawJsonTranscoder .INSTANCE );
211+ }
212+ getOptions = gOptions ;
213+ } else if (expiry != null || isTouchOnRead || options instanceof GetAndTouchOptions ) {
187214 if (expiry != null ) {
188215 expiryToUse = expiry ;
189216 } else if (isTouchOnRead ) {
0 commit comments