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("size_w").add(1).mul(2))
115//!         .from("glyph")
116//!         .and_where(Expr::col("image").like("A"))
117//!         .and_where(Expr::col("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(["size_w", "size_h"])
142//!         .from("character")
143//!         .and_where(Expr::col("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(r#""size_w" = $2 * $1"#, [3, 2]))
148//!         .and_where(Expr::col("size_h").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("id")
168//!         .from("character")
169//!         .apply_if(a, |q, v| {
170//!             q.and_where(Expr::col("font_id").eq(v));
171//!         })
172//!         .apply_if(b, |q, v| {
173//!             q.and_where(Expr::col("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("id")
199//!         .from("glyph")
200//!         .cond_where(
201//!             Cond::any()
202//!                 .add(
203//!                     Cond::all()
204//!                         .add(Expr::col("aspect").is_null())
205//!                         .add(Expr::col("image").is_null())
206//!                 )
207//!                 .add(
208//!                     Cond::all()
209//!                         .add(Expr::col("aspect").is_in([3, 4]))
210//!                         .add(Expr::col("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")
236//!     .columns(["aspect", "image"])
237//!     .values_panic([
238//!         2.into(),
239//!         3.into(),
240//!     ])
241//!     .on_conflict(
242//!         OnConflict::column("id")
243//!             .update_columns(["aspect", "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//! You can use the `Iden` derive macro to implement it.
347//!
348//! ```rust
349//! # use sea_query::Iden;
350//! #[derive(Iden)]
351//! enum Character {
352//!     Table,
353//!     Id,
354//!     FontId,
355//!     FontSize,
356//! }
357//!
358//! assert_eq!(Character::Table.to_string(), "character");
359//! assert_eq!(Character::Id.to_string(), "id");
360//! assert_eq!(Character::FontId.to_string(), "font_id");
361//! assert_eq!(Character::FontSize.to_string(), "font_size");
362//!
363//! #[derive(Iden)]
364//! struct Glyph;
365//! assert_eq!(Glyph.to_string(), "glyph");
366//! ```
367//!
368//! ```rust
369//! use sea_query::{Iden, enum_def};
370//!
371//! #[enum_def]
372//! struct Character {
373//!     pub foo: u64,
374//! }
375//!
376//! // It generates the following along with Iden impl
377//! # let not_real = || {
378//! enum CharacterIden {
379//!     Table,
380//!     Foo,
381//! }
382//! # };
383//!
384//! assert_eq!(CharacterIden::Table.to_string(), "character");
385//! assert_eq!(CharacterIden::Foo.to_string(), "foo");
386//! ```
387//!
388//! ### Expression
389//!
390//! Use [`Expr`] constructors and [`ExprTrait`] methods
391//! to construct `SELECT`, `JOIN`, `WHERE` and `HAVING` expression in query.
392//!
393//! ```rust
394//! # use sea_query::{*, tests_cfg::*};
395//! assert_eq!(
396//!     Query::select()
397//!         .column("char_code")
398//!         .from("character")
399//!         .and_where(
400//!             Expr::col("size_w")
401//!                 .add(1)
402//!                 .mul(2)
403//!                 .eq(Expr::col("size_h").div(2).sub(1))
404//!         )
405//!         .and_where(
406//!             Expr::col("size_w").in_subquery(
407//!                 Query::select()
408//!                     .expr(Expr::cust_with_values("ln($1 ^ $2)", [2.4, 1.2]))
409//!                     .take()
410//!             )
411//!         )
412//!         .and_where(
413//!             Expr::col("char_code")
414//!                 .like("D")
415//!                 .and(Expr::col("char_code").like("E"))
416//!         )
417//!         .to_string(PostgresQueryBuilder),
418//!     [
419//!         r#"SELECT "char_code" FROM "character""#,
420//!         r#"WHERE ("size_w" + 1) * 2 = ("size_h" / 2) - 1"#,
421//!         r#"AND "size_w" IN (SELECT ln(2.4 ^ 1.2))"#,
422//!         r#"AND ("char_code" LIKE 'D' AND "char_code" LIKE 'E')"#,
423//!     ]
424//!     .join(" ")
425//! );
426//! ```
427//!
428//! ### Condition
429//!
430//! If you have complex conditions to express, you can use the [`Condition`] builder,
431//! usable for [`ConditionalStatement::cond_where`] and [`SelectStatement::cond_having`].
432//!
433//! ```
434//! # use sea_query::{*, tests_cfg::*};
435//! assert_eq!(
436//!     Query::select()
437//!         .column("id")
438//!         .from("glyph")
439//!         .cond_where(
440//!             Cond::any()
441//!                 .add(
442//!                     Cond::all()
443//!                         .add(Expr::col("aspect").is_null())
444//!                         .add(Expr::col("image").is_null())
445//!                 )
446//!                 .add(
447//!                     Cond::all()
448//!                         .add(Expr::col("aspect").is_in([3, 4]))
449//!                         .add(Expr::col("image").like("A%"))
450//!                 )
451//!         )
452//!         .to_string(PostgresQueryBuilder),
453//!     [
454//!         r#"SELECT "id" FROM "glyph""#,
455//!         r#"WHERE"#,
456//!         r#"("aspect" IS NULL AND "image" IS NULL)"#,
457//!         r#"OR"#,
458//!         r#"("aspect" IN (3, 4) AND "image" LIKE 'A%')"#,
459//!     ]
460//!     .join(" ")
461//! );
462//! ```
463//!
464//! There is also the [`any!`] and [`all!`] macro at your convenience:
465//!
466//! ```
467//! # use sea_query::{*, tests_cfg::*};
468//! Query::select().cond_where(any![
469//!     Expr::col(Glyph::Aspect).is_in([3, 4]),
470//!     all![
471//!         Expr::col(Glyph::Aspect).is_null(),
472//!         Expr::col(Glyph::Image).like("A%")
473//!     ]
474//! ]);
475//! ```
476//!
477//! ### Statement Builders
478//!
479//! Statements are divided into 2 categories: Query and Schema, and to be serialized into SQL
480//! with [`QueryStatementBuilder`] and [`SchemaStatementBuilder`] respectively.
481//!
482//! Schema statement has the following interface:
483//!
484//! ```rust
485//! # use sea_query::{*};
486//! # trait ExampleSchemaBuilder {
487//! fn build<T: SchemaBuilder>(&self, schema_builder: T) -> String;
488//! # }
489//! ```
490//!
491//! Query statement has the following interfaces:
492//!
493//! ```rust
494//! # use sea_query::{*};
495//! # trait ExampleQueryBuilder {
496//! fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values);
497//!
498//! fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String;
499//! # }
500//! ```
501//!
502//! `build` builds a SQL statement as string and parameters to be passed to the database driver
503//! through the binary protocol. This is the preferred way as it has less overhead and is more secure.
504//!
505//! `to_string` builds a SQL statement as string with parameters injected. This is good for testing
506//! and debugging.
507//!
508//! ## Query Statement
509//!
510//! ### Query Select
511//!
512//! ```rust
513//! # use sea_query::{*, tests_cfg::*};
514//! let query = Query::select()
515//!     .column("char_code")
516//!     .column(("font", "name"))
517//!     .from("character")
518//!     .left_join("font", Expr::col(("character", "font_id")).equals(("font", "id")))
519//!     .and_where(Expr::col("size_w").is_in([3, 4]))
520//!     .and_where(Expr::col("char_code").like("A%"))
521//!     .to_owned();
522//!
523//! assert_eq!(
524//!     query.to_string(MysqlQueryBuilder),
525//!     r#"SELECT `char_code`, `font`.`name` FROM `character` LEFT JOIN `font` ON `character`.`font_id` = `font`.`id` WHERE `size_w` IN (3, 4) AND `char_code` LIKE 'A%'"#
526//! );
527//! assert_eq!(
528//!     query.to_string(PostgresQueryBuilder),
529//!     r#"SELECT "char_code", "font"."name" FROM "character" LEFT JOIN "font" ON "character"."font_id" = "font"."id" WHERE "size_w" IN (3, 4) AND "char_code" LIKE 'A%'"#
530//! );
531//! assert_eq!(
532//!     query.to_string(SqliteQueryBuilder),
533//!     r#"SELECT "char_code", "font"."name" FROM "character" LEFT JOIN "font" ON "character"."font_id" = "font"."id" WHERE "size_w" IN (3, 4) AND "char_code" LIKE 'A%'"#
534//! );
535//! ```
536//!
537//! ### Query Insert
538//!
539//! ```rust
540//! # use sea_query::{*, tests_cfg::*};
541//! let query = Query::insert()
542//!     .into_table(Glyph::Table)
543//!     .columns([Glyph::Aspect, Glyph::Image])
544//!     .values_panic([5.15.into(), "12A".into()])
545//!     .values_panic([4.21.into(), "123".into()])
546//!     .to_owned();
547//!
548//! assert_eq!(
549//!     query.to_string(MysqlQueryBuilder),
550//!     r#"INSERT INTO `glyph` (`aspect`, `image`) VALUES (5.15, '12A'), (4.21, '123')"#
551//! );
552//! assert_eq!(
553//!     query.to_string(PostgresQueryBuilder),
554//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
555//! );
556//! assert_eq!(
557//!     query.to_string(SqliteQueryBuilder),
558//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
559//! );
560//! ```
561//!
562//! ### Query Update
563//!
564//! ```rust
565//! # use sea_query::{*, tests_cfg::*};
566//! let query = Query::update()
567//!     .table(Glyph::Table)
568//!     .values([(Glyph::Aspect, 1.23.into()), (Glyph::Image, "123".into())])
569//!     .and_where(Expr::col(Glyph::Id).eq(1))
570//!     .to_owned();
571//!
572//! assert_eq!(
573//!     query.to_string(MysqlQueryBuilder),
574//!     r#"UPDATE `glyph` SET `aspect` = 1.23, `image` = '123' WHERE `id` = 1"#
575//! );
576//! assert_eq!(
577//!     query.to_string(PostgresQueryBuilder),
578//!     r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
579//! );
580//! assert_eq!(
581//!     query.to_string(SqliteQueryBuilder),
582//!     r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
583//! );
584//! ```
585//!
586//! ### Query Delete
587//!
588//! ```rust
589//! # use sea_query::{*, tests_cfg::*};
590//! let query = Query::delete()
591//!     .from_table(Glyph::Table)
592//!     .cond_where(
593//!         Cond::any()
594//!             .add(Expr::col(Glyph::Id).lt(1))
595//!             .add(Expr::col(Glyph::Id).gt(10)),
596//!     )
597//!     .to_owned();
598//!
599//! assert_eq!(
600//!     query.to_string(MysqlQueryBuilder),
601//!     r#"DELETE FROM `glyph` WHERE `id` < 1 OR `id` > 10"#
602//! );
603//! assert_eq!(
604//!     query.to_string(PostgresQueryBuilder),
605//!     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
606//! );
607//! assert_eq!(
608//!     query.to_string(SqliteQueryBuilder),
609//!     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
610//! );
611//! ```
612//!
613//! ## Advanced
614//!
615//! ### Aggregate Functions
616//!
617//! `max`, `min`, `sum`, `avg`, `count` etc
618//!
619//! ```rust
620//! # use sea_query::{*, tests_cfg::*};
621//! let query = Query::select()
622//!     .expr(Func::sum(Expr::col((Char::Table, Char::SizeH))))
623//!     .from(Char::Table)
624//!     .to_owned();
625//! assert_eq!(
626//!     query.to_string(MysqlQueryBuilder),
627//!     r#"SELECT SUM(`character`.`size_h`) FROM `character`"#
628//! );
629//! assert_eq!(
630//!     query.to_string(PostgresQueryBuilder),
631//!     r#"SELECT SUM("character"."size_h") FROM "character""#
632//! );
633//! assert_eq!(
634//!     query.to_string(SqliteQueryBuilder),
635//!     r#"SELECT SUM("character"."size_h") FROM "character""#
636//! );
637//! ```
638//!
639//! ### Casting
640//!
641//! ```rust
642//! # use sea_query::{*, tests_cfg::*};
643//! let query = Query::select()
644//!     .expr(Func::cast_as("hello", "MyType"))
645//!     .to_owned();
646//!
647//! assert_eq!(
648//!     query.to_string(MysqlQueryBuilder),
649//!     r#"SELECT CAST('hello' AS MyType)"#
650//! );
651//! assert_eq!(
652//!     query.to_string(PostgresQueryBuilder),
653//!     r#"SELECT CAST('hello' AS MyType)"#
654//! );
655//! assert_eq!(
656//!     query.to_string(SqliteQueryBuilder),
657//!     r#"SELECT CAST('hello' AS MyType)"#
658//! );
659//! ```
660//!
661//! ### Custom Function
662//!
663//! ```rust
664//! # use sea_query::{*, tests_cfg::*};
665//! struct MyFunction;
666//!
667//! impl Iden for MyFunction {
668//!     fn unquoted(&self) -> &str {
669//!         "MY_FUNCTION"
670//!     }
671//! }
672//!
673//! let query = Query::select()
674//!     .expr(Func::cust(MyFunction).arg(Expr::val("hello")))
675//!     .to_owned();
676//!
677//! assert_eq!(
678//!     query.to_string(MysqlQueryBuilder),
679//!     r#"SELECT MY_FUNCTION('hello')"#
680//! );
681//! assert_eq!(
682//!     query.to_string(PostgresQueryBuilder),
683//!     r#"SELECT MY_FUNCTION('hello')"#
684//! );
685//! assert_eq!(
686//!     query.to_string(SqliteQueryBuilder),
687//!     r#"SELECT MY_FUNCTION('hello')"#
688//! );
689//! ```
690//!
691//! ## Schema Statement
692//!
693//! ### Table Create
694//!
695//! ```rust
696//! # use sea_query::{*, tests_cfg::*};
697//! let table = Table::create()
698//!     .table("character")
699//!     .if_not_exists()
700//!     .col(ColumnDef::new("id").integer().not_null().auto_increment().primary_key())
701//!     .col(ColumnDef::new("font_size").integer().not_null())
702//!     .col(ColumnDef::new("character").string().not_null())
703//!     .col(ColumnDef::new("size_w").integer().not_null())
704//!     .col(ColumnDef::new("size_h").integer().not_null())
705//!     .col(ColumnDef::new("font_id").integer().default(Expr::val(1)))
706//!     .foreign_key(
707//!         ForeignKey::create()
708//!             .name("character_fk")
709//!             .from("character", "font_id")
710//!             .to("font", "id")
711//!             .on_delete(ForeignKeyAction::Cascade)
712//!             .on_update(ForeignKeyAction::Cascade)
713//!     )
714//!     .to_owned();
715//!
716//! assert_eq!(
717//!     table.to_string(MysqlQueryBuilder),
718//!     [
719//!         r#"CREATE TABLE IF NOT EXISTS `character` ("#,
720//!             r#"`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,"#,
721//!             r#"`font_size` int NOT NULL,"#,
722//!             r#"`character` varchar(255) NOT NULL,"#,
723//!             r#"`size_w` int NOT NULL,"#,
724//!             r#"`size_h` int NOT NULL,"#,
725//!             r#"`font_id` int DEFAULT 1,"#,
726//!             r#"CONSTRAINT `character_fk`"#,
727//!                 r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
728//!                 r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
729//!         r#")"#,
730//!     ].join(" ")
731//! );
732//! assert_eq!(
733//!     table.to_string(PostgresQueryBuilder),
734//!     [
735//!         r#"CREATE TABLE IF NOT EXISTS "character" ("#,
736//!             r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
737//!             r#""font_size" integer NOT NULL,"#,
738//!             r#""character" varchar NOT NULL,"#,
739//!             r#""size_w" integer NOT NULL,"#,
740//!             r#""size_h" integer NOT NULL,"#,
741//!             r#""font_id" integer DEFAULT 1,"#,
742//!             r#"CONSTRAINT "character_fk""#,
743//!                 r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
744//!                 r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
745//!         r#")"#,
746//!     ].join(" ")
747//! );
748//! assert_eq!(
749//!     table.to_string(SqliteQueryBuilder),
750//!     [
751//!        r#"CREATE TABLE IF NOT EXISTS "character" ("#,
752//!            r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
753//!            r#""font_size" integer NOT NULL,"#,
754//!            r#""character" varchar NOT NULL,"#,
755//!            r#""size_w" integer NOT NULL,"#,
756//!            r#""size_h" integer NOT NULL,"#,
757//!            r#""font_id" integer DEFAULT 1,"#,
758//!            r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
759//!        r#")"#,
760//!     ].join(" ")
761//! );
762//! ```
763//!
764//! ### Table Alter
765//!
766//! ```rust
767//! # use sea_query::{*, tests_cfg::*};
768//! let table = Table::alter()
769//!     .table(Font::Table)
770//!     .add_column(ColumnDef::new("new_col").integer().not_null().default(100))
771//!     .to_owned();
772//!
773//! assert_eq!(
774//!     table.to_string(MysqlQueryBuilder),
775//!     r#"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100"#
776//! );
777//! assert_eq!(
778//!     table.to_string(PostgresQueryBuilder),
779//!     r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#
780//! );
781//! assert_eq!(
782//!     table.to_string(SqliteQueryBuilder),
783//!     r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#,
784//! );
785//! ```
786//!
787//! ### Table Drop
788//!
789//! ```rust
790//! # use sea_query::{*, tests_cfg::*};
791//! let table = Table::drop()
792//!     .table(Glyph::Table)
793//!     .table(Char::Table)
794//!     .to_owned();
795//!
796//! assert_eq!(
797//!     table.to_string(MysqlQueryBuilder),
798//!     r#"DROP TABLE `glyph`, `character`"#
799//! );
800//! assert_eq!(
801//!     table.to_string(PostgresQueryBuilder),
802//!     r#"DROP TABLE "glyph", "character""#
803//! );
804//! assert_eq!(
805//!     table.to_string(SqliteQueryBuilder),
806//!     r#"DROP TABLE "glyph", "character""#
807//! );
808//! ```
809//!
810//! ### Table Rename
811//!
812//! ```rust
813//! # use sea_query::{*, tests_cfg::*};
814//! let table = Table::rename().table(Font::Table, "font_new").to_owned();
815//!
816//! assert_eq!(
817//!     table.to_string(MysqlQueryBuilder),
818//!     r#"RENAME TABLE `font` TO `font_new`"#
819//! );
820//! assert_eq!(
821//!     table.to_string(PostgresQueryBuilder),
822//!     r#"ALTER TABLE "font" RENAME TO "font_new""#
823//! );
824//! assert_eq!(
825//!     table.to_string(SqliteQueryBuilder),
826//!     r#"ALTER TABLE "font" RENAME TO "font_new""#
827//! );
828//! ```
829//!
830//! ### Table Truncate
831//!
832//! ```rust
833//! # use sea_query::{*, tests_cfg::*};
834//! let table = Table::truncate().table(Font::Table).to_owned();
835//!
836//! assert_eq!(
837//!     table.to_string(MysqlQueryBuilder),
838//!     r#"TRUNCATE TABLE `font`"#
839//! );
840//! assert_eq!(
841//!     table.to_string(PostgresQueryBuilder),
842//!     r#"TRUNCATE TABLE "font""#
843//! );
844//! // Sqlite does not support the TRUNCATE statement
845//! ```
846//!
847//! ### Foreign Key Create
848//!
849//! ```rust
850//! # use sea_query::{*, tests_cfg::*};
851//! let foreign_key = ForeignKey::create()
852//!     .name("FK_character_font")
853//!     .from(Char::Table, Char::FontId)
854//!     .to(Font::Table, Font::Id)
855//!     .on_delete(ForeignKeyAction::Cascade)
856//!     .on_update(ForeignKeyAction::Cascade)
857//!     .to_owned();
858//!
859//! assert_eq!(
860//!     foreign_key.to_string(MysqlQueryBuilder),
861//!     [
862//!         r#"ALTER TABLE `character`"#,
863//!         r#"ADD CONSTRAINT `FK_character_font`"#,
864//!         r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
865//!         r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
866//!     ]
867//!     .join(" ")
868//! );
869//! assert_eq!(
870//!     foreign_key.to_string(PostgresQueryBuilder),
871//!     [
872//!         r#"ALTER TABLE "character" ADD CONSTRAINT "FK_character_font""#,
873//!         r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
874//!         r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
875//!     ]
876//!     .join(" ")
877//! );
878//! // Sqlite does not support modification of foreign key constraints to existing tables
879//! ```
880//!
881//! ### Foreign Key Drop
882//!
883//! ```rust
884//! # use sea_query::{*, tests_cfg::*};
885//! let foreign_key = ForeignKey::drop()
886//!     .name("FK_character_font")
887//!     .table(Char::Table)
888//!     .to_owned();
889//!
890//! assert_eq!(
891//!     foreign_key.to_string(MysqlQueryBuilder),
892//!     r#"ALTER TABLE `character` DROP FOREIGN KEY `FK_character_font`"#
893//! );
894//! assert_eq!(
895//!     foreign_key.to_string(PostgresQueryBuilder),
896//!     r#"ALTER TABLE "character" DROP CONSTRAINT "FK_character_font""#
897//! );
898//! // Sqlite does not support modification of foreign key constraints to existing tables
899//! ```
900//!
901//! ### Index Create
902//!
903//! ```rust
904//! # use sea_query::{*, tests_cfg::*};
905//! let index = Index::create()
906//!     .name("idx-glyph-aspect")
907//!     .table(Glyph::Table)
908//!     .col(Glyph::Aspect)
909//!     .to_owned();
910//!
911//! assert_eq!(
912//!     index.to_string(MysqlQueryBuilder),
913//!     r#"CREATE INDEX `idx-glyph-aspect` ON `glyph` (`aspect`)"#
914//! );
915//! assert_eq!(
916//!     index.to_string(PostgresQueryBuilder),
917//!     r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
918//! );
919//! assert_eq!(
920//!     index.to_string(SqliteQueryBuilder),
921//!     r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
922//! );
923//! ```
924//!
925//! ### Index Drop
926//!
927//! ```rust
928//! # use sea_query::{*, tests_cfg::*};
929//! let index = Index::drop()
930//!     .name("idx-glyph-aspect")
931//!     .table(Glyph::Table)
932//!     .to_owned();
933//!
934//! assert_eq!(
935//!     index.to_string(MysqlQueryBuilder),
936//!     r#"DROP INDEX `idx-glyph-aspect` ON `glyph`"#
937//! );
938//! assert_eq!(
939//!     index.to_string(PostgresQueryBuilder),
940//!     r#"DROP INDEX "idx-glyph-aspect""#
941//! );
942//! assert_eq!(
943//!     index.to_string(SqliteQueryBuilder),
944//!     r#"DROP INDEX "idx-glyph-aspect""#
945//! );
946//! ```
947//!
948//! ## License
949//!
950//! Licensed under either of
951//!
952//! -   Apache License, Version 2.0
953//!     ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
954//! -   MIT license
955//!     ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
956//!
957//! at your option.
958//!
959//! ## Contribution
960//!
961//! Unless you explicitly state otherwise, any contribution intentionally submitted
962//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
963//! dual licensed as above, without any additional terms or conditions.
964//!
965//! SeaQuery is a community driven project. We welcome you to participate, contribute and together build for Rust's future.
966//!
967//! A big shout out to our contributors:
968//!
969//! [![Contributors](https://opencollective.com/sea-query/contributors.svg?width=1000&button=false)](https://github.com/SeaQL/sea-query/graphs/contributors)
970#![doc(
971    html_logo_url = "https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQL icon dark.png"
972)]
973
974#[cfg(feature = "audit")]
975pub mod audit;
976pub mod backend;
977pub mod error;
978pub mod expr;
979pub mod extension;
980pub mod foreign_key;
981pub mod func;
982pub mod index;
983pub mod prepare;
984pub mod query;
985pub mod raw_sql;
986pub mod schema;
987#[cfg(feature = "sqlx-utils")]
988pub mod sqlx;
989pub mod table;
990pub mod token;
991pub mod types;
992pub mod value;
993
994#[doc(hidden)]
995#[cfg(feature = "tests-cfg")]
996pub mod tests_cfg;
997
998pub use backend::*;
999pub use expr::*;
1000pub use foreign_key::*;
1001pub use func::*;
1002pub use index::*;
1003pub use prepare::*;
1004pub use query::*;
1005pub use schema::*;
1006pub use table::*;
1007pub use token::*;
1008pub use types::*;
1009pub use value::*;
1010
1011#[cfg(feature = "derive")]
1012pub use sea_query_derive::{Iden, IdenStatic, enum_def, raw_query, raw_sql};
1013
1014#[cfg(all(feature = "sea-orm", not(feature = "derive")))]
1015pub use sea_query_derive::{raw_query, raw_sql};
1016
1017#[cfg(all(feature = "attr", not(feature = "derive")))]
1018pub use sea_query_derive::enum_def;