Skip to content

Commit 52b1832

Browse files
authored
Expiration annotation on field will retrieve expiration in N1ql queries. (#1188)
Closes #1060.
1 parent 6512fc0 commit 52b1832

File tree

5 files changed

+45
-27
lines changed

5 files changed

+45
-27
lines changed

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

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@
4545
*/
4646
public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria> {
4747

48-
private static final String META_ID_PROPERTY = "id";
49-
private static final String META_CAS_PROPERTY = "cas";
48+
public static final String META_ID_PROPERTY = "id";
49+
public static final String META_CAS_PROPERTY = "cas";
50+
public static final String META_EXPIRATION_PROPERTY = "expiration";
5051

5152
private final ParameterAccessor accessor;
5253
private final MappingContext<?, CouchbasePersistentProperty> context;
@@ -68,24 +69,15 @@ public N1qlQueryCreator(final PartTree tree, final ParameterAccessor accessor, f
6869
protected QueryCriteria create(final Part part, final Iterator<Object> iterator) {
6970
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
7071
CouchbasePersistentProperty property = path.getLeafProperty();
71-
return from(part, property, where(addMetaIfRequired(path, property)), iterator);
72+
return from(part, property, where(addMetaIfRequired(bucketName, path, property)), iterator);
7273
}
7374

7475
static Converter<? super CouchbasePersistentProperty, String> cvtr = new MyConverter();
7576

7677
static class MyConverter implements Converter<CouchbasePersistentProperty, String> {
7778
@Override
7879
public String convert(CouchbasePersistentProperty source) {
79-
if (source.isIdProperty()) {
80-
return "META().id";
81-
} else if (source.isVersionProperty()) {
82-
return "META().cas";
83-
} else if (source.isExpirationProperty()) {
84-
return "META().expiration";
85-
} else {
86-
return new StringBuilder(source.getFieldName().length() + 2).append('`').append(source.getFieldName())
87-
.append('`').toString();
88-
}
80+
return new StringBuilder(source.getFieldName().length()+2).append("`").append(source.getFieldName()).append("`").toString();
8981
}
9082
}
9183

@@ -98,7 +90,7 @@ protected QueryCriteria and(final Part part, final QueryCriteria base, final Ite
9890
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
9991
CouchbasePersistentProperty property = path.getLeafProperty();
10092

101-
return from(part, property, base.and(addMetaIfRequired(path, property)), iterator);
93+
return from(part, property, base.and(addMetaIfRequired(bucketName,path, property)), iterator);
10294
}
10395

10496
@Override
@@ -174,7 +166,8 @@ private QueryCriteria from(final Part part, final CouchbasePersistentProperty pr
174166
}
175167
}
176168

177-
private N1QLExpression addMetaIfRequired(
169+
public static N1QLExpression addMetaIfRequired(
170+
String bucketName,
178171
final PersistentPropertyPath<CouchbasePersistentProperty> persistentPropertyPath,
179172
final CouchbasePersistentProperty property) {
180173
if (property.isIdProperty()) {
@@ -183,6 +176,9 @@ private N1QLExpression addMetaIfRequired(
183176
if (property.isVersionProperty()) {
184177
return path(meta(i(bucketName)), i(META_CAS_PROPERTY));
185178
}
179+
if (property.isExpirationProperty()) {
180+
return path(meta(i(bucketName)), i(META_EXPIRATION_PROPERTY));
181+
}
186182
return x(persistentPropertyPath.toDotPath(cvtr));
187183
}
188184

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

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package org.springframework.data.couchbase.repository.query;
1717

1818
import static org.springframework.data.couchbase.core.query.N1QLExpression.i;
19+
import static org.springframework.data.couchbase.core.query.N1QLExpression.meta;
20+
import static org.springframework.data.couchbase.core.query.N1QLExpression.path;
1921
import static org.springframework.data.couchbase.core.query.N1QLExpression.x;
2022
import static org.springframework.data.couchbase.core.support.TemplateUtils.SELECT_CAS;
2123
import static org.springframework.data.couchbase.core.support.TemplateUtils.SELECT_ID;
@@ -29,6 +31,7 @@
2931

3032
import org.slf4j.Logger;
3133
import org.slf4j.LoggerFactory;
34+
import org.springframework.core.convert.converter.Converter;
3235
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
3336
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
3437
import org.springframework.data.couchbase.core.query.N1QLExpression;
@@ -37,6 +40,7 @@
3740
import org.springframework.data.domain.Pageable;
3841
import org.springframework.data.domain.Sort;
3942
import org.springframework.data.mapping.PersistentEntity;
43+
import org.springframework.data.mapping.PersistentPropertyPath;
4044
import org.springframework.data.mapping.PropertyHandler;
4145
import org.springframework.data.repository.query.Parameter;
4246
import org.springframework.data.repository.query.ParameterAccessor;
@@ -183,22 +187,28 @@ private String getProjectedFields(String b, Class resultClass) {
183187
if (resultClass != null) {
184188
PersistentEntity persistentEntity = couchbaseConverter.getMappingContext().getPersistentEntity(resultClass);
185189
StringBuilder sb = new StringBuilder();
186-
getProjectedFieldsInternal(null, sb, persistentEntity.getTypeInformation(), "");
190+
getProjectedFieldsInternal(b, null, sb, persistentEntity.getTypeInformation()/*, ""*/);
187191
projectedFields = sb.toString();
188192
}
189193
return projectedFields;
190194
}
191195

192-
private void getProjectedFieldsInternal(CouchbasePersistentProperty parent, StringBuilder sb,
193-
TypeInformation resultClass, String path) {
196+
private void getProjectedFieldsInternal(String bucketName, CouchbasePersistentProperty parent, StringBuilder sb,
197+
TypeInformation resultClass/*, String path*/) {
194198

195199
PersistentEntity persistentEntity = couchbaseConverter.getMappingContext().getPersistentEntity(resultClass);
200+
//CouchbasePersistentProperty property = path.getLeafProperty();
196201
persistentEntity.doWithProperties(new PropertyHandler<CouchbasePersistentProperty>() {
197202
@Override
198203
public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
199204
if (prop.isIdProperty() && parent == null) {
200205
return;
201206
}
207+
if (prop.isVersionProperty()) {
208+
return;
209+
}
210+
PersistentPropertyPath<CouchbasePersistentProperty> path = couchbaseConverter.getMappingContext().getPersistentPropertyPath(prop.getName(), resultClass.getType());
211+
202212
// The current limitation is that only top-level properties can be projected
203213
// This traversing of nested data structures would need to replicate the processing done by
204214
// MappingCouchbaseConverter. Either the read or write
@@ -210,12 +220,7 @@ public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
210220
if (sb.length() > 0) {
211221
sb.append(", ");
212222
}
213-
sb.append('`');
214-
if (path != null && path.length() != 0) {
215-
sb.append(path);
216-
}
217-
sb.append(prop.getName());
218-
sb.append('`');
223+
sb.append(N1qlQueryCreator.addMetaIfRequired(bucketName, path, prop)); // from N1qlQueryCreator
219224
// }
220225
}
221226
});

src/test/java/org/springframework/data/couchbase/domain/Airport.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.data.annotation.TypeAlias;
2323
import org.springframework.data.annotation.Version;
2424
import org.springframework.data.couchbase.core.mapping.Document;
25+
import org.springframework.data.couchbase.core.mapping.Expiration;
2526

2627
/**
2728
* Airport entity
@@ -41,6 +42,7 @@ public class Airport extends ComparableEntity {
4142
@Version Number version;
4243

4344
@CreatedBy private String createdBy;
45+
@Expiration private long expiration;
4446

4547
@PersistenceConstructor
4648
public Airport(String id, String iata, String icao) {
@@ -61,6 +63,10 @@ public String getIcao() {
6163
return icao;
6264
}
6365

66+
public long getExpiration() {
67+
return expiration;
68+
}
69+
6470
public Airport withId(String id) {
6571
return new Airport(id, this.iata, this.icao);
6672
}

src/test/java/org/springframework/data/couchbase/domain/User.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ public class User extends ComparableEntity {
4242
@Id private String id;
4343
private String firstname;
4444
private String lastname;
45-
@Transient
46-
private String transientInfo;
45+
@Transient private String transientInfo;
4746
@CreatedBy private String createdBy;
4847
@CreatedDate private long createdDate;
4948
@LastModifiedBy private String lastModifiedBy;
@@ -97,9 +96,10 @@ public int hashCode() {
9796
return Objects.hash(id, firstname, lastname);
9897
}
9998

100-
public String getTransientInfo(){
99+
public String getTransientInfo() {
101100
return transientInfo;
102101
}
102+
103103
public void setTransientInfo(String something) {
104104
transientInfo = something;
105105
}

src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.assertj.core.api.Assertions.assertThat;
2121
import static org.junit.jupiter.api.Assertions.assertEquals;
2222
import static org.junit.jupiter.api.Assertions.assertFalse;
23+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
2324
import static org.junit.jupiter.api.Assertions.assertNotNull;
2425
import static org.junit.jupiter.api.Assertions.assertNull;
2526
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -38,6 +39,7 @@
3839
import java.util.Optional;
3940
import java.util.stream.Collectors;
4041

42+
import com.couchbase.client.java.kv.UpsertOptions;
4143
import org.junit.jupiter.api.BeforeEach;
4244
import org.junit.jupiter.api.Test;
4345
import org.springframework.beans.factory.annotation.Autowired;
@@ -376,6 +378,15 @@ public void testCas() {
376378
userRepository.delete(user);
377379
}
378380

381+
@Test
382+
public void testExpiration() {
383+
Airport airport = new Airport("1", "iata21", "icao21");
384+
airportRepository.withOptions(UpsertOptions.upsertOptions().expiry(Duration.ofSeconds(10))).save(airport);
385+
Airport foundAirport = airportRepository.findByIata(airport.getIata());
386+
assertNotEquals(0, foundAirport.getExpiration());
387+
airportRepository.delete(airport);
388+
}
389+
379390
@Test
380391
public void testStreamQuery() {
381392
User user1 = new User("1", "Dave", "Wilson");

0 commit comments

Comments
 (0)