Use expiry(duration) with duration. (#1223)
Also adds test for exceptions thrown during events - with validator. Closes #1204.
This commit is contained in:
@@ -503,7 +503,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter implem
|
||||
final TreeMap<Integer, String> suffixes = new TreeMap<>();
|
||||
final TreeMap<Integer, String> idAttributes = new TreeMap<>();
|
||||
|
||||
target.setExpiration(entity.getExpiry());
|
||||
target.setExpiration((int)(entity.getExpiryDuration().getSeconds()));
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CouchbasePersistentProperty>() {
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.data.couchbase.core.mapping;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -101,8 +103,9 @@ public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T,
|
||||
}
|
||||
|
||||
public static int getExpiry(Expiry annotation, Environment environment) {
|
||||
if (annotation == null)
|
||||
if (annotation == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int expiryValue = getExpiryValue(annotation, environment);
|
||||
|
||||
@@ -123,6 +126,47 @@ public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getExpiryDuration() {
|
||||
return getExpiryDuration(AnnotatedElementUtils.findMergedAnnotation(getType(), Expiry.class), environment);
|
||||
}
|
||||
|
||||
private static Duration getExpiryDuration(Expiry annotation, Environment environment) {
|
||||
if (annotation == null) {
|
||||
return Duration.ofSeconds(0);
|
||||
}
|
||||
int expiryValue = getExpiryValue(annotation, environment);
|
||||
long secondsShift = annotation.expiryUnit().toSeconds(expiryValue);
|
||||
return Duration.ofSeconds(secondsShift);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getExpiryInstant() {
|
||||
return getExpiryInstant(AnnotatedElementUtils.findMergedAnnotation(getType(), Expiry.class), environment);
|
||||
}
|
||||
|
||||
private static Instant getExpiryInstant(Expiry annotation, Environment environment) {
|
||||
if (annotation == null) {
|
||||
return Instant.ofEpochSecond(0);
|
||||
}
|
||||
int expiryValue = getExpiryValue(annotation, environment);
|
||||
long secondsShift = annotation.expiryUnit().toSeconds(expiryValue);
|
||||
if(secondsShift == 0 ){
|
||||
return Instant.ofEpochSecond(0);
|
||||
}
|
||||
// we want it to be represented as a UNIX timestamp style, seconds since Epoch in UTC
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
if (annotation.expiryUnit() == TimeUnit.DAYS) {
|
||||
// makes sure we won't lose resolution
|
||||
cal.add(Calendar.DAY_OF_MONTH, expiryValue);
|
||||
} else {
|
||||
// use the shift in seconds since resolution should be smaller
|
||||
cal.add(Calendar.SECOND, (int) secondsShift);
|
||||
}
|
||||
return Instant.ofEpochSecond(cal.getTimeInMillis() / 1000); // note: Unix UTC time representation in int is okay
|
||||
// until year 2038
|
||||
}
|
||||
|
||||
private static int getExpiryValue(Expiry annotation, Environment environment) {
|
||||
int expiryValue = annotation.expiry();
|
||||
String expiryExpressionString = annotation.expiryExpression();
|
||||
|
||||
@@ -18,6 +18,9 @@ package org.springframework.data.couchbase.core.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Represents an entity that can be persisted which contains 0 or more properties.
|
||||
*
|
||||
@@ -40,6 +43,26 @@ public interface CouchbasePersistentEntity<T> extends PersistentEntity<T, Couchb
|
||||
*/
|
||||
int getExpiry();
|
||||
|
||||
/**
|
||||
* Returns the expiration time of the entity.
|
||||
* <p/>
|
||||
* The Couchbase format for expiration time is: - for TTL < 31 days (<= 30 * 24 * 60 * 60): expressed as a TTL in
|
||||
* seconds - for TTL > 30 days: expressed as Unix UTC time of expiry (number of SECONDS since the Epoch)
|
||||
*
|
||||
* @return the expiration time Duration
|
||||
*/
|
||||
Duration getExpiryDuration();
|
||||
|
||||
/**
|
||||
* Returns the expiration time of the entity.
|
||||
* <p/>
|
||||
* The Couchbase format for expiration time is: - for TTL < 31 days (<= 30 * 24 * 60 * 60): expressed as a TTL in
|
||||
* seconds - for TTL > 30 days: expressed as Unix UTC time of expiry (number of SECONDS since the Epoch)
|
||||
*
|
||||
* @return the expiration time Instant
|
||||
*/
|
||||
Instant getExpiryInstant();
|
||||
|
||||
/**
|
||||
* Flag for using getAndTouch operations for reads, resetting the expiration (if one was set) when the entity is
|
||||
* directly read (eg. findOne, findById).
|
||||
|
||||
@@ -27,14 +27,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.couchbase.client.core.error.CouchbaseException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
@@ -47,7 +48,6 @@ import org.springframework.data.couchbase.core.support.OneAndAllId;
|
||||
import org.springframework.data.couchbase.core.support.WithDurability;
|
||||
import org.springframework.data.couchbase.core.support.WithExpiry;
|
||||
import org.springframework.data.couchbase.domain.Address;
|
||||
import org.springframework.data.couchbase.domain.Course;
|
||||
import org.springframework.data.couchbase.domain.NaiveAuditorAware;
|
||||
import org.springframework.data.couchbase.domain.PersonValue;
|
||||
import org.springframework.data.couchbase.domain.Submission;
|
||||
@@ -60,6 +60,7 @@ import org.springframework.data.couchbase.util.ClusterType;
|
||||
import org.springframework.data.couchbase.util.IgnoreWhen;
|
||||
import org.springframework.data.couchbase.util.JavaIntegrationTests;
|
||||
|
||||
import com.couchbase.client.core.error.CouchbaseException;
|
||||
import com.couchbase.client.java.kv.PersistTo;
|
||||
import com.couchbase.client.java.kv.ReplicateTo;
|
||||
import com.couchbase.client.java.query.QueryOptions;
|
||||
@@ -84,6 +85,7 @@ class CouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationTests {
|
||||
couchbaseTemplate.removeByQuery(UserAnnotated.class).all();
|
||||
couchbaseTemplate.removeByQuery(UserAnnotated2.class).all();
|
||||
couchbaseTemplate.removeByQuery(UserAnnotated3.class).all();
|
||||
couchbaseTemplate.removeByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -179,8 +181,8 @@ class CouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationTests {
|
||||
user.setSubmissions(
|
||||
Arrays.asList(new Submission(UUID.randomUUID().toString(), user.getId(), "tid", "status", 123)));
|
||||
couchbaseTemplate.upsertById(UserSubmission.class).one(user);
|
||||
assertThrows(CouchbaseException.class, () -> couchbaseTemplate.findByQuery(UserSubmission.class).project(new String[] { "address.street" })
|
||||
.withConsistency(QueryScanConsistency.REQUEST_PLUS).all());
|
||||
assertThrows(CouchbaseException.class, () -> couchbaseTemplate.findByQuery(UserSubmission.class)
|
||||
.project(new String[] { "address.street" }).withConsistency(QueryScanConsistency.REQUEST_PLUS).all());
|
||||
|
||||
List<UserSubmission> found = couchbaseTemplate.findByQuery(UserSubmission.class).project(new String[] { "address" })
|
||||
.withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
|
||||
@@ -282,15 +284,23 @@ class CouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationTests {
|
||||
}
|
||||
// check that they are gone after a few seconds.
|
||||
sleepSecs(4);
|
||||
List<String> errorList = new LinkedList();
|
||||
for (User user : users) {
|
||||
User found = couchbaseTemplate.findById(user.getClass()).one(user.getId());
|
||||
if (found instanceof UserAnnotated3) {
|
||||
assertNotNull(found, "found should be non null as it was set to have no expiry");
|
||||
if (user.getId().endsWith(UserAnnotated3.class.getSimpleName())) {
|
||||
if (found == null) {
|
||||
errorList.add("\nfound should be non null as it was set to have no expiry " + user.getId() );
|
||||
}
|
||||
} else {
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
if (found != null) {
|
||||
errorList.add("\nfound should have been null as document should be expired " + user.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorList.isEmpty()) {
|
||||
throw new RuntimeException(errorList.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -72,7 +73,7 @@ class ReactiveCouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationT
|
||||
@Override
|
||||
public void beforeEach() {
|
||||
super.beforeEach();
|
||||
List<RemoveResult> r1 = reactiveCouchbaseTemplate.removeByQuery(User.class).all().collectList().block();
|
||||
List<RemoveResult> r1 = reactiveCouchbaseTemplate.removeByQuery(User.class).all().collectList().block();
|
||||
List<RemoveResult> r2 = reactiveCouchbaseTemplate.removeByQuery(UserAnnotated.class).all().collectList().block();
|
||||
List<RemoveResult> r3 = reactiveCouchbaseTemplate.removeByQuery(UserAnnotated2.class).all().collectList().block();
|
||||
}
|
||||
@@ -219,15 +220,23 @@ class ReactiveCouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationT
|
||||
}
|
||||
// check that they are gone after a few seconds.
|
||||
sleepSecs(4);
|
||||
List<String> errorList = new LinkedList();
|
||||
for (User user : users) {
|
||||
User found = reactiveCouchbaseTemplate.findById(user.getClass()).one(user.getId()).block();
|
||||
if (found instanceof UserAnnotated3) {
|
||||
assertNotNull(found, "found should be non null as it was set to have no expiry");
|
||||
if (user.getId().endsWith(UserAnnotated3.class.getSimpleName())) {
|
||||
if (found == null) {
|
||||
errorList.add("\nfound should be non null as it was set to have no expiry " + user.getId());
|
||||
}
|
||||
} else {
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
if (found != null) {
|
||||
errorList.add("\nfound should have been null as document should be expired " + user.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorList.isEmpty()) {
|
||||
throw new RuntimeException(errorList.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -43,7 +43,7 @@ public class BasicCouchbasePersistentEntityTests {
|
||||
CouchbasePersistentEntity<DefaultExpiry> entity = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(DefaultExpiry.class));
|
||||
|
||||
assertThat(entity.getExpiry()).isEqualTo(0);
|
||||
assertThat(entity.getExpiryDuration().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -51,14 +51,14 @@ public class BasicCouchbasePersistentEntityTests {
|
||||
CouchbasePersistentEntity<DefaultExpiryUnit> entity = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(DefaultExpiryUnit.class));
|
||||
|
||||
assertThat(entity.getExpiry()).isEqualTo(78);
|
||||
assertThat(entity.getExpiryDuration().getSeconds()).isEqualTo(78);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLargeExpiry30DaysStillInSeconds() {
|
||||
CouchbasePersistentEntity<LimitDaysExpiry> entityUnder = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(LimitDaysExpiry.class));
|
||||
assertThat(entityUnder.getExpiry()).isEqualTo(30 * 24 * 60 * 60);
|
||||
assertThat(entityUnder.getExpiryDuration().getSeconds()).isEqualTo(30 * 24 * 60 * 60);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -66,7 +66,7 @@ public class BasicCouchbasePersistentEntityTests {
|
||||
CouchbasePersistentEntity<OverLimitDaysExpiry> entityOver = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(OverLimitDaysExpiry.class));
|
||||
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
int expiryOver = (int)entityOver.getExpiryInstant().getEpochSecond();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
|
||||
@@ -87,7 +87,7 @@ public class BasicCouchbasePersistentEntityTests {
|
||||
ClassTypeInformation.from(OverLimitDaysExpiryExpression.class));
|
||||
entityOver.setEnvironment(environment);
|
||||
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
int expiryOver = (int)entityOver.getExpiryInstant().getEpochSecond();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
|
||||
@@ -107,7 +107,7 @@ public class BasicCouchbasePersistentEntityTests {
|
||||
CouchbasePersistentEntity<OverLimitSecondsExpiry> entityOver = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(OverLimitSecondsExpiry.class));
|
||||
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
int expiryOver = (int)entityOver.getExpiryInstant().getEpochSecond();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -98,11 +99,8 @@ class StringN1qlQueryCreatorTests extends ClusterAwareIntegrationTests {
|
||||
|
||||
Query query = creator.createQuery();
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (Exception e) {}
|
||||
ExecutableFindByQuery q = (ExecutableFindByQuery) couchbaseTemplate
|
||||
.findByQuery(Airline.class).matching(query);
|
||||
.findByQuery(Airline.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).matching(query);
|
||||
|
||||
Optional<Airline> al = q.one();
|
||||
assertEquals(airline.toString(), al.get().toString());
|
||||
|
||||
Reference in New Issue
Block a user