Skip to content

Commit 279fbed

Browse files
author
Bennett Hardwick
committed
Flesh out attribute types
1 parent 64d1ce8 commit 279fbed

File tree

2 files changed

+162
-20
lines changed

2 files changed

+162
-20
lines changed

src/encrypted_table/table_entry.rs

Lines changed: 160 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::traits::ReadConversionError;
2-
use aws_sdk_dynamodb::types::AttributeValue;
3-
use paste::paste;
2+
use aws_sdk_dynamodb::{primitives::Blob, types::AttributeValue};
43
use std::collections::HashMap;
54

65
// FIXME: Clean this up
@@ -64,8 +63,17 @@ impl TableEntry {
6463
#[derive(Debug, Clone)]
6564
pub enum TableAttribute {
6665
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+
6977
Null,
7078
}
7179

@@ -79,44 +87,160 @@ impl TableAttribute {
7987
}
8088
}
8189

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+
$(
85121
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())
88130
}
89131
}
90132

91133
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+
}
94148
}
95149
}
96150

97151
impl TryFrom<TableAttribute> for $type {
98152
type Error = ReadConversionError;
99153

100154
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()))
103157
} else {
104158
Err(ReadConversionError::ConversionFailed(stringify!($type).to_string()))
105159
}
106160
}
107161
}
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
110215
}
111216

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+
}
114223

115224
impl From<TableAttribute> for AttributeValue {
116225
fn from(attribute: TableAttribute) -> Self {
117226
match attribute {
118227
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+
120244
TableAttribute::Null => AttributeValue::Null(true),
121245
}
122246
}
@@ -126,9 +250,25 @@ impl From<AttributeValue> for TableAttribute {
126250
fn from(attribute: AttributeValue) -> Self {
127251
match attribute {
128252
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),
130269
AttributeValue::Null(_) => TableAttribute::Null,
131-
_ => todo!(),
270+
271+
x => panic!("Unsupported Dynamo attribute value: {x:?}"),
132272
}
133273
}
134274
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@
119119
//! You can choose the field using the `#[sort_key]` attribute.
120120
//!
121121
//! ```rust
122+
//! use cryptonamo::Encryptable;
123+
//!
122124
//! #[derive(Debug, Encryptable)]
123125
//! struct User {
124126
//! #[partition_key]

0 commit comments

Comments
 (0)