Skip to main content

akar_function/scalar/
blob.rs

1use super::get_string;
2use crate::registry::*;
3use akar_common::types::Value;
4
5// ==================== Blob functions ====================
6
7use base64::prelude::*;
8
9fn encode_base64(data: &[u8]) -> String {
10    BASE64_STANDARD.encode(data)
11}
12
13fn decode_base64(s: &str) -> Result<Vec<u8>, String> {
14    BASE64_STANDARD.decode(s).map_err(|e| format!("Invalid base64: {}", e))
15}
16
17/// Evaluate a blob function.
18pub(crate) fn evaluate_blob(op: BlobOp, args: &[Value]) -> Result<Value, String> {
19    match op {
20        BlobOp::Encode => {
21            let s = get_string(&args[0])?;
22            Ok(Value::Blob(s.into_bytes()))
23        }
24        BlobOp::Decode => {
25            let bytes = match &args[0] {
26                Value::Blob(b) => b.clone(),
27                _ => return Err("DECODE requires a blob argument".into()),
28            };
29            let s = String::from_utf8(bytes).map_err(|_| {
30                "Failure in decode: could not convert blob to UTF8 string, the blob contained invalid UTF8 characters".to_string()
31            })?;
32            Ok(Value::String(s))
33        }
34        BlobOp::OctetLength => {
35            let len = match &args[0] {
36                Value::Blob(b) => b.len() as i64,
37                _ => return Err("OCTET_LENGTH requires a blob argument".into()),
38            };
39            Ok(Value::Int64(len))
40        }
41        BlobOp::BlobFromBytes => match &args[0] {
42            Value::Blob(b) => Ok(Value::Blob(b.clone())),
43            Value::String(s) => Ok(Value::Blob(s.clone().into_bytes())),
44            _ => Err("blob_from_bytes requires string or blob".into()),
45        },
46        BlobOp::ToBase64 => {
47            let bytes = match &args[0] {
48                Value::Blob(b) => b,
49                _ => return Err("to_base64 requires a blob argument".into()),
50            };
51            Ok(Value::String(encode_base64(bytes)))
52        }
53        BlobOp::FromBase64 => {
54            let s = match &args[0] {
55                Value::String(s) => s,
56                _ => return Err("from_base64 requires a string argument".into()),
57            };
58            let decoded = decode_base64(s)?;
59            Ok(Value::Blob(decoded))
60        }
61    }
62}