use crate::Nulid;
use sqlx_core::decode::Decode;
use sqlx_core::encode::{Encode, IsNull};
use sqlx_core::error::BoxDynError;
use sqlx_core::types::Type;
use sqlx_mysql::{MySql, MySqlTypeInfo, MySqlValueRef};
impl Type<MySql> for Nulid {
fn type_info() -> MySqlTypeInfo {
<[u8] as Type<MySql>>::type_info()
}
fn compatible(ty: &MySqlTypeInfo) -> bool {
<[u8] as Type<MySql>>::compatible(ty)
}
}
impl Encode<'_, MySql> for Nulid {
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
<&[u8] as Encode<MySql>>::encode(&self.to_bytes()[..], buf)
}
}
impl<'r> Decode<'r, MySql> for Nulid {
fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {
let bytes: &[u8] = Decode::<MySql>::decode(value)?;
if bytes.len() != 16 {
return Err("Invalid NULID length".into());
}
let mut array = [0u8; 16];
array.copy_from_slice(bytes);
Ok(Self::from_bytes(array))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_decode_roundtrip() {
let original = Nulid::new().expect("Failed to create NULID");
let bytes = original.to_bytes();
let decoded = Nulid::from_bytes(bytes);
assert_eq!(original, decoded);
assert_eq!(original.nanos(), decoded.nanos());
assert_eq!(original.random(), decoded.random());
}
#[test]
fn test_nil_nulid() {
let nil = Nulid::nil();
let bytes = nil.to_bytes();
let decoded = Nulid::from_bytes(bytes);
assert!(decoded.is_nil());
assert_eq!(decoded.nanos(), 0);
assert_eq!(decoded.random(), 0);
}
#[test]
fn test_nulid_bytes_equivalence() {
let original = Nulid::new().expect("Failed to create NULID");
let bytes = original.to_bytes();
let decoded = Nulid::from_bytes(bytes);
assert_eq!(original, decoded);
}
#[test]
fn test_encode_extends_buffer() {
let nulid = Nulid::new().expect("Failed to create NULID");
let mut buf: Vec<u8> = Vec::new();
let bytes = nulid.to_bytes();
buf.push(16); buf.extend_from_slice(&bytes);
assert_eq!(buf.len(), 17);
assert_eq!(buf[0], 16); assert_eq!(&buf[1..], &nulid.to_bytes()[..]);
}
}