Skip to content

Commit 96e5014

Browse files
Lars Maierneunhoef
Lars Maier
authored andcommitted
Added TTL index support. (#197)
1 parent b7ccc51 commit 96e5014

8 files changed

+149
-1
lines changed

collection_indexes.go

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ type CollectionIndexes interface {
6666
// Fields is a slice of attribute paths.
6767
// The index is returned, together with a boolean indicating if the index was newly created (true) or pre-existing (false).
6868
EnsureSkipListIndex(ctx context.Context, fields []string, options *EnsureSkipListIndexOptions) (Index, bool, error)
69+
70+
// EnsureTTLIndex creates a TLL collection, if it does not already exist.
71+
// The index is returned, together with a boolean indicating if the index was newly created (true) or pre-existing (false).
72+
EnsureTTLIndex(ctx context.Context, field string, expireAfter int, options *EnsureTTLIndexOptions) (Index, bool, error)
6973
}
7074

7175
// EnsureFullTextIndexOptions contains specific options for creating a full text index.
@@ -113,3 +117,7 @@ type EnsureSkipListIndexOptions struct {
113117
// Note: this setting is only relevant for indexes with array fields (e.g. "fieldName[*]")
114118
NoDeduplicate bool
115119
}
120+
121+
// EnsureTTLIndexOptions provides specific options for creating a TTL index
122+
// Currently there are not options
123+
type EnsureTTLIndexOptions struct{}

collection_indexes_impl.go

+16
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type indexData struct {
3636
Sparse *bool `json:"sparse,omitempty"`
3737
GeoJSON *bool `json:"geoJson,omitempty"`
3838
MinLength int `json:"minLength,omitempty"`
39+
ExpireAfter int `json:"expireAfter,omitempty"`
3940
}
4041

4142
type genericIndexData struct {
@@ -229,6 +230,21 @@ func (c *collection) EnsureSkipListIndex(ctx context.Context, fields []string, o
229230
return idx, created, nil
230231
}
231232

233+
// EnsureTTLIndex creates a TLL collection, if it does not already exist.
234+
// The index is returned, together with a boolean indicating if the index was newly created (true) or pre-existing (false).
235+
func (c *collection) EnsureTTLIndex(ctx context.Context, field string, expireAfter int, options *EnsureTTLIndexOptions) (Index, bool, error) {
236+
input := indexData{
237+
Type: string(TTLIndex),
238+
Fields: []string{field},
239+
ExpireAfter: expireAfter,
240+
}
241+
idx, created, err := c.ensureIndex(ctx, input)
242+
if err != nil {
243+
return nil, false, WithStack(err)
244+
}
245+
return idx, created, nil
246+
}
247+
232248
// ensureIndex creates a persistent index in the collection, if it does not already exist.
233249
// Fields is a slice of attribute paths.
234250
// The index is returned, together with a boolean indicating if the index was newly created (true) or pre-existing (false).

edge_collection_indexes_impl.go

+10
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,13 @@ func (c *edgeCollection) EnsureSkipListIndex(ctx context.Context, fields []strin
114114
}
115115
return result, created, nil
116116
}
117+
118+
// EnsureTTLIndex creates a TLL collection, if it does not already exist.
119+
// The index is returned, together with a boolean indicating if the index was newly created (true) or pre-existing (false).
120+
func (c *edgeCollection) EnsureTTLIndex(ctx context.Context, field string, expireAfter int, options *EnsureTTLIndexOptions) (Index, bool, error) {
121+
result, created, err := c.rawCollection().EnsureTTLIndex(ctx, field, expireAfter, options)
122+
if err != nil {
123+
return nil, false, WithStack(err)
124+
}
125+
return result, created, nil
126+
}

index.go

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const (
3636
PersistentIndex = IndexType("persistent")
3737
GeoIndex = IndexType("geo")
3838
EdgeIndex = IndexType("edge")
39+
TTLIndex = IndexType("ttl")
3940
)
4041

4142
// Index provides access to a single index in a single collection.

index_impl.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ func indexStringToType(indexTypeString string) (IndexType, error) {
4545
return GeoIndex, nil
4646
case string(EdgeIndex):
4747
return EdgeIndex, nil
48-
48+
case string(TTLIndex):
49+
return TTLIndex, nil
4950
default:
5051
return "", WithStack(InvalidArgumentError{Message: "unknown index type"})
5152
}

test/index_ensure_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,50 @@ func TestEnsureSkipListIndex(t *testing.T) {
309309
}
310310
}
311311
}
312+
313+
// TestEnsureTTLIndex creates a collection with a ttl index.
314+
func TestEnsureTTLIndex(t *testing.T) {
315+
c := createClientFromEnv(t, true)
316+
db := ensureDatabase(nil, c, "index_test", nil, t)
317+
skipBelowVersion(c, "3.5", t)
318+
319+
col := ensureCollection(nil, db, "ttl_index_test", nil, t)
320+
idx, created, err := col.EnsureTTLIndex(nil, "createdAt", 3600, nil)
321+
if err != nil {
322+
t.Fatalf("Failed to create new index: %s", describe(err))
323+
}
324+
if !created {
325+
t.Error("Expected created to be true, got false")
326+
}
327+
if idxType := idx.Type(); idxType != driver.TTLIndex {
328+
t.Errorf("Expected TTLIndex, found `%s`", idxType)
329+
}
330+
331+
// Index must exists now
332+
if found, err := col.IndexExists(nil, idx.Name()); err != nil {
333+
t.Fatalf("Failed to check index '%s' exists: %s", idx.Name(), describe(err))
334+
} else if !found {
335+
t.Errorf("Index '%s' does not exist, expected it to exist", idx.Name())
336+
}
337+
338+
// Ensure again, created must be false now
339+
_, created, err = col.EnsureTTLIndex(nil, "createdAt", 3600, nil)
340+
if err != nil {
341+
t.Fatalf("Failed to re-create index: %s", describe(err))
342+
}
343+
if created {
344+
t.Error("Expected created to be false, got true")
345+
}
346+
347+
// Remove index
348+
if err := idx.Remove(nil); err != nil {
349+
t.Fatalf("Failed to remove index '%s': %s", idx.Name(), describe(err))
350+
}
351+
352+
// Index must not exists now
353+
if found, err := col.IndexExists(nil, idx.Name()); err != nil {
354+
t.Fatalf("Failed to check index '%s' exists: %s", idx.Name(), describe(err))
355+
} else if found {
356+
t.Errorf("Index '%s' does exist, expected it not to exist", idx.Name())
357+
}
358+
}

test/indexes_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ package test
2525
import (
2626
"context"
2727
"testing"
28+
"time"
2829

2930
driver "github.com/arangodb/go-driver"
3031
)
@@ -282,3 +283,57 @@ func TestIndexesDeduplicateSkipList(t *testing.T) {
282283
}
283284
}
284285
}
286+
287+
// TestIndexesTTL tests TTL index.
288+
func TestIndexesTTL(t *testing.T) {
289+
c := createClientFromEnv(t, true)
290+
skipBelowVersion(c, "3.5", t)
291+
292+
db := ensureDatabase(nil, c, "index_test", nil, t)
293+
294+
// Create some indexes with de-duplication off
295+
col := ensureCollection(nil, db, "indexes_ttl_test", nil, t)
296+
if _, _, err := col.EnsureTTLIndex(nil, "createdAt", 10, nil); err != nil {
297+
t.Fatalf("Failed to create new index: %s", describe(err))
298+
}
299+
300+
doc := struct {
301+
CreatedAt int64 `json:"createdAt,omitempty"`
302+
}{
303+
CreatedAt: time.Now().Add(10 * time.Second).Unix(),
304+
}
305+
meta, err := col.CreateDocument(nil, doc)
306+
if err != nil {
307+
t.Errorf("Expected success, got %s", describe(err))
308+
}
309+
310+
wasThere := false
311+
312+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
313+
defer cancel()
314+
for {
315+
if found, err := col.DocumentExists(ctx, meta.Key); err != nil {
316+
t.Fatalf("Failed to test if document exists: %s", describe(err))
317+
} else {
318+
if found {
319+
if !wasThere {
320+
t.Log("Found document")
321+
}
322+
wasThere = true
323+
} else {
324+
break
325+
}
326+
}
327+
328+
select {
329+
case <-ctx.Done():
330+
t.Fatalf("Timeout while waiting for document to be deleted: %s", ctx.Err())
331+
case <-time.After(time.Second):
332+
break
333+
}
334+
}
335+
336+
if !wasThere {
337+
t.Fatalf("Document never existed")
338+
}
339+
}

vertex_collection_indexes_impl.go

+10
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,13 @@ func (c *vertexCollection) EnsureSkipListIndex(ctx context.Context, fields []str
114114
}
115115
return result, created, nil
116116
}
117+
118+
// EnsureTTLIndex creates a TLL collection, if it does not already exist.
119+
// The index is returned, together with a boolean indicating if the index was newly created (true) or pre-existing (false).
120+
func (c *vertexCollection) EnsureTTLIndex(ctx context.Context, field string, expireAfter int, options *EnsureTTLIndexOptions) (Index, bool, error) {
121+
result, created, err := c.rawCollection().EnsureTTLIndex(ctx, field, expireAfter, options)
122+
if err != nil {
123+
return nil, false, WithStack(err)
124+
}
125+
return result, created, nil
126+
}

0 commit comments

Comments
 (0)