-
Notifications
You must be signed in to change notification settings - Fork 0
/
datastore.go
103 lines (78 loc) · 2.56 KB
/
datastore.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
package datastore
import (
"cloud.google.com/go/datastore"
"github.com/rodrigodiez/zorro/pkg/storage"
"golang.org/x/net/context"
)
// Item represents a Google Cloud Datastore entity
type Item struct {
Data string
}
// Transaction represents a Google Cloud Datastore transaction
type Transaction interface {
Get(*datastore.Key, interface{}) error
Put(*datastore.Key, interface{}) (*datastore.PendingKey, error)
}
// TranslatorClient is a wrapper necessary to write tests around transactions
type TranslatorClient interface {
RunInTransaction(context.Context, func(Transaction) error, ...datastore.TransactionOption) (*datastore.Commit, error)
Get(context.Context, *datastore.Key, interface{}) error
}
type translator struct {
client *datastore.Client
}
// NewTranslator returns a TranslatorClient
func NewTranslator(client *datastore.Client) TranslatorClient {
return translator{client: client}
}
func (t translator) Get(ctx context.Context, key *datastore.Key, dest interface{}) error {
return t.client.Get(ctx, key, dest)
}
func (t translator) RunInTransaction(ctx context.Context, f func(Transaction) error, opts ...datastore.TransactionOption) (*datastore.Commit, error) {
return t.client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
return f(tx)
}, opts...)
}
type datastoreStorage struct {
client TranslatorClient
keyKind string
valueKind string
}
func (d *datastoreStorage) LoadOrStore(key string, value string) (string, bool) {
var (
item Item
actualValue string
loaded bool
)
gKey := datastore.NameKey(d.keyKind, key, nil)
d.client.RunInTransaction(context.TODO(), func(tx Transaction) error {
if err := tx.Get(gKey, &item); err != datastore.ErrNoSuchEntity {
actualValue = item.Data
loaded = true
return err
}
tx.Put(gKey, &Item{Data: value})
tx.Put(datastore.NameKey(d.valueKind, value, nil), &Item{Data: key})
actualValue = value
loaded = false
return nil
})
return actualValue, loaded
}
func (d *datastoreStorage) Resolve(value string) (string, bool) {
var item Item
gKey := datastore.NameKey(d.valueKind, value, nil)
if err := d.client.Get(context.TODO(), gKey, &item); err != nil {
return "", false
}
return item.Data, true
}
func (d *datastoreStorage) Close() {
}
func (d *datastoreStorage) WithMetrics(metrics *storage.Metrics) storage.Storage {
return d
}
// New creates a Storage persisted in Google Cloud Datastore
func New(client TranslatorClient, keyKind string, valueKind string) storage.Storage {
return &datastoreStorage{client: client, keyKind: keyKind, valueKind: valueKind}
}