pancake_db_client/
row_helpers.rs1use std::time::SystemTime;
2
3use pancake_db_idl::dml::field_value::Value;
4use pancake_db_idl::dml::RepeatedFieldValue;
5use prost_types::Timestamp;
6
7pub use pancake_db_idl::dml::{FieldValue, Row};
9
10pub trait FieldValueConverter {
12 fn to_value(self) -> Option<Value>;
13}
14
15impl FieldValueConverter for f32 {
16 fn to_value(self) -> Option<Value> {
17 Some(Value::Float32Val(self))
18 }
19}
20
21impl FieldValueConverter for f64 {
22 fn to_value(self) -> Option<Value> {
23 Some(Value::Float64Val(self))
24 }
25}
26
27impl FieldValueConverter for i64 {
28 fn to_value(self) -> Option<Value> {
29 Some(Value::Int64Val(self))
30 }
31}
32
33impl FieldValueConverter for SystemTime {
34 fn to_value(self) -> Option<Value> {
35 Some(Value::TimestampVal(Timestamp::from(self)))
36 }
37}
38
39impl FieldValueConverter for bool {
40 fn to_value(self) -> Option<Value> {
41 Some(Value::BoolVal(self))
42 }
43}
44
45impl FieldValueConverter for String {
46 fn to_value(self) -> Option<Value> {
47 Some(Value::StringVal(self))
48 }
49}
50
51impl FieldValueConverter for Vec<u8> {
52 fn to_value(self) -> Option<Value> {
53 Some(Value::BytesVal(self))
54 }
55}
56
57impl<T: FieldValueConverter> FieldValueConverter for Option<T> {
58 fn to_value(self) -> Option<Value> {
59 self.and_then(|inner| inner.to_value())
60 }
61}
62
63impl<T: FieldValueConverter> FieldValueConverter for Vec<T> {
64 fn to_value(self) -> Option<Value> {
65 let mut vals = Vec::with_capacity(self.len());
66 for inner in self {
67 vals.push(FieldValue {
68 value: inner.to_value(),
69 })
70 }
71 Some(Value::ListVal(RepeatedFieldValue {
72 vals,
73 }))
74 }
75}
76
77#[macro_export]
79macro_rules! make_row_insert {
80 {$row: expr;} => {};
81 {$row: expr; $key:expr => $val:expr $(,$keys:expr => $vals:expr)* $(,)?} => {
82 let fv = $crate::row_helpers::FieldValue {
83 value: $crate::row_helpers::FieldValueConverter::to_value($val),
84 };
85 $row.insert($key.to_string(), fv);
86 $crate::make_row_insert! { $row; $($keys => $vals),* }
87 };
88}
89
90#[macro_export]
114macro_rules! make_row {
115 {} => {
116 $crate::row_helpers::Row::default()
117 };
118 {$($keys:expr => $vals:expr),+ $(,)?} => {
119 {
120 let mut fields = std::collections::HashMap::<String, $crate::row_helpers::FieldValue>::new();
121 $crate::make_row_insert! { fields; $($keys => $vals),+ }
122 $crate::row_helpers::Row { fields }
123 }
124 };
125}
126
127#[cfg(test)]
128mod tests {
129 use std::time::SystemTime;
130
131 use pancake_db_idl::dml::{FieldValue, Row};
132 use pancake_db_idl::dml::field_value::Value;
133 use prost_types::Timestamp;
134
135 use crate::make_row;
136
137 #[test]
138 fn test_row_macro() {
139 let timestamp = SystemTime::now();
140 let row0 = make_row! {};
141 let row1 = make_row! { "f32" => 3.3_f32 };
142 let row2 = make_row! {
143 "f32" => 3.3_f32,
144 "i64" => 4_i64,
145 "bool" => false,
146 "timestamp" => timestamp.clone(),
147 "present" => Some("asdf".to_string()),
148 "absent" => Option::<String>::None,
149 "bytes" => vec![0_u8, 1_u8],
150 "list" => vec![1_i64, 2_i64],
151 };
152
153 assert!(row0.fields.is_empty());
154
155 assert_eq!(row1.fields.len(), 1);
156
157 assert_eq!(row2.fields.len(), 8);
158 fn assert_val_eq(row: &Row, key: &str, value: Option<Value>) {
159 assert_eq!(row.fields[key].clone(), FieldValue { value });
160 }
161 assert_val_eq(&row2, "f32", Some(Value::Float32Val(3.3)));
162 assert_val_eq(&row2, "i64", Some(Value::Int64Val(4)));
163 assert_val_eq(&row2, "bool", Some(Value::BoolVal(false)));
164 assert_val_eq(&row2, "timestamp", Some(Value::TimestampVal(Timestamp::from(timestamp.clone()))));
165 assert_val_eq(&row2, "present", Some(Value::StringVal("asdf".to_string())));
166 assert_val_eq(&row2, "absent", None);
167 assert_val_eq(&row2, "bytes", Some(Value::BytesVal(vec![0, 1])));
168 assert!(matches!(&row2.fields["list"].value, Some(Value::ListVal(_))));
169 }
170}
171
172#[cfg(test)]
173mod tests_no_imports {
174 use crate::make_row;
175
176 #[test]
177 fn test_row_macro() {
178 println!("{:?}", make_row! {});
179 println!("{:?}", make_row! { "a" => 3.3_f64 });
180 }
181}