alopex_cli/
models.rs

1//! Data models for CLI output
2//!
3//! This module defines the data structures used for representing
4//! query results and output data.
5
6use serde::Serialize;
7
8/// A single value in a row.
9///
10/// Represents all possible data types that can appear in query results.
11#[derive(Debug, Clone, Serialize, PartialEq)]
12#[serde(untagged)]
13pub enum Value {
14    /// Null/missing value
15    Null,
16    /// Boolean value
17    Bool(bool),
18    /// Integer value
19    Int(i64),
20    /// Floating-point value
21    Float(f64),
22    /// Text/string value
23    Text(String),
24    /// Binary data
25    Bytes(Vec<u8>),
26    /// Vector/embedding data
27    Vector(Vec<f32>),
28}
29
30/// A single row of output data.
31///
32/// Contains a list of values corresponding to the columns.
33#[derive(Debug, Clone, Serialize)]
34pub struct Row {
35    /// Column values in order
36    pub columns: Vec<Value>,
37}
38
39impl Row {
40    /// Create a new row with the given values.
41    pub fn new(columns: Vec<Value>) -> Self {
42        Self { columns }
43    }
44}
45
46/// Column metadata.
47///
48/// Describes the name and data type of a column in the result set.
49#[derive(Debug, Clone)]
50pub struct Column {
51    /// Column name
52    pub name: String,
53    /// Column data type
54    #[allow(dead_code)]
55    pub data_type: DataType,
56}
57
58impl Column {
59    /// Create a new column with the given name and type.
60    pub fn new(name: impl Into<String>, data_type: DataType) -> Self {
61        Self {
62            name: name.into(),
63            data_type,
64        }
65    }
66}
67
68/// Data types supported by the CLI.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70#[allow(dead_code)]
71pub enum DataType {
72    /// Boolean type
73    Bool,
74    /// Integer type
75    Int,
76    /// Floating-point type
77    Float,
78    /// Text/string type
79    Text,
80    /// Binary data type
81    Bytes,
82    /// Vector/embedding type
83    Vector,
84}
85
86/// Result of a CLI command execution.
87///
88/// Commands can return rows of data, a message, or affected row count.
89#[allow(dead_code)]
90pub enum CommandResult {
91    /// Query returned rows of data
92    Rows {
93        /// Column metadata
94        columns: Vec<Column>,
95        /// Iterator over result rows
96        rows: Box<dyn Iterator<Item = Row>>,
97    },
98    /// Command returned a message
99    Message(String),
100    /// Command affected some number of rows
101    AffectedRows(usize),
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    #[test]
109    fn test_value_null() {
110        let v = Value::Null;
111        assert_eq!(serde_json::to_string(&v).unwrap(), "null");
112    }
113
114    #[test]
115    fn test_value_bool() {
116        let v = Value::Bool(true);
117        assert_eq!(serde_json::to_string(&v).unwrap(), "true");
118    }
119
120    #[test]
121    fn test_value_int() {
122        let v = Value::Int(42);
123        assert_eq!(serde_json::to_string(&v).unwrap(), "42");
124    }
125
126    #[test]
127    fn test_value_float() {
128        let v = Value::Float(1.23);
129        assert_eq!(serde_json::to_string(&v).unwrap(), "1.23");
130    }
131
132    #[test]
133    fn test_value_text() {
134        let v = Value::Text("hello".to_string());
135        assert_eq!(serde_json::to_string(&v).unwrap(), "\"hello\"");
136    }
137
138    #[test]
139    fn test_value_bytes() {
140        let v = Value::Bytes(vec![1, 2, 3]);
141        assert_eq!(serde_json::to_string(&v).unwrap(), "[1,2,3]");
142    }
143
144    #[test]
145    fn test_value_vector() {
146        let v = Value::Vector(vec![1.0, 2.0, 3.0]);
147        assert_eq!(serde_json::to_string(&v).unwrap(), "[1.0,2.0,3.0]");
148    }
149
150    #[test]
151    fn test_row_new() {
152        let row = Row::new(vec![Value::Int(1), Value::Text("test".to_string())]);
153        assert_eq!(row.columns.len(), 2);
154    }
155
156    #[test]
157    fn test_row_serialize() {
158        let row = Row::new(vec![Value::Int(1), Value::Text("test".to_string())]);
159        let json = serde_json::to_string(&row).unwrap();
160        assert_eq!(json, r#"{"columns":[1,"test"]}"#);
161    }
162
163    #[test]
164    fn test_column_new() {
165        let col = Column::new("name", DataType::Text);
166        assert_eq!(col.name, "name");
167        assert_eq!(col.data_type, DataType::Text);
168    }
169
170    #[test]
171    fn test_data_type_equality() {
172        assert_eq!(DataType::Int, DataType::Int);
173        assert_ne!(DataType::Int, DataType::Float);
174    }
175}