{"id":13484763,"url":"https://github.com/SeaQL/sea-query","last_synced_at":"2025-03-27T16:31:16.199Z","repository":{"id":37001625,"uuid":"321860000","full_name":"SeaQL/sea-query","owner":"SeaQL","description":"🔱 A dynamic SQL query builder for MySQL, Postgres and SQLite","archived":false,"fork":false,"pushed_at":"2024-10-17T07:07:24.000Z","size":2697,"stargazers_count":1172,"open_issues_count":79,"forks_count":194,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-10-29T09:32:41.150Z","etag":null,"topics":["database","hacktoberfest","mariadb","mysql","postgres","postgresql","query-builder","rusqlite","rust","sql","sqlite","sqlx"],"latest_commit_sha":null,"homepage":"https://www.sea-ql.org","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SeaQL.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"SeaQL"}},"created_at":"2020-12-16T03:44:23.000Z","updated_at":"2024-10-28T17:35:08.000Z","dependencies_parsed_at":"2023-02-19T20:01:36.828Z","dependency_job_id":"930d5eb9-9cfe-4836-a91c-1bde179d9eff","html_url":"https://github.com/SeaQL/sea-query","commit_stats":{"total_commits":1388,"total_committers":109,"mean_commits":12.73394495412844,"dds":0.7319884726224783,"last_synced_commit":"098e88be6e286348f502aea61dcd9904c2a5bc66"},"previous_names":[],"tags_count":117,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SeaQL%2Fsea-query","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SeaQL%2Fsea-query/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SeaQL%2Fsea-query/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SeaQL%2Fsea-query/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SeaQL","download_url":"https://codeload.github.com/SeaQL/sea-query/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245526478,"owners_count":20629836,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","hacktoberfest","mariadb","mysql","postgres","postgresql","query-builder","rusqlite","rust","sql","sqlite","sqlx"],"created_at":"2024-07-31T17:01:32.832Z","updated_at":"2025-03-27T16:31:16.190Z","avatar_url":"https://github.com/SeaQL.png","language":"Rust","readme":"\u003cdiv align=\"center\"\u003e\n\n  \u003cimg src=\"https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQuery logo.png\" width=\"280\" alt=\"SeaQuery logo\"/\u003e\n\n  \u003cp\u003e\n    \u003cstrong\u003e🔱 A dynamic query builder for MySQL, Postgres and SQLite\u003c/strong\u003e\n  \u003c/p\u003e\n\n  [![crate](https://img.shields.io/crates/v/sea-query.svg)](https://crates.io/crates/sea-query)\n  [![docs](https://docs.rs/sea-query/badge.svg)](https://docs.rs/sea-query)\n  [![build status](https://github.com/SeaQL/sea-query/actions/workflows/rust.yml/badge.svg)](https://github.com/SeaQL/sea-query/actions/workflows/rust.yml)\n\n\u003c/div\u003e\n\n## SeaQuery\n\nSeaQuery is a query builder to help you construct dynamic SQL queries in Rust.\nYou can construct expressions, queries and schema as abstract syntax trees using an ergonomic API.\nWe support MySQL, Postgres and SQLite behind a common interface that aligns their behaviour where appropriate.\n\nWe provide integration for [SQLx](https://crates.io/crates/sqlx),\n[postgres](https://crates.io/crates/postgres) and [rusqlite](https://crates.io/crates/rusqlite).\nSee [examples](https://github.com/SeaQL/sea-query/blob/master/examples) for usage.\n\nSeaQuery is the foundation of [SeaORM](https://github.com/SeaQL/sea-orm), an async \u0026 dynamic ORM for Rust.\n\n[![GitHub stars](https://img.shields.io/github/stars/SeaQL/sea-query.svg?style=social\u0026label=Star\u0026maxAge=1)](https://github.com/SeaQL/sea-query/stargazers/)\nIf you like what we do, consider starring, commenting, sharing and contributing!\n\n[![Discord](https://img.shields.io/discord/873880840487206962?label=Discord)](https://discord.com/invite/uCPdDXzbdv)\nJoin our Discord server to chat with others in the SeaQL community!\n\n## Install\n\n```toml\n# Cargo.toml\n[dependencies]\nsea-query = \"0\"\n```\n\nSeaQuery is very lightweight, all dependencies are optional (except `inherent`).\n\n### Feature flags\n\nMacro: `derive`\n\nAsync support: `thread-safe` (use `Arc` inplace of `Rc`)\n\nSQL engine: `backend-mysql`, `backend-postgres`, `backend-sqlite`\n\nType support: `with-chrono`, `with-time`, `with-json`, `with-rust_decimal`, `with-bigdecimal`, `with-uuid`,\n`with-ipnetwork`, `with-mac_address`, `postgres-array`, `postgres-interval`, `postgres-vector`\n\n## Usage\n\nTable of Content\n\n1. Basics\n\n    1. [Iden](#iden)\n    1. [Expression](#expression)\n    1. [Condition](#condition)\n    1. [Statement Builders](#statement-builders)\n\n1. Query Statement\n\n    1. [Query Select](#query-select)\n    1. [Query Insert](#query-insert)\n    1. [Query Update](#query-update)\n    1. [Query Delete](#query-delete)\n\n1. Advanced\n    1. [Aggregate Functions](#aggregate-functions)\n    1. [Casting](#casting)\n    1. [Custom Function](#custom-function)\n\n1. Schema Statement\n\n    1. [Table Create](#table-create)\n    1. [Table Alter](#table-alter)\n    1. [Table Drop](#table-drop)\n    1. [Table Rename](#table-rename)\n    1. [Table Truncate](#table-truncate)\n    1. [Foreign Key Create](#foreign-key-create)\n    1. [Foreign Key Drop](#foreign-key-drop)\n    1. [Index Create](#index-create)\n    1. [Index Drop](#index-drop)\n\n### Motivation\n\nWhy would you want to use a dynamic query builder?\n\n1. Parameter bindings\n\nOne of the headaches when using raw SQL is parameter binding. With SeaQuery you can:\n\n```rust\nassert_eq!(\n    Query::select()\n        .column(Glyph::Image)\n        .from(Glyph::Table)\n        .and_where(Expr::col(Glyph::Image).like(\"A\"))\n        .and_where(Expr::col(Glyph::Id).is_in([1, 2, 3]))\n        .build(PostgresQueryBuilder),\n    (\n        r#\"SELECT \"image\" FROM \"glyph\" WHERE \"image\" LIKE $1 AND \"id\" IN ($2, $3, $4)\"#\n            .to_owned(),\n        Values(vec![\n            Value::String(Some(Box::new(\"A\".to_owned()))),\n            Value::Int(Some(1)),\n            Value::Int(Some(2)),\n            Value::Int(Some(3))\n        ])\n    )\n);\n```\n\n2. Dynamic query\n\nYou can construct the query at runtime based on user inputs:\n\n```rust\nQuery::select()\n    .column(Char::Character)\n    .from(Char::Table)\n    .conditions(\n        // some runtime condition\n        true,\n        // if condition is true then add the following condition\n        |q| {\n            q.and_where(Expr::col(Char::Id).eq(1));\n        },\n        // otherwise leave it as is\n        |q| {},\n    );\n```\n\n### Iden\n\n`Iden` is a trait for identifiers used in any query statement.\n\nCommonly implemented by Enum where each Enum represents a table found in a database,\nand its variants include table name and column name.\n\n[`Iden::unquoted()`] must be implemented to provide a mapping between Enum variants and its\ncorresponding string value.\n\n```rust\nuse sea_query::*;\n\n// For example Character table with column id, character, font_size...\npub enum Character {\n    Table,\n    Id,\n    FontId,\n    FontSize,\n}\n\n// Mapping between Enum variant and its corresponding string value\nimpl Iden for Character {\n    fn unquoted(\u0026self, s: \u0026mut dyn std::fmt::Write) {\n        write!(\n            s,\n            \"{}\",\n            match self {\n                Self::Table =\u003e \"character\",\n                Self::Id =\u003e \"id\",\n                Self::FontId =\u003e \"font_id\",\n                Self::FontSize =\u003e \"font_size\",\n            }\n        )\n        .unwrap();\n    }\n}\n```\n\nIf you're okay with running another procedural macro, you can activate\nthe `derive` feature on the crate to save you some boilerplate.\nFor more usage information, look at\n[the derive examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-derive/tests/pass).\n\n```rust\n#[cfg(feature = \"derive\")]\nuse sea_query::Iden;\n\n// This will implement Iden exactly as shown above\n#[derive(Iden)]\nenum Character {\n    Table,\n}\nassert_eq!(Character::Table.to_string(), \"character\");\n\n// You can also derive a unit struct\n#[derive(Iden)]\nstruct Glyph;\nassert_eq!(Glyph.to_string(), \"glyph\");\n```\n\n```rust\n#[cfg(feature = \"derive\")]\nuse sea_query::{enum_def, Iden};\n\n#[enum_def]\nstruct Character {\n    pub foo: u64,\n}\n\n// It generates the following along with Iden impl\nenum CharacterIden {\n    Table,\n    Foo,\n}\n\nassert_eq!(CharacterIden::Table.to_string(), \"character\");\nassert_eq!(CharacterIden::Foo.to_string(), \"foo\");\n```\n\n\n### Expression\n\nUse [`Expr`] to construct select, join, where and having expression in query.\n\n```rust\nassert_eq!(\n    Query::select()\n        .column(Char::Character)\n        .from(Char::Table)\n        .and_where(\n            Expr::expr(Expr::col(Char::SizeW).add(1))\n                .mul(2)\n                .eq(Expr::expr(Expr::col(Char::SizeH).div(2)).sub(1))\n        )\n        .and_where(\n            Expr::col(Char::SizeW).in_subquery(\n                Query::select()\n                    .expr(Expr::cust_with_values(\"ln($1 ^ $2)\", [2.4, 1.2]))\n                    .take()\n            )\n        )\n        .and_where(\n            Expr::col(Char::Character)\n                .like(\"D\")\n                .and(Expr::col(Char::Character).like(\"E\"))\n        )\n        .to_string(PostgresQueryBuilder),\n    [\n        r#\"SELECT \"character\" FROM \"character\"\"#,\n        r#\"WHERE (\"size_w\" + 1) * 2 = (\"size_h\" / 2) - 1\"#,\n        r#\"AND \"size_w\" IN (SELECT ln(2.4 ^ 1.2))\"#,\n        r#\"AND (\"character\" LIKE 'D' AND \"character\" LIKE 'E')\"#,\n    ]\n    .join(\" \")\n);\n```\n\n### Condition\n\nIf you have complex conditions to express, you can use the [`Condition`] builder,\nusable for [`ConditionalStatement::cond_where`] and [`SelectStatement::cond_having`].\n\n```rust\nassert_eq!(\n    Query::select()\n        .column(Glyph::Id)\n        .from(Glyph::Table)\n        .cond_where(\n            Cond::any()\n                .add(\n                    Cond::all()\n                        .add(Expr::col(Glyph::Aspect).is_null())\n                        .add(Expr::col(Glyph::Image).is_null())\n                )\n                .add(\n                    Cond::all()\n                        .add(Expr::col(Glyph::Aspect).is_in([3, 4]))\n                        .add(Expr::col(Glyph::Image).like(\"A%\"))\n                )\n        )\n        .to_string(PostgresQueryBuilder),\n    [\n        r#\"SELECT \"id\" FROM \"glyph\"\"#,\n        r#\"WHERE\"#,\n        r#\"(\"aspect\" IS NULL AND \"image\" IS NULL)\"#,\n        r#\"OR\"#,\n        r#\"(\"aspect\" IN (3, 4) AND \"image\" LIKE 'A%')\"#,\n    ]\n    .join(\" \")\n);\n```\n\nThere is also the [`any!`] and [`all!`] macro at your convenience:\n\n```rust\nQuery::select().cond_where(any![\n    Expr::col(Glyph::Aspect).is_in([3, 4]),\n    all![\n        Expr::col(Glyph::Aspect).is_null(),\n        Expr::col(Glyph::Image).like(\"A%\")\n    ]\n]);\n```\n\n### Statement Builders\n\nStatements are divided into 2 categories: Query and Schema, and to be serialized into SQL\nwith [`QueryStatementBuilder`] and [`SchemaStatementBuilder`] respectively.\n\nSchema statement has the following interface:\n\n```rust\nfn build\u003cT: SchemaBuilder\u003e(\u0026self, schema_builder: T) -\u003e String;\n```\n\nQuery statement has the following interfaces:\n\n```rust\nfn build\u003cT: QueryBuilder\u003e(\u0026self, query_builder: T) -\u003e (String, Values);\n\nfn to_string\u003cT: QueryBuilder\u003e(\u0026self, query_builder: T) -\u003e String;\n```\n\n`build` builds a SQL statement as string and parameters to be passed to the database driver\nthrough the binary protocol. This is the preferred way as it has less overhead and is more secure.\n\n`to_string` builds a SQL statement as string with parameters injected. This is good for testing\nand debugging.\n\n### Query Select\n\n```rust\nlet query = Query::select()\n    .column(Char::Character)\n    .column((Font::Table, Font::Name))\n    .from(Char::Table)\n    .left_join(Font::Table, Expr::col((Char::Table, Char::FontId)).equals((Font::Table, Font::Id)))\n    .and_where(Expr::col(Char::SizeW).is_in([3, 4]))\n    .and_where(Expr::col(Char::Character).like(\"A%\"))\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    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%'\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    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%'\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    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%'\"#\n);\n```\n\n### Query Insert\n\n```rust\nlet query = Query::insert()\n    .into_table(Glyph::Table)\n    .columns([Glyph::Aspect, Glyph::Image])\n    .values_panic([5.15.into(), \"12A\".into()])\n    .values_panic([4.21.into(), \"123\".into()])\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"INSERT INTO `glyph` (`aspect`, `image`) VALUES (5.15, '12A'), (4.21, '123')\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"INSERT INTO \"glyph\" (\"aspect\", \"image\") VALUES (5.15, '12A'), (4.21, '123')\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"INSERT INTO \"glyph\" (\"aspect\", \"image\") VALUES (5.15, '12A'), (4.21, '123')\"#\n);\n```\n\n### Query Update\n\n```rust\nlet query = Query::update()\n    .table(Glyph::Table)\n    .values([(Glyph::Aspect, 1.23.into()), (Glyph::Image, \"123\".into())])\n    .and_where(Expr::col(Glyph::Id).eq(1))\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"UPDATE `glyph` SET `aspect` = 1.23, `image` = '123' WHERE `id` = 1\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"UPDATE \"glyph\" SET \"aspect\" = 1.23, \"image\" = '123' WHERE \"id\" = 1\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"UPDATE \"glyph\" SET \"aspect\" = 1.23, \"image\" = '123' WHERE \"id\" = 1\"#\n);\n```\n\n### Query Delete\n\n```rust\nlet query = Query::delete()\n    .from_table(Glyph::Table)\n    .cond_where(\n        Cond::any()\n            .add(Expr::col(Glyph::Id).lt(1))\n            .add(Expr::col(Glyph::Id).gt(10)),\n    )\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"DELETE FROM `glyph` WHERE `id` \u003c 1 OR `id` \u003e 10\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"DELETE FROM \"glyph\" WHERE \"id\" \u003c 1 OR \"id\" \u003e 10\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"DELETE FROM \"glyph\" WHERE \"id\" \u003c 1 OR \"id\" \u003e 10\"#\n);\n```\n\n### Aggregate Functions\n\n`max`, `min`, `sum`, `avg`, `count` etc\n\n```rust\nlet query = Query::select()\n    .expr(Func::sum(Expr::col((Char::Table, Char::SizeH))))\n    .from(Char::Table)\n    .to_owned();\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"SELECT SUM(`character`.`size_h`) FROM `character`\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"SELECT SUM(\"character\".\"size_h\") FROM \"character\"\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"SELECT SUM(\"character\".\"size_h\") FROM \"character\"\"#\n);\n```\n\n### Casting\n\n```rust\nlet query = Query::select()\n    .expr(Func::cast_as(\"hello\", Alias::new(\"MyType\")))\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"SELECT CAST('hello' AS MyType)\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"SELECT CAST('hello' AS MyType)\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"SELECT CAST('hello' AS MyType)\"#\n);\n```\n\n### Custom Function\n\n```rust\nstruct MyFunction;\n\nimpl Iden for MyFunction {\n    fn unquoted(\u0026self, s: \u0026mut dyn Write) {\n        write!(s, \"MY_FUNCTION\").unwrap();\n    }\n}\n\nlet query = Query::select()\n    .expr(Func::cust(MyFunction).arg(Expr::val(\"hello\")))\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"SELECT MY_FUNCTION('hello')\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"SELECT MY_FUNCTION('hello')\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"SELECT MY_FUNCTION('hello')\"#\n);\n```\n\n### Table Create\n\n```rust\nlet table = Table::create()\n    .table(Char::Table)\n    .if_not_exists()\n    .col(ColumnDef::new(Char::Id).integer().not_null().auto_increment().primary_key())\n    .col(ColumnDef::new(Char::FontSize).integer().not_null())\n    .col(ColumnDef::new(Char::Character).string().not_null())\n    .col(ColumnDef::new(Char::SizeW).integer().not_null())\n    .col(ColumnDef::new(Char::SizeH).integer().not_null())\n    .col(ColumnDef::new(Char::FontId).integer().default(Value::Int(None)))\n    .foreign_key(\n        ForeignKey::create()\n            .name(\"FK_2e303c3a712662f1fc2a4d0aad6\")\n            .from(Char::Table, Char::FontId)\n            .to(Font::Table, Font::Id)\n            .on_delete(ForeignKeyAction::Cascade)\n            .on_update(ForeignKeyAction::Cascade)\n    )\n    .to_owned();\n\nassert_eq!(\n    table.to_string(MysqlQueryBuilder),\n    [\n        r#\"CREATE TABLE IF NOT EXISTS `character` (\"#,\n            r#\"`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,\"#,\n            r#\"`font_size` int NOT NULL,\"#,\n            r#\"`character` varchar(255) NOT NULL,\"#,\n            r#\"`size_w` int NOT NULL,\"#,\n            r#\"`size_h` int NOT NULL,\"#,\n            r#\"`font_id` int DEFAULT NULL,\"#,\n            r#\"CONSTRAINT `FK_2e303c3a712662f1fc2a4d0aad6`\"#,\n                r#\"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)\"#,\n                r#\"ON DELETE CASCADE ON UPDATE CASCADE\"#,\n        r#\")\"#,\n    ].join(\" \")\n);\nassert_eq!(\n    table.to_string(PostgresQueryBuilder),\n    [\n        r#\"CREATE TABLE IF NOT EXISTS \"character\" (\"#,\n            r#\"\"id\" serial NOT NULL PRIMARY KEY,\"#,\n            r#\"\"font_size\" integer NOT NULL,\"#,\n            r#\"\"character\" varchar NOT NULL,\"#,\n            r#\"\"size_w\" integer NOT NULL,\"#,\n            r#\"\"size_h\" integer NOT NULL,\"#,\n            r#\"\"font_id\" integer DEFAULT NULL,\"#,\n            r#\"CONSTRAINT \"FK_2e303c3a712662f1fc2a4d0aad6\"\"#,\n                r#\"FOREIGN KEY (\"font_id\") REFERENCES \"font\" (\"id\")\"#,\n                r#\"ON DELETE CASCADE ON UPDATE CASCADE\"#,\n        r#\")\"#,\n    ].join(\" \")\n);\nassert_eq!(\n    table.to_string(SqliteQueryBuilder),\n    [\n       r#\"CREATE TABLE IF NOT EXISTS \"character\" (\"#,\n           r#\"\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT,\"#,\n           r#\"\"font_size\" integer NOT NULL,\"#,\n           r#\"\"character\" varchar NOT NULL,\"#,\n           r#\"\"size_w\" integer NOT NULL,\"#,\n           r#\"\"size_h\" integer NOT NULL,\"#,\n           r#\"\"font_id\" integer DEFAULT NULL,\"#,\n           r#\"FOREIGN KEY (\"font_id\") REFERENCES \"font\" (\"id\") ON DELETE CASCADE ON UPDATE CASCADE\"#,\n       r#\")\"#,\n    ].join(\" \")\n);\n```\n\n### Table Alter\n\n```rust\nlet table = Table::alter()\n    .table(Font::Table)\n    .add_column(\n        ColumnDef::new(Alias::new(\"new_col\"))\n            .integer()\n            .not_null()\n            .default(100),\n    )\n    .to_owned();\n\nassert_eq!(\n    table.to_string(MysqlQueryBuilder),\n    r#\"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100\"#\n);\nassert_eq!(\n    table.to_string(PostgresQueryBuilder),\n    r#\"ALTER TABLE \"font\" ADD COLUMN \"new_col\" integer NOT NULL DEFAULT 100\"#\n);\nassert_eq!(\n    table.to_string(SqliteQueryBuilder),\n    r#\"ALTER TABLE \"font\" ADD COLUMN \"new_col\" integer NOT NULL DEFAULT 100\"#,\n);\n```\n\n### Table Drop\n\n```rust\nlet table = Table::drop()\n    .table(Glyph::Table)\n    .table(Char::Table)\n    .to_owned();\n\nassert_eq!(\n    table.to_string(MysqlQueryBuilder),\n    r#\"DROP TABLE `glyph`, `character`\"#\n);\nassert_eq!(\n    table.to_string(PostgresQueryBuilder),\n    r#\"DROP TABLE \"glyph\", \"character\"\"#\n);\nassert_eq!(\n    table.to_string(SqliteQueryBuilder),\n    r#\"DROP TABLE \"glyph\", \"character\"\"#\n);\n```\n\n### Table Rename\n\n```rust\nlet table = Table::rename()\n    .table(Font::Table, Alias::new(\"font_new\"))\n    .to_owned();\n\nassert_eq!(\n    table.to_string(MysqlQueryBuilder),\n    r#\"RENAME TABLE `font` TO `font_new`\"#\n);\nassert_eq!(\n    table.to_string(PostgresQueryBuilder),\n    r#\"ALTER TABLE \"font\" RENAME TO \"font_new\"\"#\n);\nassert_eq!(\n    table.to_string(SqliteQueryBuilder),\n    r#\"ALTER TABLE \"font\" RENAME TO \"font_new\"\"#\n);\n```\n\n### Table Truncate\n\n```rust\nlet table = Table::truncate().table(Font::Table).to_owned();\n\nassert_eq!(\n    table.to_string(MysqlQueryBuilder),\n    r#\"TRUNCATE TABLE `font`\"#\n);\nassert_eq!(\n    table.to_string(PostgresQueryBuilder),\n    r#\"TRUNCATE TABLE \"font\"\"#\n);\n// Sqlite does not support the TRUNCATE statement\n```\n\n### Foreign Key Create\n\n```rust\nlet foreign_key = ForeignKey::create()\n    .name(\"FK_character_font\")\n    .from(Char::Table, Char::FontId)\n    .to(Font::Table, Font::Id)\n    .on_delete(ForeignKeyAction::Cascade)\n    .on_update(ForeignKeyAction::Cascade)\n    .to_owned();\n\nassert_eq!(\n    foreign_key.to_string(MysqlQueryBuilder),\n    [\n        r#\"ALTER TABLE `character`\"#,\n        r#\"ADD CONSTRAINT `FK_character_font`\"#,\n        r#\"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)\"#,\n        r#\"ON DELETE CASCADE ON UPDATE CASCADE\"#,\n    ]\n    .join(\" \")\n);\nassert_eq!(\n    foreign_key.to_string(PostgresQueryBuilder),\n    [\n        r#\"ALTER TABLE \"character\" ADD CONSTRAINT \"FK_character_font\"\"#,\n        r#\"FOREIGN KEY (\"font_id\") REFERENCES \"font\" (\"id\")\"#,\n        r#\"ON DELETE CASCADE ON UPDATE CASCADE\"#,\n    ]\n    .join(\" \")\n);\n// Sqlite does not support modification of foreign key constraints to existing tables\n```\n\n### Foreign Key Drop\n\n```rust\nlet foreign_key = ForeignKey::drop()\n    .name(\"FK_character_font\")\n    .table(Char::Table)\n    .to_owned();\n\nassert_eq!(\n    foreign_key.to_string(MysqlQueryBuilder),\n    r#\"ALTER TABLE `character` DROP FOREIGN KEY `FK_character_font`\"#\n);\nassert_eq!(\n    foreign_key.to_string(PostgresQueryBuilder),\n    r#\"ALTER TABLE \"character\" DROP CONSTRAINT \"FK_character_font\"\"#\n);\n// Sqlite does not support modification of foreign key constraints to existing tables\n```\n\n### Index Create\n\n```rust\nlet index = Index::create()\n    .name(\"idx-glyph-aspect\")\n    .table(Glyph::Table)\n    .col(Glyph::Aspect)\n    .to_owned();\n\nassert_eq!(\n    index.to_string(MysqlQueryBuilder),\n    r#\"CREATE INDEX `idx-glyph-aspect` ON `glyph` (`aspect`)\"#\n);\nassert_eq!(\n    index.to_string(PostgresQueryBuilder),\n    r#\"CREATE INDEX \"idx-glyph-aspect\" ON \"glyph\" (\"aspect\")\"#\n);\nassert_eq!(\n    index.to_string(SqliteQueryBuilder),\n    r#\"CREATE INDEX \"idx-glyph-aspect\" ON \"glyph\" (\"aspect\")\"#\n);\n```\n\n### Index Drop\n\n```rust\nlet index = Index::drop()\n    .name(\"idx-glyph-aspect\")\n    .table(Glyph::Table)\n    .to_owned();\n\nassert_eq!(\n    index.to_string(MysqlQueryBuilder),\n    r#\"DROP INDEX `idx-glyph-aspect` ON `glyph`\"#\n);\nassert_eq!(\n    index.to_string(PostgresQueryBuilder),\n    r#\"DROP INDEX \"idx-glyph-aspect\"\"#\n);\nassert_eq!(\n    index.to_string(SqliteQueryBuilder),\n    r#\"DROP INDEX \"idx-glyph-aspect\"\"#\n);\n```\n\n## License\n\nLicensed under either of\n\n-   Apache License, Version 2.0\n    ([LICENSE-APACHE](LICENSE-APACHE) or \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n-   MIT license\n    ([LICENSE-MIT](LICENSE-MIT) or \u003chttp://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\n## Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\ndual licensed as above, without any additional terms or conditions.\n\nSeaQuery is a community driven project. We welcome you to participate, contribute and together build for Rust's future.\n\nA big shout out to our contributors:\n\n[![Contributors](https://opencollective.com/sea-query/contributors.svg?width=1000\u0026button=false)](https://github.com/SeaQL/sea-query/graphs/contributors)\n","funding_links":["https://github.com/sponsors/SeaQL"],"categories":["Rust","库 Libraries","Libraries","Database libraries","sqlite"],"sub_categories":["数据库 Database","Database"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSeaQL%2Fsea-query","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSeaQL%2Fsea-query","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSeaQL%2Fsea-query/lists"}