Skip to main content

prax_duckdb/
row.rs

1//! Row deserialization for DuckDB.
2
3use serde::de::DeserializeOwned;
4use serde_json::Value as JsonValue;
5
6use crate::error::{DuckDbError, DuckDbResult};
7
8/// Trait for deserializing DuckDB rows.
9pub trait FromDuckDbRow: Sized {
10    /// Deserialize from a JSON value.
11    fn from_json(json: JsonValue) -> DuckDbResult<Self>;
12}
13
14impl<T: DeserializeOwned> FromDuckDbRow for T {
15    fn from_json(json: JsonValue) -> DuckDbResult<Self> {
16        serde_json::from_value(json)
17            .map_err(|e| DuckDbError::deserialization(format!("Failed to deserialize row: {}", e)))
18    }
19}
20
21/// Extension trait for converting JSON values to typed rows.
22pub trait JsonRowExt {
23    /// Convert to a typed row.
24    fn to_row<T: FromDuckDbRow>(&self) -> DuckDbResult<T>;
25}
26
27impl JsonRowExt for JsonValue {
28    fn to_row<T: FromDuckDbRow>(&self) -> DuckDbResult<T> {
29        T::from_json(self.clone())
30    }
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36    use serde::Deserialize;
37
38    #[derive(Debug, Deserialize, PartialEq)]
39    struct User {
40        id: i64,
41        name: String,
42    }
43
44    #[test]
45    fn test_from_json() {
46        let json = serde_json::json!({
47            "id": 1,
48            "name": "Alice"
49        });
50
51        let user: User = User::from_json(json).unwrap();
52        assert_eq!(user.id, 1);
53        assert_eq!(user.name, "Alice");
54    }
55
56    #[test]
57    fn test_json_row_ext() {
58        let json = serde_json::json!({
59            "id": 2,
60            "name": "Bob"
61        });
62
63        let user: User = json.to_row().unwrap();
64        assert_eq!(user.id, 2);
65        assert_eq!(user.name, "Bob");
66    }
67
68    #[test]
69    fn test_from_json_error() {
70        let json = serde_json::json!({
71            "id": "not a number",
72            "name": "Alice"
73        });
74
75        let result: DuckDbResult<User> = User::from_json(json);
76        assert!(result.is_err());
77    }
78}