pub mod base64 {
use anyhow::Result;
use base64::engine::DecodePaddingMode;
use base64::engine::general_purpose::{
GeneralPurpose, GeneralPurposeConfig, STANDARD, STANDARD_NO_PAD,
};
use base64::{Engine, alphabet};
use crate::err::Error;
use crate::fnc::args::Optional;
use crate::val::{Bytes, Value};
const STANDARD_GENERIC_DECODER: GeneralPurpose = GeneralPurpose::new(
&alphabet::STANDARD,
GeneralPurposeConfig::new()
.with_encode_padding(false)
.with_decode_padding_mode(DecodePaddingMode::Indifferent),
);
pub fn encode((arg, Optional(padded)): (Bytes, Optional<bool>)) -> Result<Value> {
let padded = padded.unwrap_or_default();
let engine = if padded {
STANDARD
} else {
STANDARD_NO_PAD
};
Ok(Value::from(engine.encode(&*arg)))
}
pub fn decode((arg,): (String,)) -> Result<Value> {
Ok(Value::from(Bytes::from(STANDARD_GENERIC_DECODER.decode(arg).map_err(|_| {
Error::InvalidFunctionArguments {
name: "encoding::base64::decode".to_owned(),
message: "invalid base64".to_owned(),
}
})?)))
}
}
pub mod cbor {
use anyhow::Result;
use crate::err::Error;
use crate::rpc::format::cbor;
use crate::val::{Bytes, Value};
pub fn encode((arg,): (Value,)) -> Result<Value> {
let public_val = crate::val::convert_value_to_public_value(arg)?;
let val = cbor::encode(public_val).map_err(|_| Error::InvalidFunctionArguments {
name: "encoding::cbor::encode".to_owned(),
message: "Value could not be encoded into CBOR".to_owned(),
})?;
Ok(Value::Bytes(Bytes::from(val)))
}
pub fn decode((arg,): (Bytes,)) -> Result<Value> {
let public_val =
cbor::decode(arg.as_ref(), 100).map_err(|_| Error::InvalidFunctionArguments {
name: "encoding::cbor::decode".to_owned(),
message: "invalid cbor".to_owned(),
})?;
Ok(crate::sql::expression::convert_public_value_to_internal(public_val))
}
}
pub mod json {
use anyhow::Result;
use crate::err::Error;
use crate::rpc::format::json;
use crate::val::Value;
pub fn encode((arg,): (Value,)) -> Result<Value> {
let public_val = crate::val::convert_value_to_public_value(arg)?;
let val = json::encode_str(public_val).map_err(|_| Error::InvalidFunctionArguments {
name: "encoding::json::encode".to_owned(),
message: "Value could not be encoded into JSON".to_owned(),
})?;
Ok(Value::from(val))
}
pub fn decode((arg,): (String,)) -> Result<Value> {
let json: serde_json::Value =
serde_json::from_str(&arg).map_err(|_| Error::InvalidFunctionArguments {
name: "encoding::json::decode".to_owned(),
message: "Invalid JSON".to_owned(),
})?;
let public_val = crate::rpc::format::json::json_to_value(json);
Ok(crate::sql::expression::convert_public_value_to_internal(public_val))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fnc::args::Optional;
use crate::val::{Bytes, Value};
#[test]
fn test_base64_encode() {
let input = Bytes::from(b"hello".to_vec());
let result = base64::encode((input.clone(), Optional(None))).unwrap();
assert_eq!(result, Value::from("aGVsbG8"));
let result = base64::encode((input, Optional(Some(false)))).unwrap();
assert_eq!(result, Value::from("aGVsbG8"));
}
#[test]
fn test_base64_encode_padded() {
let input = Bytes::from(b"hello".to_vec());
let result = base64::encode((input, Optional(Some(true)))).unwrap();
assert_eq!(result, Value::from("aGVsbG8="));
}
#[test]
fn test_base64_decode_no_pad() {
let input = "aGVsbG8".to_string();
let result = base64::decode((input,)).unwrap();
assert_eq!(result, Value::from(Bytes::from(b"hello".to_vec())));
}
#[test]
fn test_base64_decode_with_pad() {
let input = "aGVsbG8=".to_string();
let result = base64::decode((input,)).unwrap();
assert_eq!(result, Value::from(Bytes::from(b"hello".to_vec())));
}
#[test]
fn test_json_encode_string() {
let input = Value::from("hello");
let result = json::encode((input,)).unwrap();
assert_eq!(result, Value::from("\"hello\""));
}
#[test]
fn test_json_encode_number() {
let input = Value::from(42);
let result = json::encode((input,)).unwrap();
assert_eq!(result, Value::from("42"));
}
#[test]
fn test_json_decode_object() {
let input = r#"{"name":"test","value":42}"#.to_string();
let result = json::decode((input,)).unwrap();
match result {
Value::Object(_) => {}
other => panic!("expected object, got: {other:?}"),
}
}
#[test]
fn test_json_decode_array() {
let input = r#"[1, 2, 3]"#.to_string();
let result = json::decode((input,)).unwrap();
match result {
Value::Array(_) => {}
other => panic!("expected array, got: {other:?}"),
}
}
#[test]
fn test_json_decode_invalid() {
let input = r#"{invalid json"#.to_string();
assert!(json::decode((input,)).is_err());
}
}