Skip to main content

dpp/document/serialization_traits/platform_value_conversion/
mod.rs

1mod v0;
2
3pub use v0::*;
4
5use crate::document::Document;
6use crate::ProtocolError;
7use platform_value::Value;
8use std::collections::BTreeMap;
9
10impl DocumentPlatformValueMethodsV0<'_> for Document {
11    /// Convert the document to a map value.
12    fn to_map_value(&self) -> Result<BTreeMap<String, Value>, ProtocolError> {
13        match self {
14            Document::V0(v0) => v0.to_map_value(),
15        }
16    }
17
18    /// Convert the document to a map value consuming the document.
19    fn into_map_value(self) -> Result<BTreeMap<String, Value>, ProtocolError> {
20        match self {
21            Document::V0(v0) => v0.into_map_value(),
22        }
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29    use crate::data_contract::accessors::v0::DataContractV0Getters;
30    use crate::data_contract::document_type::random_document::CreateRandomDocument;
31    use crate::document::{DocumentV0, DocumentV0Getters};
32    use crate::serialization::ValueConvertible;
33    use crate::tests::json_document::json_document_to_contract;
34    use platform_value::Identifier;
35    use platform_version::version::PlatformVersion;
36
37    // After Phase D step 8 slice A, the Value-shape round-trip lives on
38    // canonical `ValueConvertible` (`to_object` / `into_object` /
39    // `from_object`). The `to_map_value` / `into_map_value` helpers on
40    // this trait are tested below — they're the only methods that stay.
41
42    // ================================================================
43    //  Round-trip: Document -> Value -> Document via canonical traits
44    // ================================================================
45
46    #[test]
47    fn round_trip_document_to_value_and_back() {
48        let platform_version = PlatformVersion::latest();
49        let contract = json_document_to_contract(
50            "../rs-drive/tests/supporting_files/contract/dashpay/dashpay-contract.json",
51            false,
52            platform_version,
53        )
54        .expect("expected to load dashpay contract");
55
56        let document_type = contract
57            .document_type_for_name("profile")
58            .expect("expected profile document type");
59
60        for seed in 0..10u64 {
61            let document = document_type
62                .random_document(Some(seed), platform_version)
63                .expect("expected random document");
64
65            let value = document.clone().into_object().expect("into_object");
66            let recovered = Document::from_object(value).expect("from_object");
67
68            assert_eq!(document.id(), recovered.id(), "id mismatch for seed {seed}");
69            assert_eq!(
70                document.owner_id(),
71                recovered.owner_id(),
72                "owner_id mismatch for seed {seed}"
73            );
74            assert_eq!(
75                document.revision(),
76                recovered.revision(),
77                "revision mismatch for seed {seed}"
78            );
79            assert_eq!(
80                document.properties(),
81                recovered.properties(),
82                "properties mismatch for seed {seed}"
83            );
84        }
85    }
86
87    // ================================================================
88    //  to_map_value preserves all fields
89    // ================================================================
90
91    #[test]
92    fn to_map_value_contains_id_and_owner_id() {
93        let platform_version = PlatformVersion::latest();
94        let contract = json_document_to_contract(
95            "../rs-drive/tests/supporting_files/contract/dashpay/dashpay-contract.json",
96            false,
97            platform_version,
98        )
99        .expect("expected to load dashpay contract");
100
101        let document_type = contract
102            .document_type_for_name("profile")
103            .expect("expected profile document type");
104
105        let document = document_type
106            .random_document(Some(42), platform_version)
107            .expect("expected random document");
108
109        let map = document
110            .to_map_value()
111            .expect("to_map_value should succeed");
112        assert!(map.contains_key("$id"), "map should contain $id");
113        assert!(map.contains_key("$ownerId"), "map should contain $ownerId");
114    }
115
116    // ================================================================
117    //  into_map_value consumes document
118    // ================================================================
119
120    #[test]
121    fn into_map_value_consumes_and_returns_correct_data() {
122        let platform_version = PlatformVersion::latest();
123        let contract = json_document_to_contract(
124            "../rs-drive/tests/supporting_files/contract/dashpay/dashpay-contract.json",
125            false,
126            platform_version,
127        )
128        .expect("expected to load dashpay contract");
129
130        let document_type = contract
131            .document_type_for_name("profile")
132            .expect("expected profile document type");
133
134        let document = document_type
135            .random_document(Some(55), platform_version)
136            .expect("expected random document");
137
138        let original_id = document.id();
139        let map = document
140            .into_map_value()
141            .expect("into_map_value should succeed");
142
143        let id_val = map.get("$id").expect("should have $id");
144        match id_val {
145            Value::Identifier(bytes) => {
146                assert_eq!(Identifier::new(*bytes), original_id);
147            }
148            _ => panic!("$id should be an Identifier value"),
149        }
150    }
151
152    // ================================================================
153    //  from_object via canonical traits with minimal document
154    // ================================================================
155
156    #[test]
157    fn from_object_with_minimal_data() {
158        let id = Identifier::new([1u8; 32]);
159        let owner_id = Identifier::new([2u8; 32]);
160
161        let doc_v0 = DocumentV0 {
162            id,
163            owner_id,
164            properties: std::collections::BTreeMap::new(),
165            revision: None,
166            created_at: None,
167            updated_at: None,
168            transferred_at: None,
169            created_at_block_height: None,
170            updated_at_block_height: None,
171            transferred_at_block_height: None,
172            created_at_core_block_height: None,
173            updated_at_core_block_height: None,
174            transferred_at_core_block_height: None,
175            creator_id: None,
176        };
177
178        let document: Document = doc_v0.into();
179        let value = document.clone().into_object().expect("into_object");
180        let recovered = Document::from_object(value).expect("from_object");
181
182        assert_eq!(recovered.id(), id);
183        assert_eq!(recovered.owner_id(), owner_id);
184    }
185}