1
1
use crate :: traits:: ReadConversionError ;
2
- use aws_sdk_dynamodb:: types:: AttributeValue ;
3
- use paste:: paste;
2
+ use aws_sdk_dynamodb:: { primitives:: Blob , types:: AttributeValue } ;
4
3
use std:: collections:: HashMap ;
5
4
6
5
// FIXME: Clean this up
@@ -64,8 +63,17 @@ impl TableEntry {
64
63
#[ derive( Debug , Clone ) ]
65
64
pub enum TableAttribute {
66
65
String ( String ) ,
67
- I32 ( i32 ) ,
68
- // TODO: More here
66
+ Number ( String ) ,
67
+ Bool ( bool ) ,
68
+ Bytes ( Vec < u8 > ) ,
69
+
70
+ StringVec ( Vec < String > ) ,
71
+ ByteVec ( Vec < Vec < u8 > > ) ,
72
+ NumberVec ( Vec < String > ) ,
73
+
74
+ Map ( HashMap < String , TableAttribute > ) ,
75
+ List ( Vec < TableAttribute > ) ,
76
+
69
77
Null ,
70
78
}
71
79
@@ -79,44 +87,160 @@ impl TableAttribute {
79
87
}
80
88
}
81
89
82
- macro_rules! impl_table_attribute_conversion {
83
- ( $type: ident) => {
84
- paste! {
90
+ macro_rules! impl_option_conversion {
91
+ ( $( $type: ty) ,* ) => {
92
+ $(
93
+ impl From <Option <$type>> for TableAttribute {
94
+ fn from( value: Option <$type>) -> Self {
95
+ if let Some ( value) = value {
96
+ value. into( )
97
+ } else {
98
+ TableAttribute :: Null
99
+ }
100
+ }
101
+ }
102
+
103
+ impl TryFrom <TableAttribute > for Option <$type> {
104
+ type Error = ReadConversionError ;
105
+
106
+ fn try_from( value: TableAttribute ) -> Result <Self , Self :: Error > {
107
+ if let TableAttribute :: Null = value {
108
+ return Ok ( None ) ;
109
+ }
110
+
111
+ value. try_into( ) . map( Some )
112
+ }
113
+ }
114
+ ) *
115
+ } ;
116
+ }
117
+
118
+ macro_rules! impl_number_conversions {
119
+ ( $( $type: ty) ,* ) => {
120
+ $(
85
121
impl From <$type> for TableAttribute {
86
- fn from( value: $type) -> Self {
87
- Self :: [ <$type: camel>] ( value)
122
+ fn from( v: $type) -> Self {
123
+ Self :: Number ( v. to_string( ) )
124
+ }
125
+ }
126
+
127
+ impl From <Vec <$type>> for TableAttribute {
128
+ fn from( v: Vec <$type>) -> Self {
129
+ Self :: NumberVec ( v. into_iter( ) . map( |x| x. to_string( ) ) . collect( ) )
88
130
}
89
131
}
90
132
91
133
impl From <& $type> for TableAttribute {
92
- fn from( value: & $type) -> Self {
93
- Self :: [ <$type: camel>] ( value. clone( ) )
134
+ fn from( v: & $type) -> Self {
135
+ Self :: Number ( v. to_string( ) )
136
+ }
137
+ }
138
+
139
+ impl TryFrom <TableAttribute > for Vec <$type> {
140
+ type Error = ReadConversionError ;
141
+
142
+ fn try_from( value: TableAttribute ) -> Result <Self , Self :: Error > {
143
+ if let TableAttribute :: NumberVec ( x) = value {
144
+ x. into_iter( ) . map( |x| x. parse( ) . map_err( |_| ReadConversionError :: ConversionFailed ( stringify!( $type) . to_string( ) ) ) ) . collect:: <Result <_, _>>( )
145
+ } else {
146
+ Err ( ReadConversionError :: ConversionFailed ( stringify!( $type) . to_string( ) ) )
147
+ }
94
148
}
95
149
}
96
150
97
151
impl TryFrom <TableAttribute > for $type {
98
152
type Error = ReadConversionError ;
99
153
100
154
fn try_from( value: TableAttribute ) -> Result <Self , Self :: Error > {
101
- if let TableAttribute :: [ <$type : camel> ] ( x) = value {
102
- Ok ( x )
155
+ if let TableAttribute :: Number ( x) = value {
156
+ x . parse ( ) . map_err ( |_| ReadConversionError :: ConversionFailed ( stringify! ( $type ) . to_string ( ) ) )
103
157
} else {
104
158
Err ( ReadConversionError :: ConversionFailed ( stringify!( $type) . to_string( ) ) )
105
159
}
106
160
}
107
161
}
108
- }
109
- } ;
162
+
163
+ impl_option_conversion! {
164
+ $type,
165
+ Vec <$type>
166
+ }
167
+ ) *
168
+ }
169
+ }
170
+
171
+ macro_rules! impl_simple_conversions {
172
+ ( $( $variant: ident => $type: ty) ,* ) => {
173
+ $(
174
+ impl From <$type> for TableAttribute {
175
+ fn from( v: $type) -> Self {
176
+ TableAttribute :: $variant( v)
177
+ }
178
+ }
179
+
180
+ impl From <& $type> for TableAttribute {
181
+ fn from( v: & $type) -> Self {
182
+ TableAttribute :: $variant( v. to_owned( ) )
183
+ }
184
+ }
185
+
186
+ impl TryFrom <TableAttribute > for $type {
187
+ type Error = ReadConversionError ;
188
+
189
+ fn try_from( v: TableAttribute ) -> Result <Self , Self :: Error > {
190
+ if let TableAttribute :: $variant( x) = v {
191
+ Ok ( x. into( ) )
192
+ } else {
193
+ Err ( ReadConversionError :: ConversionFailed ( stringify!( $type) . to_string( ) ) )
194
+ }
195
+ }
196
+ }
197
+
198
+ impl_option_conversion! {
199
+ $type
200
+ }
201
+ ) *
202
+ }
203
+ }
204
+
205
+ impl_number_conversions ! {
206
+ i16 ,
207
+ i32 ,
208
+ i64 ,
209
+ u16 ,
210
+ u32 ,
211
+ u64 ,
212
+ usize ,
213
+ f32 ,
214
+ f64
110
215
}
111
216
112
- impl_table_attribute_conversion ! ( String ) ;
113
- impl_table_attribute_conversion ! ( i32 ) ;
217
+ impl_simple_conversions ! {
218
+ String => String ,
219
+ Bytes => Vec <u8 >,
220
+ StringVec => Vec <String >,
221
+ ByteVec => Vec <Vec <u8 >>
222
+ }
114
223
115
224
impl From < TableAttribute > for AttributeValue {
116
225
fn from ( attribute : TableAttribute ) -> Self {
117
226
match attribute {
118
227
TableAttribute :: String ( s) => AttributeValue :: S ( s) ,
119
- TableAttribute :: I32 ( i) => AttributeValue :: N ( i. to_string ( ) ) ,
228
+ TableAttribute :: StringVec ( s) => AttributeValue :: Ss ( s) ,
229
+
230
+ TableAttribute :: Number ( i) => AttributeValue :: N ( i. to_string ( ) ) ,
231
+ TableAttribute :: NumberVec ( x) => AttributeValue :: Ns ( x) ,
232
+
233
+ TableAttribute :: Bytes ( x) => AttributeValue :: B ( Blob :: new ( x) ) ,
234
+ TableAttribute :: ByteVec ( x) => {
235
+ AttributeValue :: Bs ( x. into_iter ( ) . map ( |x| Blob :: new ( x) ) . collect ( ) )
236
+ }
237
+
238
+ TableAttribute :: Bool ( x) => AttributeValue :: Bool ( x) ,
239
+ TableAttribute :: List ( x) => AttributeValue :: L ( x. into_iter ( ) . map ( |x| x. into ( ) ) . collect ( ) ) ,
240
+ TableAttribute :: Map ( x) => {
241
+ AttributeValue :: M ( x. into_iter ( ) . map ( |( k, v) | ( k, v. into ( ) ) ) . collect ( ) )
242
+ }
243
+
120
244
TableAttribute :: Null => AttributeValue :: Null ( true ) ,
121
245
}
122
246
}
@@ -126,9 +250,25 @@ impl From<AttributeValue> for TableAttribute {
126
250
fn from ( attribute : AttributeValue ) -> Self {
127
251
match attribute {
128
252
AttributeValue :: S ( s) => TableAttribute :: String ( s) ,
129
- AttributeValue :: N ( n) => TableAttribute :: I32 ( n. parse ( ) . unwrap ( ) ) ,
253
+ AttributeValue :: N ( n) => TableAttribute :: Number ( n) ,
254
+ AttributeValue :: Bool ( n) => TableAttribute :: Bool ( n) ,
255
+ AttributeValue :: B ( n) => TableAttribute :: Bytes ( n. into_inner ( ) ) ,
256
+ AttributeValue :: L ( l) => {
257
+ TableAttribute :: List ( l. into_iter ( ) . map ( TableAttribute :: from) . collect ( ) )
258
+ }
259
+ AttributeValue :: M ( l) => TableAttribute :: Map (
260
+ l. into_iter ( )
261
+ . map ( |( k, v) | ( k, TableAttribute :: from ( v) ) )
262
+ . collect ( ) ,
263
+ ) ,
264
+ AttributeValue :: Bs ( x) => {
265
+ TableAttribute :: ByteVec ( x. into_iter ( ) . map ( |x| x. into_inner ( ) ) . collect ( ) )
266
+ }
267
+ AttributeValue :: Ss ( x) => TableAttribute :: StringVec ( x) ,
268
+ AttributeValue :: Ns ( x) => TableAttribute :: NumberVec ( x) ,
130
269
AttributeValue :: Null ( _) => TableAttribute :: Null ,
131
- _ => todo ! ( ) ,
270
+
271
+ x => panic ! ( "Unsupported Dynamo attribute value: {x:?}" ) ,
132
272
}
133
273
}
134
274
}
0 commit comments