aether_protocol/
lib.rs

1// File: src/lib.rs
2// =============================================================================
3// This is the main library file. Its primary job is to declare the modules
4// and re-export their contents so they are easily accessible to any crate
5// that uses `aether-protocol`.
6
7//! # AetherDB Network Protocol
8//!
9//! This crate defines the official, stable network protocol for communicating
10//! with an AetherDB instance. It contains all request and response data
11//! structures, serialized using `bincode` for maximum performance.
12
13// Declare the modules that make up our library.
14pub mod request;
15pub mod response;
16pub mod types;
17
18// Re-export the most important structs and enums for convenience.
19pub use request::Request;
20pub use response::Response;
21pub use types::{BatchRequest, BatchResponse, DbStats, Direction, Filter, QueryOptions, Record, RecordSet};
22
23#[cfg(test)]
24mod tests {
25    use crate::types::{BatchRequest, BatchResponse, DbStats, Direction, Filter, QueryOptions, Record, RecordSet};
26    use crate::{Request, Response};
27    use serde_json::json;
28    use std::collections::HashMap;
29
30    // Helper functions to test serialization/deserialization roundtrip
31    
32    // Use serde_json for testing since it handles serde_json::Value better than bincode
33    fn test_serialization_json<T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + std::fmt::Debug>(
34        value: T,
35    ) -> T {
36        let serialized = serde_json::to_string(&value).expect("Failed to serialize to JSON");
37        let deserialized = serde_json::from_str(&serialized).expect("Failed to deserialize from JSON");
38        assert_eq!(value, deserialized, "Data loss during JSON serialization roundtrip");
39        deserialized
40    }
41    
42    // For non-JSON-Value types, we can still use bincode to ensure it works
43    fn test_serialization_bincode<T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + std::fmt::Debug>(
44        value: T,
45    ) -> T {
46        let serialized = bincode::serialize(&value).expect("Failed to serialize");
47        let deserialized = bincode::deserialize(&serialized).expect("Failed to deserialize");
48        assert_eq!(value, deserialized, "Data loss during bincode serialization roundtrip");
49        deserialized
50    }
51
52    #[test]
53    fn test_record_serialization() {
54        let mut record = Record::new();
55        record.insert("name".to_string(), json!("John Doe"));
56        record.insert("age".to_string(), json!(30));
57        record.insert("active".to_string(), json!(true));
58        record.insert("scores".to_string(), json!([85, 90, 78]));
59        
60        let deserialized = test_serialization_json(record);
61        assert_eq!(deserialized["name"], json!("John Doe"));
62    }
63
64    #[test]
65    fn test_recordset_serialization() {
66        let mut record1 = Record::new();
67        record1.insert("id".to_string(), json!(1));
68        record1.insert("name".to_string(), json!("Record 1"));
69        
70        let mut record2 = Record::new();
71        record2.insert("id".to_string(), json!(2));
72        record2.insert("name".to_string(), json!("Record 2"));
73        
74        let recordset = RecordSet {
75            records: vec![record1, record2],
76        };
77        
78        test_serialization_json(recordset);
79    }
80
81    #[test]
82    fn test_filter_serialization() {
83        // Test each Filter variant
84        let filters = vec![
85            Filter::Equals {
86                field: "status".to_string(),
87                value: json!("active"),
88            },
89            Filter::NotEquals {
90                field: "deleted".to_string(),
91                value: json!(true),
92            },
93            Filter::GreaterThan {
94                field: "age".to_string(),
95                value: 18.0,
96            },
97            Filter::LessThan {
98                field: "price".to_string(),
99                value: 100.0,
100            },
101            Filter::In {
102                field: "category".to_string(),
103                values: vec![json!("electronics"), json!("books")],
104            },
105            Filter::And(vec![
106                Filter::Equals {
107                    field: "active".to_string(),
108                    value: json!(true),
109                },
110                Filter::GreaterThan {
111                    field: "score".to_string(),
112                    value: 70.0,
113                },
114            ]),
115            Filter::Or(vec![
116                Filter::Equals {
117                    field: "type".to_string(),
118                    value: json!("premium"),
119                },
120                Filter::Equals {
121                    field: "special".to_string(),
122                    value: json!(true),
123                },
124            ]),
125        ];
126        
127        for filter in filters {
128            test_serialization_json(filter);
129        }
130    }
131
132    #[test]
133    fn test_query_options_serialization() {
134        let options = QueryOptions {
135            sort_by: Some(("created_at".to_string(), Direction::Desc)),
136            limit: Some(100),
137            offset: Some(20),
138        };
139        
140        // Can use bincode for this since it doesn't have serde_json::Value
141        test_serialization_bincode(options);
142    }
143
144    #[test]
145    fn test_db_stats_serialization() {
146        let stats = DbStats {
147            collection_count: 5,
148            record_count: 1000,
149        };
150        
151        // Can use bincode for this since it doesn't have serde_json::Value
152        test_serialization_bincode(stats);
153    }
154
155    #[test]
156    fn test_batch_request_serialization() {
157        let mut requests = HashMap::new();
158        requests.insert("key1".to_string(), ("testdb".to_string(), "users".to_string(), "user_1".to_string()));
159        requests.insert("key2".to_string(), ("testdb".to_string(), "products".to_string(), "product_1".to_string()));
160        
161        let batch_request = BatchRequest { requests };
162        // Can use bincode for this since it doesn't have serde_json::Value
163        test_serialization_bincode(batch_request);
164    }
165
166    #[test]
167    fn test_batch_response_serialization() {
168        let mut record1 = Record::new();
169        record1.insert("id".to_string(), json!("user_1"));
170        record1.insert("name".to_string(), json!("John Doe"));
171        
172        let mut record2 = Record::new();
173        record2.insert("id".to_string(), json!("product_1"));
174        record2.insert("name".to_string(), json!("Widget"));
175        
176        let mut results = HashMap::new();
177        results.insert("key1".to_string(), Some(record1));
178        results.insert("key2".to_string(), Some(record2));
179        results.insert("key3".to_string(), None); // Test None case
180        
181        let batch_response = BatchResponse { results };
182        test_serialization_json(batch_response);
183    }
184
185    #[test]
186    fn test_request_serialization() {
187        // Test all Request variants
188        let requests = vec![
189            // Database Management
190            Request::CreateDatabase { db_name: "testdb".to_string() },
191            Request::DropDatabase { db_name: "testdb".to_string() },
192            Request::ListDatabases,
193            
194            // Collection Management
195            Request::ListCollections,
196            Request::CreateCollection { db_name: "users".to_string(), collection_name: "users".to_string() },
197            Request::DropCollection { db_name: "users".to_string(), collection_name: "users".to_string() },
198            Request::GetStats,
199            Request::Flush,
200            
201            // Index Management
202            Request::CreateIndex {
203                db_name: "users".to_string(),
204                collection: "users".to_string(),
205                field_name: "email".to_string(),
206            },
207            Request::DropIndex {
208                db_name: "users".to_string(),
209                collection: "users".to_string(),
210                field_name: "email".to_string(),
211            },
212            Request::ListIndexes {
213                db_name: "users".to_string(),
214                collection: "users".to_string(),
215            },
216            
217            // CRUD Operations
218            Request::CreateRecord {
219                db_name: "users".to_string(),
220                collection: "users".to_string(),
221                record_id: "user123".to_string(),
222                data: {
223                    let mut record = Record::new();
224                    record.insert("name".to_string(), json!("Alice"));
225                    record.insert("email".to_string(), json!("alice@example.com"));
226                    record
227                },
228            },
229            Request::UpdateRecord {
230                db_name: "users".to_string(),
231                collection: "users".to_string(),
232                record_id: "user123".to_string(),
233                data: {
234                    let mut record = Record::new();
235                    record.insert("active".to_string(), json!(false));
236                    record
237                },
238            },
239            Request::UpsertRecord {
240                db_name: "users".to_string(),
241                collection: "users".to_string(),
242                record_id: "user123".to_string(),
243                data: {
244                    let mut record = Record::new();
245                    record.insert("name".to_string(), json!("Alice"));
246                    record.insert("email".to_string(), json!("updated@example.com"));
247                    record
248                },
249            },
250            Request::GetRecord {
251                db_name: "users".to_string(),
252                collection: "users".to_string(),
253                record_id: "user123".to_string(),
254            },
255            Request::DeleteRecord {
256                db_name: "users".to_string(),
257                collection: "users".to_string(),
258                record_id: "user123".to_string(),
259                cascade: true,
260            },
261            Request::GetLastInsertId,
262            
263            // Querying & Relational
264            Request::FindRecords {
265                db_name: "users".to_string(),
266                collection: "users".to_string(),
267                filter: crate::types::Filter::And(vec![
268                    crate::types::Filter::Equals {
269                        field: "active".to_string(),
270                        value: json!(true),
271                    },
272                    crate::types::Filter::GreaterThan {
273                        field: "age".to_string(),
274                        value: 21.0,
275                    },
276                ]),
277                options: Some(crate::types::QueryOptions {
278                    sort_by: Some(("created_at".to_string(), crate::types::Direction::Desc)),
279                    limit: Some(50),
280                    offset: Some(0),
281                }),
282            },
283            Request::CountRecords {
284                db_name: "users".to_string(),
285                collection: "users".to_string(),
286                filter: crate::types::Filter::Equals {
287                    field: "active".to_string(),
288                    value: json!(true),
289                },
290            },
291            Request::GetRecordWithRelated {
292                db_name: "users".to_string(),
293                primary_collection: "orders".to_string(),
294                primary_record_id: "order123".to_string(),
295                relation_key_field: "user_id".to_string(),
296                related_collection: "users".to_string(),
297            },
298            Request::ExecuteBatchGet({
299                let mut requests = HashMap::new();
300                requests.insert("key1".to_string(), ("testdb".to_string(), "users".to_string(), "user123".to_string()));
301                requests.insert("key2".to_string(), ("testdb".to_string(), "products".to_string(), "product456".to_string()));
302                crate::types::BatchRequest { requests }
303            }),
304        ];
305        
306        for request in requests {
307            test_serialization_json(request);
308        }
309    }
310
311    #[test]
312    fn test_response_serialization() {
313        // Test all Response variants
314        let responses = vec![
315            // General Responses
316            Response::Success,
317            Response::Error("Invalid request format".to_string()),
318            
319            // Database Management Responses
320            Response::DatabaseList(vec![
321                "testdb".to_string(),
322                "userdb".to_string(),
323                "analytics".to_string(),
324            ]),
325            Response::DatabaseCreated(true),
326            Response::DatabaseDropped(true),
327            
328            // Collection Management Responses
329            Response::CollectionList(vec![
330                "users".to_string(),
331                "products".to_string(),
332                "orders".to_string(),
333            ]),
334            Response::Stats(crate::types::DbStats {
335                collection_count: 3,
336                record_count: 1500,
337            }),
338            Response::IndexList(vec![
339                "email".to_string(),
340                "username".to_string(),
341            ]),
342            
343            // Record & Query Responses
344            Response::Record(Some({
345                let mut record = Record::new();
346                record.insert("id".to_string(), json!("user123"));
347                record.insert("name".to_string(), json!("Bob"));
348                record.insert("email".to_string(), json!("bob@example.com"));
349                record
350            })),
351            Response::Record(None), // Test None case
352            Response::RecordSet(crate::types::RecordSet {
353                records: vec![
354                    {
355                        let mut record = Record::new();
356                        record.insert("id".to_string(), json!("1"));
357                        record.insert("name".to_string(), json!("Item 1"));
358                        record
359                    },
360                    {
361                        let mut record = Record::new();
362                        record.insert("id".to_string(), json!("2"));
363                        record.insert("name".to_string(), json!("Item 2"));
364                        record
365                    },
366                ],
367            }),
368            Response::RecordCount(42),
369            Response::RecordDeleted(true),
370            Response::LastInsertId(123),
371            Response::RecordWithRelated(Some(({
372                let mut order = Record::new();
373                order.insert("id".to_string(), json!("order123"));
374                order.insert("amount".to_string(), json!(99.99));
375                order
376            }, {
377                let mut user = Record::new();
378                user.insert("id".to_string(), json!("user456"));
379                user.insert("name".to_string(), json!("Charlie"));
380                user
381            }))),
382            Response::RecordWithRelated(None), // Test None case
383            Response::BatchResponse({
384                let mut results = HashMap::new();
385                let mut user_record = Record::new();
386                user_record.insert("id".to_string(), json!("user123"));
387                user_record.insert("name".to_string(), json!("Dave"));
388                
389                let mut product_record = Record::new();
390                product_record.insert("id".to_string(), json!("product456"));
391                product_record.insert("name".to_string(), json!("Gadget"));
392                
393                results.insert("key1".to_string(), Some(user_record));
394                results.insert("key2".to_string(), Some(product_record));
395                results.insert("key3".to_string(), None); // Test None case
396                
397                crate::types::BatchResponse { results }
398            }),
399        ];
400        
401        for response in responses {
402            test_serialization_json(response);
403        }
404    }
405}