Last active
November 25, 2022 08:52
-
-
Save andream16/49d198486aebc403269805a9544d6f7b to your computer and use it in GitHub Desktop.
Build ExpressionAttributeValues and UpdateExpression from map[string]interface{} - AWS Go SDK, DynamoDB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"github.com/fatih/structs" | |
"github.com/aws/aws-sdk-go/aws" | |
"github.com/aws/aws-sdk-go/service/dynamodb" | |
"strings" | |
"fmt" | |
) | |
type TestStruct struct { | |
Name string | |
NestedStuff NestedStuff | |
SuperNestedStuff SuperNestedStuff | |
} | |
type NestedStuff struct { | |
Something string | |
} | |
type SuperNestedStuff struct { | |
SomethingNested NestedStuff | |
} | |
// Useful for https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/dynamo-example-update-table-item.html | |
// input := &dynamodb.UpdateItemInput{ | |
// ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ | |
// ":r": { | |
// N: aws.String("0.5"), | |
// }, | |
// }, | |
// TableName: aws.String("Movies"), | |
// Key: map[string]*dynamodb.AttributeValue{ | |
// "year": { | |
// N: aws.String("2015"), | |
// }, | |
// "title": { | |
// S: aws.String("The Big New Movie"), | |
// }, | |
// }, | |
// ReturnValues: aws.String("UPDATED_NEW"), | |
// UpdateExpression: aws.String("set info.rating = :r"), | |
//} | |
func main() { | |
// Just a test nested Struct | |
test := TestStruct{ | |
Name : "hello", | |
NestedStuff : NestedStuff{ | |
Something: "something1", | |
}, | |
SuperNestedStuff : SuperNestedStuff{ | |
SomethingNested : NestedStuff{ | |
Something: "something2", | |
}, | |
}, | |
} | |
// Get map[string]interface{} from struct | |
m := structs.Map(test) | |
// Get ExpressionAttributeValues from a map[string]interface{}. | |
// Second parameter is parent's name that is used recursively. The first time it's an empty string. | |
exprAttrValues := BuildExpressionAttributeValues(m, "") | |
fmt.Println(fmt.Sprintf("ExpressionAttributeValues %v", exprAttrValues)) | |
// ExpressionAttributeValues map[:name:{ | |
// S: "hello" | |
//} :nestedstuff:{ | |
// M: { | |
// :nestedstuffsomething: { | |
// S: "something1" | |
// } | |
// } | |
//} :supernestedstuff:{ | |
// M: { | |
// :supernestedstuffsomethingnested: { | |
// M: { | |
// :supernestedstuffsomethingnestedsomething: { | |
// S: "something2" | |
// } | |
// } | |
// } | |
// } | |
//}] | |
// Get UpdateExpression from a map[string]interface{}. | |
// Second and Third parameters are parent's name that are used recursively. The first time they are both empty strings. | |
updateExpr := BuildUpdateExpression(m, "", "") | |
fmt.Println(fmt.Sprintf("UpdateExpression %v", updateExpr)) | |
// UpdateExpression Name = :name, NestedStuff.Something = :nestedstuffsomething, SuperNestedStuff.SomethingNested.Something = :supernestedstuffsomethingnestedsomething | |
} | |
func BuildExpressionAttributeValues(input map[string]interface{}, parentName string) map[string]*dynamodb.AttributeValue { | |
// Map to be returned | |
m := make(map[string]*dynamodb.AttributeValue) | |
for k, v := range input { | |
keyName := strings.Join([]string{":", parentName, strings.ToLower(k)}, "") | |
// Add All the cases you need. | |
switch t := v.(type) { | |
case map[string]interface{}: | |
nextName := strings.TrimPrefix(keyName, ":") | |
m[keyName] = &dynamodb.AttributeValue{ | |
M : BuildExpressionAttributeValues(t, nextName), | |
} | |
case string: | |
m[keyName] = &dynamodb.AttributeValue{ | |
S : aws.String(t), | |
} | |
case bool: | |
m[keyName] = &dynamodb.AttributeValue{ | |
BOOL : aws.Bool(t), | |
} | |
} | |
} | |
return m | |
} | |
func BuildUpdateExpression(input map[string]interface{}, parentName, exprParentName string) string { | |
var s []string | |
for k, v := range input { | |
keyName := strings.Join([]string{":", exprParentName, strings.ToLower(k)}, "") | |
// Add All the cases you need. | |
switch t := v.(type) { | |
case string, bool: | |
currAttrName := k | |
if len(parentName) > 0 { | |
currAttrName = strings.Join([]string{parentName, currAttrName}, ".") | |
} | |
s = append(s, strings.Join([]string{currAttrName, "=", keyName}, " ")) | |
case map[string]interface{}: | |
nextExprParentName := strings.TrimPrefix(keyName, ":") | |
nextParentName := k | |
if len(parentName) > 0 { | |
nextParentName = strings.Join([]string{parentName, k}, ".") | |
} | |
s = append(s, BuildUpdateExpression(t, nextParentName, nextExprParentName)) | |
} | |
} | |
return strings.Join(s, ", ") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment