forked from guregu/dynamo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
delete.go
171 lines (151 loc) · 4.33 KB
/
delete.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
165
166
167
168
169
170
171
package dynamo
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
)
// Delete is a request to delete an item.
// See: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html
type Delete struct {
table Table
returnType string
hashKey string
hashValue *dynamodb.AttributeValue
rangeKey string
rangeValue *dynamodb.AttributeValue
subber
condition string
err error
cc *ConsumedCapacity
}
// Delete creates a new request to delete an item.
// Key is the name of the hash key (a.k.a. partition key).
// Value is the value of the hash key.
func (table Table) Delete(name string, value interface{}) *Delete {
d := &Delete{
table: table,
hashKey: name,
}
d.hashValue, d.err = marshal(value, "")
return d
}
// Range specifies the range key (a.k.a. sort key) to delete.
// Name is the name of the range key.
// Value is the value of the range key.
func (d *Delete) Range(name string, value interface{}) *Delete {
var err error
d.rangeKey = name
d.rangeValue, err = marshal(value, "")
d.setError(err)
return d
}
// If specifies a conditional expression for this delete to succeed.
// Use single quotes to specificy reserved names inline (like 'Count').
// Use the placeholder ? within the expression to substitute values, and use $ for names.
// You need to use quoted or placeholder names when the name is a reserved word in DynamoDB.
// Multiple calls to If will be combined with AND.
func (d *Delete) If(expr string, args ...interface{}) *Delete {
expr = wrapExpr(expr)
expr, err := d.subExpr(expr, args...)
d.setError(err)
if d.condition != "" {
d.condition += " AND "
}
d.condition += expr
return d
}
// ConsumedCapacity will measure the throughput capacity consumed by this operation and add it to cc.
func (d *Delete) ConsumedCapacity(cc *ConsumedCapacity) *Delete {
d.cc = cc
return d
}
// Run executes this delete request.
func (d *Delete) Run() error {
ctx, cancel := defaultContext()
defer cancel()
return d.RunWithContext(ctx)
}
func (d *Delete) RunWithContext(ctx aws.Context) error {
d.returnType = "NONE"
_, err := d.run(ctx)
return err
}
// OldValue executes this delete request, unmarshaling the previous value to out.
// Returns ErrNotFound is there was no previous value.
func (d *Delete) OldValue(out interface{}) error {
ctx, cancel := defaultContext()
defer cancel()
return d.OldValueWithContext(ctx, out)
}
func (d *Delete) OldValueWithContext(ctx aws.Context, out interface{}) error {
d.returnType = "ALL_OLD"
output, err := d.run(ctx)
switch {
case err != nil:
return err
case output.Attributes == nil:
return ErrNotFound
}
return unmarshalItem(output.Attributes, out)
}
func (d *Delete) run(ctx aws.Context) (*dynamodb.DeleteItemOutput, error) {
if d.err != nil {
return nil, d.err
}
input := d.deleteInput()
var output *dynamodb.DeleteItemOutput
err := retry(ctx, func() error {
var err error
output, err = d.table.db.client.DeleteItemWithContext(ctx, input)
return err
})
if d.cc != nil {
addConsumedCapacity(d.cc, output.ConsumedCapacity)
}
return output, err
}
func (d *Delete) deleteInput() *dynamodb.DeleteItemInput {
input := &dynamodb.DeleteItemInput{
TableName: &d.table.name,
Key: d.key(),
ReturnValues: &d.returnType,
ExpressionAttributeNames: d.nameExpr,
ExpressionAttributeValues: d.valueExpr,
}
if d.condition != "" {
input.ConditionExpression = &d.condition
}
if d.cc != nil {
input.ReturnConsumedCapacity = aws.String(dynamodb.ReturnConsumedCapacityIndexes)
}
return input
}
func (d *Delete) writeTxItem() (*dynamodb.TransactWriteItem, error) {
if d.err != nil {
return nil, d.err
}
input := d.deleteInput()
item := &dynamodb.TransactWriteItem{
Delete: &dynamodb.Delete{
TableName: input.TableName,
Key: input.Key,
ExpressionAttributeNames: input.ExpressionAttributeNames,
ExpressionAttributeValues: input.ExpressionAttributeValues,
ConditionExpression: input.ConditionExpression,
},
}
return item, nil
}
func (d *Delete) key() map[string]*dynamodb.AttributeValue {
key := map[string]*dynamodb.AttributeValue{
d.hashKey: d.hashValue,
}
if d.rangeKey != "" {
key[d.rangeKey] = d.rangeValue
}
return key
}
func (d *Delete) setError(err error) {
if d.err == nil {
d.err = err
}
}