libsql_orm/
types.rs

1//! Type definitions for libsql-orm
2//!
3//! This module contains core type definitions used throughout the library,
4//! including database values, operators, sort orders, and aggregate functions.
5//!
6//! # Core Types
7//!
8//! - [`Value`] - Represents any database value with automatic type conversion
9//! - [`Row`] - Type alias for a database row (HashMap of column names to values)
10//! - [`SortOrder`] - Ascending or descending sort order
11//! - [`Aggregate`] - SQL aggregate functions (COUNT, SUM, AVG, etc.)
12//! - [`JoinType`] - SQL join types (INNER, LEFT, RIGHT, FULL)
13//! - [`Operator`] - SQL comparison operators
14//!
15//! # Examples
16//!
17//! ```rust
18//! use libsql_orm::{Value, SortOrder, Aggregate};
19//!
20//! // Creating values
21//! let text_value = Value::from("hello");
22//! let int_value = Value::from(42i64);
23//! let bool_value = Value::from(true);
24//!
25//! // Using in queries
26//! let sort = SortOrder::Desc;
27//! let agg = Aggregate::Count;
28//! ```
29
30use serde::{Deserialize, Deserializer, Serialize};
31use std::collections::HashMap;
32
33/// Represents a database row as a map of column names to values
34///
35/// This type alias provides a convenient way to work with database rows
36/// as key-value pairs where keys are column names and values are database values.
37pub type Row = HashMap<String, Value>;
38
39/// Represents a database value that can be serialized/deserialized
40///
41/// The `Value` enum covers all possible SQLite/libsql data types and provides
42/// automatic conversion from common Rust types. It supports JSON serialization
43/// for easy data exchange.
44///
45/// # Examples
46///
47/// ```rust
48/// use libsql_orm::Value;
49///
50/// let null_val = Value::Null;
51/// let int_val = Value::Integer(42);
52/// let text_val = Value::Text("hello".to_string());
53/// let bool_val = Value::Boolean(true);
54///
55/// // Automatic conversion
56/// let converted: Value = "hello".into();
57/// let converted: Value = 42i64.into();
58/// let converted: Value = true.into();
59/// ```
60#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
61pub enum Value {
62    Null,
63    Integer(i64),
64    Real(f64),
65    Text(String),
66    Blob(Vec<u8>),
67    Boolean(bool),
68}
69
70impl From<i64> for Value {
71    fn from(v: i64) -> Self {
72        Value::Integer(v)
73    }
74}
75
76impl From<f64> for Value {
77    fn from(v: f64) -> Self {
78        Value::Real(v)
79    }
80}
81
82impl From<String> for Value {
83    fn from(v: String) -> Self {
84        Value::Text(v)
85    }
86}
87
88impl From<&str> for Value {
89    fn from(v: &str) -> Self {
90        Value::Text(v.to_string())
91    }
92}
93
94impl From<bool> for Value {
95    fn from(v: bool) -> Self {
96        Value::Boolean(v)
97    }
98}
99
100impl From<Vec<u8>> for Value {
101    fn from(v: Vec<u8>) -> Self {
102        Value::Blob(v)
103    }
104}
105
106impl From<Option<String>> for Value {
107    fn from(v: Option<String>) -> Self {
108        match v {
109            Some(s) => Value::Text(s),
110            None => Value::Null,
111        }
112    }
113}
114
115impl From<Option<i64>> for Value {
116    fn from(v: Option<i64>) -> Self {
117        match v {
118            Some(i) => Value::Integer(i),
119            None => Value::Null,
120        }
121    }
122}
123
124impl From<Option<f64>> for Value {
125    fn from(v: Option<f64>) -> Self {
126        match v {
127            Some(f) => Value::Real(f),
128            None => Value::Null,
129        }
130    }
131}
132
133impl From<Option<bool>> for Value {
134    fn from(v: Option<bool>) -> Self {
135        match v {
136            Some(b) => Value::Boolean(b),
137            None => Value::Null,
138        }
139    }
140}
141
142impl From<Option<Vec<u8>>> for Value {
143    fn from(v: Option<Vec<u8>>) -> Self {
144        match v {
145            Some(b) => Value::Blob(b),
146            None => Value::Null,
147        }
148    }
149}
150
151impl From<serde_json::Value> for Value {
152    fn from(v: serde_json::Value) -> Self {
153        match v {
154            serde_json::Value::Null => Value::Null,
155            serde_json::Value::Bool(b) => Value::Boolean(b),
156            serde_json::Value::Number(n) => {
157                if let Some(i) = n.as_i64() {
158                    Value::Integer(i)
159                } else if let Some(f) = n.as_f64() {
160                    Value::Real(f)
161                } else {
162                    Value::Text(n.to_string())
163                }
164            }
165            serde_json::Value::String(s) => Value::Text(s),
166            serde_json::Value::Array(_) | serde_json::Value::Object(_) => {
167                Value::Text(v.to_string())
168            }
169        }
170    }
171}
172
173/// Sort order for queries
174///
175/// Specifies whether query results should be sorted in ascending or descending order.
176///
177/// # Examples
178///
179/// ```rust
180/// use libsql_orm::{SortOrder, Sort};
181///
182/// let asc_sort = Sort::new("name", SortOrder::Asc);
183/// let desc_sort = Sort::new("created_at", SortOrder::Desc);
184/// ```
185#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
186pub enum SortOrder {
187    #[default]
188    Asc,
189    Desc,
190}
191
192impl std::fmt::Display for SortOrder {
193    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194        match self {
195            SortOrder::Asc => write!(f, "ASC"),
196            SortOrder::Desc => write!(f, "DESC"),
197        }
198    }
199}
200
201/// Aggregate functions
202///
203/// SQL aggregate functions for performing calculations on sets of values.
204///
205/// # Examples
206///
207/// ```rust
208/// use libsql_orm::{Model, Aggregate};
209///
210/// // Count all users
211/// let count = User::aggregate(Aggregate::Count, "*", None, &db).await?;
212///
213/// // Average age
214/// let avg_age = User::aggregate(Aggregate::Avg, "age", None, &db).await?;
215///
216/// // Maximum salary
217/// let max_salary = User::aggregate(Aggregate::Max, "salary", None, &db).await?;
218/// ```
219#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
220pub enum Aggregate {
221    Count,
222    Sum,
223    Avg,
224    Min,
225    Max,
226}
227
228impl std::fmt::Display for Aggregate {
229    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
230        match self {
231            Aggregate::Count => write!(f, "COUNT"),
232            Aggregate::Sum => write!(f, "SUM"),
233            Aggregate::Avg => write!(f, "AVG"),
234            Aggregate::Min => write!(f, "MIN"),
235            Aggregate::Max => write!(f, "MAX"),
236        }
237    }
238}
239
240/// Join types for queries
241///
242/// SQL join types for combining data from multiple tables.
243///
244/// # Examples
245///
246/// ```rust
247/// use libsql_orm::JoinType;
248///
249/// let inner = JoinType::Inner; // INNER JOIN
250/// let left = JoinType::Left;   // LEFT JOIN
251/// let right = JoinType::Right; // RIGHT JOIN
252/// let full = JoinType::Full;   // FULL JOIN
253/// ```
254#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
255pub enum JoinType {
256    Inner,
257    Left,
258    Right,
259    Full,
260}
261
262impl std::fmt::Display for JoinType {
263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264        match self {
265            JoinType::Inner => write!(f, "INNER JOIN"),
266            JoinType::Left => write!(f, "LEFT JOIN"),
267            JoinType::Right => write!(f, "RIGHT JOIN"),
268            JoinType::Full => write!(f, "FULL JOIN"),
269        }
270    }
271}
272
273/// SQL operator types
274///
275/// Comparison and logical operators for use in WHERE clauses and filters.
276///
277/// # Examples
278///
279/// ```rust
280/// use libsql_orm::{Operator, FilterOperator, Value};
281///
282/// // Equal comparison
283/// let filter = FilterOperator::Eq("status".to_string(), Value::Text("active".to_string()));
284///
285/// // Greater than
286/// let filter = FilterOperator::Gt("age".to_string(), Value::Integer(18));
287///
288/// // LIKE pattern matching
289/// let filter = FilterOperator::Like("name".to_string(), Value::Text("%john%".to_string()));
290/// ```
291#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
292pub enum Operator {
293    Eq,
294    Ne,
295    Lt,
296    Le,
297    Gt,
298    Ge,
299    Like,
300    NotLike,
301    In,
302    NotIn,
303    IsNull,
304    IsNotNull,
305    Between,
306    NotBetween,
307}
308
309impl std::fmt::Display for Operator {
310    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311        match self {
312            Operator::Eq => write!(f, "="),
313            Operator::Ne => write!(f, "!="),
314            Operator::Lt => write!(f, "<"),
315            Operator::Le => write!(f, "<="),
316            Operator::Gt => write!(f, ">"),
317            Operator::Ge => write!(f, ">="),
318            Operator::Like => write!(f, "LIKE"),
319            Operator::NotLike => write!(f, "NOT LIKE"),
320            Operator::In => write!(f, "IN"),
321            Operator::NotIn => write!(f, "NOT IN"),
322            Operator::IsNull => write!(f, "IS NULL"),
323            Operator::IsNotNull => write!(f, "IS NOT NULL"),
324            Operator::Between => write!(f, "BETWEEN"),
325            Operator::NotBetween => write!(f, "NOT BETWEEN"),
326        }
327    }
328}
329
330/// Custom deserializer for boolean fields that handles SQLite integer conversion
331///
332/// SQLite stores boolean values as integers (0 for false, 1 for true).
333/// This deserializer automatically converts these integers to proper Rust boolean types.
334///
335/// # Usage
336///
337/// ```rust
338/// use libsql_orm::deserialize_bool;
339/// use serde::{Deserialize, Serialize};
340///
341/// #[derive(Serialize, Deserialize)]
342/// struct User {
343///     pub id: Option<i64>,
344///     pub name: String,
345///     #[serde(deserialize_with = "deserialize_bool")]
346///     pub is_active: bool,
347/// }
348/// ```
349pub fn deserialize_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
350where
351    D: Deserializer<'de>,
352{
353    use serde::de::Error;
354
355    let value = serde_json::Value::deserialize(deserializer)?;
356    match value {
357        serde_json::Value::Bool(b) => Ok(b),
358        serde_json::Value::Number(n) => {
359            if let Some(i) = n.as_i64() {
360                Ok(i != 0)
361            } else if let Some(f) = n.as_f64() {
362                Ok(f != 0.0)
363            } else {
364                Err(Error::custom("Invalid number format for boolean"))
365            }
366        }
367        serde_json::Value::String(s) => match s.to_lowercase().as_str() {
368            "true" | "1" | "yes" | "on" => Ok(true),
369            "false" | "0" | "no" | "off" => Ok(false),
370            _ => Err(Error::custom(format!(
371                "Invalid string value for boolean: {s}"
372            ))),
373        },
374        _ => Err(Error::custom("Expected boolean, integer, or string")),
375    }
376}