drizzle_core/expr/mod.rs
1//! Type-safe SQL expression system.
2//!
3//! This module provides a type-safe wrapper around SQL expressions that tracks:
4//! - The SQL data type of the expression
5//! - Whether the expression can be NULL
6//! - Whether the expression is an aggregate or scalar
7//!
8//! # Example
9//!
10//! ```ignore
11//! use drizzle_core::expr::*;
12//!
13//! // Type-safe comparisons
14//! let condition = eq(users.id, 10); // OK: Int == Int
15//! // let bad = eq(users.id, "hello"); // ERROR: Int != Text
16//!
17//! // Type-safe arithmetic
18//! let total = users.price + users.tax; // OK: both Numeric
19//! // let bad = users.name + users.id; // ERROR: Text + Int
20//! ```
21
22mod agg;
23mod cmp;
24mod column_ops;
25mod datetime;
26mod logical;
27mod math;
28mod null;
29mod ops;
30mod primitives;
31mod set;
32mod string;
33mod typed;
34mod util;
35
36pub use agg::*;
37pub use cmp::*;
38#[doc(hidden)]
39pub use column_ops::*;
40pub use datetime::*;
41pub use logical::*;
42pub use math::*;
43pub use null::*;
44pub use set::*;
45pub use string::*;
46// ops has only trait impls - no items to re-export
47pub use typed::*;
48pub use util::*;
49
50use crate::traits::{SQLParam, ToSQL};
51use crate::types::DataType;
52
53// =============================================================================
54// Sealed Trait Pattern
55// =============================================================================
56
57mod private {
58 pub trait Sealed {}
59}
60
61// =============================================================================
62// Nullability Markers
63// =============================================================================
64
65/// Marker trait for nullability state.
66pub trait Nullability: private::Sealed + Copy + Default + 'static {}
67
68/// Marker indicating an expression cannot be NULL.
69#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
70pub struct NonNull;
71
72/// Marker indicating an expression can be NULL.
73#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
74pub struct Null;
75
76impl private::Sealed for NonNull {}
77impl private::Sealed for Null {}
78impl Nullability for NonNull {}
79impl Nullability for Null {}
80
81// =============================================================================
82// Aggregate Kind Markers
83// =============================================================================
84
85/// Marker trait for expression aggregation state.
86pub trait AggregateKind: private::Sealed + Copy + Default + 'static {}
87
88/// Marker indicating a scalar (non-aggregate) expression.
89#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
90pub struct Scalar;
91
92/// Marker indicating an aggregate expression (COUNT, SUM, etc.).
93#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
94pub struct Agg;
95
96impl private::Sealed for Scalar {}
97impl private::Sealed for Agg {}
98impl AggregateKind for Scalar {}
99impl AggregateKind for Agg {}
100
101// =============================================================================
102// Core Expression Trait
103// =============================================================================
104
105/// An expression in SQL with an associated data type.
106///
107/// This is the core trait for type-safe SQL expressions. Every SQL expression
108/// (column, literal, function result) implements this with its SQL type.
109///
110/// # Type Parameters
111///
112/// - `'a`: Lifetime of borrowed data in the expression
113/// - `V`: The dialect's value type (SQLiteValue, PostgresValue)
114///
115/// # Associated Types
116///
117/// - `SQLType`: The SQL data type this expression evaluates to
118/// - `Nullable`: Whether this expression can be NULL
119/// - `Aggregate`: Whether this is an aggregate or scalar expression
120///
121/// # Example
122///
123/// ```ignore
124/// use drizzle_core::expr::{Expr, NonNull, Scalar};
125/// use drizzle_core::types::Int;
126///
127/// // i32 literals are Int, NonNull, Scalar
128/// fn check_expr<'a, V, E: Expr<'a, V>>() {}
129/// check_expr::<_, i32>(); // SQLType=Int, Nullable=NonNull, Aggregate=Scalar
130/// ```
131pub trait Expr<'a, V: SQLParam>: ToSQL<'a, V> {
132 /// The SQL data type this expression evaluates to.
133 type SQLType: DataType;
134
135 /// Whether this expression can be NULL.
136 type Nullable: Nullability;
137
138 /// Whether this is an aggregate (COUNT, SUM) or scalar expression.
139 type Aggregate: AggregateKind;
140}
141
142// Note: Columns implement Expr via explicit impls generated by macros,
143// not via a blanket impl, to avoid conflicts with `impl Expr for &T`.