Skip to content

Expiration annotation on field will retrieve expiration in N1ql queries. #1188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
*/
public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria> {

private static final String META_ID_PROPERTY = "id";
private static final String META_CAS_PROPERTY = "cas";
public static final String META_ID_PROPERTY = "id";
public static final String META_CAS_PROPERTY = "cas";
public static final String META_EXPIRATION_PROPERTY = "expiration";

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

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

static class MyConverter implements Converter<CouchbasePersistentProperty, String> {
@Override
public String convert(CouchbasePersistentProperty source) {
if (source.isIdProperty()) {
return "META().id";
} else if (source.isVersionProperty()) {
return "META().cas";
} else if (source.isExpirationProperty()) {
return "META().expiration";
} else {
return new StringBuilder(source.getFieldName().length() + 2).append('`').append(source.getFieldName())
.append('`').toString();
}
return new StringBuilder(source.getFieldName().length()+2).append("`").append(source.getFieldName()).append("`").toString();
}
}

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

return from(part, property, base.and(addMetaIfRequired(path, property)), iterator);
return from(part, property, base.and(addMetaIfRequired(bucketName,path, property)), iterator);
}

@Override
Expand Down Expand Up @@ -174,7 +166,8 @@ private QueryCriteria from(final Part part, final CouchbasePersistentProperty pr
}
}

private N1QLExpression addMetaIfRequired(
public static N1QLExpression addMetaIfRequired(
String bucketName,
final PersistentPropertyPath<CouchbasePersistentProperty> persistentPropertyPath,
final CouchbasePersistentProperty property) {
if (property.isIdProperty()) {
Expand All @@ -183,6 +176,9 @@ private N1QLExpression addMetaIfRequired(
if (property.isVersionProperty()) {
return path(meta(i(bucketName)), i(META_CAS_PROPERTY));
}
if (property.isExpirationProperty()) {
return path(meta(i(bucketName)), i(META_EXPIRATION_PROPERTY));
}
return x(persistentPropertyPath.toDotPath(cvtr));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package org.springframework.data.couchbase.repository.query;

import static org.springframework.data.couchbase.core.query.N1QLExpression.i;
import static org.springframework.data.couchbase.core.query.N1QLExpression.meta;
import static org.springframework.data.couchbase.core.query.N1QLExpression.path;
import static org.springframework.data.couchbase.core.query.N1QLExpression.x;
import static org.springframework.data.couchbase.core.support.TemplateUtils.SELECT_CAS;
import static org.springframework.data.couchbase.core.support.TemplateUtils.SELECT_ID;
Expand All @@ -29,6 +31,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.couchbase.core.query.N1QLExpression;
Expand All @@ -37,6 +40,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.ParameterAccessor;
Expand Down Expand Up @@ -183,22 +187,28 @@ private String getProjectedFields(String b, Class resultClass) {
if (resultClass != null) {
PersistentEntity persistentEntity = couchbaseConverter.getMappingContext().getPersistentEntity(resultClass);
StringBuilder sb = new StringBuilder();
getProjectedFieldsInternal(null, sb, persistentEntity.getTypeInformation(), "");
getProjectedFieldsInternal(b, null, sb, persistentEntity.getTypeInformation()/*, ""*/);
projectedFields = sb.toString();
}
return projectedFields;
}

private void getProjectedFieldsInternal(CouchbasePersistentProperty parent, StringBuilder sb,
TypeInformation resultClass, String path) {
private void getProjectedFieldsInternal(String bucketName, CouchbasePersistentProperty parent, StringBuilder sb,
TypeInformation resultClass/*, String path*/) {

PersistentEntity persistentEntity = couchbaseConverter.getMappingContext().getPersistentEntity(resultClass);
//CouchbasePersistentProperty property = path.getLeafProperty();
persistentEntity.doWithProperties(new PropertyHandler<CouchbasePersistentProperty>() {
@Override
public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
if (prop.isIdProperty() && parent == null) {
return;
}
if (prop.isVersionProperty()) {
return;
}
PersistentPropertyPath<CouchbasePersistentProperty> path = couchbaseConverter.getMappingContext().getPersistentPropertyPath(prop.getName(), resultClass.getType());

// The current limitation is that only top-level properties can be projected
// This traversing of nested data structures would need to replicate the processing done by
// MappingCouchbaseConverter. Either the read or write
Expand All @@ -210,12 +220,7 @@ public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append('`');
if (path != null && path.length() != 0) {
sb.append(path);
}
sb.append(prop.getName());
sb.append('`');
sb.append(N1qlQueryCreator.addMetaIfRequired(bucketName, path, prop)); // from N1qlQueryCreator
// }
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.Expiration;

/**
* Airport entity
Expand All @@ -41,6 +42,7 @@ public class Airport extends ComparableEntity {
@Version Number version;

@CreatedBy private String createdBy;
@Expiration private long expiration;

@PersistenceConstructor
public Airport(String id, String iata, String icao) {
Expand All @@ -61,6 +63,10 @@ public String getIcao() {
return icao;
}

public long getExpiration() {
return expiration;
}

public Airport withId(String id) {
return new Airport(id, this.iata, this.icao);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ public class User extends ComparableEntity {
@Id private String id;
private String firstname;
private String lastname;
@Transient
private String transientInfo;
@Transient private String transientInfo;
@CreatedBy private String createdBy;
@CreatedDate private long createdDate;
@LastModifiedBy private String lastModifiedBy;
Expand Down Expand Up @@ -97,9 +96,10 @@ public int hashCode() {
return Objects.hash(id, firstname, lastname);
}

public String getTransientInfo(){
public String getTransientInfo() {
return transientInfo;
}

public void setTransientInfo(String something) {
transientInfo = something;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand All @@ -38,6 +39,7 @@
import java.util.Optional;
import java.util.stream.Collectors;

import com.couchbase.client.java.kv.UpsertOptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -376,6 +378,15 @@ public void testCas() {
userRepository.delete(user);
}

@Test
public void testExpiration() {
Airport airport = new Airport("1", "iata21", "icao21");
airportRepository.withOptions(UpsertOptions.upsertOptions().expiry(Duration.ofSeconds(10))).save(airport);
Airport foundAirport = airportRepository.findByIata(airport.getIata());
assertNotEquals(0, foundAirport.getExpiration());
airportRepository.delete(airport);
}

@Test
public void testStreamQuery() {
User user1 = new User("1", "Dave", "Wilson");
Expand Down