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("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//! [](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;