Skip to content

Commit 7c1167f

Browse files
authored
Specifying withExpiry(Duration) on findById() uses getTouchAndRead(). (#1196)
Closes #982.
1 parent 345af53 commit 7c1167f

16 files changed

+238
-70
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.couchbase.core;
1717

18+
import java.time.Duration;
1819
import java.util.Collection;
1920

2021
import org.springframework.data.couchbase.core.support.OneAndAllId;
@@ -24,6 +25,7 @@
2425
import org.springframework.data.couchbase.core.support.InScope;
2526

2627
import com.couchbase.client.java.kv.GetOptions;
28+
import org.springframework.data.couchbase.core.support.WithExpiry;
2729

2830
/**
2931
* Get Operations
@@ -120,11 +122,21 @@ interface FindByIdWithProjection<T> extends FindByIdInScope<T>, WithProjectionId
120122
FindByIdInScope<T> project(String... fields);
121123
}
122124

125+
interface FindByIdWithExpiry<T> extends FindByIdWithProjection<T>, WithExpiry<T> {
126+
/**
127+
* Load only certain fields for the document.
128+
*
129+
* @param expiry the projected fields to load.
130+
*/
131+
@Override
132+
FindByIdWithProjection<T> withExpiry(Duration expiry);
133+
}
134+
123135
/**
124136
* Provides methods for constructing query operations in a fluent way.
125137
*
126138
* @param <T> the entity type to use for the results
127139
*/
128-
interface ExecutableFindById<T> extends FindByIdWithProjection<T> {}
140+
interface ExecutableFindById<T> extends FindByIdWithExpiry<T> {}
129141

130142
}

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.couchbase.core;
1717

18+
import java.time.Duration;
1819
import java.util.Arrays;
1920
import java.util.Collection;
2021
import java.util.List;
@@ -34,7 +35,7 @@ public class ExecutableFindByIdOperationSupport implements ExecutableFindByIdOpe
3435

3536
@Override
3637
public <T> ExecutableFindById<T> findById(Class<T> domainType) {
37-
return new ExecutableFindByIdSupport<>(template, domainType, null, null, null, null);
38+
return new ExecutableFindByIdSupport<>(template, domainType, null, null, null, null, null);
3839
}
3940

4041
static class ExecutableFindByIdSupport<T> implements ExecutableFindById<T> {
@@ -45,18 +46,20 @@ static class ExecutableFindByIdSupport<T> implements ExecutableFindById<T> {
4546
private final String collection;
4647
private final GetOptions options;
4748
private final List<String> fields;
49+
private final Duration expiry;
4850
private final ReactiveFindByIdSupport<T> reactiveSupport;
4951

5052
ExecutableFindByIdSupport(CouchbaseTemplate template, Class<T> domainType, String scope, String collection,
51-
GetOptions options, List<String> fields) {
53+
GetOptions options, List<String> fields, Duration expiry) {
5254
this.template = template;
5355
this.domainType = domainType;
5456
this.scope = scope;
5557
this.collection = collection;
5658
this.options = options;
5759
this.fields = fields;
60+
this.expiry = expiry;
5861
this.reactiveSupport = new ReactiveFindByIdSupport<>(template.reactive(), domainType, scope, collection, options,
59-
fields, new NonReactiveSupportWrapper(template.support()));
62+
fields, expiry, new NonReactiveSupportWrapper(template.support()));
6063
}
6164

6265
@Override
@@ -72,23 +75,29 @@ public Collection<? extends T> all(final Collection<String> ids) {
7275
@Override
7376
public TerminatingFindById<T> withOptions(final GetOptions options) {
7477
Assert.notNull(options, "Options must not be null.");
75-
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, fields);
78+
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, fields, expiry);
7679
}
7780

7881
@Override
7982
public FindByIdWithOptions<T> inCollection(final String collection) {
80-
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, fields);
83+
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, fields, expiry);
8184
}
8285

8386
@Override
8487
public FindByIdInCollection<T> inScope(final String scope) {
85-
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, fields);
88+
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, fields, expiry);
8689
}
8790

8891
@Override
8992
public FindByIdInScope<T> project(String... fields) {
9093
Assert.notEmpty(fields, "Fields must not be null.");
91-
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, Arrays.asList(fields));
94+
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, Arrays.asList(fields), expiry);
95+
}
96+
97+
@Override
98+
public FindByIdWithProjection<T> withExpiry(final Duration expiry) {
99+
return new ExecutableFindByIdSupport<>(template, domainType, scope, collection, options, fields,
100+
expiry);
92101
}
93102

94103
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import org.springframework.data.couchbase.core.support.InCollection;
2222
import org.springframework.data.couchbase.core.support.InScope;
2323
import org.springframework.data.couchbase.core.support.OneAndAllEntity;
24+
import org.springframework.data.couchbase.core.support.WithDurability;
25+
import org.springframework.data.couchbase.core.support.WithExpiry;
2426
import org.springframework.data.couchbase.core.support.WithInsertOptions;
2527

2628
import com.couchbase.client.core.msg.kv.DurabilityLevel;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.springframework.data.couchbase.core.support.InCollection;
2222
import org.springframework.data.couchbase.core.support.InScope;
2323
import org.springframework.data.couchbase.core.support.OneAndAllId;
24+
import org.springframework.data.couchbase.core.support.WithDurability;
2425
import org.springframework.data.couchbase.core.support.WithRemoveOptions;
2526

2627
import com.couchbase.client.core.msg.kv.DurabilityLevel;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import org.springframework.data.couchbase.core.support.InCollection;
2222
import org.springframework.data.couchbase.core.support.InScope;
2323
import org.springframework.data.couchbase.core.support.OneAndAllEntity;
24+
import org.springframework.data.couchbase.core.support.WithDurability;
25+
import org.springframework.data.couchbase.core.support.WithExpiry;
2426
import org.springframework.data.couchbase.core.support.WithReplaceOptions;
2527

2628
import com.couchbase.client.core.msg.kv.DurabilityLevel;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import org.springframework.data.couchbase.core.support.InCollection;
2222
import org.springframework.data.couchbase.core.support.InScope;
2323
import org.springframework.data.couchbase.core.support.OneAndAllEntity;
24+
import org.springframework.data.couchbase.core.support.WithDurability;
25+
import org.springframework.data.couchbase.core.support.WithExpiry;
2426
import org.springframework.data.couchbase.core.support.WithUpsertOptions;
2527

2628
import com.couchbase.client.core.msg.kv.DurabilityLevel;

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
import reactor.core.publisher.Flux;
1919
import reactor.core.publisher.Mono;
2020

21+
import java.time.Duration;
2122
import java.util.Collection;
2223

2324
import org.springframework.data.couchbase.core.support.InCollection;
2425
import org.springframework.data.couchbase.core.support.InScope;
2526
import org.springframework.data.couchbase.core.support.OneAndAllIdReactive;
27+
import org.springframework.data.couchbase.core.support.WithExpiry;
2628
import org.springframework.data.couchbase.core.support.WithGetOptions;
2729
import org.springframework.data.couchbase.core.support.WithProjectionId;
2830

@@ -124,11 +126,21 @@ interface FindByIdWithProjection<T> extends FindByIdInScope<T>, WithProjectionId
124126

125127
}
126128

129+
interface FindByIdWithExpiry<T> extends FindByIdWithProjection<T>, WithExpiry<T> {
130+
/**
131+
* Load only certain fields for the document.
132+
*
133+
* @param expiry the projected fields to load.
134+
*/
135+
@Override
136+
FindByIdWithProjection<T> withExpiry(Duration expiry);
137+
}
138+
127139
/**
128140
* Provides methods for constructing query operations in a fluent way.
129141
*
130142
* @param <T> the entity type to use for the results
131143
*/
132-
interface ReactiveFindById<T> extends FindByIdWithProjection<T> {}
144+
interface ReactiveFindById<T> extends FindByIdWithExpiry<T> {}
133145

134146
}

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

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,27 @@
1515
*/
1616
package org.springframework.data.couchbase.core;
1717

18-
import static com.couchbase.client.java.kv.GetOptions.getOptions;
18+
import static com.couchbase.client.java.kv.GetAndTouchOptions.getAndTouchOptions;
1919

2020
import reactor.core.publisher.Flux;
2121
import reactor.core.publisher.Mono;
2222

23+
import java.time.Duration;
2324
import java.util.Arrays;
2425
import java.util.Collection;
2526
import java.util.List;
2627

2728
import org.slf4j.Logger;
2829
import org.slf4j.LoggerFactory;
30+
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
2931
import org.springframework.data.couchbase.core.support.PseudoArgs;
3032
import org.springframework.util.Assert;
3133

3234
import com.couchbase.client.core.error.DocumentNotFoundException;
35+
import com.couchbase.client.java.CommonOptions;
36+
import com.couchbase.client.java.ReactiveCollection;
3337
import com.couchbase.client.java.codec.RawJsonTranscoder;
38+
import com.couchbase.client.java.kv.GetAndTouchOptions;
3439
import com.couchbase.client.java.kv.GetOptions;
3540

3641
public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperation {
@@ -44,7 +49,7 @@ public class ReactiveFindByIdOperationSupport implements ReactiveFindByIdOperati
4449

4550
@Override
4651
public <T> ReactiveFindById<T> findById(Class<T> domainType) {
47-
return new ReactiveFindByIdSupport<>(template, domainType, null, null, null, null, template.support());
52+
return new ReactiveFindByIdSupport<>(template, domainType, null, null, null, null, null, template.support());
4853
}
4954

5055
static class ReactiveFindByIdSupport<T> implements ReactiveFindById<T> {
@@ -53,36 +58,39 @@ static class ReactiveFindByIdSupport<T> implements ReactiveFindById<T> {
5358
private final Class<T> domainType;
5459
private final String scope;
5560
private final String collection;
56-
private final GetOptions options;
61+
private final CommonOptions<?> options;
5762
private final List<String> fields;
5863
private final ReactiveTemplateSupport support;
64+
private final Duration expiry;
5965

6066
ReactiveFindByIdSupport(ReactiveCouchbaseTemplate template, Class<T> domainType, String scope, String collection,
61-
GetOptions options, List<String> fields, ReactiveTemplateSupport support) {
67+
CommonOptions<?> options, List<String> fields, Duration expiry, ReactiveTemplateSupport support) {
6268
this.template = template;
6369
this.domainType = domainType;
6470
this.scope = scope;
6571
this.collection = collection;
6672
this.options = options;
6773
this.fields = fields;
74+
this.expiry = expiry;
6875
this.support = support;
6976
}
7077

7178
@Override
7279
public Mono<T> one(final String id) {
73-
GetOptions gOptions = options != null ? options : getOptions();
74-
if (gOptions.build().transcoder() == null) {
75-
gOptions.transcoder(RawJsonTranscoder.INSTANCE);
76-
}
77-
if (fields != null && !fields.isEmpty()) {
78-
gOptions.project(fields);
79-
}
80-
PseudoArgs<GetOptions> pArgs = new PseudoArgs(template, scope, collection, gOptions, domainType);
80+
81+
CommonOptions<?> gOptions = initGetOptions();
82+
PseudoArgs<?> pArgs = new PseudoArgs(template, scope, collection, gOptions, domainType);
8183
LOG.trace("findById {}", pArgs);
82-
return Mono.just(id)
83-
.flatMap(docId -> template.getCouchbaseClientFactory().withScope(pArgs.getScope())
84-
.getCollection(pArgs.getCollection()).reactive().get(docId, pArgs.getOptions()))
85-
.flatMap(result -> support.decodeEntity(id, result.contentAs(String.class), result.cas(), domainType))
84+
85+
return Mono.just(id).flatMap(docId -> {
86+
ReactiveCollection reactive = template.getCouchbaseClientFactory().withScope(pArgs.getScope())
87+
.getCollection(pArgs.getCollection()).reactive();
88+
if (pArgs.getOptions() instanceof GetAndTouchOptions) {
89+
return reactive.getAndTouch(docId, expiryToUse(), (GetAndTouchOptions) pArgs.getOptions());
90+
} else {
91+
return reactive.get(docId, (GetOptions) pArgs.getOptions());
92+
}
93+
}).flatMap(result -> support.decodeEntity(id, result.contentAs(String.class), result.cas(), domainType))
8694
.onErrorResume(throwable -> {
8795
if (throwable instanceof RuntimeException) {
8896
if (throwable instanceof DocumentNotFoundException) {
@@ -107,24 +115,62 @@ public Flux<? extends T> all(final Collection<String> ids) {
107115
@Override
108116
public TerminatingFindById<T> withOptions(final GetOptions options) {
109117
Assert.notNull(options, "Options must not be null.");
110-
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, fields, support);
118+
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, fields, expiry, support);
111119
}
112120

113121
@Override
114122
public FindByIdWithOptions<T> inCollection(final String collection) {
115-
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, fields, support);
123+
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, fields, expiry, support);
116124
}
117125

118126
@Override
119127
public FindByIdInCollection<T> inScope(final String scope) {
120-
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, fields, support);
128+
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, fields, expiry, support);
121129
}
122130

123131
@Override
124132
public FindByIdInScope<T> project(String... fields) {
125133
Assert.notNull(fields, "Fields must not be null");
126134
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, Arrays.asList(fields),
127-
support);
135+
expiry, support);
136+
}
137+
138+
@Override
139+
public FindByIdWithProjection<T> withExpiry(final Duration expiry) {
140+
return new ReactiveFindByIdSupport<>(template, domainType, scope, collection, options, fields, expiry, support);
141+
}
142+
143+
private CommonOptions<?> initGetOptions() {
144+
CommonOptions<?> getOptions;
145+
if (expiry != null || options instanceof GetAndTouchOptions) {
146+
GetAndTouchOptions gOptions = options != null ? (GetAndTouchOptions) options : getAndTouchOptions();
147+
if (gOptions.build().transcoder() == null) {
148+
gOptions.transcoder(RawJsonTranscoder.INSTANCE);
149+
}
150+
getOptions = gOptions;
151+
} else {
152+
GetOptions gOptions = options != null ? (GetOptions) options : GetOptions.getOptions();
153+
if (gOptions.build().transcoder() == null) {
154+
gOptions.transcoder(RawJsonTranscoder.INSTANCE);
155+
}
156+
if (fields != null && !fields.isEmpty()) {
157+
gOptions.project(fields);
158+
}
159+
getOptions = gOptions;
160+
}
161+
return getOptions;
162+
}
163+
164+
private Duration expiryToUse() {
165+
Duration expiryToUse = expiry;
166+
if (expiryToUse != null || options instanceof GetAndTouchOptions) {
167+
if (expiryToUse == null) { // GetAndTouchOptions without specifying expiry -> get expiry from annoation
168+
final CouchbasePersistentEntity<?> entity = template.getConverter().getMappingContext()
169+
.getRequiredPersistentEntity(domainType);
170+
expiryToUse = Duration.ofSeconds(entity.getExpiry());
171+
}
172+
}
173+
return expiry;
128174
}
129175
}
130176

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.springframework.data.couchbase.core.support.InCollection;
2525
import org.springframework.data.couchbase.core.support.InScope;
2626
import org.springframework.data.couchbase.core.support.OneAndAllEntityReactive;
27+
import org.springframework.data.couchbase.core.support.WithDurability;
28+
import org.springframework.data.couchbase.core.support.WithExpiry;
2729
import org.springframework.data.couchbase.core.support.WithInsertOptions;
2830

2931
import com.couchbase.client.core.msg.kv.DurabilityLevel;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.data.couchbase.core.support.InCollection;
2424
import org.springframework.data.couchbase.core.support.InScope;
2525
import org.springframework.data.couchbase.core.support.OneAndAllIdReactive;
26+
import org.springframework.data.couchbase.core.support.WithDurability;
2627
import org.springframework.data.couchbase.core.support.WithRemoveOptions;
2728

2829
import com.couchbase.client.core.msg.kv.DurabilityLevel;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.springframework.data.couchbase.core.support.InCollection;
2525
import org.springframework.data.couchbase.core.support.InScope;
2626
import org.springframework.data.couchbase.core.support.OneAndAllEntityReactive;
27+
import org.springframework.data.couchbase.core.support.WithDurability;
28+
import org.springframework.data.couchbase.core.support.WithExpiry;
2729
import org.springframework.data.couchbase.core.support.WithReplaceOptions;
2830

2931
import com.couchbase.client.core.msg.kv.DurabilityLevel;

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.springframework.data.couchbase.core.support.InCollection;
2525
import org.springframework.data.couchbase.core.support.InScope;
2626
import org.springframework.data.couchbase.core.support.OneAndAllEntityReactive;
27+
import org.springframework.data.couchbase.core.support.WithDurability;
28+
import org.springframework.data.couchbase.core.support.WithExpiry;
2729
import org.springframework.data.couchbase.core.support.WithUpsertOptions;
2830

2931
import com.couchbase.client.core.msg.kv.DurabilityLevel;
@@ -39,7 +41,6 @@
3941
*/
4042
public interface ReactiveUpsertByIdOperation {
4143

42-
4344
/**
4445
* Upsert using the KV service.
4546
*
@@ -118,6 +119,7 @@ interface UpsertByIdInScope<T> extends UpsertByIdInCollection<T>, InScope<Object
118119
interface UpsertByIdWithDurability<T> extends UpsertByIdInScope<T>, WithDurability<T> {
119120
@Override
120121
UpsertByIdInCollection<T> withDurability(DurabilityLevel durabilityLevel);
122+
121123
@Override
122124
UpsertByIdInCollection<T> withDurability(PersistTo persistTo, ReplicateTo replicateTo);
123125

0 commit comments

Comments
 (0)