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//! [](https://crates.io/crates/sea-query)
22//! [](https://docs.rs/sea-query)
23//! [](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//! [](https://github.com/SeaQL/sea-query/stargazers/)
42//! If you like what we do, consider starring, commenting, sharing and contributing!
43//!
44//! [](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//! [](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;