Skip to content

Commit 5e7add2

Browse files
hkernbachrashtao
authored andcommitted
Feature/ttl index (#284)
* added index type ttl, added ttl index options * more work on ttl index * modified index ttl options * added ttl index test * trigger test only with version >= 3.5 * also check ttl expireAfter attribute * changelog * properly shut down the executor service * use different db name in tests to prevent races between tests * TtlIndexOptions extends IndexOptions
1 parent 53e4ba8 commit 5e7add2

File tree

10 files changed

+162
-52
lines changed

10 files changed

+162
-52
lines changed

ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
99
### Added
1010

1111
- added support for named indices
12+
- added support for TTL indices
1213
- added minReplicationAttribute for collections and graphs
1314
- added batched thread support in ArangoCollection.importDocuments (by @rkhaja)
1415

src/main/java/com/arangodb/ArangoCollection.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,15 @@
3232
import com.arangodb.entity.IndexEntity;
3333
import com.arangodb.entity.MultiDocumentEntity;
3434
import com.arangodb.entity.Permissions;
35-
import com.arangodb.model.CollectionCreateOptions;
36-
import com.arangodb.model.CollectionPropertiesOptions;
37-
import com.arangodb.model.DocumentCreateOptions;
38-
import com.arangodb.model.DocumentDeleteOptions;
39-
import com.arangodb.model.DocumentExistsOptions;
40-
import com.arangodb.model.DocumentImportOptions;
41-
import com.arangodb.model.DocumentReadOptions;
42-
import com.arangodb.model.DocumentReplaceOptions;
43-
import com.arangodb.model.DocumentUpdateOptions;
44-
import com.arangodb.model.FulltextIndexOptions;
45-
import com.arangodb.model.GeoIndexOptions;
46-
import com.arangodb.model.HashIndexOptions;
47-
import com.arangodb.model.PersistentIndexOptions;
48-
import com.arangodb.model.SkiplistIndexOptions;
35+
import com.arangodb.model.*;
4936

5037
/**
5138
* Interface for operations on ArangoDB collection level.
5239
*
5340
* @see <a href="https://docs.arangodb.com/current/HTTP/Collection/">Collection API Documentation</a>
5441
* @see <a href="https://docs.arangodb.com/current/HTTP/Collection/">Documents API Documentation</a>
5542
* @author Mark Vollmary
43+
* @author Heiko Kernbach
5644
*/
5745
public interface ArangoCollection extends ArangoSerializationAccessor {
5846

@@ -561,6 +549,20 @@ <T> MultiDocumentEntity<DocumentDeleteEntity<T>> deleteDocuments(
561549
*/
562550
IndexEntity ensureFulltextIndex(Iterable<String> fields, FulltextIndexOptions options) throws ArangoDBException;
563551

552+
/**
553+
* Creates a ttl index for the collection, if it does not already exist.
554+
*
555+
* @see <a href="https://www.arangodb.com/docs/stable/http/indexes-ttl.html">API
556+
* Documentation</a>
557+
* @param fields
558+
* A list of attribute paths
559+
* @param options
560+
* Additional options, can be null
561+
* @return information about the index
562+
* @throws ArangoDBException
563+
*/
564+
IndexEntity ensureTtlIndex(Iterable<String> fields, TtlIndexOptions options) throws ArangoDBException;
565+
564566
/**
565567
* Fetches a list of all indexes on this collection.
566568
*

src/main/java/com/arangodb/entity/IndexEntity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public class IndexEntity implements Entity {
4040
private Boolean geoJson;
4141
private Boolean constraint;
4242
private Boolean deduplicate;
43+
private Integer expireAfter;
4344
private Boolean inBackground;
4445

4546
public IndexEntity() {
@@ -90,6 +91,10 @@ public Boolean getGeoJson() {
9091
return geoJson;
9192
}
9293

94+
public Integer getExpireAfter() {
95+
return expireAfter;
96+
}
97+
9398
public Boolean getConstraint() {
9499
return constraint;
95100
}

src/main/java/com/arangodb/entity/IndexType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222

2323
/**
2424
* @author Mark Vollmary
25+
* @author Heiko Kernbach
2526
*
2627
*/
2728
public enum IndexType {
28-
primary, hash, skiplist, persistent, geo, geo1, geo2, fulltext, edge
29+
primary, hash, skiplist, persistent, geo, geo1, geo2, fulltext, edge, ttl
2930
}

src/main/java/com/arangodb/internal/ArangoCollectionImpl.java

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.slf4j.Logger;
3333
import org.slf4j.LoggerFactory;
3434

35+
import com.arangodb.model.*;
3536
import com.arangodb.ArangoCollection;
3637
import com.arangodb.ArangoDBException;
3738
import com.arangodb.entity.CollectionEntity;
@@ -45,20 +46,6 @@
4546
import com.arangodb.entity.MultiDocumentEntity;
4647
import com.arangodb.entity.Permissions;
4748
import com.arangodb.internal.util.DocumentUtil;
48-
import com.arangodb.model.CollectionCreateOptions;
49-
import com.arangodb.model.CollectionPropertiesOptions;
50-
import com.arangodb.model.DocumentCreateOptions;
51-
import com.arangodb.model.DocumentDeleteOptions;
52-
import com.arangodb.model.DocumentExistsOptions;
53-
import com.arangodb.model.DocumentImportOptions;
54-
import com.arangodb.model.DocumentReadOptions;
55-
import com.arangodb.model.DocumentReplaceOptions;
56-
import com.arangodb.model.DocumentUpdateOptions;
57-
import com.arangodb.model.FulltextIndexOptions;
58-
import com.arangodb.model.GeoIndexOptions;
59-
import com.arangodb.model.HashIndexOptions;
60-
import com.arangodb.model.PersistentIndexOptions;
61-
import com.arangodb.model.SkiplistIndexOptions;
6249
import com.arangodb.velocypack.VPackSlice;
6350

6451
/**
@@ -131,10 +118,12 @@ public Collection<DocumentImportEntity> importDocuments(Collection<?> values, Do
131118
try {
132119
documentImportEntity = completableFuture.get();
133120
} catch (InterruptedException | ExecutionException e) {
121+
executorService.shutdown();
134122
throw new ArangoDBException(e);
135123
}
136124
documentImportEntityList.add(documentImportEntity);
137125
}
126+
executorService.shutdown();
138127
return documentImportEntityList;
139128
}
140129

@@ -334,6 +323,12 @@ public IndexEntity ensureFulltextIndex(final Iterable<String> fields, final Full
334323
return executor.execute(createFulltextIndexRequest(fields, options), IndexEntity.class);
335324
}
336325

326+
@Override
327+
public IndexEntity ensureTtlIndex(final Iterable<String> fields, final TtlIndexOptions options)
328+
throws ArangoDBException {
329+
return executor.execute(createTtlIndexRequest(fields, options), IndexEntity.class);
330+
}
331+
337332
@Override
338333
public Collection<IndexEntity> getIndexes() throws ArangoDBException {
339334
return executor.execute(getIndexesRequest(), getIndexesResponseDeserializer());

src/main/java/com/arangodb/internal/InternalArangoCollection.java

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,7 @@
3939
import com.arangodb.internal.util.ArangoSerializationFactory.Serializer;
4040
import com.arangodb.internal.util.DocumentUtil;
4141
import com.arangodb.internal.util.RequestUtils;
42-
import com.arangodb.model.CollectionPropertiesOptions;
43-
import com.arangodb.model.CollectionRenameOptions;
44-
import com.arangodb.model.DocumentCreateOptions;
45-
import com.arangodb.model.DocumentDeleteOptions;
46-
import com.arangodb.model.DocumentExistsOptions;
47-
import com.arangodb.model.DocumentImportOptions;
48-
import com.arangodb.model.DocumentReadOptions;
49-
import com.arangodb.model.DocumentReplaceOptions;
50-
import com.arangodb.model.DocumentUpdateOptions;
51-
import com.arangodb.model.FulltextIndexOptions;
52-
import com.arangodb.model.GeoIndexOptions;
53-
import com.arangodb.model.HashIndexOptions;
54-
import com.arangodb.model.ImportType;
55-
import com.arangodb.model.OptionsBuilder;
56-
import com.arangodb.model.PersistentIndexOptions;
57-
import com.arangodb.model.SkiplistIndexOptions;
58-
import com.arangodb.model.UserAccessOptions;
42+
import com.arangodb.model.*;
5943
import com.arangodb.util.ArangoSerializer;
6044
import com.arangodb.velocypack.Type;
6145
import com.arangodb.velocypack.VPackSlice;
@@ -654,6 +638,14 @@ protected Request createFulltextIndexRequest(final Iterable<String> fields, fina
654638
return request;
655639
}
656640

641+
protected Request createTtlIndexRequest(final Iterable<String> fields, final TtlIndexOptions options) {
642+
final Request request = request(db.name(), RequestType.POST, PATH_API_INDEX);
643+
request.putQueryParam(COLLECTION, name);
644+
request.setBody(
645+
util().serialize(OptionsBuilder.build(options != null ? options : new TtlIndexOptions(), fields)));
646+
return request;
647+
}
648+
657649
protected Request getIndexesRequest() {
658650
final Request request = request(db.name(), RequestType.GET, PATH_API_INDEX);
659651
request.putQueryParam(COLLECTION, name);

src/main/java/com/arangodb/model/OptionsBuilder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ public static FulltextIndexOptions build(final FulltextIndexOptions options, fin
6262
return options.fields(fields);
6363
}
6464

65+
public static TtlIndexOptions build(final TtlIndexOptions options, final Iterable<String> fields) {
66+
return options.fields(fields);
67+
}
68+
6569
public static CollectionCreateOptions build(final CollectionCreateOptions options, final String name) {
6670
return options.name(name);
6771
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* DISCLAIMER
3+
*
4+
* Copyright 2019 ArangoDB GmbH, Cologne, Germany
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
*/
20+
21+
package com.arangodb.model;
22+
23+
import com.arangodb.entity.IndexType;
24+
25+
/**
26+
* @author Heiko Kernbach
27+
* @see <a href="https://www.arangodb.com/docs/stable/http/indexes-ttl.html">API Documentation</a>
28+
*/
29+
public class TtlIndexOptions extends IndexOptions {
30+
31+
private Iterable<String> fields;
32+
private final IndexType type = IndexType.ttl;
33+
private Integer expireAfter;
34+
35+
public TtlIndexOptions() {
36+
super();
37+
}
38+
39+
protected Iterable<String> getFields() {
40+
return fields;
41+
}
42+
43+
/**
44+
* @param fields A list of attribute paths
45+
* @return options
46+
*/
47+
protected TtlIndexOptions fields(final Iterable<String> fields) {
48+
this.fields = fields;
49+
return this;
50+
}
51+
52+
protected IndexType getType() {
53+
return type;
54+
}
55+
56+
/**
57+
* @param expireAfter The time (in seconds) after a document’s creation after which the documents count as “expired”.
58+
* @return options
59+
*/
60+
public TtlIndexOptions expireAfter(final Integer expireAfter) {
61+
this.expireAfter = expireAfter;
62+
return this;
63+
}
64+
65+
protected Integer getExpireAfter() {
66+
return expireAfter;
67+
}
68+
69+
}

src/test/java/com/arangodb/ArangoCollectionTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,44 @@ public void createFulltextIndexWithOptions() {
12881288
assertThat(indexResult.getName(), is("myFulltextIndex"));
12891289
}
12901290

1291+
@Test
1292+
public void createTtlIndexWithoutOptions() {
1293+
if (!requireVersion(3, 5)) {
1294+
return;
1295+
}
1296+
final Collection<String> fields = new ArrayList<String>();
1297+
fields.add("a");
1298+
try {
1299+
final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureTtlIndex(fields, null);
1300+
} catch (final ArangoDBException e) {
1301+
assertThat(e.getResponseCode(), is(400));
1302+
assertThat(e.getErrorNum(), is(10));
1303+
assertThat(e.getMessage(), containsString("expireAfter attribute must be a number"));
1304+
}
1305+
}
1306+
1307+
@Test
1308+
public void createTtlIndexWithOptions() {
1309+
if (!requireVersion(3, 5)) {
1310+
return;
1311+
}
1312+
final Collection<String> fields = new ArrayList<String>();
1313+
fields.add("a");
1314+
1315+
final TtlIndexOptions options = new TtlIndexOptions();
1316+
options.name("myTtlIndex");
1317+
options.expireAfter(3600);
1318+
1319+
final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureTtlIndex(fields, options);
1320+
assertThat(indexResult, is(notNullValue()));
1321+
assertThat(indexResult.getFields(), hasItem("a"));
1322+
assertThat(indexResult.getId(), startsWith(COLLECTION_NAME));
1323+
assertThat(indexResult.getIsNewlyCreated(), is(true));
1324+
assertThat(indexResult.getType(), is(IndexType.ttl));
1325+
assertThat(indexResult.getExpireAfter(), is(3600));
1326+
assertThat(indexResult.getName(), is("myTtlIndex"));
1327+
}
1328+
12911329
@Test
12921330
public void getIndexes() {
12931331
final Collection<String> fields = new ArrayList<String>();

src/test/java/com/arangodb/ArangoDBTest.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -441,17 +441,20 @@ public void loadproperties2() {
441441

442442
@Test
443443
public void accessMultipleDatabases() {
444+
String db1 = "multipledb1";
445+
String db2 = "multipledb2";
446+
444447
try {
445-
arangoDB.createDatabase("db1");
446-
arangoDB.createDatabase("db2");
448+
arangoDB.createDatabase(db1);
449+
arangoDB.createDatabase(db2);
447450

448-
final ArangoDBVersion version1 = arangoDB.db("db1").getVersion();
451+
final ArangoDBVersion version1 = arangoDB.db(db1).getVersion();
449452
assertThat(version1, is(notNullValue()));
450-
final ArangoDBVersion version2 = arangoDB.db("db2").getVersion();
453+
final ArangoDBVersion version2 = arangoDB.db(db2).getVersion();
451454
assertThat(version2, is(notNullValue()));
452455
} finally {
453-
arangoDB.db("db1").drop();
454-
arangoDB.db("db2").drop();
456+
arangoDB.db(db1).drop();
457+
arangoDB.db(db2).drop();
455458
}
456459
}
457460

0 commit comments

Comments
 (0)