horizon-sdk 16.0.0

Canonical Rust data access layer for the Horizon platform
//! Relay global node ids as encoded by the Horizon GraphQL API.

use base64::Engine as _;
use base64::engine::general_purpose::STANDARD;
use uuid::Uuid;

/// Decode a Relay global node id into its UUID when it names `type_name`.
#[must_use]
pub fn decode_node_id(type_name: &str, node_id: &str) -> Option<Uuid> {
    let bytes = STANDARD.decode(node_id).ok()?;
    let (decoded_type_name, id): (String, Uuid) = serde_json::from_slice(&bytes).ok()?;
    (decoded_type_name == type_name).then_some(id)
}

/// Encode a Relay global node id: base64 of the JSON array `[type_name, id]`.
#[must_use]
pub fn encode_node_id(type_name: &str, id: Uuid) -> String {
    STANDARD.encode(serde_json::json!([type_name, id]).to_string())
}

#[cfg(test)]
mod tests {
    use super::*;

    const NIL_PLATFORM_NODE_ID: &str =
        "WyJQbGF0Zm9ybSIsIjAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMCJd";

    #[test]
    fn decode_node_id_rejects_other_type_name() {
        assert_eq!(decode_node_id("DataStream", NIL_PLATFORM_NODE_ID), None);
    }

    #[test]
    fn decode_node_id_rejects_malformed_input() {
        assert_eq!(decode_node_id("Platform", "not base64!"), None);
    }

    #[test]
    fn encode_node_id_matches_horizon_app() {
        assert_eq!(
            encode_node_id("Platform", Uuid::nil()),
            NIL_PLATFORM_NODE_ID
        );
    }

    #[test]
    fn node_id_round_trips() {
        let id = Uuid::new_v4();
        let node_id = encode_node_id("DataCollection", id);
        assert_eq!(decode_node_id("DataCollection", &node_id), Some(id));
    }
}