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/// ```no_run
208/// use libsql_orm::{Model, Aggregate, Database};
209/// # use libsql_orm::Result;
210/// # #[derive(libsql_orm::Model, Clone, serde::Serialize, serde::Deserialize)] struct User { id: Option<i64>, name: String }
211/// # async fn example(db: &Database) -> Result<()> {
212/// // Count all users
213/// let count = User::aggregate(Aggregate::Count, "*", None, db).await?;
214///
215/// // Average age
216/// let avg_age = User::aggregate(Aggregate::Avg, "age", None, db).await?;
217///
218/// // Maximum salary
219/// let max_salary = User::aggregate(Aggregate::Max, "salary", None, db).await?;
220/// # Ok(())
221/// # }
222/// ```
223#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
224pub enum Aggregate {
225    Count,
226    Sum,
227    Avg,
228    Min,
229    Max,
230}
231
232impl std::fmt::Display for Aggregate {
233    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234        match self {
235            Aggregate::Count => write!(f, "COUNT"),
236            Aggregate::Sum => write!(f, "SUM"),
237            Aggregate::Avg => write!(f, "AVG"),
238            Aggregate::Min => write!(f, "MIN"),
239            Aggregate::Max => write!(f, "MAX"),
240        }
241    }
242}
243
244/// Join types for queries
245///
246/// SQL join types for combining data from multiple tables.
247///
248/// # Examples
249///
250/// ```rust
251/// use libsql_orm::JoinType;
252///
253/// let inner = JoinType::Inner; // INNER JOIN
254/// let left = JoinType::Left;   // LEFT JOIN
255/// let right = JoinType::Right; // RIGHT JOIN
256/// let full = JoinType::Full;   // FULL JOIN
257/// ```
258#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
259pub enum JoinType {
260    Inner,
261    Left,
262    Right,
263    Full,
264}
265
266impl std::fmt::Display for JoinType {
267    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
268        match self {
269            JoinType::Inner => write!(f, "INNER JOIN"),
270            JoinType::Left => write!(f, "LEFT JOIN"),
271            JoinType::Right => write!(f, "RIGHT JOIN"),
272            JoinType::Full => write!(f, "FULL JOIN"),
273        }
274    }
275}
276
277/// SQL operator types
278///
279/// Comparison and logical operators for use in WHERE clauses and filters.
280///
281/// # Examples
282///
283/// ```rust
284/// use libsql_orm::{Operator, FilterOperator, Filter, Value};
285///
286/// // Equal comparison
287/// let filter = FilterOperator::Single(Filter::eq("status", "active"));
288///
289/// // Greater than
290/// let filter = FilterOperator::Single(Filter::gt("age", 18i64));
291///
292/// // LIKE pattern matching
293/// let filter = FilterOperator::Single(Filter::like("name", "%john%"));
294/// ```
295#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
296pub enum Operator {
297    Eq,
298    Ne,
299    Lt,
300    Le,
301    Gt,
302    Ge,
303    Like,
304    NotLike,
305    In,
306    NotIn,
307    IsNull,
308    IsNotNull,
309    Between,
310    NotBetween,
311}
312
313impl std::fmt::Display for Operator {
314    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315        match self {
316            Operator::Eq => write!(f, "="),
317            Operator::Ne => write!(f, "!="),
318            Operator::Lt => write!(f, "<"),
319            Operator::Le => write!(f, "<="),
320            Operator::Gt => write!(f, ">"),
321            Operator::Ge => write!(f, ">="),
322            Operator::Like => write!(f, "LIKE"),
323            Operator::NotLike => write!(f, "NOT LIKE"),
324            Operator::In => write!(f, "IN"),
325            Operator::NotIn => write!(f, "NOT IN"),
326            Operator::IsNull => write!(f, "IS NULL"),
327            Operator::IsNotNull => write!(f, "IS NOT NULL"),
328            Operator::Between => write!(f, "BETWEEN"),
329            Operator::NotBetween => write!(f, "NOT BETWEEN"),
330        }
331    }
332}
333
334/// Custom deserializer for boolean fields that handles SQLite integer conversion
335///
336/// SQLite stores boolean values as integers (0 for false, 1 for true).
337/// This deserializer automatically converts these integers to proper Rust boolean types.
338///
339/// # Usage
340///
341/// ```rust
342/// use libsql_orm::deserialize_bool;
343/// use serde::{Deserialize, Serialize};
344///
345/// #[derive(Serialize, Deserialize)]
346/// struct User {
347///     pub id: Option<i64>,
348///     pub name: String,
349///     #[serde(deserialize_with = "deserialize_bool")]
350///     pub is_active: bool,
351/// }
352/// ```
353pub fn deserialize_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
354where
355    D: Deserializer<'de>,
356{
357    use serde::de::Error;
358
359    let value = serde_json::Value::deserialize(deserializer)?;
360    match value {
361        serde_json::Value::Bool(b) => Ok(b),
362        serde_json::Value::Number(n) => {
363            if let Some(i) = n.as_i64() {
364                Ok(i != 0)
365            } else if let Some(f) = n.as_f64() {
366                Ok(f != 0.0)
367            } else {
368                Err(Error::custom("Invalid number format for boolean"))
369            }
370        }
371        serde_json::Value::String(s) => match s.to_lowercase().as_str() {
372            "true" | "1" | "yes" | "on" => Ok(true),
373            "false" | "0" | "no" | "off" => Ok(false),
374            _ => Err(Error::custom(format!(
375                "Invalid string value for boolean: {s}"
376            ))),
377        },
378        _ => Err(Error::custom("Expected boolean, integer, or string")),
379    }
380}