Skip to content

Commit 0e131ae

Browse files
authored
[DynamoDB] refactor!: Use dynamodbattribute for Unmarshal; Add DescribeTable; (#48)
1 parent 7e6b504 commit 0e131ae

14 files changed

+862
-162
lines changed

dynamodb/client.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ func (svc *DynamoDB) CreateTable(design *TableDesign) error {
7272
design.name = originalName
7373
return err
7474
}
75-
design = newTableDesignFromDescription(out.TableDescription)
75+
76+
design = newTableDesignFromDescription(NewTableDescription(out.TableDescription))
7677
svc.Infof("success on `CreateTable` operation; table=%s; status=%s;", design.GetName(), design.status)
7778
return nil
7879
}
@@ -95,8 +96,8 @@ func (svc *DynamoDB) ForceDeleteTable(name string) error {
9596
}
9697
svc.tablesMu.Unlock()
9798

98-
design := newTableDesignFromDescription(out.TableDescription)
99-
svc.Infof("success on `DeleteTable` operation; table=%s; status=%s;", tableName, design.status)
99+
desc := NewTableDescription(out.TableDescription)
100+
svc.Infof("success on `DeleteTable` operation; table=%s; status=%s;", tableName, desc.TableStatus)
100101
return nil
101102
}
102103

@@ -138,6 +139,24 @@ func (svc *DynamoDB) ListTables() ([]string, error) {
138139
return list, nil
139140
}
140141

142+
// DescribeTable executes `DescribeTable` operation and get table info.
143+
func (svc *DynamoDB) DescribeTable(name string) (TableDescription, error) {
144+
res, err := svc.client.DescribeTable(&SDK.DescribeTableInput{
145+
TableName: pointers.String(name),
146+
})
147+
switch {
148+
case err != nil:
149+
svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
150+
return TableDescription{}, err
151+
case res == nil:
152+
err := fmt.Errorf("response is nil")
153+
svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
154+
return TableDescription{}, err
155+
}
156+
157+
return NewTableDescription(res.Table), nil
158+
}
159+
141160
// ========================
142161
// Query&Command Operation
143162
// ========================

dynamodb/condition.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,6 @@ import (
99
"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
1010
)
1111

12-
const (
13-
conditionEQ = "="
14-
conditionLE = "<="
15-
conditionLT = "<"
16-
conditionGE = ">="
17-
conditionGT = ">"
18-
conditionBETWEEN = "BETWEEN"
19-
20-
conditionOR = "OR"
21-
conditionAND = "AND"
22-
)
23-
2412
// ConditionList contains multiple condition.
2513
type ConditionList struct {
2614
keyAttributes map[string]string

dynamodb/const.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// DynamoDB utility
2+
3+
package dynamodb
4+
5+
import (
6+
SDK "github.com/aws/aws-sdk-go/service/dynamodb"
7+
)
8+
9+
const (
10+
// attribvute types
11+
AttributeTypeString = "S"
12+
AttributeTypeNumber = "N"
13+
AttributeTypeBinary = "B"
14+
AttributeTypeBool = "BOOL"
15+
AttributeTypeNull = "NULL"
16+
AttributeTypeMap = "M"
17+
AttributeTypeList = "L"
18+
AttributeTypeStringSet = "SS"
19+
AttributeTypeNumberSet = "NS"
20+
AttributeTypeBinarySet = "BS"
21+
22+
conditionEQ = "="
23+
conditionLE = "<="
24+
conditionLT = "<"
25+
conditionGE = ">="
26+
conditionGT = ">"
27+
conditionBETWEEN = SDK.ComparisonOperatorBetween
28+
conditionOR = SDK.ConditionalOperatorOr
29+
conditionAND = SDK.ConditionalOperatorAnd
30+
31+
// comparison operators
32+
ComparisonOperatorEQ = SDK.ComparisonOperatorEq
33+
ComparisonOperatorNE = "NE"
34+
ComparisonOperatorGT = "GT"
35+
ComparisonOperatorLT = "LT"
36+
ComparisonOperatorGE = "GE"
37+
ComparisonOperatorLE = "LE"
38+
39+
// key type name for DynamoDB Index.
40+
KeyTypeHash = SDK.KeyTypeHash
41+
KeyTypeRange = SDK.KeyTypeRange
42+
43+
SelectCount = SDK.SelectCount
44+
)

dynamodb/item.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,6 @@ import (
66
"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
77
)
88

9-
// comparison operators
10-
const (
11-
ComparisonOperatorEQ = "EQ"
12-
ComparisonOperatorNE = "NE"
13-
ComparisonOperatorGT = "GT"
14-
ComparisonOperatorLT = "LT"
15-
ComparisonOperatorGE = "GE"
16-
ComparisonOperatorLE = "LE"
17-
)
18-
199
// PutItem is wrapped struct for DynamoDB Item to put.
2010
type PutItem struct {
2111
data map[string]*SDK.AttributeValue

dynamodb/query_result.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dynamodb
22

33
import (
44
SDK "github.com/aws/aws-sdk-go/service/dynamodb"
5-
"github.com/mitchellh/mapstructure"
5+
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
66
)
77

88
const defaultResultTag = "dynamodb"
@@ -20,29 +20,28 @@ type QueryResult struct {
2020
func (r QueryResult) ToSliceMap() []map[string]interface{} {
2121
m := make([]map[string]interface{}, len(r.Items))
2222
for i, item := range r.Items {
23+
// benachmark: https://gist.github.com/evalphobia/c1b436ef15038bc9fc9c588ca0163c93#gistcomment-3120916
2324
m[i] = UnmarshalAttributeValue(item)
2425
}
2526
return m
2627
}
2728

28-
// Unmarshal parse DynamoDB item data and mapping value to given slice pointer sturct.
29+
// Unmarshal unmarshals given slice pointer sturct from DynamoDB item result to mapping.
2930
// e.g. err = Unmarshal(&[]*yourStruct)
31+
// The struct tag `dynamodb:""` is used to unmarshal.
3032
func (r QueryResult) Unmarshal(v interface{}) error {
31-
m := r.ToSliceMap()
33+
return r.UnmarshalWithTagName(v, defaultResultTag)
34+
}
3235

33-
tagName := r.tagName
34-
if tagName == "" {
35-
tagName = defaultResultTag
36-
}
36+
// UnmarshalWithTagName unmarshals given slice pointer sturct and tag name from DynamoDB item result to mapping.
37+
func (r QueryResult) UnmarshalWithTagName(v interface{}, structTag string) error {
38+
decoder := dynamodbattribute.NewDecoder()
39+
decoder.TagKey = structTag
3740

38-
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
39-
Metadata: nil,
40-
Result: v,
41-
TagName: tagName,
42-
WeaklyTypedInput: true,
43-
})
44-
if err != nil {
45-
return err
41+
items := make([]*SDK.AttributeValue, len(r.Items))
42+
for i, m := range r.Items {
43+
items[i] = &SDK.AttributeValue{M: m}
4644
}
47-
return decoder.Decode(m)
45+
err := decoder.Decode(&SDK.AttributeValue{L: items}, v)
46+
return err
4847
}

dynamodb/query_result_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"github.com/stretchr/testify/assert"
77
)
88

9-
func getTestQueryRsult(t *testing.T) *QueryResult {
9+
func getTestQueryResult(t *testing.T) *QueryResult {
1010
setupQueryTable(t)
1111
tbl := getTestTable(t)
1212

@@ -20,7 +20,7 @@ func getTestQueryRsult(t *testing.T) *QueryResult {
2020
func TestToSliceMap(t *testing.T) {
2121
assert := assert.New(t)
2222

23-
r := getTestQueryRsult(t)
23+
r := getTestQueryResult(t)
2424

2525
list := r.ToSliceMap()
2626
assert.Len(list, 2)
@@ -43,7 +43,7 @@ func TestUnmarshal(t *testing.T) {
4343
LSIKey string `dynamodb:"lsi_key"`
4444
}
4545

46-
r := getTestQueryRsult(t)
46+
r := getTestQueryResult(t)
4747

4848
var list []*myStruct
4949
err := r.Unmarshal(&list)

dynamodb/sdk_attribute_definition.go

Lines changed: 0 additions & 49 deletions
This file was deleted.

dynamodb/sdk_attribute_value.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,26 @@ import (
1414

1515
func newAttributeValue(typ string, val interface{}) *SDK.AttributeValue {
1616
switch typ {
17-
case "S":
17+
case AttributeTypeString:
1818
return newAttributeValueS(val)
19-
case "N":
19+
case AttributeTypeNumber:
2020
return newAttributeValueN(val)
21-
case "B":
21+
case AttributeTypeBinary:
2222
return newAttributeValueB(val)
23-
case "BOOL":
23+
case AttributeTypeBool:
2424
return newAttributeValueBOOL(val)
25-
case "SS":
25+
case AttributeTypeStringSet:
2626
return newAttributeValueSS(val)
27-
case "NS":
27+
case AttributeTypeNumberSet:
2828
return newAttributeValueNS(val)
29-
case "L":
29+
case AttributeTypeBinarySet:
30+
return newAttributeValueBS(val)
31+
case AttributeTypeList:
3032
return newAttributeValueL(val)
31-
case "M":
33+
case AttributeTypeMap:
3234
return newAttributeValueM(val)
35+
case AttributeTypeNull:
36+
return newAttributeValueNull(val)
3337
}
3438
return nil
3539
}
@@ -100,6 +104,14 @@ func newAttributeValueL(val interface{}) *SDK.AttributeValue {
100104
return &SDK.AttributeValue{L: list}
101105
}
102106

107+
func newAttributeValueNull(val interface{}) *SDK.AttributeValue {
108+
switch t := val.(type) {
109+
case bool:
110+
return &SDK.AttributeValue{NULL: pointers.Bool(t)}
111+
}
112+
return nil
113+
}
114+
103115
// Create new AttributeValue from the type of value
104116
func createAttributeValue(v interface{}) *SDK.AttributeValue {
105117
switch t := v.(type) {

dynamodb/sdk_keyschema_element.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ import (
88
"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
99
)
1010

11-
// key type name for DynamoDB Index.
12-
const (
13-
KeyTypeHash = "HASH"
14-
KeyTypeRange = "RANGE"
15-
)
16-
1711
// NewKeySchema creates new []*SDK.KeySchemaElement.
1812
func NewKeySchema(elements ...*SDK.KeySchemaElement) []*SDK.KeySchemaElement {
1913
if len(elements) > 1 {

dynamodb/table.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,12 @@ type Table struct {
2929
// NewTable returns initialized *Table.
3030
func NewTable(svc *DynamoDB, name string) (*Table, error) {
3131
tableName := svc.prefix + name
32-
req, err := svc.client.DescribeTable(&SDK.DescribeTableInput{
33-
TableName: pointers.String(tableName),
34-
})
32+
desc, err := svc.DescribeTable(tableName)
3533
if err != nil {
36-
svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
3734
return nil, err
3835
}
3936

40-
design := newTableDesignFromDescription(req.Table)
37+
design := newTableDesignFromDescription(desc)
4138
return &Table{
4239
service: svc,
4340
name: name,
@@ -80,15 +77,12 @@ func (t *Table) SetDesign(design *TableDesign) {
8077

8178
// RefreshDesign returns refreshed table design.
8279
func (t *Table) RefreshDesign() (*TableDesign, error) {
83-
req, err := t.service.client.DescribeTable(&SDK.DescribeTableInput{
84-
TableName: pointers.String(t.nameWithPrefix),
85-
})
80+
desc, err := t.service.DescribeTable(t.nameWithPrefix)
8681
if err != nil {
87-
t.service.Errorf("error on `DescribeTable` operation; table=%s; error=%s", t.nameWithPrefix, err.Error())
8882
return nil, err
8983
}
9084

91-
t.design = newTableDesignFromDescription(req.Table)
85+
t.design = newTableDesignFromDescription(desc)
9286
return t.design, nil
9387
}
9488

@@ -152,7 +146,7 @@ func (t *Table) AddItem(item *PutItem) {
152146
// Put executes put operation from the write-waiting list (writeItem)
153147
func (t *Table) Put() error {
154148
errList := newErrors()
155-
// アイテムの保存処理
149+
// save items in spool
156150
for _, item := range t.putSpool {
157151
err := t.validatePutItem(item)
158152
if err != nil {
@@ -183,7 +177,7 @@ func (t *Table) BatchPut() error {
183177
err := t.validatePutItem(item)
184178
if err != nil {
185179
errList.Add(err)
186-
// バリデーションエラーのアイテムは送信スプールから除外するリストに加える
180+
// add to ignore list
187181
errorSpoolIndices = append(errorSpoolIndices, index)
188182
continue
189183
}
@@ -321,7 +315,7 @@ func (t *Table) Query(cond *ConditionList) (*QueryResult, error) {
321315
// Count executes Query operation and get Count.
322316
func (t *Table) Count(cond *ConditionList) (*QueryResult, error) {
323317
return t.query(cond, &SDK.QueryInput{
324-
Select: pointers.String("COUNT"),
318+
Select: pointers.String(SelectCount),
325319
})
326320
}
327321

0 commit comments

Comments
 (0)