byteorm 0.1.6

A lightweight ORM for Rust
Documentation
use proc_macro2::TokenStream;
use quote::quote;

type Error = Box<dyn std::error::Error + Send + Sync>;

pub fn generate_jsonb_ext() -> TokenStream {
    quote! {
        pub trait JsonbExt {
            fn get_value<T>(&self, key: &str) -> Result<T, Box<dyn std::error::Error + Send + Sync>>
            where T: serde::de::DeserializeOwned;

            fn get_string(&self, key: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>>;

            fn get_i64(&self, key: &str) -> Result<i64, Box<dyn std::error::Error + Send + Sync>>;
            fn get_bool(&self, key: &str) -> Result<bool, Box<dyn std::error::Error + Send + Sync>>;

            fn get_or_default<T>(&self, key: &str, default: T) -> T
            where T: serde::de::DeserializeOwned;

            fn has_key(&self, key: &str) -> bool;
        }

        impl JsonbExt for serde_json::Value {
            fn get_value<T>(&self, key: &str) -> Result<T, Box<dyn std::error::Error + Send + Sync>>
            where T: serde::de::DeserializeOwned {
                let value = self.get(key).ok_or_else(|| {
                    Box::<dyn std::error::Error + Send + Sync>::from(format!("Key '{}' not found", key))
                })?;
                serde_json::from_value(value.clone())
                    .map_err(|e| Box::<dyn std::error::Error + Send + Sync>::from(format!("Failed to parse key '{}': {}", key, e)))
            }

            fn get_string(&self, key: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
                match self.get(key) {
                    Some(serde_json::Value::String(s)) => Ok(s.clone()),
                    Some(v) => serde_json::from_value(v.clone())
                        .map_err(|e| Box::<dyn std::error::Error + Send + Sync>::from(format!("Failed to parse '{}' as string: {}", key, e))),
                    None => Err(Box::<dyn std::error::Error + Send + Sync>::from(format!("Key '{}' not found", key))),
                }
            }

            fn get_i64(&self, key: &str) -> Result<i64, Box<dyn std::error::Error + Send + Sync>> {
                match self.get(key) {
                    Some(serde_json::Value::Number(n)) => n.as_i64().ok_or_else(|| {
                        Box::<dyn std::error::Error + Send + Sync>::from(format!("Key '{}' is not a valid i64", key))
                    }),
                    Some(v) => serde_json::from_value(v.clone())
                        .map_err(|e| Box::<dyn std::error::Error + Send + Sync>::from(format!("Failed to parse '{}' as i64: {}", key, e))),
                    None => Err(Box::<dyn std::error::Error + Send + Sync>::from(format!("Key '{}' not found", key))),
                }
            }

            fn get_bool(&self, key: &str) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
                match self.get(key) {
                    Some(serde_json::Value::Bool(b)) => Ok(*b),
                    Some(v) => serde_json::from_value(v.clone())
                        .map_err(|e| Box::<dyn std::error::Error + Send + Sync>::from(format!("Failed to parse '{}' as bool: {}", key, e))),
                    None => Err(Box::<dyn std::error::Error + Send + Sync>::from(format!("Key '{}' not found", key))),
                }
            }

            fn get_or_default<T>(&self, key: &str, default: T) -> T
            where T: serde::de::DeserializeOwned {
                self.get_value(key).unwrap_or(default)
            }

            fn has_key(&self, key: &str) -> bool {
                self.get(key).is_some()
            }
        }
    }
}