sea_query/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![warn(clippy::nursery)]
3#![deny(missing_debug_implementations)]
4#![forbid(unsafe_code)]
5#![allow(
6    clippy::derive_partial_eq_without_eq,
7    clippy::option_if_let_else,
8    clippy::redundant_pub_crate,
9    clippy::use_self,
10    clippy::missing_const_for_fn
11)]
12
13//! <div align="center">
14//!
15//!   <img src="https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQuery logo.png" width="280" alt="SeaQuery logo"/>
16//!
17//!   <p>
18//!     <strong>🔱 A dynamic query builder for MySQL, Postgres and SQLite</strong>
19//!   </p>
20//!
21//!   [![crate](https://img.shields.io/crates/v/sea-query.svg)](https://crates.io/crates/sea-query)
22//!   [![docs](https://docs.rs/sea-query/badge.svg)](https://docs.rs/sea-query)
23//!   [![build status](https://github.com/SeaQL/sea-query/actions/workflows/rust.yml/badge.svg)](https://github.com/SeaQL/sea-query/actions/workflows/rust.yml)
24//!
25//! </div>
26//!
27//! ## SeaQuery
28//!
29//! SeaQuery is a query builder to help you construct dynamic SQL queries in Rust.
30//! You can construct expressions, queries and schema as abstract syntax trees using an ergonomic API.
31//! We support MySQL, Postgres and SQLite behind a common interface that aligns their behaviour where appropriate.
32//! MS SQL Server Support is available under [SeaORM X](https://www.sea-ql.org/SeaORM-X/).
33//!
34//! SeaQuery is written in 100% safe Rust. All workspace crates has `#![forbid(unsafe_code)]`.
35//!
36//! SeaQuery is the foundation of [SeaORM](https://github.com/SeaQL/sea-orm), an async & dynamic ORM for Rust.
37//! We provide integration for [SQLx](https://crates.io/crates/sqlx),
38//! [postgres](https://crates.io/crates/postgres) and [rusqlite](https://crates.io/crates/rusqlite).
39//! See [examples](https://github.com/SeaQL/sea-query/blob/master/examples) for usage.
40//!
41//! [![GitHub stars](https://img.shields.io/github/stars/SeaQL/sea-query.svg?style=social&label=Star&maxAge=1)](https://github.com/SeaQL/sea-query/stargazers/)
42//! If you like what we do, consider starring, commenting, sharing and contributing!
43//!
44//! [![Discord](https://img.shields.io/discord/873880840487206962?label=Discord)](https://discord.com/invite/uCPdDXzbdv)
45//! Join our Discord server to chat with others in the SeaQL community!
46//!
47//! ## Install
48//!
49//! ```toml
50//! # Cargo.toml
51//! [dependencies]
52//! sea-query = "1.0.0-rc.1"
53//! ```
54//!
55//! SeaQuery is very lightweight, all dependencies are optional (except `inherent`).
56//!
57//! ### Feature flags
58//!
59//! Macro: `derive`
60//!
61//! SQL engine: `backend-mysql`, `backend-postgres`, `backend-sqlite`
62//!
63//! Type support: `with-chrono`, `with-time`, `with-json`, `with-rust_decimal`, `with-bigdecimal`, `with-uuid`,
64//! `with-ipnetwork`, `with-mac_address`, `postgres-array`, `postgres-interval`, `postgres-vector`
65//!
66//! ## Usage
67//!
68//! Table of Content
69//!
70//! 1. Basics
71//!
72//!     1. [Iden](#iden)
73//!     1. [Expression](#expression)
74//!     1. [Condition](#condition)
75//!     1. [Statement Builders](#statement-builders)
76//!
77//! 1. Query Statement
78//!
79//!     1. [Query Select](#query-select)
80//!     1. [Query Insert](#query-insert)
81//!     1. [Query Update](#query-update)
82//!     1. [Query Delete](#query-delete)
83//!
84//! 1. Advanced
85//!     1. [Aggregate Functions](#aggregate-functions)
86//!     1. [Casting](#casting)
87//!     1. [Custom Function](#custom-function)
88//!
89//! 1. Schema Statement
90//!
91//!     1. [Table Create](#table-create)
92//!     1. [Table Alter](#table-alter)
93//!     1. [Table Drop](#table-drop)
94//!     1. [Table Rename](#table-rename)
95//!     1. [Table Truncate](#table-truncate)
96//!     1. [Foreign Key Create](#foreign-key-create)
97//!     1. [Foreign Key Drop](#foreign-key-drop)
98//!     1. [Index Create](#index-create)
99//!     1. [Index Drop](#index-drop)
100//!
101//! ## Motivation
102//!
103//! Why would you want to use a dynamic query builder?
104//!
105//! ### 1. Parameter bindings
106//!
107//! One of the headaches when using raw SQL is parameter binding. With SeaQuery you can inject parameters
108//! right alongside the expression, and the $N sequencing will be handled for you. No more "off by one" errors!
109//!
110//! ```
111//! # use sea_query::{*, tests_cfg::*};
112//! assert_eq!(
113//!     Query::select()
114//!         .expr(Expr::col(Char::SizeW).add(1).mul(2))
115//!         .from(Glyph::Table)
116//!         .and_where(Expr::col(Glyph::Image).like("A"))
117//!         .and_where(Expr::col(Glyph::Id).is_in([3, 4, 5]))
118//!         .build(PostgresQueryBuilder),
119//!     (
120//!         r#"SELECT ("size_w" + $1) * $2 FROM "glyph" WHERE "image" LIKE $3 AND "id" IN ($4, $5, $6)"#
121//!             .to_owned(),
122//!         Values(vec![
123//!             1.into(),
124//!             2.into(),
125//!             "A".to_owned().into(),
126//!             3.into(),
127//!             4.into(),
128//!             5.into(),
129//!         ])
130//!     )
131//! );
132//! ```
133//!
134//! If you need an "escape hatch" to construct complex queries, you can use custom expressions,
135//! and still have the benefit of sequentially-binded parameters.
136//!
137//! ```
138//! # use sea_query::{tests_cfg::*, *};
139//! assert_eq!(
140//!     Query::select()
141//!         .columns([Char::SizeW, Char::SizeH])
142//!         .from(Char::Table)
143//!         .and_where(Expr::col(Char::Id).eq(1)) // this is $1
144//!         // custom expressions only need to define local parameter sequence.
145//!         // its global sequence will be re-written.
146//!         // here, we flip the order of $2 & $1 to make it look tricker!
147//!         .and_where(Expr::cust_with_values("\"size_w\" = $2 * $1", [3, 2]))
148//!         .and_where(Expr::col(Char::SizeH).gt(4)) // this is $N?
149//!         .build(PostgresQueryBuilder),
150//!     (
151//!         r#"SELECT "size_w", "size_h" FROM "character" WHERE "id" = $1 AND ("size_w" = $2 * $3) AND "size_h" > $4"#
152//!             .to_owned(),
153//!         Values(vec![1.into(), 2.into(), 3.into(), 4.into()])
154//!     )
155//! );
156//! ```
157//!
158//! ### 2. Dynamic query
159//!
160//! You can construct the query at runtime based on user inputs with a fluent interface,
161//! so you don't have to append `WHERE` or `AND` conditionally.
162//!
163//! ```
164//! # use sea_query::{*, tests_cfg::*};
165//! fn query(a: Option<i32>, b: Option<char>) -> SelectStatement {
166//!     Query::select()
167//!         .column(Char::Id)
168//!         .from(Char::Table)
169//!         .apply_if(a, |q, v| {
170//!             q.and_where(Expr::col(Char::FontId).eq(v));
171//!         })
172//!         .apply_if(b, |q, v| {
173//!             q.and_where(Expr::col(Char::Ascii).like(v));
174//!         })
175//!         .take()
176//! }
177//!
178//! assert_eq!(
179//!     query(Some(5), Some('A')).to_string(MysqlQueryBuilder),
180//!     "SELECT `id` FROM `character` WHERE `font_id` = 5 AND `ascii` LIKE 'A'"
181//! );
182//! assert_eq!(
183//!     query(Some(5), None).to_string(MysqlQueryBuilder),
184//!     "SELECT `id` FROM `character` WHERE `font_id` = 5"
185//! );
186//! assert_eq!(
187//!     query(None, None).to_string(MysqlQueryBuilder),
188//!     "SELECT `id` FROM `character`"
189//! );
190//! ```
191//!
192//! Conditions can be arbitrarily complex, thanks to SeaQuery's internal AST:
193//!
194//! ```
195//! # use sea_query::{*, tests_cfg::*};
196//! assert_eq!(
197//!     Query::select()
198//!         .column(Glyph::Id)
199//!         .from(Glyph::Table)
200//!         .cond_where(
201//!             Cond::any()
202//!                 .add(
203//!                     Cond::all()
204//!                         .add(Expr::col(Glyph::Aspect).is_null())
205//!                         .add(Expr::col(Glyph::Image).is_null())
206//!                 )
207//!                 .add(
208//!                     Cond::all()
209//!                         .add(Expr::col(Glyph::Aspect).is_in([3, 4]))
210//!                         .add(Expr::col(Glyph::Image).like("A%"))
211//!                 )
212//!         )
213//!         .to_string(PostgresQueryBuilder),
214//!     [
215//!         r#"SELECT "id" FROM "glyph""#,
216//!         r#"WHERE"#,
217//!         r#"("aspect" IS NULL AND "image" IS NULL)"#,
218//!         r#"OR"#,
219//!         r#"("aspect" IN (3, 4) AND "image" LIKE 'A%')"#,
220//!     ]
221//!     .join(" ")
222//! );
223//! ```
224//!
225//! There is no superfluous parentheses `((((` cluttering the query, because SeaQuery respects
226//! operator precedence when injecting them.
227//!
228//! ### 3. Cross database support
229//!
230//! With SeaQuery, you can target multiple database backends while maintaining a single source of query logic.
231//!
232//! ```
233//! # use sea_query::{tests_cfg::*, *};
234//! let query = Query::insert()
235//!     .into_table(Glyph::Table)
236//!     .columns([Glyph::Aspect, Glyph::Image])
237//!     .values_panic([
238//!         2.into(),
239//!         3.into(),
240//!     ])
241//!     .on_conflict(
242//!         OnConflict::column(Glyph::Id)
243//!             .update_columns([Glyph::Aspect, Glyph::Image])
244//!             .to_owned(),
245//!     )
246//!     .to_owned();
247//!
248//! assert_eq!(
249//!     query.to_string(MysqlQueryBuilder),
250//!     r#"INSERT INTO `glyph` (`aspect`, `image`) VALUES (2, 3) ON DUPLICATE KEY UPDATE `aspect` = VALUES(`aspect`), `image` = VALUES(`image`)"#
251//! );
252//! assert_eq!(
253//!     query.to_string(PostgresQueryBuilder),
254//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (2, 3) ON CONFLICT ("id") DO UPDATE SET "aspect" = "excluded"."aspect", "image" = "excluded"."image""#
255//! );
256//! assert_eq!(
257//!     query.to_string(SqliteQueryBuilder),
258//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (2, 3) ON CONFLICT ("id") DO UPDATE SET "aspect" = "excluded"."aspect", "image" = "excluded"."image""#
259//! );
260//! ```
261//!
262//! ### 4. Improved raw SQL ergonomics
263//!
264//! SeaQuery 1.0 added a new `raw_query!` macro with named parameters, nested field access, array expansion and tuple expansion.
265//! It surely will make crafting complex query easier.
266//!
267//! ```
268//! # use sea_query::Values;
269//! let (a, b, c) = (1, 2, "A");
270//! let d = vec![3, 4, 5];
271//! let query = sea_query::raw_query!(
272//!     PostgresQueryBuilder,
273//!     r#"SELECT ("size_w" + {a}) * {b} FROM "glyph" WHERE "image" LIKE {c} AND "id" IN ({..d})"#
274//! );
275//!
276//! assert_eq!(
277//!     query.sql,
278//!     r#"SELECT ("size_w" + $1) * $2 FROM "glyph" WHERE "image" LIKE $3 AND "id" IN ($4, $5, $6)"#
279//! );
280//! assert_eq!(
281//!     query.values,
282//!     Values(vec![
283//!         1.into(),
284//!         2.into(),
285//!         "A".into(),
286//!         3.into(),
287//!         4.into(),
288//!         5.into()
289//!     ])
290//! );
291//! ```
292//!
293//! Insert with vector-of-tuple expansion.
294//!
295//! ```
296//! # use sea_query::Values;
297//! let values = vec![(2.1345, "24B"), (5.15, "12A")];
298//! let query = sea_query::raw_query!(
299//!     PostgresQueryBuilder,
300//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES {..(values.0:1),}"#
301//! );
302//!
303//! assert_eq!(
304//!     query.sql,
305//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES ($1, $2), ($3, $4)"#
306//! );
307//! assert_eq!(
308//!     query.values,
309//!     Values(vec![2.1345.into(), "24B".into(), 5.15.into(), "12A".into()])
310//! );
311//! ```
312//!
313//! Update with nested field access.
314//!
315//! ```
316//! # use sea_query::Values;
317//! struct Character {
318//!     id: i32,
319//!     font_size: u16,
320//! }
321//! let c = Character {
322//!     id: 11,
323//!     font_size: 22,
324//! };
325//! let query = sea_query::raw_query!(
326//!     MysqlQueryBuilder,
327//!     "UPDATE `character` SET `font_size` = {c.font_size} WHERE `id` = {c.id}"
328//! );
329//!
330//! assert_eq!(
331//!     query.sql,
332//!     "UPDATE `character` SET `font_size` = ? WHERE `id` = ?"
333//! );
334//! assert_eq!(query.values, Values(vec![22u16.into(), 11i32.into()]));
335//! ```
336//!
337//! ## Basics
338//!
339//! ### Iden
340//!
341//! `Iden` is a trait for identifiers used in any query statement.
342//!
343//! Commonly implemented by Enum where each Enum represents a table found in a database,
344//! and its variants include table name and column name.
345//!
346//! [`Iden::unquoted()`] must be implemented to provide a mapping between Enum variants and its
347//! corresponding string value.
348//!
349//! ```rust
350//! use sea_query::*;
351//!
352//! // For example Character table with column id, character, font_size...
353//! pub enum Character {
354//!     Table,
355//!     Id,
356//!     FontId,
357//!     FontSize,
358//! }
359//!
360//! // Mapping between Enum variant and its corresponding string value
361//! impl Iden for Character {
362//!     fn unquoted(&self) -> &str {
363//!         match self {
364//!             Self::Table => "character",
365//!             Self::Id => "id",
366//!             Self::FontId => "font_id",
367//!             Self::FontSize => "font_size",
368//!         }
369//!     }
370//! }
371//! ```
372//!
373//! If you're okay with running another procedural macro, you can activate
374//! the `derive` feature on the crate to save you some boilerplate.
375//! For more usage information, look at
376//! [the derive examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-derive/tests/pass).
377//!
378//! ```rust
379//! #[cfg(feature = "derive")]
380//! use sea_query::Iden;
381//!
382//! // This will implement Iden exactly as shown above
383//! #[derive(Iden)]
384//! enum Character {
385//!     Table,
386//! }
387//! assert_eq!(Character::Table.to_string(), "character");
388//!
389//! // You can also derive a unit struct
390//! #[derive(Iden)]
391//! struct Glyph;
392//! assert_eq!(Glyph.to_string(), "glyph");
393//! ```
394//!
395//! ```rust
396//! #[cfg(feature = "derive")]
397//! # fn test() {
398//! use sea_query::{Iden, enum_def};
399//!
400//! #[enum_def]
401//! struct Character {
402//!     pub foo: u64,
403//! }
404//!
405//! // It generates the following along with Iden impl
406//! # let not_real = || {
407//! enum CharacterIden {
408//!     Table,
409//!     Foo,
410//! }
411//! # };
412//!
413//! assert_eq!(CharacterIden::Table.to_string(), "character");
414//! assert_eq!(CharacterIden::Foo.to_string(), "foo");
415//! # }
416//! # #[cfg(feature = "derive")]
417//! # test();
418//! ```
419//!
420//!
421//! ### Expression
422//!
423//! Use [`Expr`] constructors and [`ExprTrait`] methods
424//! to construct `SELECT`, `JOIN`, `WHERE` and `HAVING` expression in query.
425//!
426//! ```rust
427//! # use sea_query::{*, tests_cfg::*};
428//! assert_eq!(
429//!     Query::select()
430//!         .column(Char::Character)
431//!         .from(Char::Table)
432//!         .and_where(
433//!             Expr::col(Char::SizeW)
434//!                 .add(1)
435//!                 .mul(2)
436//!                 .eq(Expr::col(Char::SizeH).div(2).sub(1))
437//!         )
438//!         .and_where(
439//!             Expr::col(Char::SizeW).in_subquery(
440//!                 Query::select()
441//!                     .expr(Expr::cust_with_values("ln($1 ^ $2)", [2.4, 1.2]))
442//!                     .take()
443//!             )
444//!         )
445//!         .and_where(
446//!             Expr::col(Char::Character)
447//!                 .like("D")
448//!                 .and(Expr::col(Char::Character).like("E"))
449//!         )
450//!         .to_string(PostgresQueryBuilder),
451//!     [
452//!         r#"SELECT "character" FROM "character""#,
453//!         r#"WHERE ("size_w" + 1) * 2 = ("size_h" / 2) - 1"#,
454//!         r#"AND "size_w" IN (SELECT ln(2.4 ^ 1.2))"#,
455//!         r#"AND ("character" LIKE 'D' AND "character" LIKE 'E')"#,
456//!     ]
457//!     .join(" ")
458//! );
459//! ```
460//!
461//! ### Condition
462//!
463//! If you have complex conditions to express, you can use the [`Condition`] builder,
464//! usable for [`ConditionalStatement::cond_where`] and [`SelectStatement::cond_having`].
465//!
466//! ```
467//! # use sea_query::{*, tests_cfg::*};
468//! assert_eq!(
469//!     Query::select()
470//!         .column(Glyph::Id)
471//!         .from(Glyph::Table)
472//!         .cond_where(
473//!             Cond::any()
474//!                 .add(
475//!                     Cond::all()
476//!                         .add(Expr::col(Glyph::Aspect).is_null())
477//!                         .add(Expr::col(Glyph::Image).is_null())
478//!                 )
479//!                 .add(
480//!                     Cond::all()
481//!                         .add(Expr::col(Glyph::Aspect).is_in([3, 4]))
482//!                         .add(Expr::col(Glyph::Image).like("A%"))
483//!                 )
484//!         )
485//!         .to_string(PostgresQueryBuilder),
486//!     [
487//!         r#"SELECT "id" FROM "glyph""#,
488//!         r#"WHERE"#,
489//!         r#"("aspect" IS NULL AND "image" IS NULL)"#,
490//!         r#"OR"#,
491//!         r#"("aspect" IN (3, 4) AND "image" LIKE 'A%')"#,
492//!     ]
493//!     .join(" ")
494//! );
495//! ```
496//!
497//! There is also the [`any!`] and [`all!`] macro at your convenience:
498//!
499//! ```
500//! # use sea_query::{*, tests_cfg::*};
501//! Query::select().cond_where(any![
502//!     Expr::col(Glyph::Aspect).is_in([3, 4]),
503//!     all![
504//!         Expr::col(Glyph::Aspect).is_null(),
505//!         Expr::col(Glyph::Image).like("A%")
506//!     ]
507//! ]);
508//! ```
509//!
510//! ### Statement Builders
511//!
512//! Statements are divided into 2 categories: Query and Schema, and to be serialized into SQL
513//! with [`QueryStatementBuilder`] and [`SchemaStatementBuilder`] respectively.
514//!
515//! Schema statement has the following interface:
516//!
517//! ```rust
518//! # use sea_query::{*};
519//! # trait ExampleSchemaBuilder {
520//! fn build<T: SchemaBuilder>(&self, schema_builder: T) -> String;
521//! # }
522//! ```
523//!
524//! Query statement has the following interfaces:
525//!
526//! ```rust
527//! # use sea_query::{*};
528//! # trait ExampleQueryBuilder {
529//! fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values);
530//!
531//! fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String;
532//! # }
533//! ```
534//!
535//! `build` builds a SQL statement as string and parameters to be passed to the database driver
536//! through the binary protocol. This is the preferred way as it has less overhead and is more secure.
537//!
538//! `to_string` builds a SQL statement as string with parameters injected. This is good for testing
539//! and debugging.
540//!
541//! ## Query Statement
542//!
543//! ### Query Select
544//!
545//! ```rust
546//! # use sea_query::{*, tests_cfg::*};
547//! let query = Query::select()
548//!     .column(Char::Character)
549//!     .column((Font::Table, Font::Name))
550//!     .from(Char::Table)
551//!     .left_join(Font::Table, Expr::col((Char::Table, Char::FontId)).equals((Font::Table, Font::Id)))
552//!     .and_where(Expr::col(Char::SizeW).is_in([3, 4]))
553//!     .and_where(Expr::col(Char::Character).like("A%"))
554//!     .to_owned();
555//!
556//! assert_eq!(
557//!     query.to_string(MysqlQueryBuilder),
558//!     r#"SELECT `character`, `font`.`name` FROM `character` LEFT JOIN `font` ON `character`.`font_id` = `font`.`id` WHERE `size_w` IN (3, 4) AND `character` LIKE 'A%'"#
559//! );
560//! assert_eq!(
561//!     query.to_string(PostgresQueryBuilder),
562//!     r#"SELECT "character", "font"."name" FROM "character" LEFT JOIN "font" ON "character"."font_id" = "font"."id" WHERE "size_w" IN (3, 4) AND "character" LIKE 'A%'"#
563//! );
564//! assert_eq!(
565//!     query.to_string(SqliteQueryBuilder),
566//!     r#"SELECT "character", "font"."name" FROM "character" LEFT JOIN "font" ON "character"."font_id" = "font"."id" WHERE "size_w" IN (3, 4) AND "character" LIKE 'A%'"#
567//! );
568//! ```
569//!
570//! ### Query Insert
571//!
572//! ```rust
573//! # use sea_query::{*, tests_cfg::*};
574//! let query = Query::insert()
575//!     .into_table(Glyph::Table)
576//!     .columns([Glyph::Aspect, Glyph::Image])
577//!     .values_panic([5.15.into(), "12A".into()])
578//!     .values_panic([4.21.into(), "123".into()])
579//!     .to_owned();
580//!
581//! assert_eq!(
582//!     query.to_string(MysqlQueryBuilder),
583//!     r#"INSERT INTO `glyph` (`aspect`, `image`) VALUES (5.15, '12A'), (4.21, '123')"#
584//! );
585//! assert_eq!(
586//!     query.to_string(PostgresQueryBuilder),
587//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
588//! );
589//! assert_eq!(
590//!     query.to_string(SqliteQueryBuilder),
591//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
592//! );
593//! ```
594//!
595//! ### Query Update
596//!
597//! ```rust
598//! # use sea_query::{*, tests_cfg::*};
599//! let query = Query::update()
600//!     .table(Glyph::Table)
601//!     .values([(Glyph::Aspect, 1.23.into()), (Glyph::Image, "123".into())])
602//!     .and_where(Expr::col(Glyph::Id).eq(1))
603//!     .to_owned();
604//!
605//! assert_eq!(
606//!     query.to_string(MysqlQueryBuilder),
607//!     r#"UPDATE `glyph` SET `aspect` = 1.23, `image` = '123' WHERE `id` = 1"#
608//! );
609//! assert_eq!(
610//!     query.to_string(PostgresQueryBuilder),
611//!     r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
612//! );
613//! assert_eq!(
614//!     query.to_string(SqliteQueryBuilder),
615//!     r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
616//! );
617//! ```
618//!
619//! ### Query Delete
620//!
621//! ```rust
622//! # use sea_query::{*, tests_cfg::*};
623//! let query = Query::delete()
624//!     .from_table(Glyph::Table)
625//!     .cond_where(
626//!         Cond::any()
627//!             .add(Expr::col(Glyph::Id).lt(1))
628//!             .add(Expr::col(Glyph::Id).gt(10)),
629//!     )
630//!     .to_owned();
631//!
632//! assert_eq!(
633//!     query.to_string(MysqlQueryBuilder),
634//!     r#"DELETE FROM `glyph` WHERE `id` < 1 OR `id` > 10"#
635//! );
636//! assert_eq!(
637//!     query.to_string(PostgresQueryBuilder),
638//!     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
639//! );
640//! assert_eq!(
641//!     query.to_string(SqliteQueryBuilder),
642//!     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
643//! );
644//! ```
645//!
646//! ## Advanced
647//!
648//! ### Aggregate Functions
649//!
650//! `max`, `min`, `sum`, `avg`, `count` etc
651//!
652//! ```rust
653//! # use sea_query::{*, tests_cfg::*};
654//! let query = Query::select()
655//!     .expr(Func::sum(Expr::col((Char::Table, Char::SizeH))))
656//!     .from(Char::Table)
657//!     .to_owned();
658//! assert_eq!(
659//!     query.to_string(MysqlQueryBuilder),
660//!     r#"SELECT SUM(`character`.`size_h`) FROM `character`"#
661//! );
662//! assert_eq!(
663//!     query.to_string(PostgresQueryBuilder),
664//!     r#"SELECT SUM("character"."size_h") FROM "character""#
665//! );
666//! assert_eq!(
667//!     query.to_string(SqliteQueryBuilder),
668//!     r#"SELECT SUM("character"."size_h") FROM "character""#
669//! );
670//! ```
671//!
672//! ### Casting
673//!
674//! ```rust
675//! # use sea_query::{*, tests_cfg::*};
676//! let query = Query::select()
677//!     .expr(Func::cast_as("hello", "MyType"))
678//!     .to_owned();
679//!
680//! assert_eq!(
681//!     query.to_string(MysqlQueryBuilder),
682//!     r#"SELECT CAST('hello' AS MyType)"#
683//! );
684//! assert_eq!(
685//!     query.to_string(PostgresQueryBuilder),
686//!     r#"SELECT CAST('hello' AS MyType)"#
687//! );
688//! assert_eq!(
689//!     query.to_string(SqliteQueryBuilder),
690//!     r#"SELECT CAST('hello' AS MyType)"#
691//! );
692//! ```
693//!
694//! ### Custom Function
695//!
696//! ```rust
697//! # use sea_query::{*, tests_cfg::*};
698//! struct MyFunction;
699//!
700//! impl Iden for MyFunction {
701//!     fn unquoted(&self) -> &str {
702//!         "MY_FUNCTION"
703//!     }
704//! }
705//!
706//! let query = Query::select()
707//!     .expr(Func::cust(MyFunction).arg(Expr::val("hello")))
708//!     .to_owned();
709//!
710//! assert_eq!(
711//!     query.to_string(MysqlQueryBuilder),
712//!     r#"SELECT MY_FUNCTION('hello')"#
713//! );
714//! assert_eq!(
715//!     query.to_string(PostgresQueryBuilder),
716//!     r#"SELECT MY_FUNCTION('hello')"#
717//! );
718//! assert_eq!(
719//!     query.to_string(SqliteQueryBuilder),
720//!     r#"SELECT MY_FUNCTION('hello')"#
721//! );
722//! ```
723//!
724//! ## Schema Statement
725//!
726//! ### Table Create
727//!
728//! ```rust
729//! # use sea_query::{*, tests_cfg::*};
730//! let table = Table::create()
731//!     .table(Char::Table)
732//!     .if_not_exists()
733//!     .col(ColumnDef::new(Char::Id).integer().not_null().auto_increment().primary_key())
734//!     .col(ColumnDef::new(Char::FontSize).integer().not_null())
735//!     .col(ColumnDef::new(Char::Character).string().not_null())
736//!     .col(ColumnDef::new(Char::SizeW).integer().not_null())
737//!     .col(ColumnDef::new(Char::SizeH).integer().not_null())
738//!     .col(ColumnDef::new(Char::FontId).integer().default(Expr::val(1)))
739//!     .foreign_key(
740//!         ForeignKey::create()
741//!             .name("character_fk")
742//!             .from(Char::Table, Char::FontId)
743//!             .to(Font::Table, Font::Id)
744//!             .on_delete(ForeignKeyAction::Cascade)
745//!             .on_update(ForeignKeyAction::Cascade)
746//!     )
747//!     .to_owned();
748//!
749//! assert_eq!(
750//!     table.to_string(MysqlQueryBuilder),
751//!     [
752//!         r#"CREATE TABLE IF NOT EXISTS `character` ("#,
753//!             r#"`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,"#,
754//!             r#"`font_size` int NOT NULL,"#,
755//!             r#"`character` varchar(255) NOT NULL,"#,
756//!             r#"`size_w` int NOT NULL,"#,
757//!             r#"`size_h` int NOT NULL,"#,
758//!             r#"`font_id` int DEFAULT 1,"#,
759//!             r#"CONSTRAINT `character_fk`"#,
760//!                 r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
761//!                 r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
762//!         r#")"#,
763//!     ].join(" ")
764//! );
765//! assert_eq!(
766//!     table.to_string(PostgresQueryBuilder),
767//!     [
768//!         r#"CREATE TABLE IF NOT EXISTS "character" ("#,
769//!             r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
770//!             r#""font_size" integer NOT NULL,"#,
771//!             r#""character" varchar NOT NULL,"#,
772//!             r#""size_w" integer NOT NULL,"#,
773//!             r#""size_h" integer NOT NULL,"#,
774//!             r#""font_id" integer DEFAULT 1,"#,
775//!             r#"CONSTRAINT "character_fk""#,
776//!                 r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
777//!                 r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
778//!         r#")"#,
779//!     ].join(" ")
780//! );
781//! assert_eq!(
782//!     table.to_string(SqliteQueryBuilder),
783//!     [
784//!        r#"CREATE TABLE IF NOT EXISTS "character" ("#,
785//!            r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
786//!            r#""font_size" integer NOT NULL,"#,
787//!            r#""character" varchar NOT NULL,"#,
788//!            r#""size_w" integer NOT NULL,"#,
789//!            r#""size_h" integer NOT NULL,"#,
790//!            r#""font_id" integer DEFAULT 1,"#,
791//!            r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
792//!        r#")"#,
793//!     ].join(" ")
794//! );
795//! ```
796//!
797//! ### Table Alter
798//!
799//! ```rust
800//! # use sea_query::{*, tests_cfg::*};
801//! let table = Table::alter()
802//!     .table(Font::Table)
803//!     .add_column(ColumnDef::new("new_col").integer().not_null().default(100))
804//!     .to_owned();
805//!
806//! assert_eq!(
807//!     table.to_string(MysqlQueryBuilder),
808//!     r#"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100"#
809//! );
810//! assert_eq!(
811//!     table.to_string(PostgresQueryBuilder),
812//!     r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#
813//! );
814//! assert_eq!(
815//!     table.to_string(SqliteQueryBuilder),
816//!     r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#,
817//! );
818//! ```
819//!
820//! ### Table Drop
821//!
822//! ```rust
823//! # use sea_query::{*, tests_cfg::*};
824//! let table = Table::drop()
825//!     .table(Glyph::Table)
826//!     .table(Char::Table)
827//!     .to_owned();
828//!
829//! assert_eq!(
830//!     table.to_string(MysqlQueryBuilder),
831//!     r#"DROP TABLE `glyph`, `character`"#
832//! );
833//! assert_eq!(
834//!     table.to_string(PostgresQueryBuilder),
835//!     r#"DROP TABLE "glyph", "character""#
836//! );
837//! assert_eq!(
838//!     table.to_string(SqliteQueryBuilder),
839//!     r#"DROP TABLE "glyph", "character""#
840//! );
841//! ```
842//!
843//! ### Table Rename
844//!
845//! ```rust
846//! # use sea_query::{*, tests_cfg::*};
847//! let table = Table::rename().table(Font::Table, "font_new").to_owned();
848//!
849//! assert_eq!(
850//!     table.to_string(MysqlQueryBuilder),
851//!     r#"RENAME TABLE `font` TO `font_new`"#
852//! );
853//! assert_eq!(
854//!     table.to_string(PostgresQueryBuilder),
855//!     r#"ALTER TABLE "font" RENAME TO "font_new""#
856//! );
857//! assert_eq!(
858//!     table.to_string(SqliteQueryBuilder),
859//!     r#"ALTER TABLE "font" RENAME TO "font_new""#
860//! );
861//! ```
862//!
863//! ### Table Truncate
864//!
865//! ```rust
866//! # use sea_query::{*, tests_cfg::*};
867//! let table = Table::truncate().table(Font::Table).to_owned();
868//!
869//! assert_eq!(
870//!     table.to_string(MysqlQueryBuilder),
871//!     r#"TRUNCATE TABLE `font`"#
872//! );
873//! assert_eq!(
874//!     table.to_string(PostgresQueryBuilder),
875//!     r#"TRUNCATE TABLE "font""#
876//! );
877//! // Sqlite does not support the TRUNCATE statement
878//! ```
879//!
880//! ### Foreign Key Create
881//!
882//! ```rust
883//! # use sea_query::{*, tests_cfg::*};
884//! let foreign_key = ForeignKey::create()
885//!     .name("FK_character_font")
886//!     .from(Char::Table, Char::FontId)
887//!     .to(Font::Table, Font::Id)
888//!     .on_delete(ForeignKeyAction::Cascade)
889//!     .on_update(ForeignKeyAction::Cascade)
890//!     .to_owned();
891//!
892//! assert_eq!(
893//!     foreign_key.to_string(MysqlQueryBuilder),
894//!     [
895//!         r#"ALTER TABLE `character`"#,
896//!         r#"ADD CONSTRAINT `FK_character_font`"#,
897//!         r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
898//!         r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
899//!     ]
900//!     .join(" ")
901//! );
902//! assert_eq!(
903//!     foreign_key.to_string(PostgresQueryBuilder),
904//!     [
905//!         r#"ALTER TABLE "character" ADD CONSTRAINT "FK_character_font""#,
906//!         r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
907//!         r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
908//!     ]
909//!     .join(" ")
910//! );
911//! // Sqlite does not support modification of foreign key constraints to existing tables
912//! ```
913//!
914//! ### Foreign Key Drop
915//!
916//! ```rust
917//! # use sea_query::{*, tests_cfg::*};
918//! let foreign_key = ForeignKey::drop()
919//!     .name("FK_character_font")
920//!     .table(Char::Table)
921//!     .to_owned();
922//!
923//! assert_eq!(
924//!     foreign_key.to_string(MysqlQueryBuilder),
925//!     r#"ALTER TABLE `character` DROP FOREIGN KEY `FK_character_font`"#
926//! );
927//! assert_eq!(
928//!     foreign_key.to_string(PostgresQueryBuilder),
929//!     r#"ALTER TABLE "character" DROP CONSTRAINT "FK_character_font""#
930//! );
931//! // Sqlite does not support modification of foreign key constraints to existing tables
932//! ```
933//!
934//! ### Index Create
935//!
936//! ```rust
937//! # use sea_query::{*, tests_cfg::*};
938//! let index = Index::create()
939//!     .name("idx-glyph-aspect")
940//!     .table(Glyph::Table)
941//!     .col(Glyph::Aspect)
942//!     .to_owned();
943//!
944//! assert_eq!(
945//!     index.to_string(MysqlQueryBuilder),
946//!     r#"CREATE INDEX `idx-glyph-aspect` ON `glyph` (`aspect`)"#
947//! );
948//! assert_eq!(
949//!     index.to_string(PostgresQueryBuilder),
950//!     r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
951//! );
952//! assert_eq!(
953//!     index.to_string(SqliteQueryBuilder),
954//!     r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
955//! );
956//! ```
957//!
958//! ### Index Drop
959//!
960//! ```rust
961//! # use sea_query::{*, tests_cfg::*};
962//! let index = Index::drop()
963//!     .name("idx-glyph-aspect")
964//!     .table(Glyph::Table)
965//!     .to_owned();
966//!
967//! assert_eq!(
968//!     index.to_string(MysqlQueryBuilder),
969//!     r#"DROP INDEX `idx-glyph-aspect` ON `glyph`"#
970//! );
971//! assert_eq!(
972//!     index.to_string(PostgresQueryBuilder),
973//!     r#"DROP INDEX "idx-glyph-aspect""#
974//! );
975//! assert_eq!(
976//!     index.to_string(SqliteQueryBuilder),
977//!     r#"DROP INDEX "idx-glyph-aspect""#
978//! );
979//! ```
980//!
981//! ## License
982//!
983//! Licensed under either of
984//!
985//! -   Apache License, Version 2.0
986//!     ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
987//! -   MIT license
988//!     ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
989//!
990//! at your option.
991//!
992//! ## Contribution
993//!
994//! Unless you explicitly state otherwise, any contribution intentionally submitted
995//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
996//! dual licensed as above, without any additional terms or conditions.
997//!
998//! SeaQuery is a community driven project. We welcome you to participate, contribute and together build for Rust's future.
999//!
1000//! A big shout out to our contributors:
1001//!
1002//! [![Contributors](https://opencollective.com/sea-query/contributors.svg?width=1000&button=false)](https://github.com/SeaQL/sea-query/graphs/contributors)
1003#![doc(
1004    html_logo_url = "https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQL icon dark.png"
1005)]
1006
1007#[cfg(feature = "audit")]
1008pub mod audit;
1009pub mod backend;
1010pub mod error;
1011pub mod expr;
1012pub mod extension;
1013pub mod foreign_key;
1014pub mod func;
1015pub mod index;
1016pub mod prepare;
1017pub mod query;
1018pub mod raw_sql;
1019pub mod schema;
1020#[cfg(feature = "sqlx-utils")]
1021pub mod sqlx;
1022pub mod table;
1023pub mod token;
1024pub mod types;
1025pub mod value;
1026
1027#[doc(hidden)]
1028#[cfg(feature = "tests-cfg")]
1029pub mod tests_cfg;
1030
1031pub use backend::*;
1032pub use expr::*;
1033pub use foreign_key::*;
1034pub use func::*;
1035pub use index::*;
1036pub use prepare::*;
1037pub use query::*;
1038pub use schema::*;
1039pub use table::*;
1040pub use token::*;
1041pub use types::*;
1042pub use value::*;
1043
1044#[cfg(feature = "derive")]
1045pub use sea_query_derive::{Iden, IdenStatic, enum_def, raw_query, raw_sql};
1046
1047#[cfg(all(feature = "sea-orm", not(feature = "derive")))]
1048pub use sea_query_derive::{raw_query, raw_sql};
1049
1050#[cfg(all(feature = "attr", not(feature = "derive")))]
1051pub use sea_query_derive::enum_def;