Skip to content

Commit

Permalink
[DynamoDB] refactor!: Use dynamodbattribute for Unmarshal; Add Descri…
Browse files Browse the repository at this point in the history
…beTable; (#48)
  • Loading branch information
evalphobia authored Dec 26, 2019
1 parent 7e6b504 commit 0e131ae
Show file tree
Hide file tree
Showing 14 changed files with 862 additions and 162 deletions.
25 changes: 22 additions & 3 deletions dynamodb/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ func (svc *DynamoDB) CreateTable(design *TableDesign) error {
design.name = originalName
return err
}
design = newTableDesignFromDescription(out.TableDescription)

design = newTableDesignFromDescription(NewTableDescription(out.TableDescription))
svc.Infof("success on `CreateTable` operation; table=%s; status=%s;", design.GetName(), design.status)
return nil
}
Expand All @@ -95,8 +96,8 @@ func (svc *DynamoDB) ForceDeleteTable(name string) error {
}
svc.tablesMu.Unlock()

design := newTableDesignFromDescription(out.TableDescription)
svc.Infof("success on `DeleteTable` operation; table=%s; status=%s;", tableName, design.status)
desc := NewTableDescription(out.TableDescription)
svc.Infof("success on `DeleteTable` operation; table=%s; status=%s;", tableName, desc.TableStatus)
return nil
}

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

// DescribeTable executes `DescribeTable` operation and get table info.
func (svc *DynamoDB) DescribeTable(name string) (TableDescription, error) {
res, err := svc.client.DescribeTable(&SDK.DescribeTableInput{
TableName: pointers.String(name),
})
switch {
case err != nil:
svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
return TableDescription{}, err
case res == nil:
err := fmt.Errorf("response is nil")
svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
return TableDescription{}, err
}

return NewTableDescription(res.Table), nil
}

// ========================
// Query&Command Operation
// ========================
Expand Down
12 changes: 0 additions & 12 deletions dynamodb/condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ import (
"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
)

const (
conditionEQ = "="
conditionLE = "<="
conditionLT = "<"
conditionGE = ">="
conditionGT = ">"
conditionBETWEEN = "BETWEEN"

conditionOR = "OR"
conditionAND = "AND"
)

// ConditionList contains multiple condition.
type ConditionList struct {
keyAttributes map[string]string
Expand Down
44 changes: 44 additions & 0 deletions dynamodb/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// DynamoDB utility

package dynamodb

import (
SDK "github.com/aws/aws-sdk-go/service/dynamodb"
)

const (
// attribvute types
AttributeTypeString = "S"
AttributeTypeNumber = "N"
AttributeTypeBinary = "B"
AttributeTypeBool = "BOOL"
AttributeTypeNull = "NULL"
AttributeTypeMap = "M"
AttributeTypeList = "L"
AttributeTypeStringSet = "SS"
AttributeTypeNumberSet = "NS"
AttributeTypeBinarySet = "BS"

conditionEQ = "="
conditionLE = "<="
conditionLT = "<"
conditionGE = ">="
conditionGT = ">"
conditionBETWEEN = SDK.ComparisonOperatorBetween
conditionOR = SDK.ConditionalOperatorOr
conditionAND = SDK.ConditionalOperatorAnd

// comparison operators
ComparisonOperatorEQ = SDK.ComparisonOperatorEq
ComparisonOperatorNE = "NE"
ComparisonOperatorGT = "GT"
ComparisonOperatorLT = "LT"
ComparisonOperatorGE = "GE"
ComparisonOperatorLE = "LE"

// key type name for DynamoDB Index.
KeyTypeHash = SDK.KeyTypeHash
KeyTypeRange = SDK.KeyTypeRange

SelectCount = SDK.SelectCount
)
10 changes: 0 additions & 10 deletions dynamodb/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@ import (
"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
)

// comparison operators
const (
ComparisonOperatorEQ = "EQ"
ComparisonOperatorNE = "NE"
ComparisonOperatorGT = "GT"
ComparisonOperatorLT = "LT"
ComparisonOperatorGE = "GE"
ComparisonOperatorLE = "LE"
)

// PutItem is wrapped struct for DynamoDB Item to put.
type PutItem struct {
data map[string]*SDK.AttributeValue
Expand Down
31 changes: 15 additions & 16 deletions dynamodb/query_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dynamodb

import (
SDK "github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/mitchellh/mapstructure"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)

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

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

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

decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Metadata: nil,
Result: v,
TagName: tagName,
WeaklyTypedInput: true,
})
if err != nil {
return err
items := make([]*SDK.AttributeValue, len(r.Items))
for i, m := range r.Items {
items[i] = &SDK.AttributeValue{M: m}
}
return decoder.Decode(m)
err := decoder.Decode(&SDK.AttributeValue{L: items}, v)
return err
}
6 changes: 3 additions & 3 deletions dynamodb/query_result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/assert"
)

func getTestQueryRsult(t *testing.T) *QueryResult {
func getTestQueryResult(t *testing.T) *QueryResult {
setupQueryTable(t)
tbl := getTestTable(t)

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

r := getTestQueryRsult(t)
r := getTestQueryResult(t)

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

r := getTestQueryRsult(t)
r := getTestQueryResult(t)

var list []*myStruct
err := r.Unmarshal(&list)
Expand Down
49 changes: 0 additions & 49 deletions dynamodb/sdk_attribute_definition.go

This file was deleted.

28 changes: 20 additions & 8 deletions dynamodb/sdk_attribute_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,26 @@ import (

func newAttributeValue(typ string, val interface{}) *SDK.AttributeValue {
switch typ {
case "S":
case AttributeTypeString:
return newAttributeValueS(val)
case "N":
case AttributeTypeNumber:
return newAttributeValueN(val)
case "B":
case AttributeTypeBinary:
return newAttributeValueB(val)
case "BOOL":
case AttributeTypeBool:
return newAttributeValueBOOL(val)
case "SS":
case AttributeTypeStringSet:
return newAttributeValueSS(val)
case "NS":
case AttributeTypeNumberSet:
return newAttributeValueNS(val)
case "L":
case AttributeTypeBinarySet:
return newAttributeValueBS(val)
case AttributeTypeList:
return newAttributeValueL(val)
case "M":
case AttributeTypeMap:
return newAttributeValueM(val)
case AttributeTypeNull:
return newAttributeValueNull(val)
}
return nil
}
Expand Down Expand Up @@ -100,6 +104,14 @@ func newAttributeValueL(val interface{}) *SDK.AttributeValue {
return &SDK.AttributeValue{L: list}
}

func newAttributeValueNull(val interface{}) *SDK.AttributeValue {
switch t := val.(type) {
case bool:
return &SDK.AttributeValue{NULL: pointers.Bool(t)}
}
return nil
}

// Create new AttributeValue from the type of value
func createAttributeValue(v interface{}) *SDK.AttributeValue {
switch t := v.(type) {
Expand Down
6 changes: 0 additions & 6 deletions dynamodb/sdk_keyschema_element.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@ import (
"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
)

// key type name for DynamoDB Index.
const (
KeyTypeHash = "HASH"
KeyTypeRange = "RANGE"
)

// NewKeySchema creates new []*SDK.KeySchemaElement.
func NewKeySchema(elements ...*SDK.KeySchemaElement) []*SDK.KeySchemaElement {
if len(elements) > 1 {
Expand Down
20 changes: 7 additions & 13 deletions dynamodb/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,12 @@ type Table struct {
// NewTable returns initialized *Table.
func NewTable(svc *DynamoDB, name string) (*Table, error) {
tableName := svc.prefix + name
req, err := svc.client.DescribeTable(&SDK.DescribeTableInput{
TableName: pointers.String(tableName),
})
desc, err := svc.DescribeTable(tableName)
if err != nil {
svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
return nil, err
}

design := newTableDesignFromDescription(req.Table)
design := newTableDesignFromDescription(desc)
return &Table{
service: svc,
name: name,
Expand Down Expand Up @@ -80,15 +77,12 @@ func (t *Table) SetDesign(design *TableDesign) {

// RefreshDesign returns refreshed table design.
func (t *Table) RefreshDesign() (*TableDesign, error) {
req, err := t.service.client.DescribeTable(&SDK.DescribeTableInput{
TableName: pointers.String(t.nameWithPrefix),
})
desc, err := t.service.DescribeTable(t.nameWithPrefix)
if err != nil {
t.service.Errorf("error on `DescribeTable` operation; table=%s; error=%s", t.nameWithPrefix, err.Error())
return nil, err
}

t.design = newTableDesignFromDescription(req.Table)
t.design = newTableDesignFromDescription(desc)
return t.design, nil
}

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

Expand Down
Loading

0 comments on commit 0e131ae

Please sign in to comment.