diff --git a/Cargo.lock b/Cargo.lock index 45860bcc..af26c9e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,9 +162,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -605,6 +605,7 @@ version = "0.2.1" dependencies = [ "assert_cmd", "atty", + "base64 0.21.5", "brotli", "bytes", "chrono", @@ -1704,7 +1705,7 @@ version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" dependencies = [ - "base64 0.21.2", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", diff --git a/Cargo.toml b/Cargo.toml index e2115087..4d01dfb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ bytes = "1.4.0" itertools = "0.10.5" console = "0.15.7" brotli = "3.3.4" +base64 = "0.21.5" [dev-dependencies] assert_cmd = "2.0.2" # contains helpers make executing the main binary on integration tests easier. diff --git a/src/batch.rs b/src/batch.rs index e88aaddf..b9ecd5f6 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -14,6 +14,8 @@ * limitations under the License. */ +use base64::{engine::general_purpose, Engine as _}; +use bytes::Bytes; use log::{debug, error}; use rusoto_core::RusotoError; use rusoto_dynamodb::{ @@ -431,6 +433,11 @@ fn ddbjson_val_to_attrval(ddb_jsonval: &JsonValue) -> Option { n: Some(x.as_str().unwrap().to_string()), ..Default::default() }) + } else if let Some(x) = ddb_jsonval.get("B") { + Some(AttributeValue { + b: Some(json_binary_val_to_bytes(x)), + ..Default::default() + }) } else if let Some(x) = ddb_jsonval.get("BOOL") { Some(AttributeValue { bool: Some(x.as_bool().unwrap()), @@ -446,6 +453,18 @@ fn ddbjson_val_to_attrval(ddb_jsonval: &JsonValue) -> Option { ns: Some(set_logic(x)), ..Default::default() }) + } else if let Some(x) = ddb_jsonval.get("BS") { + let binary_set = x + .as_array() + .expect("should be valid JSON array") + .iter() + .map(|el| json_binary_val_to_bytes(el)) + .collect::>(); + debug!("Binary Set: {:?}", binary_set); + Some(AttributeValue { + bs: Some(binary_set), + ..Default::default() + }) } else if let Some(x) = ddb_jsonval.get("L") { let list_element = x .as_array() @@ -473,3 +492,12 @@ fn ddbjson_val_to_attrval(ddb_jsonval: &JsonValue) -> Option { None } } + +// Decodes a base64 encoded binary value to Bytes. +fn json_binary_val_to_bytes(v: &JsonValue) -> Bytes { + Bytes::from( + general_purpose::STANDARD + .decode(v.as_str().expect("binary inputs should be string value")) + .expect("binary inputs should be base64 with padding encoded"), + ) +} diff --git a/tests/bwrite.rs b/tests/bwrite.rs index fe0933cb..4ed69d41 100644 --- a/tests/bwrite.rs +++ b/tests/bwrite.rs @@ -18,6 +18,8 @@ pub mod util; use assert_cmd::prelude::*; // Add methods on commands use predicates::prelude::*; // Used for writing assertions +use serde_json::Value; +use std::collections::HashSet; use std::fs::File; use std::io::Write; use std::path::PathBuf; @@ -108,5 +110,35 @@ async fn test_batch_write() -> Result<(), Box> { predicate::str::is_match("\"Dimensions\":")?.eval(String::from_utf8(output)?.as_str()) ); + let mut c = tm.command()?; + let get_cmd = c.args(&[ + "--region", + "local", + "--table", + &table_name, + "get", + "ichi", + "-o", + "raw", + ]); + + let output = get_cmd.output()?.stdout; + let data: Value = serde_json::from_str(&String::from_utf8(output)?)?; + + let binary = data["Binary"]["B"].as_str().unwrap(); + assert_eq!(binary, "dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk"); + + // The order of the values within a set is not preserved, so I will use HashSet to compare them. + let binary_set: HashSet = data["BinarySet"]["BS"] + .as_array() + .unwrap() + .iter() + .filter_map(Value::as_str) + .map(|s| s.to_string()) + .collect(); + let binary_set_expected: HashSet = + HashSet::from(["U3Vubnk=", "UmFpbnk=", "U25vd3k="].map(String::from)); + assert_eq!(binary_set, binary_set_expected); + Ok(()) } diff --git a/tests/resources/test_batch_write.json b/tests/resources/test_batch_write.json index 7aa147cc..4bae7f10 100644 --- a/tests/resources/test_batch_write.json +++ b/tests/resources/test_batch_write.json @@ -9,6 +9,8 @@ "Dimensions": { "SS": ["Giraffe", "Hippo" ,"Zebra"] }, "PageCount": { "NS": ["42.2", "-19", "7.5", "3.14"] }, "InPublication": { "BOOL": false }, + "Binary": {"B": "dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk"}, + "BinarySet": {"BS": ["U3Vubnk=", "UmFpbnk=", "U25vd3k="]}, "Nothing": { "NULL": true }, "Authors": { "L": [