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            Request::Search {
305                db_name: "users".to_string(),
306                collection: "users".to_string(),
307                query: "John Doe".to_string(),
308                field: Some("name".to_string()),
309            },
310            Request::Search {
311                db_name: "users".to_string(),
312                collection: "users".to_string(),
313                query: "John Doe".to_string(),
314                field: None, // The field is absent
315            },
316        ];
317        
318        for request in requests {
319            test_serialization_json(request);
320        }
321    }
322
323    #[test]
324    fn test_response_serialization() {
325        // Test all Response variants
326        let responses = vec![
327            // General Responses
328            Response::Success,
329            Response::Error("Invalid request format".to_string()),
330            
331            // Database Management Responses
332            Response::DatabaseList(vec![
333                "testdb".to_string(),
334                "userdb".to_string(),
335                "analytics".to_string(),
336            ]),
337            Response::DatabaseCreated(true),
338            Response::DatabaseDropped(true),
339            
340            // Collection Management Responses
341            Response::CollectionList(vec![
342                "users".to_string(),
343                "products".to_string(),
344                "orders".to_string(),
345            ]),
346            Response::Stats(crate::types::DbStats {
347                collection_count: 3,
348                record_count: 1500,
349            }),
350            Response::IndexList(vec![
351                "email".to_string(),
352                "username".to_string(),
353            ]),
354            
355            // Record & Query Responses
356            Response::Record(Some({
357                let mut record = Record::new();
358                record.insert("id".to_string(), json!("user123"));
359                record.insert("name".to_string(), json!("Bob"));
360                record.insert("email".to_string(), json!("bob@example.com"));
361                record
362            })),
363            Response::Record(None), // Test None case
364            Response::RecordSet(crate::types::RecordSet {
365                records: vec![
366                    {
367                        let mut record = Record::new();
368                        record.insert("id".to_string(), json!("1"));
369                        record.insert("name".to_string(), json!("Item 1"));
370                        record
371                    },
372                    {
373                        let mut record = Record::new();
374                        record.insert("id".to_string(), json!("2"));
375                        record.insert("name".to_string(), json!("Item 2"));
376                        record
377                    },
378                ],
379            }),
380            Response::RecordCount(42),
381            Response::RecordDeleted(true),
382            Response::LastInsertId(123),
383            Response::RecordWithRelated(Some(({
384                let mut order = Record::new();
385                order.insert("id".to_string(), json!("order123"));
386                order.insert("amount".to_string(), json!(99.99));
387                order
388            }, {
389                let mut user = Record::new();
390                user.insert("id".to_string(), json!("user456"));
391                user.insert("name".to_string(), json!("Charlie"));
392                user
393            }))),
394            Response::RecordWithRelated(None), // Test None case
395            Response::BatchResponse({
396                let mut results = HashMap::new();
397                let mut user_record = Record::new();
398                user_record.insert("id".to_string(), json!("user123"));
399                user_record.insert("name".to_string(), json!("Dave"));
400                
401                let mut product_record = Record::new();
402                product_record.insert("id".to_string(), json!("product456"));
403                product_record.insert("name".to_string(), json!("Gadget"));
404                
405                results.insert("key1".to_string(), Some(user_record));
406                results.insert("key2".to_string(), Some(product_record));
407                results.insert("key3".to_string(), None); // Test None case
408                
409                crate::types::BatchResponse { results }
410            }),
411        ];
412        
413        for response in responses {
414            test_serialization_json(response);
415        }
416    }
417}