Skip to main content

robin_sparkless_core/
schema.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub enum DataType {
5    String,
6    Integer,
7    Long,
8    Double,
9    Boolean,
10    Date,
11    Timestamp,
12    Array(Box<DataType>),
13    Map(Box<DataType>, Box<DataType>),
14    Struct(Vec<StructField>),
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct StructField {
19    pub name: String,
20    pub data_type: DataType,
21    pub nullable: bool,
22}
23
24impl StructField {
25    pub fn new(name: String, data_type: DataType, nullable: bool) -> Self {
26        StructField {
27            name,
28            data_type,
29            nullable,
30        }
31    }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct StructType {
36    fields: Vec<StructField>,
37}
38
39impl StructType {
40    pub fn new(fields: Vec<StructField>) -> Self {
41        StructType { fields }
42    }
43
44    pub fn fields(&self) -> &[StructField] {
45        &self.fields
46    }
47
48    /// Serialize the schema to a JSON string (array of field objects with name, data_type, nullable).
49    /// Useful for bindings that need to expose schema to the host without Polars types.
50    pub fn to_json(&self) -> Result<String, serde_json::Error> {
51        serde_json::to_string(self)
52    }
53
54    /// Serialize the schema to a pretty-printed JSON string.
55    pub fn to_json_pretty(&self) -> Result<String, serde_json::Error> {
56        serde_json::to_string_pretty(self)
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_struct_field_new() {
66        let field = StructField::new("age".to_string(), DataType::Integer, true);
67        assert_eq!(field.name, "age");
68        assert!(field.nullable);
69        assert!(matches!(field.data_type, DataType::Integer));
70    }
71
72    #[test]
73    fn test_struct_type_new() {
74        let fields = vec![
75            StructField::new("id".to_string(), DataType::Long, false),
76            StructField::new("name".to_string(), DataType::String, true),
77        ];
78        let schema = StructType::new(fields);
79        assert_eq!(schema.fields().len(), 2);
80        assert_eq!(schema.fields()[0].name, "id");
81        assert_eq!(schema.fields()[1].name, "name");
82    }
83
84    #[test]
85    fn test_struct_type_to_json() {
86        let fields = vec![
87            StructField::new("id".to_string(), DataType::Long, false),
88            StructField::new("name".to_string(), DataType::String, true),
89        ];
90        let schema = StructType::new(fields);
91        let json = schema.to_json().unwrap();
92        assert!(json.contains("\"name\":\"id\""));
93        assert!(json.contains("\"name\":\"name\""));
94        assert!(json.contains("\"data_type\""));
95        assert!(json.contains("\"nullable\""));
96        let _parsed: StructType = serde_json::from_str(&json).unwrap();
97        let pretty = schema.to_json_pretty().unwrap();
98        assert!(pretty.contains('\n'));
99    }
100
101    #[test]
102    fn test_empty_struct_type() {
103        let empty = StructType::new(vec![]);
104        assert!(empty.fields().is_empty());
105    }
106}