forked from guregu/dynamo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
db.go
164 lines (139 loc) · 4.03 KB
/
db.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Package dynamo offers a rich DynamoDB client.
package dynamo
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
)
// DB is a DynamoDB client.
type DB struct {
client dynamodbiface.DynamoDBAPI
}
// New creates a new client with the given configuration.
func New(p client.ConfigProvider, cfgs ...*aws.Config) *DB {
db := &DB{
dynamodb.New(p, cfgs...),
}
return db
}
// NewFromIface creates a new client with the given interface.
func NewFromIface(client dynamodbiface.DynamoDBAPI) *DB {
return &DB{client}
}
// Client returns this DB's internal client used to make API requests.
func (db *DB) Client() dynamodbiface.DynamoDBAPI {
return db.client
}
// ListTables is a request to list tables.
// See: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListTables.html
type ListTables struct {
db *DB
}
// ListTables begins a new request to list all tables.
func (db *DB) ListTables() *ListTables {
return &ListTables{db: db}
}
// All returns every table or an error.
func (lt *ListTables) All() ([]string, error) {
ctx, cancel := defaultContext()
defer cancel()
return lt.AllWithContext(ctx)
}
// AllWithContext returns every table or an error.
func (lt *ListTables) AllWithContext(ctx aws.Context) ([]string, error) {
var tables []string
itr := lt.Iter()
var name string
for itr.NextWithContext(ctx, &name) {
tables = append(tables, name)
}
return tables, itr.Err()
}
type ltIter struct {
lt *ListTables
result *dynamodb.ListTablesOutput
idx int
err error
}
// Iter returns an iterator of table names.
// This iterator's Next functions will only accept type *string as their out parameter.
func (lt *ListTables) Iter() Iter {
return <Iter{lt: lt}
}
func (itr *ltIter) Next(out interface{}) bool {
ctx, cancel := defaultContext()
defer cancel()
return itr.NextWithContext(ctx, out)
}
func (itr *ltIter) NextWithContext(ctx aws.Context, out interface{}) bool {
if itr.err != nil {
return false
}
if _, ok := out.(*string); !ok {
itr.err = fmt.Errorf("dynamo: list tables: iter out must be *string, got %T", out)
return false
}
if itr.result != nil {
if itr.idx < len(itr.result.TableNames) {
*out.(*string) = *itr.result.TableNames[itr.idx]
itr.idx++
return true
}
// no more tables
if itr.result.LastEvaluatedTableName == nil {
return false
}
}
itr.err = retry(ctx, func() error {
res, err := itr.lt.db.client.ListTables(itr.input())
if err != nil {
return err
}
itr.result = res
return nil
})
if itr.err != nil {
return false
}
if len(itr.result.TableNames) == 0 {
return false
}
*out.(*string) = *itr.result.TableNames[0]
itr.idx = 1
return true
}
func (itr *ltIter) Err() error {
return itr.err
}
func (itr *ltIter) input() *dynamodb.ListTablesInput {
input := &dynamodb.ListTablesInput{}
if itr.result != nil {
input.ExclusiveStartTableName = itr.result.LastEvaluatedTableName
}
return input
}
// Iter is an iterator for request results.
type Iter interface {
// Next tries to unmarshal the next result into out.
// Returns false when it is complete or if it runs into an error.
Next(out interface{}) bool
// NextWithContext tries to unmarshal the next result into out.
// Returns false when it is complete or if it runs into an error.
NextWithContext(ctx aws.Context, out interface{}) bool
// Err returns the error encountered, if any.
// You should check this after Next is finished.
Err() error
}
// PagingIter is an iterator of request results that can also return a key
// used for splitting results.
type PagingIter interface {
Iter
// LastEvaluatedKey returns a key that can be passed to StartFrom in Query or Scan.
// Combined with SearchLimit, it is useful for paginating partial results.
LastEvaluatedKey() PagingKey
}
// PagingKey is a key used for splitting up partial results.
// Get a PagingKey from a PagingIter and pass it to StartFrom in Query or Scan.
type PagingKey map[string]*dynamodb.AttributeValue