stately 0.5.0

Type-safe state management with entity relationships and CRUD operations
Documentation
#![expect(unused_crate_dependencies)]
//! Tests for foreign type support

use stately::prelude::*;

// Define the state first - this generates the ForeignEntity trait
#[stately::state]
struct ForeignTestState {
    #[collection(foreign, variant = "JsonConfig")]
    json_configs: serde_json::Value,

    #[collection(foreign)]
    values: serde_json::Value,
}

// Now implement the GENERATED ForeignEntity trait for the foreign type
// This is allowed because ForeignEntity is defined in this module (generated by the macro above)
impl ForeignEntity for serde_json::Value {
    fn name(&self) -> &str {
        // Use the "name" field if it's an object, otherwise use a default
        self.get("name").and_then(|v| v.as_str()).unwrap_or("unnamed")
    }

    fn description(&self) -> Option<&str> { self.get("description").and_then(|v| v.as_str()) }
}

#[test]
fn test_foreign_type_basic() {
    let mut state = ForeignTestState::new();

    // Create foreign entities
    let config1 = serde_json::json!({
        "name": "config1",
        "description": "First config",
        "setting": "value1"
    });

    let config2 = serde_json::json!({
        "name": "config2",
        "setting": "value2"
    });

    let id1 = state.json_configs.create(JsonConfig::from(config1));
    let id2 = state.values.create(Value::from(config2));

    // Verify entities were created
    assert_eq!(state.json_configs.len(), 1);
    assert_eq!(state.values.len(), 1);

    // Verify we can retrieve them
    let retrieved1 = state.json_configs.get_by_id(&id1).unwrap();
    assert_eq!(retrieved1.get("name").and_then(|v| v.as_str()), Some("config1"));

    let retrieved2 = state.values.get_by_id(&id2).unwrap();
    assert_eq!(retrieved2.get("name").and_then(|v| v.as_str()), Some("config2"));

    // Verify get_by_name works (uses ForeignEntity::name)
    let (_, found) = state.json_configs.get_by_name("config1").unwrap();
    assert_eq!(found.get("setting").and_then(|v| v.as_str()), Some("value1"));
}

#[test]
fn test_foreign_type_serialization() {
    let mut state = ForeignTestState::new();

    let config = serde_json::json!({
        "name": "test-config",
        "description": "Test configuration",
        "nested": {
            "key": "value"
        }
    });

    let _id = state.json_configs.create(JsonConfig::from(config));

    // Serialize the entire state
    let json = serde_json::to_string(&state).expect("Failed to serialize");

    // Should not contain "inner" fields
    assert!(!json.contains("\"inner\""));

    // Deserialize back
    let deserialized: ForeignTestState =
        serde_json::from_str(&json).expect("Failed to deserialize");

    // Verify data is preserved
    assert_eq!(deserialized.json_configs.len(), 1);
    let (_, config) = deserialized.json_configs.get_by_name("test-config").unwrap();
    assert_eq!(
        config.get("nested").and_then(|v| v.get("key")).and_then(|v| v.as_str()),
        Some("value")
    );
}

#[test]
fn test_foreign_type_state_entry() {
    // Verify that the StateEntry enum has the correct variants
    assert_eq!(StateEntry::JsonConfig.as_ref(), "json_config");
    assert_eq!(StateEntry::Value.as_ref(), "value");
}