Open5
DynamoDB小技 (guregu/dynamo)
アトミックカウンター
Autoincrementみたいなサムシング
func NextID(ctx context.Context, class string) (n int, err error) {
var counter struct {
Class string
Count int
}
table := dynamoTable("Counters")
err = table.Update("Class", class).Add("Count", 1).ValueWithContext(ctx, &counter)
return counter.Count, err
}
使い方
type User struct {
ID int
Regdate time.Time
// ...
}
func (u *User) Create(ctx context.Context) error {
if u.ID != 0 {
panic("user already exists")
}
now := time.Now().UTC()
u.Regdate = now
var err error
u.ID, err = NextID(ctx, counterUsers)
if err != nil {
return err
}
users := dynamoTable(tableUsers)
err = users.Put(u).If("attribute_not_exists(ID)").RunWithContext(ctx)
return err
}
errorがConditionalCheckFailedExceptionか否か
func IsCondCheckErr(err error) bool {
if ae, ok := err.(awserr.Error); ok && ae.Code() == "ConditionalCheckFailedException" {
return true
}
return false
}
テーブルにprefix付けると管理しやすい
const tablePrefix = "Hoge-"
var db = dynamo.New(session.New(), &aws.Config{
Region: aws.String("us-west-2"),
// LogLevel: aws.LogLevel(aws.LogDebugWithHTTPBody),
})
func dynamoTable(name string) dynamo.Table {
return db.Table(tablePrefix + name)
}
こうすれば一々importせずにエラー判定できる
package hoge
import "github.com/guregu/dynamo"
var ErrNotFound = dynamo.ErrNotFound
Listな属性が存在しなければ初期化、存在していたらappend
update.SetExpr("'Usage' = list_append(if_not_exists('Usage', ?), ?)", []InviteUsage{}, []InviteUsage{{Time: time.Now().UTC(), UserID: u.ID}}).