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//!   [![crate](https://img.shields.io/crates/v/sea-query.svg)](https://crates.io/crates/sea-query)
13//!   [![docs](https://docs.rs/sea-query/badge.svg)](https://docs.rs/sea-query)
14//!   [![build status](https://github.com/SeaQL/sea-query/actions/workflows/rust.yml/badge.svg)](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//! [![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/)
31//! If you like what we do, consider starring, commenting, sharing and contributing!
32//!
33//! [![Discord](https://img.shields.io/discord/873880840487206962?label=Discord)](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`] to construct select, join, where and having expression in query.
233//!
234//! ```rust
235//! # use sea_query::{*, tests_cfg::*};
236//! assert_eq!(
237//!     Query::select()
238//!         .column(Char::Character)
239//!         .from(Char::Table)
240//!         .and_where(
241//!             Expr::expr(Expr::col(Char::SizeW).add(1))
242//!                 .mul(2)
243//!                 .eq(Expr::expr(Expr::col(Char::SizeH).div(2)).sub(1))
244//!         )
245//!         .and_where(
246//!             Expr::col(Char::SizeW).in_subquery(
247//!                 Query::select()
248//!                     .expr(Expr::cust_with_values("ln($1 ^ $2)", [2.4, 1.2]))
249//!                     .take()
250//!             )
251//!         )
252//!         .and_where(
253//!             Expr::col(Char::Character)
254//!                 .like("D")
255//!                 .and(Expr::col(Char::Character).like("E"))
256//!         )
257//!         .to_string(PostgresQueryBuilder),
258//!     [
259//!         r#"SELECT "character" FROM "character""#,
260//!         r#"WHERE ("size_w" + 1) * 2 = ("size_h" / 2) - 1"#,
261//!         r#"AND "size_w" IN (SELECT ln(2.4 ^ 1.2))"#,
262//!         r#"AND ("character" LIKE 'D' AND "character" LIKE 'E')"#,
263//!     ]
264//!     .join(" ")
265//! );
266//! ```
267//!
268//! ### Condition
269//!
270//! If you have complex conditions to express, you can use the [`Condition`] builder,
271//! usable for [`ConditionalStatement::cond_where`] and [`SelectStatement::cond_having`].
272//!
273//! ```
274//! # use sea_query::{*, tests_cfg::*};
275//! assert_eq!(
276//!     Query::select()
277//!         .column(Glyph::Id)
278//!         .from(Glyph::Table)
279//!         .cond_where(
280//!             Cond::any()
281//!                 .add(
282//!                     Cond::all()
283//!                         .add(Expr::col(Glyph::Aspect).is_null())
284//!                         .add(Expr::col(Glyph::Image).is_null())
285//!                 )
286//!                 .add(
287//!                     Cond::all()
288//!                         .add(Expr::col(Glyph::Aspect).is_in([3, 4]))
289//!                         .add(Expr::col(Glyph::Image).like("A%"))
290//!                 )
291//!         )
292//!         .to_string(PostgresQueryBuilder),
293//!     [
294//!         r#"SELECT "id" FROM "glyph""#,
295//!         r#"WHERE"#,
296//!         r#"("aspect" IS NULL AND "image" IS NULL)"#,
297//!         r#"OR"#,
298//!         r#"("aspect" IN (3, 4) AND "image" LIKE 'A%')"#,
299//!     ]
300//!     .join(" ")
301//! );
302//! ```
303//!
304//! There is also the [`any!`] and [`all!`] macro at your convenience:
305//!
306//! ```
307//! # use sea_query::{*, tests_cfg::*};
308//! Query::select().cond_where(any![
309//!     Expr::col(Glyph::Aspect).is_in([3, 4]),
310//!     all![
311//!         Expr::col(Glyph::Aspect).is_null(),
312//!         Expr::col(Glyph::Image).like("A%")
313//!     ]
314//! ]);
315//! ```
316//!
317//! ### Statement Builders
318//!
319//! Statements are divided into 2 categories: Query and Schema, and to be serialized into SQL
320//! with [`QueryStatementBuilder`] and [`SchemaStatementBuilder`] respectively.
321//!
322//! Schema statement has the following interface:
323//!
324//! ```rust
325//! # use sea_query::{*};
326//! # trait ExampleSchemaBuilder {
327//! fn build<T: SchemaBuilder>(&self, schema_builder: T) -> String;
328//! # }
329//! ```
330//!
331//! Query statement has the following interfaces:
332//!
333//! ```rust
334//! # use sea_query::{*};
335//! # trait ExampleQueryBuilder {
336//! fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values);
337//!
338//! fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String;
339//! # }
340//! ```
341//!
342//! `build` builds a SQL statement as string and parameters to be passed to the database driver
343//! through the binary protocol. This is the preferred way as it has less overhead and is more secure.
344//!
345//! `to_string` builds a SQL statement as string with parameters injected. This is good for testing
346//! and debugging.
347//!
348//! ### Query Select
349//!
350//! ```rust
351//! # use sea_query::{*, tests_cfg::*};
352//! let query = Query::select()
353//!     .column(Char::Character)
354//!     .column((Font::Table, Font::Name))
355//!     .from(Char::Table)
356//!     .left_join(Font::Table, Expr::col((Char::Table, Char::FontId)).equals((Font::Table, Font::Id)))
357//!     .and_where(Expr::col(Char::SizeW).is_in([3, 4]))
358//!     .and_where(Expr::col(Char::Character).like("A%"))
359//!     .to_owned();
360//!
361//! assert_eq!(
362//!     query.to_string(MysqlQueryBuilder),
363//!     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%'"#
364//! );
365//! assert_eq!(
366//!     query.to_string(PostgresQueryBuilder),
367//!     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%'"#
368//! );
369//! assert_eq!(
370//!     query.to_string(SqliteQueryBuilder),
371//!     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%'"#
372//! );
373//! ```
374//!
375//! ### Query Insert
376//!
377//! ```rust
378//! # use sea_query::{*, tests_cfg::*};
379//! let query = Query::insert()
380//!     .into_table(Glyph::Table)
381//!     .columns([Glyph::Aspect, Glyph::Image])
382//!     .values_panic([5.15.into(), "12A".into()])
383//!     .values_panic([4.21.into(), "123".into()])
384//!     .to_owned();
385//!
386//! assert_eq!(
387//!     query.to_string(MysqlQueryBuilder),
388//!     r#"INSERT INTO `glyph` (`aspect`, `image`) VALUES (5.15, '12A'), (4.21, '123')"#
389//! );
390//! assert_eq!(
391//!     query.to_string(PostgresQueryBuilder),
392//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
393//! );
394//! assert_eq!(
395//!     query.to_string(SqliteQueryBuilder),
396//!     r#"INSERT INTO "glyph" ("aspect", "image") VALUES (5.15, '12A'), (4.21, '123')"#
397//! );
398//! ```
399//!
400//! ### Query Update
401//!
402//! ```rust
403//! # use sea_query::{*, tests_cfg::*};
404//! let query = Query::update()
405//!     .table(Glyph::Table)
406//!     .values([(Glyph::Aspect, 1.23.into()), (Glyph::Image, "123".into())])
407//!     .and_where(Expr::col(Glyph::Id).eq(1))
408//!     .to_owned();
409//!
410//! assert_eq!(
411//!     query.to_string(MysqlQueryBuilder),
412//!     r#"UPDATE `glyph` SET `aspect` = 1.23, `image` = '123' WHERE `id` = 1"#
413//! );
414//! assert_eq!(
415//!     query.to_string(PostgresQueryBuilder),
416//!     r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
417//! );
418//! assert_eq!(
419//!     query.to_string(SqliteQueryBuilder),
420//!     r#"UPDATE "glyph" SET "aspect" = 1.23, "image" = '123' WHERE "id" = 1"#
421//! );
422//! ```
423//!
424//! ### Query Delete
425//!
426//! ```rust
427//! # use sea_query::{*, tests_cfg::*};
428//! let query = Query::delete()
429//!     .from_table(Glyph::Table)
430//!     .cond_where(
431//!         Cond::any()
432//!             .add(Expr::col(Glyph::Id).lt(1))
433//!             .add(Expr::col(Glyph::Id).gt(10)),
434//!     )
435//!     .to_owned();
436//!
437//! assert_eq!(
438//!     query.to_string(MysqlQueryBuilder),
439//!     r#"DELETE FROM `glyph` WHERE `id` < 1 OR `id` > 10"#
440//! );
441//! assert_eq!(
442//!     query.to_string(PostgresQueryBuilder),
443//!     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
444//! );
445//! assert_eq!(
446//!     query.to_string(SqliteQueryBuilder),
447//!     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
448//! );
449//! ```
450//!
451//! ### Aggregate Functions
452//!
453//! `max`, `min`, `sum`, `avg`, `count` etc
454//!
455//! ```rust
456//! # use sea_query::{*, tests_cfg::*};
457//! let query = Query::select()
458//!     .expr(Func::sum(Expr::col((Char::Table, Char::SizeH))))
459//!     .from(Char::Table)
460//!     .to_owned();
461//! assert_eq!(
462//!     query.to_string(MysqlQueryBuilder),
463//!     r#"SELECT SUM(`character`.`size_h`) FROM `character`"#
464//! );
465//! assert_eq!(
466//!     query.to_string(PostgresQueryBuilder),
467//!     r#"SELECT SUM("character"."size_h") FROM "character""#
468//! );
469//! assert_eq!(
470//!     query.to_string(SqliteQueryBuilder),
471//!     r#"SELECT SUM("character"."size_h") FROM "character""#
472//! );
473//! ```
474//!
475//! ### Casting
476//!
477//! ```rust
478//! # use sea_query::{*, tests_cfg::*};
479//! let query = Query::select()
480//!     .expr(Func::cast_as("hello", Alias::new("MyType")))
481//!     .to_owned();
482//!
483//! assert_eq!(
484//!     query.to_string(MysqlQueryBuilder),
485//!     r#"SELECT CAST('hello' AS MyType)"#
486//! );
487//! assert_eq!(
488//!     query.to_string(PostgresQueryBuilder),
489//!     r#"SELECT CAST('hello' AS MyType)"#
490//! );
491//! assert_eq!(
492//!     query.to_string(SqliteQueryBuilder),
493//!     r#"SELECT CAST('hello' AS MyType)"#
494//! );
495//! ```
496//!
497//! ### Custom Function
498//!
499//! ```rust
500//! # use sea_query::{*, tests_cfg::*};
501//! struct MyFunction;
502//!
503//! impl Iden for MyFunction {
504//!     fn unquoted(&self, s: &mut dyn Write) {
505//!         write!(s, "MY_FUNCTION").unwrap();
506//!     }
507//! }
508//!
509//! let query = Query::select()
510//!     .expr(Func::cust(MyFunction).arg(Expr::val("hello")))
511//!     .to_owned();
512//!
513//! assert_eq!(
514//!     query.to_string(MysqlQueryBuilder),
515//!     r#"SELECT MY_FUNCTION('hello')"#
516//! );
517//! assert_eq!(
518//!     query.to_string(PostgresQueryBuilder),
519//!     r#"SELECT MY_FUNCTION('hello')"#
520//! );
521//! assert_eq!(
522//!     query.to_string(SqliteQueryBuilder),
523//!     r#"SELECT MY_FUNCTION('hello')"#
524//! );
525//! ```
526//!
527//! ### Table Create
528//!
529//! ```rust
530//! # use sea_query::{*, tests_cfg::*};
531//! let table = Table::create()
532//!     .table(Char::Table)
533//!     .if_not_exists()
534//!     .col(ColumnDef::new(Char::Id).integer().not_null().auto_increment().primary_key())
535//!     .col(ColumnDef::new(Char::FontSize).integer().not_null())
536//!     .col(ColumnDef::new(Char::Character).string().not_null())
537//!     .col(ColumnDef::new(Char::SizeW).integer().not_null())
538//!     .col(ColumnDef::new(Char::SizeH).integer().not_null())
539//!     .col(ColumnDef::new(Char::FontId).integer().default(Value::Int(None)))
540//!     .foreign_key(
541//!         ForeignKey::create()
542//!             .name("FK_2e303c3a712662f1fc2a4d0aad6")
543//!             .from(Char::Table, Char::FontId)
544//!             .to(Font::Table, Font::Id)
545//!             .on_delete(ForeignKeyAction::Cascade)
546//!             .on_update(ForeignKeyAction::Cascade)
547//!     )
548//!     .to_owned();
549//!
550//! assert_eq!(
551//!     table.to_string(MysqlQueryBuilder),
552//!     [
553//!         r#"CREATE TABLE IF NOT EXISTS `character` ("#,
554//!             r#"`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,"#,
555//!             r#"`font_size` int NOT NULL,"#,
556//!             r#"`character` varchar(255) NOT NULL,"#,
557//!             r#"`size_w` int NOT NULL,"#,
558//!             r#"`size_h` int NOT NULL,"#,
559//!             r#"`font_id` int DEFAULT NULL,"#,
560//!             r#"CONSTRAINT `FK_2e303c3a712662f1fc2a4d0aad6`"#,
561//!                 r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
562//!                 r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
563//!         r#")"#,
564//!     ].join(" ")
565//! );
566//! assert_eq!(
567//!     table.to_string(PostgresQueryBuilder),
568//!     [
569//!         r#"CREATE TABLE IF NOT EXISTS "character" ("#,
570//!             r#""id" serial NOT NULL PRIMARY KEY,"#,
571//!             r#""font_size" integer NOT NULL,"#,
572//!             r#""character" varchar NOT NULL,"#,
573//!             r#""size_w" integer NOT NULL,"#,
574//!             r#""size_h" integer NOT NULL,"#,
575//!             r#""font_id" integer DEFAULT NULL,"#,
576//!             r#"CONSTRAINT "FK_2e303c3a712662f1fc2a4d0aad6""#,
577//!                 r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
578//!                 r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
579//!         r#")"#,
580//!     ].join(" ")
581//! );
582//! assert_eq!(
583//!     table.to_string(SqliteQueryBuilder),
584//!     [
585//!        r#"CREATE TABLE IF NOT EXISTS "character" ("#,
586//!            r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
587//!            r#""font_size" integer NOT NULL,"#,
588//!            r#""character" varchar NOT NULL,"#,
589//!            r#""size_w" integer NOT NULL,"#,
590//!            r#""size_h" integer NOT NULL,"#,
591//!            r#""font_id" integer DEFAULT NULL,"#,
592//!            r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
593//!        r#")"#,
594//!     ].join(" ")
595//! );
596//! ```
597//!
598//! ### Table Alter
599//!
600//! ```rust
601//! # use sea_query::{*, tests_cfg::*};
602//! let table = Table::alter()
603//!     .table(Font::Table)
604//!     .add_column(
605//!         ColumnDef::new(Alias::new("new_col"))
606//!             .integer()
607//!             .not_null()
608//!             .default(100),
609//!     )
610//!     .to_owned();
611//!
612//! assert_eq!(
613//!     table.to_string(MysqlQueryBuilder),
614//!     r#"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100"#
615//! );
616//! assert_eq!(
617//!     table.to_string(PostgresQueryBuilder),
618//!     r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#
619//! );
620//! assert_eq!(
621//!     table.to_string(SqliteQueryBuilder),
622//!     r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#,
623//! );
624//! ```
625//!
626//! ### Table Drop
627//!
628//! ```rust
629//! # use sea_query::{*, tests_cfg::*};
630//! let table = Table::drop()
631//!     .table(Glyph::Table)
632//!     .table(Char::Table)
633//!     .to_owned();
634//!
635//! assert_eq!(
636//!     table.to_string(MysqlQueryBuilder),
637//!     r#"DROP TABLE `glyph`, `character`"#
638//! );
639//! assert_eq!(
640//!     table.to_string(PostgresQueryBuilder),
641//!     r#"DROP TABLE "glyph", "character""#
642//! );
643//! assert_eq!(
644//!     table.to_string(SqliteQueryBuilder),
645//!     r#"DROP TABLE "glyph", "character""#
646//! );
647//! ```
648//!
649//! ### Table Rename
650//!
651//! ```rust
652//! # use sea_query::{*, tests_cfg::*};
653//! let table = Table::rename()
654//!     .table(Font::Table, Alias::new("font_new"))
655//!     .to_owned();
656//!
657//! assert_eq!(
658//!     table.to_string(MysqlQueryBuilder),
659//!     r#"RENAME TABLE `font` TO `font_new`"#
660//! );
661//! assert_eq!(
662//!     table.to_string(PostgresQueryBuilder),
663//!     r#"ALTER TABLE "font" RENAME TO "font_new""#
664//! );
665//! assert_eq!(
666//!     table.to_string(SqliteQueryBuilder),
667//!     r#"ALTER TABLE "font" RENAME TO "font_new""#
668//! );
669//! ```
670//!
671//! ### Table Truncate
672//!
673//! ```rust
674//! # use sea_query::{*, tests_cfg::*};
675//! let table = Table::truncate().table(Font::Table).to_owned();
676//!
677//! assert_eq!(
678//!     table.to_string(MysqlQueryBuilder),
679//!     r#"TRUNCATE TABLE `font`"#
680//! );
681//! assert_eq!(
682//!     table.to_string(PostgresQueryBuilder),
683//!     r#"TRUNCATE TABLE "font""#
684//! );
685//! // Sqlite does not support the TRUNCATE statement
686//! ```
687//!
688//! ### Foreign Key Create
689//!
690//! ```rust
691//! # use sea_query::{*, tests_cfg::*};
692//! let foreign_key = ForeignKey::create()
693//!     .name("FK_character_font")
694//!     .from(Char::Table, Char::FontId)
695//!     .to(Font::Table, Font::Id)
696//!     .on_delete(ForeignKeyAction::Cascade)
697//!     .on_update(ForeignKeyAction::Cascade)
698//!     .to_owned();
699//!
700//! assert_eq!(
701//!     foreign_key.to_string(MysqlQueryBuilder),
702//!     [
703//!         r#"ALTER TABLE `character`"#,
704//!         r#"ADD CONSTRAINT `FK_character_font`"#,
705//!         r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
706//!         r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
707//!     ]
708//!     .join(" ")
709//! );
710//! assert_eq!(
711//!     foreign_key.to_string(PostgresQueryBuilder),
712//!     [
713//!         r#"ALTER TABLE "character" ADD CONSTRAINT "FK_character_font""#,
714//!         r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
715//!         r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
716//!     ]
717//!     .join(" ")
718//! );
719//! // Sqlite does not support modification of foreign key constraints to existing tables
720//! ```
721//!
722//! ### Foreign Key Drop
723//!
724//! ```rust
725//! # use sea_query::{*, tests_cfg::*};
726//! let foreign_key = ForeignKey::drop()
727//!     .name("FK_character_font")
728//!     .table(Char::Table)
729//!     .to_owned();
730//!
731//! assert_eq!(
732//!     foreign_key.to_string(MysqlQueryBuilder),
733//!     r#"ALTER TABLE `character` DROP FOREIGN KEY `FK_character_font`"#
734//! );
735//! assert_eq!(
736//!     foreign_key.to_string(PostgresQueryBuilder),
737//!     r#"ALTER TABLE "character" DROP CONSTRAINT "FK_character_font""#
738//! );
739//! // Sqlite does not support modification of foreign key constraints to existing tables
740//! ```
741//!
742//! ### Index Create
743//!
744//! ```rust
745//! # use sea_query::{*, tests_cfg::*};
746//! let index = Index::create()
747//!     .name("idx-glyph-aspect")
748//!     .table(Glyph::Table)
749//!     .col(Glyph::Aspect)
750//!     .to_owned();
751//!
752//! assert_eq!(
753//!     index.to_string(MysqlQueryBuilder),
754//!     r#"CREATE INDEX `idx-glyph-aspect` ON `glyph` (`aspect`)"#
755//! );
756//! assert_eq!(
757//!     index.to_string(PostgresQueryBuilder),
758//!     r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
759//! );
760//! assert_eq!(
761//!     index.to_string(SqliteQueryBuilder),
762//!     r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
763//! );
764//! ```
765//!
766//! ### Index Drop
767//!
768//! ```rust
769//! # use sea_query::{*, tests_cfg::*};
770//! let index = Index::drop()
771//!     .name("idx-glyph-aspect")
772//!     .table(Glyph::Table)
773//!     .to_owned();
774//!
775//! assert_eq!(
776//!     index.to_string(MysqlQueryBuilder),
777//!     r#"DROP INDEX `idx-glyph-aspect` ON `glyph`"#
778//! );
779//! assert_eq!(
780//!     index.to_string(PostgresQueryBuilder),
781//!     r#"DROP INDEX "idx-glyph-aspect""#
782//! );
783//! assert_eq!(
784//!     index.to_string(SqliteQueryBuilder),
785//!     r#"DROP INDEX "idx-glyph-aspect""#
786//! );
787//! ```
788//!
789//! ## License
790//!
791//! Licensed under either of
792//!
793//! -   Apache License, Version 2.0
794//!     ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
795//! -   MIT license
796//!     ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
797//!
798//! at your option.
799//!
800//! ## Contribution
801//!
802//! Unless you explicitly state otherwise, any contribution intentionally submitted
803//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
804//! dual licensed as above, without any additional terms or conditions.
805//!
806//! SeaQuery is a community driven project. We welcome you to participate, contribute and together build for Rust's future.
807//!
808//! A big shout out to our contributors:
809//!
810//! [![Contributors](https://opencollective.com/sea-query/contributors.svg?width=1000&button=false)](https://github.com/SeaQL/sea-query/graphs/contributors)
811#![doc(
812    html_logo_url = "https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQL icon dark.png"
813)]
814
815pub mod backend;
816pub mod error;
817pub mod expr;
818pub mod extension;
819pub mod foreign_key;
820pub mod func;
821pub mod index;
822pub mod prepare;
823pub mod query;
824pub mod schema;
825pub mod table;
826pub mod token;
827pub mod types;
828pub mod value;
829
830#[doc(hidden)]
831#[cfg(feature = "tests-cfg")]
832pub mod tests_cfg;
833
834pub use backend::*;
835pub use expr::*;
836pub use foreign_key::*;
837pub use func::*;
838pub use index::*;
839pub use prepare::*;
840pub use query::*;
841pub use schema::*;
842pub use table::*;
843pub use token::*;
844pub use types::*;
845pub use value::*;
846
847#[cfg(feature = "derive")]
848pub use sea_query_derive::{enum_def, Iden, IdenStatic};
849
850#[cfg(all(feature = "attr", not(feature = "derive")))]
851pub use sea_query_derive::enum_def;