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}