reinhardt_query/lib.rs
1//! # reinhardt-query
2//!
3//! A type-safe SQL query builder for the Reinhardt framework.
4//!
5//! This crate provides a fluent API for constructing SQL queries that target
6//! PostgreSQL, MySQL, and SQLite databases. It generates parameterized queries
7//! with proper identifier escaping and value placeholders for each backend.
8//!
9//! ## Features
10//!
11//! ### DML (Data Manipulation Language)
12//! - **Type-safe query construction** - Build SELECT, INSERT, UPDATE, DELETE statements
13//! - **DCL (Data Control Language) support** - Build GRANT and REVOKE statements
14//! - **Expression system** - Rich expression API with arithmetic, comparison, and logical operators
15//! - **Advanced SQL features** - JOINs, GROUP BY, HAVING, DISTINCT, UNION, CTEs, Window functions
16//!
17//! ### DDL (Data Definition Language)
18//! - **Schema management** - CREATE/ALTER/DROP SCHEMA (PostgreSQL, CockroachDB)
19//! - **Sequence operations** - CREATE/ALTER/DROP SEQUENCE (PostgreSQL, CockroachDB)
20//! - **Database operations** - CREATE/ALTER/DROP DATABASE (all backends)
21//! - **Functions & Procedures** - CREATE/ALTER/DROP FUNCTION/PROCEDURE (PostgreSQL, MySQL, CockroachDB)
22//! - **Custom types** - CREATE/ALTER/DROP TYPE (PostgreSQL, CockroachDB)
23//! - **Materialized views** - CREATE/ALTER/DROP/REFRESH MATERIALIZED VIEW (PostgreSQL, CockroachDB)
24//! - **Events** - CREATE/ALTER/DROP EVENT (MySQL)
25//! - **Comments** - COMMENT ON for all database objects (PostgreSQL, CockroachDB)
26//! - **Maintenance** - VACUUM, ANALYZE, OPTIMIZE/REPAIR/CHECK TABLE
27//!
28//! ### Multi-Backend Support
29//! - **PostgreSQL** - Full DDL and DML support with advanced features
30//! - **MySQL** - DML, Functions, Procedures, Events, and table maintenance
31//! - **SQLite** - DML and basic DDL operations
32//! - **CockroachDB** - Full PostgreSQL compatibility with distributed database features
33//! - **Parameterized queries** - Automatic placeholder generation (`$1` for PostgreSQL, `?` for MySQL/SQLite)
34//!
35//! ## Architecture
36//!
37//! The crate is organized into several modules:
38//!
39//! - [`value`]: Core value types for representing SQL values
40//! - [`types`]: Identifier, column reference, table reference, and operator types
41//! - [`expr`]: Expression building with the [`ExprTrait`] system
42//! - [`query`]: Query builders ([`SelectStatement`],
43//! [`InsertStatement`], [`UpdateStatement`],
44//! [`DeleteStatement`])
45//! - [`dcl`]: DCL (Data Control Language) builders ([`GrantStatement`],
46//! [`RevokeStatement`], [`Privilege`], [`ObjectType`], [`Grantee`])
47//! - [`backend`]: Database backend implementations
48//! ([`PostgresQueryBuilder`],
49//! [`MySqlQueryBuilder`],
50//! [`SqliteQueryBuilder`])
51//!
52//! ## Quick Start
53//!
54//! ```rust
55//! use reinhardt_query::prelude::*;
56//!
57//! // Build a SELECT query
58//! let mut stmt = Query::select();
59//! stmt.column("name")
60//! .column("email")
61//! .from("users")
62//! .and_where(Expr::col("active").eq(true))
63//! .order_by("name", Order::Asc)
64//! .limit(10);
65//!
66//! // Generate SQL for PostgreSQL
67//! let builder = PostgresQueryBuilder::new();
68//! let (sql, values) = builder.build_select(&stmt);
69//! assert_eq!(
70//! sql,
71//! r#"SELECT "name", "email" FROM "users" WHERE "active" = $1 ORDER BY "name" ASC LIMIT $2"#
72//! );
73//! assert_eq!(values.len(), 2);
74//! ```
75//!
76//! ## Backend Differences
77//!
78//! ### DML Features
79//! | Feature | PostgreSQL | MySQL | SQLite | CockroachDB |
80//! |---------|-----------|-------|--------|-------------|
81//! | Identifier quoting | `"name"` | `` `name` `` | `"name"` | `"name"` |
82//! | Placeholders | `$1, $2, ...` | `?, ?, ...` | `?, ?, ...` | `$1, $2, ...` |
83//! | NULLS FIRST/LAST | ✅ Native | ❌ | ✅ Native | ✅ Native |
84//! | DISTINCT ON | ✅ | ❌ | ❌ | ✅ |
85//! | Window functions | ✅ Full | ✅ Full | ✅ Full | ✅ Full |
86//! | CTEs (WITH) | ✅ | ✅ | ✅ | ✅ |
87//!
88//! ### DDL Features
89//! | Feature | PostgreSQL | MySQL | SQLite | CockroachDB |
90//! |---------|-----------|-------|--------|-------------|
91//! | CREATE/ALTER/DROP SCHEMA | ✅ | ❌ | ❌ | ✅ |
92//! | CREATE/ALTER/DROP SEQUENCE | ✅ | ❌ | ❌ | ✅ |
93//! | CREATE/ALTER/DROP DATABASE | ✅ | ✅ | ✅ | ✅ |
94//! | CREATE/ALTER/DROP FUNCTION | ✅ | ✅ | ❌ | ✅ |
95//! | CREATE/ALTER/DROP PROCEDURE | ✅ | ✅ | ❌ | ✅ |
96//! | CREATE/ALTER/DROP TYPE | ✅ | ❌ | ❌ | ✅ |
97//! | CREATE/ALTER/DROP EVENT | ❌ | ✅ | ❌ | ❌ |
98//! | MATERIALIZED VIEW | ✅ | ❌ | ❌ | ✅ |
99//! | COMMENT ON | ✅ | ❌ | ❌ | ✅ |
100//! | VACUUM/ANALYZE | ✅ | ❌ | ✅ | ✅ |
101//! | OPTIMIZE/REPAIR/CHECK | ❌ | ✅ | ❌ | ❌ |
102//!
103//! ### DCL Features
104//! | Feature | PostgreSQL | MySQL | SQLite | CockroachDB |
105//! |---------|-----------|-------|--------|-------------|
106//! | GRANT/REVOKE | ✅ | ✅ | ❌ | ✅ |
107//! | CREATE/DROP/ALTER ROLE | ✅ | ✅ | ❌ | ✅ |
108//! | CREATE/DROP/ALTER USER | ✅ | ✅ | ❌ | ✅ |
109//! | RENAME USER | ❌ | ✅ | ❌ | ❌ |
110//! | SET ROLE | ✅ | ✅ | ❌ | ✅ |
111//! | RESET ROLE | ✅ | ❌ | ❌ | ✅ |
112//! | SET DEFAULT ROLE | ❌ | ✅ | ❌ | ❌ |
113//!
114//! ## Expression Examples
115//!
116//! ```rust
117//! use reinhardt_query::prelude::*;
118//!
119//! // Arithmetic expressions
120//! let expr = Expr::col("price").mul(Expr::col("quantity"));
121//!
122//! // Comparison with chaining
123//! let cond = Expr::col("age").gte(18i32).and(Expr::col("active").eq(true));
124//!
125//! // CASE WHEN expressions
126//! let case_expr = Expr::case()
127//! .when(Expr::col("score").gte(90i32), "A")
128//! .when(Expr::col("score").gte(80i32), "B")
129//! .else_result("C");
130//!
131//! // LIKE pattern matching
132//! let like_expr = Expr::col("email").like("%@example.com");
133//! ```
134//!
135//! ## DDL Examples
136//!
137//! ```rust,ignore
138//! use reinhardt_query::prelude::*;
139//!
140//! // Create a schema (PostgreSQL, CockroachDB)
141//! let mut stmt = Query::create_schema();
142//! stmt.name("app_schema").if_not_exists();
143//!
144//! // Create a sequence (PostgreSQL, CockroachDB)
145//! let mut stmt = Query::create_sequence();
146//! stmt.name("user_id_seq").start_with(1000).increment_by(1);
147//!
148//! // Create a function (PostgreSQL, MySQL, CockroachDB)
149//! use reinhardt_query::types::function::FunctionLanguage;
150//! let mut stmt = Query::create_function();
151//! stmt.name("add_numbers")
152//! .add_parameter("a", "INTEGER")
153//! .add_parameter("b", "INTEGER")
154//! .returns("INTEGER")
155//! .language(FunctionLanguage::Sql)
156//! .body("SELECT $1 + $2");
157//!
158//! // Create a procedure (PostgreSQL, MySQL, CockroachDB)
159//! let mut stmt = Query::create_procedure();
160//! stmt.name("log_event")
161//! .add_parameter("message", "text")
162//! .language(FunctionLanguage::Sql)
163//! .body("INSERT INTO event_log (message) VALUES ($1)");
164//!
165//! // Create a custom ENUM type (PostgreSQL, CockroachDB)
166//! let mut stmt = Query::create_type();
167//! stmt.name("status")
168//! .as_enum(vec!["pending".to_string(), "active".to_string(), "completed".to_string()]);
169//!
170//! // Create a COMPOSITE type (PostgreSQL, CockroachDB)
171//! let mut stmt = Query::create_type();
172//! stmt.name("address")
173//! .as_composite(vec![
174//! ("street".to_string(), "text".to_string()),
175//! ("city".to_string(), "text".to_string()),
176//! ]);
177//!
178//! // Create a materialized view (PostgreSQL, CockroachDB)
179//! let select = Query::select()
180//! .column(Expr::col("id"))
181//! .column(Expr::col("name"))
182//! .from("users")
183//! .and_where(Expr::col("active").eq(true));
184//!
185//! let mut stmt = Query::create_materialized_view();
186//! stmt.name("active_users").as_select(select);
187//!
188//! // Add a comment (PostgreSQL, CockroachDB)
189//! let mut stmt = Query::comment();
190//! stmt.target(CommentTarget::Table("users".into_iden()))
191//! .comment("Stores user account information");
192//! ```
193//!
194//! ## DCL Examples
195//!
196//! ### Privilege Management
197//!
198//! ```rust
199//! use reinhardt_query::prelude::*;
200//!
201//! // GRANT privileges
202//! let grant_stmt = Query::grant()
203//! .privilege(Privilege::Select)
204//! .privilege(Privilege::Insert)
205//! .on_table("users")
206//! .to("app_user")
207//! .with_grant_option(true);
208//!
209//! let builder = PostgresQueryBuilder::new();
210//! let (sql, values) = builder.build_grant(&grant_stmt);
211//! // sql = r#"GRANT SELECT, INSERT ON TABLE "users" TO "app_user" WITH GRANT OPTION"#
212//!
213//! // REVOKE privileges
214//! let revoke_stmt = Query::revoke()
215//! .privilege(Privilege::Insert)
216//! .from_table("users")
217//! .from("app_user")
218//! .cascade(true);
219//!
220//! let (sql, values) = builder.build_revoke(&revoke_stmt);
221//! // sql = r#"REVOKE INSERT ON TABLE "users" FROM "app_user" CASCADE"#
222//! ```
223//!
224//! ### Role Management
225//!
226//! ```rust
227//! use reinhardt_query::prelude::*;
228//!
229//! // PostgreSQL: CREATE ROLE with attributes
230//! let create_role = Query::create_role()
231//! .role("app_admin")
232//! .attribute(RoleAttribute::Login)
233//! .attribute(RoleAttribute::CreateDb)
234//! .attribute(RoleAttribute::Password("secure_password".to_string()));
235//!
236//! let builder = PostgresQueryBuilder::new();
237//! let (sql, _) = builder.build_create_role(&create_role);
238//! // sql = r#"CREATE ROLE "app_admin" WITH LOGIN CREATEDB PASSWORD $1"#
239//!
240//! // ALTER ROLE
241//! let alter_role = Query::alter_role()
242//! .role("app_admin")
243//! .attribute(RoleAttribute::CreateRole);
244//!
245//! let (sql, _) = builder.build_alter_role(&alter_role);
246//! // sql = r#"ALTER ROLE "app_admin" WITH CREATEROLE"#
247//!
248//! // DROP ROLE
249//! let drop_role = Query::drop_role()
250//! .role("app_admin")
251//! .if_exists(true);
252//!
253//! let (sql, _) = builder.build_drop_role(&drop_role);
254//! // sql = r#"DROP ROLE IF EXISTS "app_admin""#
255//! ```
256//!
257//! ### User Management
258//!
259//! ```rust
260//! use reinhardt_query::prelude::*;
261//!
262//! // MySQL: CREATE USER with options
263//! let create_user = Query::create_user()
264//! .user("webapp@localhost")
265//! .if_not_exists(true)
266//! .option(UserOption::Password("webapp_pass".to_string()))
267//! .option(UserOption::AccountUnlock);
268//!
269//! let builder = MySqlQueryBuilder::new();
270//! let (sql, _) = builder.build_create_user(&create_user);
271//! // sql = r#"CREATE USER IF NOT EXISTS `webapp@localhost` IDENTIFIED BY ? ACCOUNT UNLOCK"#
272//!
273//! // MySQL: RENAME USER
274//! let rename = Query::rename_user()
275//! .rename("old_user", "new_user");
276//!
277//! let (sql, _) = builder.build_rename_user(&rename);
278//! // sql = r#"RENAME USER `old_user` TO `new_user`"#
279//! ```
280//!
281//! ### Session Management
282//!
283//! ```rust
284//! use reinhardt_query::prelude::*;
285//!
286//! // PostgreSQL: SET ROLE
287//! let set_role = Query::set_role()
288//! .role(RoleTarget::Named("admin".to_string()));
289//!
290//! let builder = PostgresQueryBuilder::new();
291//! let (sql, _) = builder.build_set_role(&set_role);
292//! // sql = r#"SET ROLE "admin""#
293//!
294//! // PostgreSQL: RESET ROLE
295//! let reset_role = Query::reset_role();
296//!
297//! let (sql, _) = builder.build_reset_role(&reset_role);
298//! // sql = r#"RESET ROLE"#
299//!
300//! // MySQL: SET DEFAULT ROLE
301//! let set_default = Query::set_default_role()
302//! .roles(DefaultRoleSpec::All)
303//! .user("webapp");
304//!
305//! let builder = MySqlQueryBuilder::new();
306//! let (sql, _) = builder.build_set_default_role(&set_default);
307//! // sql = r#"SET DEFAULT ROLE ALL TO `webapp`"#
308//! ```
309//!
310//! ## Feature Flags
311//!
312//! - `thread-safe`: Use `Arc` instead of `Rc` for `DynIden` (enables thread-safe identifiers)
313//! - `with-chrono`: Enable chrono date/time types in `Value`
314//! - `with-uuid`: Enable UUID type in `Value`
315//! - `with-json`: Enable JSON type in `Value`
316//! - `with-rust_decimal`: Enable Decimal type in `Value`
317//! - `with-bigdecimal`: Enable BigDecimal type in `Value`
318//! - `full`: Enable all optional features
319
320// Core modules
321pub mod types;
322pub mod value;
323
324// Expression module
325pub mod expr;
326
327// Query builders
328pub mod query;
329
330// DCL (Data Control Language)
331pub mod dcl;
332
333// Backend implementations
334pub mod backend;
335
336/// Prelude module for convenient imports.
337///
338/// Import everything from this module to get started quickly:
339///
340/// ```rust
341/// use reinhardt_query::prelude::*;
342/// ```
343pub mod prelude {
344 // Backend builders
345 pub use crate::backend::{
346 MySqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqlWriter, SqliteQueryBuilder,
347 };
348 // DCL statements
349 pub use crate::dcl::{
350 AlterRoleStatement, AlterUserStatement, CreateRoleStatement, CreateUserStatement,
351 DefaultRoleSpec, DropRoleStatement, DropUserStatement, GrantRoleStatement, GrantStatement,
352 Grantee, ObjectType, Privilege, RenameUserStatement, ResetRoleStatement,
353 RevokeRoleStatement, RevokeStatement, RoleAttribute, RoleSpecification, RoleTarget,
354 SetDefaultRoleStatement, SetRoleStatement, UserOption,
355 };
356 // Expression system
357 pub use crate::expr::{
358 CaseExprBuilder, CaseStatement, Cond, Condition, ConditionExpression, ConditionHolder,
359 ConditionType, Expr, ExprTrait, Func, IntoCondition, Keyword, SimpleExpr,
360 };
361 // DML query builders
362 pub use crate::query::{
363 DeleteStatement, ForeignKey, ForeignKeyCreateStatement, InsertStatement, OnConflict, Query,
364 QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter, SelectStatement,
365 UpdateStatement,
366 };
367 // DDL query builders
368 pub use crate::query::{
369 AlterIndexStatement, AlterTableStatement, CreateIndexStatement, CreateTableStatement,
370 CreateViewStatement, DropIndexStatement, DropTableStatement, DropViewStatement,
371 TruncateTableStatement,
372 };
373 // Function/Procedure/Type DDL
374 pub use crate::query::{
375 AlterFunctionStatement, AlterProcedureStatement, AlterTypeStatement,
376 CreateFunctionStatement, CreateProcedureStatement, CreateTypeStatement,
377 DropFunctionStatement, DropProcedureStatement, DropTypeStatement,
378 };
379 // Type system
380 pub use crate::types::{
381 Alias, ColumnRef, DynIden, Iden, IdenStatic, IntoColumnRef, IntoIden, IntoTableRef, Order,
382 TableRef,
383 };
384 // DDL types
385 pub use crate::types::{BinOper, JoinType};
386 pub use crate::types::{ColumnDef, ColumnType, ForeignKeyAction, IndexDef, TableConstraint};
387 // Value system
388 pub use crate::value::{ArrayType, IntoValue, Value, ValueTuple, Values};
389 // Iden derive macro (feature-gated)
390 #[cfg(feature = "derive")]
391 pub use reinhardt_query_macros::Iden;
392}
393
394// Re-export commonly used types at crate root
395pub use prelude::*;