sea_query/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![deny(missing_debug_implementations)]
3
4//! <div align="center">
5//!
6//! <img src="https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQuery logo.png" width="280" alt="SeaQuery logo"/>
7//!
8//! <p>
9//! <strong>🔱 A dynamic query builder for MySQL, Postgres and SQLite</strong>
10//! </p>
11//!
12//! [](https://crates.io/crates/sea-query)
13//! [](https://docs.rs/sea-query)
14//! [](https://github.com/SeaQL/sea-query/actions/workflows/rust.yml)
15//!
16//! </div>
17//!
18//! ## SeaQuery
19//!
20//! SeaQuery is a query builder to help you construct dynamic SQL queries in Rust.
21//! You can construct expressions, queries and schema as abstract syntax trees using an ergonomic API.
22//! We support MySQL, Postgres and SQLite behind a common interface that aligns their behaviour where appropriate.
23//!
24//! We provide integration for [SQLx](https://crates.io/crates/sqlx),
25//! [postgres](https://crates.io/crates/postgres) and [rusqlite](https://crates.io/crates/rusqlite).
26//! See [examples](https://github.com/SeaQL/sea-query/blob/master/examples) for usage.
27//!
28//! SeaQuery is the foundation of [SeaORM](https://github.com/SeaQL/sea-orm), an async & dynamic ORM for Rust.
29//!
30//! [](https://github.com/SeaQL/sea-query/stargazers/)
31//! If you like what we do, consider starring, commenting, sharing and contributing!
32//!
33//! [](https://discord.com/invite/uCPdDXzbdv)
34//! Join our Discord server to chat with others in the SeaQL community!
35//!
36//! ## Install
37//!
38//! ```toml
39//! # Cargo.toml
40//! [dependencies]
41//! sea-query = "0"
42//! ```
43//!
44//! SeaQuery is very lightweight, all dependencies are optional (except `inherent`).
45//!
46//! ### Feature flags
47//!
48//! Macro: `derive`
49//!
50//! Async support: `thread-safe` (use `Arc` inplace of `Rc`)
51//!
52//! SQL engine: `backend-mysql`, `backend-postgres`, `backend-sqlite`
53//!
54//! Type support: `with-chrono`, `with-time`, `with-json`, `with-rust_decimal`, `with-bigdecimal`, `with-uuid`,
55//! `with-ipnetwork`, `with-mac_address`, `postgres-array`, `postgres-interval`, `postgres-vector`
56//!
57//! ## Usage
58//!
59//! Table of Content
60//!
61//! 1. Basics
62//!
63//! 1. [Iden](#iden)
64//! 1. [Expression](#expression)
65//! 1. [Condition](#condition)
66//! 1. [Statement Builders](#statement-builders)
67//!
68//! 1. Query Statement
69//!
70//! 1. [Query Select](#query-select)
71//! 1. [Query Insert](#query-insert)
72//! 1. [Query Update](#query-update)
73//! 1. [Query Delete](#query-delete)
74//!
75//! 1. Advanced
76//! 1. [Aggregate Functions](#aggregate-functions)
77//! 1. [Casting](#casting)
78//! 1. [Custom Function](#custom-function)
79//!
80//! 1. Schema Statement
81//!
82//! 1. [Table Create](#table-create)
83//! 1. [Table Alter](#table-alter)
84//! 1. [Table Drop](#table-drop)
85//! 1. [Table Rename](#table-rename)
86//! 1. [Table Truncate](#table-truncate)
87//! 1. [Foreign Key Create](#foreign-key-create)
88//! 1. [Foreign Key Drop](#foreign-key-drop)
89//! 1. [Index Create](#index-create)
90//! 1. [Index Drop](#index-drop)
91//!
92//! ### Motivation
93//!
94//! Why would you want to use a dynamic query builder?
95//!
96//! 1. Parameter bindings
97//!
98//! One of the headaches when using raw SQL is parameter binding. With SeaQuery you can:
99//!
100//! ```
101//! # use sea_query::{*, tests_cfg::*};
102//! assert_eq!(
103//! Query::select()
104//! .column(Glyph::Image)
105//! .from(Glyph::Table)
106//! .and_where(Expr::col(Glyph::Image).like("A"))
107//! .and_where(Expr::col(Glyph::Id).is_in([1, 2, 3]))
108//! .build(PostgresQueryBuilder),
109//! (
110//! r#"SELECT "image" FROM "glyph" WHERE "image" LIKE $1 AND "id" IN ($2, $3, $4)"#
111//! .to_owned(),
112//! Values(vec![
113//! Value::String(Some(Box::new("A".to_owned()))),
114//! Value::Int(Some(1)),
115//! Value::Int(Some(2)),
116//! Value::Int(Some(3))
117//! ])
118//! )
119//! );
120//! ```
121//!
122//! 2. Dynamic query
123//!
124//! You can construct the query at runtime based on user inputs:
125//!
126//! ```
127//! # use sea_query::{*, tests_cfg::*};
128//! Query::select()
129//! .column(Char::Character)
130//! .from(Char::Table)
131//! .conditions(
132//! // some runtime condition
133//! true,
134//! // if condition is true then add the following condition
135//! |q| {
136//! q.and_where(Expr::col(Char::Id).eq(1));
137//! },
138//! // otherwise leave it as is
139//! |q| {},
140//! );
141//! ```
142//!
143//! ### Iden
144//!
145//! `Iden` is a trait for identifiers used in any query statement.
146//!
147//! Commonly implemented by Enum where each Enum represents a table found in a database,
148//! and its variants include table name and column name.
149//!
150//! [`Iden::unquoted()`] must be implemented to provide a mapping between Enum variants and its
151//! corresponding string value.
152//!
153//! ```rust
154//! use sea_query::*;
155//!
156//! // For example Character table with column id, character, font_size...
157//! pub enum Character {
158//! Table,
159//! Id,
160//! FontId,
161//! FontSize,
162//! }
163//!
164//! // Mapping between Enum variant and its corresponding string value
165//! impl Iden for Character {
166//! fn unquoted(&self, s: &mut dyn std::fmt::Write) {
167//! write!(
168//! s,
169//! "{}",
170//! match self {
171//! Self::Table => "character",
172//! Self::Id => "id",
173//! Self::FontId => "font_id",
174//! Self::FontSize => "font_size",
175//! }
176//! )
177//! .unwrap();
178//! }
179//! }
180//! ```
181//!
182//! If you're okay with running another procedural macro, you can activate
183//! the `derive` feature on the crate to save you some boilerplate.
184//! For more usage information, look at
185//! [the derive examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-derive/tests/pass).
186//!
187//! ```rust
188//! #[cfg(feature = "derive")]
189//! use sea_query::Iden;
190//!
191//! // This will implement Iden exactly as shown above
192//! #[derive(Iden)]
193//! enum Character {
194//! Table,
195//! }
196//! assert_eq!(Character::Table.to_string(), "character");
197//!
198//! // You can also derive a unit struct
199//! #[derive(Iden)]
200//! struct Glyph;
201//! assert_eq!(Glyph.to_string(), "glyph");
202//! ```
203//!
204//! ```rust
205//! #[cfg(feature = "derive")]
206//! # fn test() {
207//! use sea_query::{enum_def, Iden};
208//!
209//! #[enum_def]
210//! struct Character {
211//! pub foo: u64,
212//! }
213//!
214//! // It generates the following along with Iden impl
215//! # let not_real = || {
216//! enum CharacterIden {
217//! Table,
218//! Foo,
219//! }
220//! # };
221//!
222//! assert_eq!(CharacterIden::Table.to_string(), "character");
223//! assert_eq!(CharacterIden::Foo.to_string(), "foo");
224//! # }
225//! # #[cfg(feature = "derive")]
226//! # test();
227//! ```
228//!
229//!
230//! ### Expression
231//!
232//! Use [`Expr`] constructors and [`ExprTrait`] methods
233//! to construct `SELECT`, `JOIN`, `WHERE` and `HAVING` expression in query.
234//!
235//! ```rust
236//! # use sea_query::{*, tests_cfg::*};
237//! assert_eq!(
238//! Query::select()
239//! .column(Char::Character)
240//! .from(Char::Table)
241//! .and_where(
242//! Expr::col(Char::SizeW)
243//! .add(1)
244//! .mul(2)
245//! .eq(Expr::col(Char::SizeH).div(2).sub(1))
246//! )
247//! .and_where(
248//! Expr::col(Char::SizeW).in_subquery(
249//! Query::select()
250//! .expr(Expr::cust_with_values("ln($1 ^ $2)", [2.4, 1.2]))
251//! .take()
252//! )
253//! )
254//! .and_where(
255//! Expr::col(Char::Character)
256//! .like("D")
257//! .and(Expr::col(Char::Character).like("E"))
258//! )
259//! .to_string(PostgresQueryBuilder),
260//! [
261//! r#"SELECT "character" FROM "character""#,
262//! r#"WHERE ("size_w" + 1) * 2 = ("size_h" / 2) - 1"#,
263//! r#"AND "size_w" IN (SELECT ln(2.4 ^ 1.2))"#,
264//! r#"AND ("character" LIKE 'D' AND "character" LIKE 'E')"#,
265//! ]
266//! .join(" ")
267//! );
268//! ```
269//!
270//! ### Condition
271//!
272//! If you have complex conditions to express, you can use the [`Condition`] builder,
273//! usable for [`ConditionalStatement::cond_where`] and [`SelectStatement::cond_having`].
274//!
275//! ```
276//! # use sea_query::{*, tests_cfg::*};
277//! assert_eq!(
278//! Query::select()
279//! .column(Glyph::Id)
280//! .from(Glyph::Table)
281//! .cond_where(
282//! Cond::any()
283//! .add(
284//! Cond::all()
285//! .add(Expr::col(Glyph::Aspect).is_null())
286//! .add(Expr::col(Glyph::Image).is_null())
287//! )
288//! .add(
289//! Cond::all()
290//! .add(Expr::col(Glyph::Aspect).is_in([3, 4]))
291//! .add(Expr::col(Glyph::Image).like("A%"))
292//! )
293//! )
294//! .to_string(PostgresQueryBuilder),
295//! [
296//! r#"SELECT "id" FROM "glyph""#,
297//! r#"WHERE"#,
298//! r#"("aspect" IS NULL AND "image" IS NULL)"#,
299//! r#"OR"#,
300//! r#"("aspect" IN (3, 4) AND "image" LIKE 'A%')"#,
301//! ]
302//! .join(" ")
303//! );
304//! ```
305//!
306//! There is also the [`any!`] and [`all!`] macro at your convenience:
307//!
308//! ```
309//! # use sea_query::{*, tests_cfg::*};
310//! Query::select().cond_where(any![
311//! Expr::col(Glyph::Aspect).is_in([3, 4]),
312//! all![
313//! Expr::col(Glyph::Aspect).is_null(),
314//! Expr::col(Glyph::Image).like("A%")
315//! ]
316//! ]);
317//! ```
318//!
319//! ### Statement Builders
320//!
321//! Statements are divided into 2 categories: Query and Schema, and to be serialized into SQL
322//! with [`QueryStatementBuilder`] and [`SchemaStatementBuilder`] respectively.
323//!
324//! Schema statement has the following interface:
325//!
326//! ```rust
327//! # use sea_query::{*};
328//! # trait ExampleSchemaBuilder {
329//! fn build<T: SchemaBuilder>(&self, schema_builder: T) -> String;
330//! # }
331//! ```
332//!
333//! Query statement has the following interfaces:
334//!
335//! ```rust
336//! # use sea_query::{*};
337//! # trait ExampleQueryBuilder {
338//! fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values);
339//!
340//! fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String;
341//! # }
342//! ```
343//!
344//! `build` builds a SQL statement as string and parameters to be passed to the database driver
345//! through the binary protocol. This is the preferred way as it has less overhead and is more secure.
346//!
347//! `to_string` builds a SQL statement as string with parameters injected. This is good for testing
348//! and debugging.
349//!
350//! ### Query Select
351//!
352//! ```rust
353//! # use sea_query::{*, tests_cfg::*};
354//! let query = Query::select()
355//! .column(Char::Character)
356//! .column((Font::Table, Font::Name))
357//! .from(Char::Table)
358//! .left_join(Font::Table, Expr::col((Char::Table, Char::FontId)).equals((Font::Table, Font::Id)))
359//! .and_where(Expr::col(Char::SizeW).is_in([3, 4]))
360//! .and_where(Expr::col(Char::Character).like("A%"))
361//! .to_owned();
362//!
363//! assert_eq!(
364//! query.to_string(MysqlQueryBuilder),
365//! 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%'"#
366//! );
367//! assert_eq!(
368//! query.to_string(PostgresQueryBuilder),
369//! 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%'"#
370//! );
371//! assert_eq!(
372//! query.to_string(SqliteQueryBuilder),
373//! 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%'"#
374//! );
375//! ```
376//!
377//! ### Query Insert
378//!
379//! ```rust
380//! # use sea_query::{*, tests_cfg::*};
381//! let query = Query::insert()
382//! .into_table(Glyph::Table)
383//! .columns([Glyph::Aspect, Glyph::Image])
384//! .values_panic([5.15.into(), "12A".into()])
385//! .values_panic([4.21.into(), "123".into()])
386//! .to_owned();
387//!
388//! assert_eq!(
389//! query.to_string(MysqlQueryBuilder),
390//! r#"INSERT INTO `glyph` (`aspect`, `image`) VALUES (5.15, '12A'), (4.21, '123')"#
391//! );
392//! assert_eq!(
393//! query.to_string(PostgresQueryBuilder),
394//! r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
395//! );
396//! assert_eq!(
397//! query.to_string(SqliteQueryBuilder),
398//! r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
399//! );
400//! ```
401//!
402//! ### Query Update
403//!
404//! ```rust
405//! # use sea_query::{*, tests_cfg::*};
406//! let query = Query::update()
407//! .table(Glyph::Table)
408//! .values([(Glyph::Aspect, 1.23.into()), (Glyph::Image, "123".into())])
409//! .and_where(Expr::col(Glyph::Id).eq(1))
410//! .to_owned();
411//!
412//! assert_eq!(
413//! query.to_string(MysqlQueryBuilder),
414//! r#"UPDATE `glyph` SET `aspect` = 1.23, `image` = '123' WHERE `id` = 1"#
415//! );
416//! assert_eq!(
417//! query.to_string(PostgresQueryBuilder),
418//! r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
419//! );
420//! assert_eq!(
421//! query.to_string(SqliteQueryBuilder),
422//! r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
423//! );
424//! ```
425//!
426//! ### Query Delete
427//!
428//! ```rust
429//! # use sea_query::{*, tests_cfg::*};
430//! let query = Query::delete()
431//! .from_table(Glyph::Table)
432//! .cond_where(
433//! Cond::any()
434//! .add(Expr::col(Glyph::Id).lt(1))
435//! .add(Expr::col(Glyph::Id).gt(10)),
436//! )
437//! .to_owned();
438//!
439//! assert_eq!(
440//! query.to_string(MysqlQueryBuilder),
441//! r#"DELETE FROM `glyph` WHERE `id` < 1 OR `id` > 10"#
442//! );
443//! assert_eq!(
444//! query.to_string(PostgresQueryBuilder),
445//! r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
446//! );
447//! assert_eq!(
448//! query.to_string(SqliteQueryBuilder),
449//! r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
450//! );
451//! ```
452//!
453//! ### Aggregate Functions
454//!
455//! `max`, `min`, `sum`, `avg`, `count` etc
456//!
457//! ```rust
458//! # use sea_query::{*, tests_cfg::*};
459//! let query = Query::select()
460//! .expr(Func::sum(Expr::col((Char::Table, Char::SizeH))))
461//! .from(Char::Table)
462//! .to_owned();
463//! assert_eq!(
464//! query.to_string(MysqlQueryBuilder),
465//! r#"SELECT SUM(`character`.`size_h`) FROM `character`"#
466//! );
467//! assert_eq!(
468//! query.to_string(PostgresQueryBuilder),
469//! r#"SELECT SUM("character"."size_h") FROM "character""#
470//! );
471//! assert_eq!(
472//! query.to_string(SqliteQueryBuilder),
473//! r#"SELECT SUM("character"."size_h") FROM "character""#
474//! );
475//! ```
476//!
477//! ### Casting
478//!
479//! ```rust
480//! # use sea_query::{*, tests_cfg::*};
481//! let query = Query::select()
482//! .expr(Func::cast_as("hello", "MyType"))
483//! .to_owned();
484//!
485//! assert_eq!(
486//! query.to_string(MysqlQueryBuilder),
487//! r#"SELECT CAST('hello' AS MyType)"#
488//! );
489//! assert_eq!(
490//! query.to_string(PostgresQueryBuilder),
491//! r#"SELECT CAST('hello' AS MyType)"#
492//! );
493//! assert_eq!(
494//! query.to_string(SqliteQueryBuilder),
495//! r#"SELECT CAST('hello' AS MyType)"#
496//! );
497//! ```
498//!
499//! ### Custom Function
500//!
501//! ```rust
502//! # use sea_query::{*, tests_cfg::*};
503//! struct MyFunction;
504//!
505//! impl Iden for MyFunction {
506//! fn unquoted(&self, s: &mut dyn Write) {
507//! write!(s, "MY_FUNCTION").unwrap();
508//! }
509//! }
510//!
511//! let query = Query::select()
512//! .expr(Func::cust(MyFunction).arg(Expr::val("hello")))
513//! .to_owned();
514//!
515//! assert_eq!(
516//! query.to_string(MysqlQueryBuilder),
517//! r#"SELECT MY_FUNCTION('hello')"#
518//! );
519//! assert_eq!(
520//! query.to_string(PostgresQueryBuilder),
521//! r#"SELECT MY_FUNCTION('hello')"#
522//! );
523//! assert_eq!(
524//! query.to_string(SqliteQueryBuilder),
525//! r#"SELECT MY_FUNCTION('hello')"#
526//! );
527//! ```
528//!
529//! ### Table Create
530//!
531//! ```rust
532//! # use sea_query::{*, tests_cfg::*};
533//! let table = Table::create()
534//! .table(Char::Table)
535//! .if_not_exists()
536//! .col(ColumnDef::new(Char::Id).integer().not_null().auto_increment().primary_key())
537//! .col(ColumnDef::new(Char::FontSize).integer().not_null())
538//! .col(ColumnDef::new(Char::Character).string().not_null())
539//! .col(ColumnDef::new(Char::SizeW).integer().not_null())
540//! .col(ColumnDef::new(Char::SizeH).integer().not_null())
541//! .col(ColumnDef::new(Char::FontId).integer().default(Value::Int(None)))
542//! .foreign_key(
543//! ForeignKey::create()
544//! .name("FK_2e303c3a712662f1fc2a4d0aad6")
545//! .from(Char::Table, Char::FontId)
546//! .to(Font::Table, Font::Id)
547//! .on_delete(ForeignKeyAction::Cascade)
548//! .on_update(ForeignKeyAction::Cascade)
549//! )
550//! .to_owned();
551//!
552//! assert_eq!(
553//! table.to_string(MysqlQueryBuilder),
554//! [
555//! r#"CREATE TABLE IF NOT EXISTS `character` ("#,
556//! r#"`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,"#,
557//! r#"`font_size` int NOT NULL,"#,
558//! r#"`character` varchar(255) NOT NULL,"#,
559//! r#"`size_w` int NOT NULL,"#,
560//! r#"`size_h` int NOT NULL,"#,
561//! r#"`font_id` int DEFAULT NULL,"#,
562//! r#"CONSTRAINT `FK_2e303c3a712662f1fc2a4d0aad6`"#,
563//! r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
564//! r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
565//! r#")"#,
566//! ].join(" ")
567//! );
568//! assert_eq!(
569//! table.to_string(PostgresQueryBuilder),
570//! [
571//! r#"CREATE TABLE IF NOT EXISTS "character" ("#,
572//! r#""id" serial NOT NULL PRIMARY KEY,"#,
573//! r#""font_size" integer NOT NULL,"#,
574//! r#""character" varchar NOT NULL,"#,
575//! r#""size_w" integer NOT NULL,"#,
576//! r#""size_h" integer NOT NULL,"#,
577//! r#""font_id" integer DEFAULT NULL,"#,
578//! r#"CONSTRAINT "FK_2e303c3a712662f1fc2a4d0aad6""#,
579//! r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
580//! r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
581//! r#")"#,
582//! ].join(" ")
583//! );
584//! assert_eq!(
585//! table.to_string(SqliteQueryBuilder),
586//! [
587//! r#"CREATE TABLE IF NOT EXISTS "character" ("#,
588//! r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
589//! r#""font_size" integer NOT NULL,"#,
590//! r#""character" varchar NOT NULL,"#,
591//! r#""size_w" integer NOT NULL,"#,
592//! r#""size_h" integer NOT NULL,"#,
593//! r#""font_id" integer DEFAULT NULL,"#,
594//! r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
595//! r#")"#,
596//! ].join(" ")
597//! );
598//! ```
599//!
600//! ### Table Alter
601//!
602//! ```rust
603//! # use sea_query::{*, tests_cfg::*};
604//! let table = Table::alter()
605//! .table(Font::Table)
606//! .add_column(ColumnDef::new("new_col").integer().not_null().default(100))
607//! .to_owned();
608//!
609//! assert_eq!(
610//! table.to_string(MysqlQueryBuilder),
611//! r#"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100"#
612//! );
613//! assert_eq!(
614//! table.to_string(PostgresQueryBuilder),
615//! r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#
616//! );
617//! assert_eq!(
618//! table.to_string(SqliteQueryBuilder),
619//! r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#,
620//! );
621//! ```
622//!
623//! ### Table Drop
624//!
625//! ```rust
626//! # use sea_query::{*, tests_cfg::*};
627//! let table = Table::drop()
628//! .table(Glyph::Table)
629//! .table(Char::Table)
630//! .to_owned();
631//!
632//! assert_eq!(
633//! table.to_string(MysqlQueryBuilder),
634//! r#"DROP TABLE `glyph`, `character`"#
635//! );
636//! assert_eq!(
637//! table.to_string(PostgresQueryBuilder),
638//! r#"DROP TABLE "glyph", "character""#
639//! );
640//! assert_eq!(
641//! table.to_string(SqliteQueryBuilder),
642//! r#"DROP TABLE "glyph", "character""#
643//! );
644//! ```
645//!
646//! ### Table Rename
647//!
648//! ```rust
649//! # use sea_query::{*, tests_cfg::*};
650//! let table = Table::rename().table(Font::Table, "font_new").to_owned();
651//!
652//! assert_eq!(
653//! table.to_string(MysqlQueryBuilder),
654//! r#"RENAME TABLE `font` TO `font_new`"#
655//! );
656//! assert_eq!(
657//! table.to_string(PostgresQueryBuilder),
658//! r#"ALTER TABLE "font" RENAME TO "font_new""#
659//! );
660//! assert_eq!(
661//! table.to_string(SqliteQueryBuilder),
662//! r#"ALTER TABLE "font" RENAME TO "font_new""#
663//! );
664//! ```
665//!
666//! ### Table Truncate
667//!
668//! ```rust
669//! # use sea_query::{*, tests_cfg::*};
670//! let table = Table::truncate().table(Font::Table).to_owned();
671//!
672//! assert_eq!(
673//! table.to_string(MysqlQueryBuilder),
674//! r#"TRUNCATE TABLE `font`"#
675//! );
676//! assert_eq!(
677//! table.to_string(PostgresQueryBuilder),
678//! r#"TRUNCATE TABLE "font""#
679//! );
680//! // Sqlite does not support the TRUNCATE statement
681//! ```
682//!
683//! ### Foreign Key Create
684//!
685//! ```rust
686//! # use sea_query::{*, tests_cfg::*};
687//! let foreign_key = ForeignKey::create()
688//! .name("FK_character_font")
689//! .from(Char::Table, Char::FontId)
690//! .to(Font::Table, Font::Id)
691//! .on_delete(ForeignKeyAction::Cascade)
692//! .on_update(ForeignKeyAction::Cascade)
693//! .to_owned();
694//!
695//! assert_eq!(
696//! foreign_key.to_string(MysqlQueryBuilder),
697//! [
698//! r#"ALTER TABLE `character`"#,
699//! r#"ADD CONSTRAINT `FK_character_font`"#,
700//! r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
701//! r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
702//! ]
703//! .join(" ")
704//! );
705//! assert_eq!(
706//! foreign_key.to_string(PostgresQueryBuilder),
707//! [
708//! r#"ALTER TABLE "character" ADD CONSTRAINT "FK_character_font""#,
709//! r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
710//! r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
711//! ]
712//! .join(" ")
713//! );
714//! // Sqlite does not support modification of foreign key constraints to existing tables
715//! ```
716//!
717//! ### Foreign Key Drop
718//!
719//! ```rust
720//! # use sea_query::{*, tests_cfg::*};
721//! let foreign_key = ForeignKey::drop()
722//! .name("FK_character_font")
723//! .table(Char::Table)
724//! .to_owned();
725//!
726//! assert_eq!(
727//! foreign_key.to_string(MysqlQueryBuilder),
728//! r#"ALTER TABLE `character` DROP FOREIGN KEY `FK_character_font`"#
729//! );
730//! assert_eq!(
731//! foreign_key.to_string(PostgresQueryBuilder),
732//! r#"ALTER TABLE "character" DROP CONSTRAINT "FK_character_font""#
733//! );
734//! // Sqlite does not support modification of foreign key constraints to existing tables
735//! ```
736//!
737//! ### Index Create
738//!
739//! ```rust
740//! # use sea_query::{*, tests_cfg::*};
741//! let index = Index::create()
742//! .name("idx-glyph-aspect")
743//! .table(Glyph::Table)
744//! .col(Glyph::Aspect)
745//! .to_owned();
746//!
747//! assert_eq!(
748//! index.to_string(MysqlQueryBuilder),
749//! r#"CREATE INDEX `idx-glyph-aspect` ON `glyph` (`aspect`)"#
750//! );
751//! assert_eq!(
752//! index.to_string(PostgresQueryBuilder),
753//! r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
754//! );
755//! assert_eq!(
756//! index.to_string(SqliteQueryBuilder),
757//! r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
758//! );
759//! ```
760//!
761//! ### Index Drop
762//!
763//! ```rust
764//! # use sea_query::{*, tests_cfg::*};
765//! let index = Index::drop()
766//! .name("idx-glyph-aspect")
767//! .table(Glyph::Table)
768//! .to_owned();
769//!
770//! assert_eq!(
771//! index.to_string(MysqlQueryBuilder),
772//! r#"DROP INDEX `idx-glyph-aspect` ON `glyph`"#
773//! );
774//! assert_eq!(
775//! index.to_string(PostgresQueryBuilder),
776//! r#"DROP INDEX "idx-glyph-aspect""#
777//! );
778//! assert_eq!(
779//! index.to_string(SqliteQueryBuilder),
780//! r#"DROP INDEX "idx-glyph-aspect""#
781//! );
782//! ```
783//!
784//! ## License
785//!
786//! Licensed under either of
787//!
788//! - Apache License, Version 2.0
789//! ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
790//! - MIT license
791//! ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
792//!
793//! at your option.
794//!
795//! ## Contribution
796//!
797//! Unless you explicitly state otherwise, any contribution intentionally submitted
798//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
799//! dual licensed as above, without any additional terms or conditions.
800//!
801//! SeaQuery is a community driven project. We welcome you to participate, contribute and together build for Rust's future.
802//!
803//! A big shout out to our contributors:
804//!
805//! [](https://github.com/SeaQL/sea-query/graphs/contributors)
806#![doc(
807 html_logo_url = "https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQL icon dark.png"
808)]
809
810pub mod backend;
811pub mod error;
812pub mod expr;
813pub mod extension;
814pub mod foreign_key;
815pub mod func;
816pub mod index;
817pub mod prepare;
818pub mod query;
819pub mod schema;
820pub mod table;
821pub mod token;
822pub mod types;
823pub mod value;
824
825#[doc(hidden)]
826#[cfg(feature = "tests-cfg")]
827pub mod tests_cfg;
828
829pub use backend::*;
830pub use expr::*;
831pub use foreign_key::*;
832pub use func::*;
833pub use index::*;
834pub use prepare::*;
835pub use query::*;
836pub use schema::*;
837pub use table::*;
838pub use token::*;
839pub use types::*;
840pub use value::*;
841
842#[cfg(feature = "derive")]
843pub use sea_query_derive::{enum_def, Iden, IdenStatic};
844
845#[cfg(all(feature = "attr", not(feature = "derive")))]
846pub use sea_query_derive::enum_def;