func TestDynamoBasic(t *testing.T) { ctx := core.NewContext("test") ddb, err := NewStorage(ctx, testConfig) if noConnection(err) { t.Skip() } if err != nil { t.Fatal(err) } server := ddb.server { tables, err := server.ListTables() if err != nil { t.Fatal(err) } for _, t := range tables { log.Println("table " + t) } } table := ddb.table { attrs := []dynamodb.Attribute{ *dynamodb.NewStringAttribute("likes", "beer"), } if ok, err := table.PutItem("homer", "", attrs); !ok { t.Fatal(err) } } { attrs := []dynamodb.Attribute{ *dynamodb.NewStringAttribute("likes", "tacos"), } k := dynamodb.Key{HashKey: "homer"} if ok, err := table.UpdateAttributes(&k, attrs); !ok { t.Fatal(err) } } { k := dynamodb.Key{HashKey: "homer"} as, err := table.GetItem(&k) if err != nil { t.Fatal(err) } for _, v := range as { log.Println(v) } } }
// Remove removes the given data from DynamoDB. // // If 'CheckLastUpdated' is true, this function attempts to verify // that the state in DynamoDB hasn't changed since we last loaded it // or changed it. If the state has changed unexpectedly, you get an // error (which should be ConcurrentStateChange, but currently is just // the error returned by the SDK). func (s *DynamoDBStorage) Remove(ctx *Context, loc string, id []byte) (int64, error) { Log(INFO, ctx, "DynamoDBStorage.Remove", "location", loc, "id", string(id)) lastUpdated, updating := ctx.Location().Update(ctx, "") Log(DEBUG, ctx, "DynamoDBStorage.Add", "location", loc, "lastUpdated", lastUpdated, "updatingAt", updating) attrs := []dynamodb.Attribute{ *dynamodb.NewStringAttribute(string(id), ""), *dynamodb.NewStringAttribute(LastUpdatedKey, updating), } k := dynamodb.Key{HashKey: loc} var err error n := int64(1) var ok bool if CheckLastUpdated { // See comments elsewhere near CheckLastUpdated uses. update := dynamodb.Expression{ Text: "REMOVE #a SET #u = :u", AttributeNames: map[string]string{ "#a": string(id), "#u": lastUpdated, }, AttributeValues: []dynamodb.Attribute{ *dynamodb.NewStringAttribute(":u", updating), }, } var cond dynamodb.Expression if lastUpdated == "" { cond = dynamodb.Expression{ Text: "attribute_not_exists(#u)", AttributeNames: map[string]string{ "#u": LastUpdatedKey, }, } } else { cond = dynamodb.Expression{ Text: "#u = :v", AttributeNames: map[string]string{ "#u": LastUpdatedKey, }, AttributeValues: []dynamodb.Attribute{ *dynamodb.NewStringAttribute(":v", lastUpdated), }, } } ok, err = s.table.UpdateExpressionUpdateAttributes(&k, &cond, &update) } else { ok, err = s.table.DeleteAttributes(&k, attrs) } if !ok { n = 0 } return n, err }
// Add writes the given additional state to DynamoDB. // // If 'CheckLastUpdated' is true, this function attempts to verify // that the state in DynamoDB hasn't changed since we last loaded it // or changed it. If the state has changed unexpectedly, you get an // error (which should be ConcurrentStateChange, but currently is just // the error returned by the SDK). func (s *DynamoDBStorage) Add(ctx *Context, loc string, m *Pair) error { Log(INFO, ctx, "DynamoDBStorage.Add", "location", loc, "m", m.String()) lastUpdated, updating := ctx.Location().Update(ctx, "") Log(DEBUG, ctx, "DynamoDBStorage.Add", "location", loc, "lastUpdated", lastUpdated, "updatingAt", updating) attrs := []dynamodb.Attribute{ *dynamodb.NewStringAttribute(string(m.K), string(m.V)), *dynamodb.NewStringAttribute(LastUpdatedKey, updating), } k := dynamodb.Key{HashKey: loc} var err error var ok bool if CheckLastUpdated { // Maybe retry a little to see if we get the state we expect? // Probably no point, so don't actually loop. for i := 0; i < 1; i++ { // Ugh: "ExpressionAttributeValues contains invalid // value: One or more parameter values were invalid: // An AttributeValue may not contain an empty string // for key :Expected0." if lastUpdated == "" { cond := dynamodb.Expression{ Text: "attribute_not_exists(#u)", AttributeNames: map[string]string{ "#u": LastUpdatedKey, }, } ok, err = s.table.ConditionExpressionUpdateAttributes(&k, attrs, &cond) } else { expected := []dynamodb.Attribute{ *dynamodb.NewStringAttribute(LastUpdatedKey, lastUpdated), } ok, err = s.table.ConditionalUpdateAttributes(&k, attrs, expected) } if !ConditionalCheckFailedException(err) { break } // s.peek(ctx, loc) Log(WARN, ctx, "DynamoDBStorage.Add", "location", loc, "error", err, "retry", i) time.Sleep(10 * time.Millisecond) } } else { ok, err = s.table.UpdateAttributes(&k, attrs) } if err != nil { Log(WARN, ctx, "DynamoDBStorage.Add", "location", loc, "error", err, "ok", ok) return err } return nil }
func (r *MikroAdapter) Register(service *bridge.Service) error { attrs := []dynamodb.Attribute{ //*dynamodb.NewStringAttribute("InstanceID", instanceId), *dynamodb.NewStringAttribute("HostAddr", service.IP), *dynamodb.NewNumericAttribute("HostPort", strconv.Itoa(service.Port)), *dynamodb.NewStringAttribute("ExpiresAt", time.Now().Add( time.Second*time.Duration(service.TTL)).Format(time.RFC3339)), *dynamodb.NewStringAttribute("UpdatedAt", time.Now().Format(time.RFC3339)), } ok, err := r.table.PutItem(service.Name, service.ID, attrs) if !ok { log.Println("mikro: failed to register service:", err) } return err }
// init creates the given table if it doesn't exist. func (s *DynamoDBStorage) init(ctx *Context, table string) error { Log(INFO, ctx, "DynamoDBStorage.init", "table", table) td, err := s.server.DescribeTable(table) if err != nil { Log(INFO, ctx, "DynamoDBStorage.init", "creating", table) td = dynamodbTableDescription(table) _, err = s.server.CreateTable(*td) if err != nil { Log(INFO, ctx, "DynamoDBStorage.init", "error", err) return err } } Log(INFO, ctx, "DynamoDBStorage.init", "td", td) pk, err := td.BuildPrimaryKey() if err != nil { panic(err) } if pk.KeyAttribute == nil { // Puslar issue? name := td.AttributeDefinitions[0].Name attr := dynamodb.NewStringAttribute(name, "") attr.Type = td.AttributeDefinitions[0].Type pk.KeyAttribute = attr Log(INFO, ctx, "DynamoDBStorage.init", "pulsar", *pk.KeyAttribute) } s.table = s.server.NewTable(table, pk) return nil }
func (s *DynamoDBStorage) Clear(ctx *Context, loc string) (int64, error) { Log(INFO, ctx, "DynamoDBStorage.Clear", "location", loc) lastUpdated, updating := ctx.Location().Update(ctx, "clear") Log(DEBUG, ctx, "DynamoDBStorage.Clear", "location", loc, "lastUpdated", lastUpdated, "updatingAt", updating) k := dynamodb.Key{HashKey: loc} var ok bool var err error n := int64(0) if CheckLastUpdated && lastUpdated != "" { // See comments elsewhere near CheckLastUpdated uses. cond := []dynamodb.Attribute{ *dynamodb.NewStringAttribute(LastUpdatedKey, lastUpdated), } ok, err = s.table.ConditionalDeleteItem(&k, cond) } else { ok, err = s.table.DeleteItem(&k) } if ok { n = 1 } return n, err }