sqlmodel_query/lib.rs
1//! Type-safe SQL query builder for SQLModel Rust.
2//!
3//! `sqlmodel-query` is the **query construction layer**. It provides the fluent builder
4//! API and expression DSL that turn `Model` metadata into executable SQL plus parameters.
5//!
6//! # Role In The Architecture
7//!
8//! - **Query macros**: `select!`, `insert!`, `update!`, `delete!` build typed queries.
9//! - **Expression DSL**: `Expr` and operators build WHERE/HAVING clauses safely.
10//! - **Dialect support**: generates SQL for Postgres, MySQL, and SQLite.
11//!
12//! The resulting queries execute through the `Connection` trait from `sqlmodel-core`.
13//! Most users access these builders via the `sqlmodel` facade crate.
14
15pub mod builder;
16pub mod cache;
17pub mod clause;
18pub mod cte;
19pub mod eager;
20pub mod expr;
21pub mod join;
22pub mod select;
23pub mod set_ops;
24pub mod subquery;
25
26pub use builder::{
27 DeleteBuilder, InsertBuilder, InsertManyBuilder, OnConflict, QueryBuilder, SetClause,
28 UpdateBuilder,
29};
30pub use cache::{StatementCache, cache_key};
31pub use clause::{Limit, Offset, OrderBy, Where};
32pub use cte::{Cte, CteRef, WithQuery};
33pub use eager::{EagerLoader, IncludePath};
34pub use expr::{
35 BinaryOp, Dialect, Expr, UnaryOp, WindowBuilder, WindowFrame, WindowFrameBound, WindowFrameType,
36};
37pub use join::{Join, JoinType};
38pub use select::{
39 PolymorphicJoined, PolymorphicJoined2, PolymorphicJoined3, PolymorphicJoinedSelect,
40 PolymorphicJoinedSelect2, PolymorphicJoinedSelect3, Select,
41};
42pub use set_ops::{
43 SetOpType, SetOperation, except, except_all, intersect, intersect_all, union, union_all,
44};
45pub use subquery::SelectQuery;
46
47use asupersync::{Cx, Outcome};
48use sqlmodel_core::{Connection, Row, Value};
49
50/// Create a SELECT query for a model.
51///
52/// # Example
53///
54/// ```ignore
55/// let heroes = select!(Hero)
56/// .filter(Hero::age.gt(18))
57/// .order_by(Hero::name.asc())
58/// .all(cx, &conn)
59/// .await?;
60/// ```
61#[macro_export]
62macro_rules! select {
63 ($model:ty) => {
64 $crate::Select::<$model>::new()
65 };
66}
67
68/// Create an INSERT query for a model.
69///
70/// # Example
71///
72/// ```ignore
73/// let id = insert!(hero)
74/// .execute(cx, &conn)
75/// .await?;
76/// ```
77#[macro_export]
78macro_rules! insert {
79 ($model:expr) => {
80 $crate::builder::InsertBuilder::new($model)
81 };
82}
83
84/// Create a bulk INSERT query for multiple models.
85///
86/// # Example
87///
88/// ```ignore
89/// let heroes = vec![hero1, hero2, hero3];
90/// let count = insert_many!(heroes)
91/// .execute(cx, &conn)
92/// .await?;
93///
94/// // With UPSERT
95/// insert_many!(heroes)
96/// .on_conflict_do_update(&["name", "age"])
97/// .execute(cx, &conn)
98/// .await?;
99/// ```
100#[macro_export]
101macro_rules! insert_many {
102 ($models:expr) => {
103 $crate::builder::InsertManyBuilder::new($models)
104 };
105}
106
107/// Create an UPDATE query for a model.
108///
109/// # Example
110///
111/// ```ignore
112/// update!(hero)
113/// .execute(cx, &conn)
114/// .await?;
115/// ```
116#[macro_export]
117macro_rules! update {
118 ($model:expr) => {
119 $crate::builder::UpdateBuilder::new($model)
120 };
121}
122
123/// Create a DELETE query for a model.
124///
125/// # Example
126///
127/// ```ignore
128/// delete!(Hero)
129/// .filter(Hero::age.lt(18))
130/// .execute(cx, &conn)
131/// .await?;
132/// ```
133#[macro_export]
134macro_rules! delete {
135 ($model:ty) => {
136 $crate::builder::DeleteBuilder::<$model>::new()
137 };
138}
139
140/// Raw SQL query execution.
141///
142/// For queries that can't be expressed with the type-safe builder.
143pub async fn raw_query<C: Connection>(
144 cx: &Cx,
145 conn: &C,
146 sql: &str,
147 params: &[Value],
148) -> Outcome<Vec<Row>, sqlmodel_core::Error> {
149 conn.query(cx, sql, params).await
150}
151
152/// Raw SQL statement execution.
153pub async fn raw_execute<C: Connection>(
154 cx: &Cx,
155 conn: &C,
156 sql: &str,
157 params: &[Value],
158) -> Outcome<u64, sqlmodel_core::Error> {
159 conn.execute(cx, sql, params).await
160}