Skip to content

Commit

Permalink
add ttl index annotation support (#215)
Browse files Browse the repository at this point in the history
* add ttl index annotation support

* TtlIndexed tests

* TtlIndex

Co-authored-by: Michele Rastelli <rashtao@gmail.com>
  • Loading branch information
krasaev and rashtao authored Apr 16, 2021
1 parent e4540da commit eb46251
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* DISCLAIMER
*
* Copyright 2017 ArangoDB GmbH, Cologne, Germany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright holder is ArangoDB GmbH, Cologne, Germany
*/

package com.arangodb.springframework.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to define given field to be indexed using ArangoDB's TTL index.
*
* @author Michele Rastelli
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface TtlIndex {

/**
* attribute path
*/
String field();

/**
* The time interval (in seconds) from the point in time of the value of the field specified in {@link this#field()}
* after which the documents count as expired. Default is 0, which means that the documents expire as soon as the
* server time passes the point in time stored in the document attribute.
*/
int expireAfter() default 0;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.arangodb.springframework.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to mark a field to be indexed using ArangoDB's Ttl index.
*
* @author Dmitry Krasaev
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TtlIndexed {

/**
* The time interval (in seconds) from the point in time of the value of the annotated field after which the
* documents count as expired. Default is 0, which means that the documents expire as soon as the server time passes
* the point in time stored in the document attribute.
*/
int expireAfter() default 0;

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.arangodb.model.HashIndexOptions;
import com.arangodb.model.PersistentIndexOptions;
import com.arangodb.model.SkiplistIndexOptions;
import com.arangodb.model.TtlIndexOptions;

/**
* Interface that specifies a basic set of ArangoDB operations on collection
Expand Down Expand Up @@ -148,6 +149,18 @@ IndexEntity ensurePersistentIndex(Iterable<String> fields, PersistentIndexOption
*/
IndexEntity ensureFulltextIndex(Iterable<String> fields, FulltextIndexOptions options) throws DataAccessException;

/**
* Creates a ttl index for the collection, if it does not already exist.
*
* @param fields
* A list of attribute paths
* @param options
* Additional options, can be null
* @return information about the index
* @throws DataAccessException
*/
IndexEntity ensureTtlIndex(Iterable<String> fields, TtlIndexOptions options) throws DataAccessException;

/**
* Deletes the index with the given {@code id} from the collection.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Collection;
import java.util.Optional;

import com.arangodb.springframework.annotation.TtlIndex;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.data.mapping.PersistentEntity;
Expand Down Expand Up @@ -60,6 +61,8 @@ public interface ArangoPersistentEntity<T>

Collection<FulltextIndex> getFulltextIndexes();

Optional<TtlIndex> getTtlIndex();

Collection<ArangoPersistentProperty> getHashIndexedProperties();

Collection<ArangoPersistentProperty> getSkiplistIndexedProperties();
Expand All @@ -70,6 +73,8 @@ public interface ArangoPersistentEntity<T>

Collection<ArangoPersistentProperty> getFulltextIndexedProperties();

Optional<ArangoPersistentProperty> getTtlIndexedProperty();

IdentifierAccessor getArangoIdAccessor(Object bean);

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.arangodb.springframework.annotation.Relations;
import com.arangodb.springframework.annotation.SkiplistIndexed;
import com.arangodb.springframework.annotation.To;
import com.arangodb.springframework.annotation.TtlIndexed;

/**
* @author Mark Vollmary
Expand Down Expand Up @@ -64,4 +65,5 @@ public interface ArangoPersistentProperty extends PersistentProperty<ArangoPersi

Optional<FulltextIndexed> getFulltextIndexed();

Optional<TtlIndexed> getTtlIndexed();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,28 @@

package com.arangodb.springframework.core.mapping;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import com.arangodb.entity.CollectionType;
import com.arangodb.model.CollectionCreateOptions;
import com.arangodb.springframework.annotation.Document;
import com.arangodb.springframework.annotation.Edge;
import com.arangodb.springframework.annotation.FulltextIndex;
import com.arangodb.springframework.annotation.FulltextIndexes;
import com.arangodb.springframework.annotation.GeoIndex;
import com.arangodb.springframework.annotation.GeoIndexes;
import com.arangodb.springframework.annotation.HashIndex;
import com.arangodb.springframework.annotation.HashIndexes;
import com.arangodb.springframework.annotation.PersistentIndex;
import com.arangodb.springframework.annotation.PersistentIndexes;
import com.arangodb.springframework.annotation.SkiplistIndex;
import com.arangodb.springframework.annotation.SkiplistIndexes;
import com.arangodb.springframework.annotation.TtlIndex;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryAccessor;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.TargetAwareIdentifierAccessor;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.util.TypeInformation;
Expand All @@ -47,20 +52,16 @@
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

import com.arangodb.entity.CollectionType;
import com.arangodb.model.CollectionCreateOptions;
import com.arangodb.springframework.annotation.Document;
import com.arangodb.springframework.annotation.Edge;
import com.arangodb.springframework.annotation.FulltextIndex;
import com.arangodb.springframework.annotation.FulltextIndexes;
import com.arangodb.springframework.annotation.GeoIndex;
import com.arangodb.springframework.annotation.GeoIndexes;
import com.arangodb.springframework.annotation.HashIndex;
import com.arangodb.springframework.annotation.HashIndexes;
import com.arangodb.springframework.annotation.PersistentIndex;
import com.arangodb.springframework.annotation.PersistentIndexes;
import com.arangodb.springframework.annotation.SkiplistIndex;
import com.arangodb.springframework.annotation.SkiplistIndexes;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
* @author Mark Vollmary
Expand All @@ -78,6 +79,7 @@ public class DefaultArangoPersistentEntity<T> extends BasicPersistentEntity<T, A

private ArangoPersistentProperty arangoIdProperty;
private ArangoPersistentProperty revProperty;
private ArangoPersistentProperty ttlIndexedProperty;
private final Collection<ArangoPersistentProperty> hashIndexedProperties;
private final Collection<ArangoPersistentProperty> skiplistIndexedProperties;
private final Collection<ArangoPersistentProperty> persistentIndexedProperties;
Expand Down Expand Up @@ -187,11 +189,23 @@ public void setApplicationContext(final ApplicationContext applicationContext) t
public void addPersistentProperty(final ArangoPersistentProperty property) {
super.addPersistentProperty(property);
if (property.isArangoIdProperty()) {
if (arangoIdProperty != null) {
throw new MappingException("Found multiple id indexed properties!");
}
arangoIdProperty = property;
}
if (property.isRevProperty()) {
if (revProperty != null) {
throw new MappingException("Found multiple rev indexed properties!");
}
revProperty = property;
}
if (property.getTtlIndexed().isPresent()) {
if (ttlIndexedProperty != null) {
throw new MappingException("Found multiple ttl indexed properties!");
}
ttlIndexedProperty = property;
}
property.getHashIndexed().ifPresent(i -> hashIndexedProperties.add(property));
property.getSkiplistIndexed().ifPresent(i -> skiplistIndexedProperties.add(property));
property.getPersistentIndexed().ifPresent(i -> persistentIndexedProperties.add(property));
Expand Down Expand Up @@ -252,6 +266,15 @@ public Collection<FulltextIndex> getFulltextIndexes() {
return indexes;
}

@Override
public Optional<TtlIndex> getTtlIndex() {
return getIndex(TtlIndex.class);
}

private <A extends Annotation> Optional<A> getIndex(final Class<A> annotation) {
return Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(getType(), annotation));
}

public <A extends Annotation> Collection<A> getIndexes(final Class<A> annotation) {
final List<A> indexes = findAnnotations(annotation).stream().filter(a -> annotation.isInstance(a))
.map(a -> annotation.cast(a)).collect(Collectors.toList());
Expand Down Expand Up @@ -283,6 +306,11 @@ public Collection<ArangoPersistentProperty> getFulltextIndexedProperties() {
return fulltextIndexedProperties;
}

@Override
public Optional<ArangoPersistentProperty> getTtlIndexedProperty() {
return Optional.ofNullable(ttlIndexedProperty);
}

@SuppressWarnings("unchecked")
public <A extends Annotation> Set<A> findAnnotations(final Class<A> annotationType) {
return (Set<A>) repeatableAnnotationCache.computeIfAbsent(annotationType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.arangodb.springframework.annotation.Rev;
import com.arangodb.springframework.annotation.SkiplistIndexed;
import com.arangodb.springframework.annotation.To;
import com.arangodb.springframework.annotation.TtlIndexed;

/**
* @author Mark Vollmary
Expand Down Expand Up @@ -145,4 +146,9 @@ public Optional<FulltextIndexed> getFulltextIndexed() {
return Optional.ofNullable(findAnnotation(FulltextIndexed.class));
}

@Override
public Optional<TtlIndexed> getTtlIndexed() {
return Optional.ofNullable(findAnnotation(TtlIndexed.class));
}

}
Loading

0 comments on commit eb46251

Please sign in to comment.