/
index.go
130 lines (107 loc) · 3 KB
/
index.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package coal
import (
"context"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Index is an index registered with a model.
type Index struct {
// The un-prefixed index fields.
Fields []string
// The translated keys of the index.
Keys bson.D
// Whether the index is unique.
Unique bool
// The automatic expiry of documents.
Expiry time.Duration
// The partial filter expression.
Filter bson.D
}
// Compile will compile the index to a mongo.IndexModel.
func (i *Index) Compile() mongo.IndexModel {
// prepare options
opts := options.Index().SetUnique(i.Unique)
// set expire if available
if i.Expiry > 0 {
opts.SetExpireAfterSeconds(int32(i.Expiry / time.Second))
}
// set partial filter expression if available
if i.Filter != nil {
opts.SetPartialFilterExpression(i.Filter)
}
// add index
return mongo.IndexModel{
Keys: i.Keys,
Options: opts,
}
}
// AddIndex will add an index to the models index list. Fields that are prefixed
// with a dash will result in a descending key. Fields may be paths to nested
// item fields or begin wih a "#" (after prefix) to specify unknown fields.
func AddIndex(model Model, unique bool, expiry time.Duration, fields ...string) {
addIndex(model, unique, expiry, fields, nil)
}
// AddPartialIndex adds an index with a partial filter expression.
func AddPartialIndex(model Model, unique bool, expiry time.Duration, fields []string, filter bson.M) {
// check filter
if len(filter) == 0 {
panic(`coal: empty partial filter expression`)
}
// add index
addIndex(model, unique, expiry, fields, filter)
}
func addIndex(model Model, unique bool, expiry time.Duration, fields []string, filter bson.M) {
// get meta and translator
meta := GetMeta(model)
trans := NewTranslator(model)
// translate keys
keys, err := trans.Sort(fields)
if err != nil {
panic(err)
}
// translate filter
var filterDoc bson.D
if filter != nil {
filterDoc, err = trans.Document(filter)
if err != nil {
panic(err)
}
}
// clean fields
cleanFields := make([]string, 0, len(fields))
for _, field := range fields {
cleanFields = append(cleanFields, strings.TrimPrefix(field, "-"))
}
// add index
meta.Indexes = append(meta.Indexes, Index{
Fields: cleanFields,
Keys: keys,
Unique: unique,
Expiry: expiry,
Filter: filterDoc,
})
}
// EnsureIndexes will ensure that the registered indexes of the specified models
// exist. It may fail early if some indexes are already existing and do not
// match the registered indexes.
func EnsureIndexes(store *Store, models ...Model) error {
// create context
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
// iterate models
for _, model := range models {
// get meta
meta := GetMeta(model)
// ensure all indexes
for _, index := range meta.Indexes {
_, err := store.C(model).Native().Indexes().CreateOne(ctx, index.Compile())
if err != nil {
return err
}
}
}
return nil
}