Skip to content

Commit 07e5d3e

Browse files
radutopalajasdel
andauthored
i1494 passing opts to attributevalue marshalling (#1495)
Fixes the SDK's code generation to pin smithy-cli to $smithyVersion to restrict the supported version. Co-authored-by: Jason Del Ponte <[email protected]>
1 parent 576b415 commit 07e5d3e

File tree

4 files changed

+233
-0
lines changed

4 files changed

+233
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "5ab32814-eb5e-456e-a921-d0f0a645ca5b",
3+
"type": "feature",
4+
"description": "Adds new MarshalWithOptions and UnmarshalWithOptions helpers allowing Encoding and Decoding options to be specified when serializing AttributeValues. Addresses issue: https://github.com/aws/aws-sdk-go-v2/issues/1494",
5+
"modules": [
6+
"feature/dynamodb/attributevalue"
7+
]
8+
}

codegen/protocol-test-codegen/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ plugins {
3232
}
3333

3434
dependencies {
35+
implementation("software.amazon.smithy:smithy-cli:$smithyVersion")
3536
implementation("software.amazon.smithy:smithy-aws-protocol-tests:$smithyVersion")
3637
implementation(project(":smithy-aws-go-codegen"))
3738
}

feature/dynamodb/attributevalue/decode.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,53 @@ func Unmarshal(av types.AttributeValue, out interface{}) error {
7979
return NewDecoder().Decode(av, out)
8080
}
8181

82+
// UnmarshalWithOptions will unmarshal AttributeValues to Go value types.
83+
// Both generic interface{} and concrete types are valid unmarshal
84+
// destination types.
85+
//
86+
// Use the `optsFns` functional options to override the default configuration.
87+
//
88+
// UnmarshalWithOptions will allocate maps, slices, and pointers as needed to
89+
// unmarshal the AttributeValue into the provided type value.
90+
//
91+
// When unmarshaling AttributeValues into structs Unmarshal matches
92+
// the field names of the struct to the AttributeValue Map keys.
93+
// Initially it will look for exact field name matching, but will
94+
// fall back to case insensitive if not exact match is found.
95+
//
96+
// With the exception of omitempty, omitemptyelem, binaryset, numberset
97+
// and stringset all struct tags used by Marshal are also used by
98+
// UnmarshalWithOptions.
99+
//
100+
// When decoding AttributeValues to interfaces Unmarshal will use the
101+
// following types.
102+
//
103+
// []byte, AV Binary (B)
104+
// [][]byte, AV Binary Set (BS)
105+
// bool, AV Boolean (BOOL)
106+
// []interface{}, AV List (L)
107+
// map[string]interface{}, AV Map (M)
108+
// float64, AV Number (N)
109+
// Number, AV Number (N) with UseNumber set
110+
// []float64, AV Number Set (NS)
111+
// []Number, AV Number Set (NS) with UseNumber set
112+
// string, AV String (S)
113+
// []string, AV String Set (SS)
114+
//
115+
// If the Decoder option, UseNumber is set numbers will be unmarshaled
116+
// as Number values instead of float64. Use this to maintain the original
117+
// string formating of the number as it was represented in the AttributeValue.
118+
// In addition provides additional opportunities to parse the number
119+
// string based on individual use cases.
120+
//
121+
// When unmarshaling any error that occurs will halt the unmarshal
122+
// and return the error.
123+
//
124+
// The output value provided must be a non-nil pointer
125+
func UnmarshalWithOptions(av types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error {
126+
return NewDecoder(optFns...).Decode(av, out)
127+
}
128+
82129
// UnmarshalMap is an alias for Unmarshal which unmarshals from
83130
// a map of AttributeValues.
84131
//
@@ -87,6 +134,16 @@ func UnmarshalMap(m map[string]types.AttributeValue, out interface{}) error {
87134
return NewDecoder().Decode(&types.AttributeValueMemberM{Value: m}, out)
88135
}
89136

137+
// UnmarshalMapWithOptions is an alias for UnmarshalWithOptions which unmarshals from
138+
// a map of AttributeValues.
139+
//
140+
// Use the `optsFns` functional options to override the default configuration.
141+
//
142+
// The output value provided must be a non-nil pointer
143+
func UnmarshalMapWithOptions(m map[string]types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error {
144+
return NewDecoder(optFns...).Decode(&types.AttributeValueMemberM{Value: m}, out)
145+
}
146+
90147
// UnmarshalList is an alias for Unmarshal func which unmarshals
91148
// a slice of AttributeValues.
92149
//
@@ -95,6 +152,16 @@ func UnmarshalList(l []types.AttributeValue, out interface{}) error {
95152
return NewDecoder().Decode(&types.AttributeValueMemberL{Value: l}, out)
96153
}
97154

155+
// UnmarshalListWithOptions is an alias for UnmarshalWithOptions func which unmarshals
156+
// a slice of AttributeValues.
157+
//
158+
// Use the `optsFns` functional options to override the default configuration.
159+
//
160+
// The output value provided must be a non-nil pointer
161+
func UnmarshalListWithOptions(l []types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error {
162+
return NewDecoder(optFns...).Decode(&types.AttributeValueMemberL{Value: l}, out)
163+
}
164+
98165
// UnmarshalListOfMaps is an alias for Unmarshal func which unmarshals a
99166
// slice of maps of attribute values.
100167
//
@@ -111,6 +178,24 @@ func UnmarshalListOfMaps(l []map[string]types.AttributeValue, out interface{}) e
111178
return UnmarshalList(items, out)
112179
}
113180

181+
// UnmarshalListOfMapsWithOptions is an alias for UnmarshalWithOptions func which unmarshals a
182+
// slice of maps of attribute values.
183+
//
184+
// Use the `optsFns` functional options to override the default configuration.
185+
//
186+
// This is useful for when you need to unmarshal the Items from a Query API
187+
// call.
188+
//
189+
// The output value provided must be a non-nil pointer
190+
func UnmarshalListOfMapsWithOptions(l []map[string]types.AttributeValue, out interface{}, optFns ...func(options *DecoderOptions)) error {
191+
items := make([]types.AttributeValue, len(l))
192+
for i, m := range l {
193+
items[i] = &types.AttributeValueMemberM{Value: m}
194+
}
195+
196+
return UnmarshalListWithOptions(items, out, optFns...)
197+
}
198+
114199
// DecoderOptions is a collection of options to configure how the decoder
115200
// unmarshalls the value.
116201
type DecoderOptions struct {

feature/dynamodb/attributevalue/encode.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,115 @@ func Marshal(in interface{}) (types.AttributeValue, error) {
179179
return NewEncoder().Encode(in)
180180
}
181181

182+
// MarshalWithOptions will serialize the passed in Go value type into a AttributeValue
183+
// type, by using . This value can be used in API operations to simplify marshaling
184+
// your Go value types into AttributeValues.
185+
//
186+
// Use the `optsFns` functional options to override the default configuration.
187+
//
188+
// MarshalWithOptions will recursively transverse the passed in value marshaling its
189+
// contents into a AttributeValue. Marshal supports basic scalars
190+
// (int,uint,float,bool,string), maps, slices, and structs. Anonymous
191+
// nested types are flattened based on Go anonymous type visibility.
192+
//
193+
// Marshaling slices to AttributeValue will default to a List for all
194+
// types except for []byte and [][]byte. []byte will be marshaled as
195+
// Binary data (B), and [][]byte will be marshaled as binary data set
196+
// (BS).
197+
//
198+
// The `time.Time` type is marshaled as `time.RFC3339Nano` format.
199+
//
200+
// `dynamodbav` struct tag can be used to control how the value will be
201+
// marshaled into a AttributeValue.
202+
//
203+
// // Field is ignored
204+
// Field int `dynamodbav:"-"`
205+
//
206+
// // Field AttributeValue map key "myName"
207+
// Field int `dynamodbav:"myName"`
208+
//
209+
// // Field AttributeValue map key "myName", and
210+
// // Field is omitted if the field is a zero value for the type.
211+
// Field int `dynamodbav:"myName,omitempty"`
212+
//
213+
// // Field AttributeValue map key "Field", and
214+
// // Field is omitted if the field is a zero value for the type.
215+
// Field int `dynamodbav:",omitempty"`
216+
//
217+
// // Field's elems will be omitted if the elem's value is empty.
218+
// // only valid for slices, and maps.
219+
// Field []string `dynamodbav:",omitemptyelem"`
220+
//
221+
// // Field AttributeValue map key "Field", and
222+
// // Field is sent as NULL if the field is a zero value for the type.
223+
// Field int `dynamodbav:",nullempty"`
224+
//
225+
// // Field's elems will be sent as NULL if the elem's value a zero value
226+
// // for the type. Only valid for slices, and maps.
227+
// Field []string `dynamodbav:",nullemptyelem"`
228+
//
229+
// // Field will be marshaled as a AttributeValue string
230+
// // only value for number types, (int,uint,float)
231+
// Field int `dynamodbav:",string"`
232+
//
233+
// // Field will be marshaled as a binary set
234+
// Field [][]byte `dynamodbav:",binaryset"`
235+
//
236+
// // Field will be marshaled as a number set
237+
// Field []int `dynamodbav:",numberset"`
238+
//
239+
// // Field will be marshaled as a string set
240+
// Field []string `dynamodbav:",stringset"`
241+
//
242+
// // Field will be marshaled as Unix time number in seconds.
243+
// // This tag is only valid with time.Time typed struct fields.
244+
// // Important to note that zero value time as unixtime is not 0 seconds
245+
// // from January 1, 1970 UTC, but -62135596800. Which is seconds between
246+
// // January 1, 0001 UTC, and January 1, 0001 UTC.
247+
// Field time.Time `dynamodbav:",unixtime"`
248+
//
249+
// The omitempty tag is only used during Marshaling and is ignored for
250+
// Unmarshal. omitempty will skip any member if the Go value of the member is
251+
// zero. The omitemptyelem tag works the same as omitempty except it applies to
252+
// the elements of maps and slices instead of struct fields, and will not be
253+
// included in the marshaled AttributeValue Map, List, or Set.
254+
//
255+
// The nullempty tag is only used during Marshaling and is ignored for
256+
// Unmarshal. nullempty will serialize a AttributeValueMemberNULL for the
257+
// member if the Go value of the member is zero. nullemptyelem tag works the
258+
// same as nullempty except it applies to the elements of maps and slices
259+
// instead of struct fields, and will not be included in the marshaled
260+
// AttributeValue Map, List, or Set.
261+
//
262+
// All struct fields and with anonymous fields, are marshaled unless the
263+
// any of the following conditions are meet.
264+
//
265+
// - the field is not exported
266+
// - json or dynamodbav field tag is "-"
267+
// - json or dynamodbav field tag specifies "omitempty", and is a zero value.
268+
//
269+
// Pointer and interfaces values are encoded as the value pointed to or
270+
// contained in the interface. A nil value encodes as the AttributeValue NULL
271+
// value unless `omitempty` struct tag is provided.
272+
//
273+
// Channel, complex, and function values are not encoded and will be skipped
274+
// when walking the value to be marshaled.
275+
//
276+
// Error that occurs when marshaling will stop the marshal, and return
277+
// the error.
278+
//
279+
// MarshalWithOptions cannot represent cyclic data structures and will not handle them.
280+
// Passing cyclic structures to Marshal will result in an infinite recursion.
281+
func MarshalWithOptions(in interface{}, optFns ...func(*EncoderOptions)) (types.AttributeValue, error) {
282+
return NewEncoder(optFns...).Encode(in)
283+
}
284+
182285
// MarshalMap is an alias for Marshal func which marshals Go value type to a
183286
// map of AttributeValues. If the in parameter does not serialize to a map, an
184287
// empty AttributeValue map will be returned.
185288
//
289+
// Use the `optsFns` functional options to override the default configuration.
290+
//
186291
// This is useful for APIs such as PutItem.
187292
func MarshalMap(in interface{}) (map[string]types.AttributeValue, error) {
188293
av, err := NewEncoder().Encode(in)
@@ -195,6 +300,24 @@ func MarshalMap(in interface{}) (map[string]types.AttributeValue, error) {
195300
return asMap.Value, nil
196301
}
197302

303+
// MarshalMapWithOptions is an alias for MarshalWithOptions func which marshals Go value type to a
304+
// map of AttributeValues. If the in parameter does not serialize to a map, an
305+
// empty AttributeValue map will be returned.
306+
//
307+
// Use the `optsFns` functional options to override the default configuration.
308+
//
309+
// This is useful for APIs such as PutItem.
310+
func MarshalMapWithOptions(in interface{}, optFns ...func(*EncoderOptions)) (map[string]types.AttributeValue, error) {
311+
av, err := NewEncoder(optFns...).Encode(in)
312+
313+
asMap, ok := av.(*types.AttributeValueMemberM)
314+
if err != nil || av == nil || !ok {
315+
return map[string]types.AttributeValue{}, err
316+
}
317+
318+
return asMap.Value, nil
319+
}
320+
198321
// MarshalList is an alias for Marshal func which marshals Go value
199322
// type to a slice of AttributeValues. If the in parameter does not serialize
200323
// to a slice, an empty AttributeValue slice will be returned.
@@ -209,6 +332,22 @@ func MarshalList(in interface{}) ([]types.AttributeValue, error) {
209332
return asList.Value, nil
210333
}
211334

335+
// MarshalListWithOptions is an alias for MarshalWithOptions func which marshals Go value
336+
// type to a slice of AttributeValues. If the in parameter does not serialize
337+
// to a slice, an empty AttributeValue slice will be returned.
338+
//
339+
// Use the `optsFns` functional options to override the default configuration.
340+
func MarshalListWithOptions(in interface{}, optFns ...func(*EncoderOptions)) ([]types.AttributeValue, error) {
341+
av, err := NewEncoder(optFns...).Encode(in)
342+
343+
asList, ok := av.(*types.AttributeValueMemberL)
344+
if err != nil || av == nil || !ok {
345+
return []types.AttributeValue{}, err
346+
}
347+
348+
return asList.Value, nil
349+
}
350+
212351
// EncoderOptions is a collection of options shared between marshaling
213352
// and unmarshaling
214353
type EncoderOptions struct {

0 commit comments

Comments
 (0)