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