{"id":14969039,"url":"https://github.com/seaql/sea-query","last_synced_at":"2026-02-08T22:10:02.389Z","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":"2025-05-07T20:45:12.000Z","size":2865,"stargazers_count":1385,"open_issues_count":83,"forks_count":206,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-11T03:45:59.713Z","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,"zenodo":null},"funding":{"github":"SeaQL"}},"created_at":"2020-12-16T03:44:23.000Z","updated_at":"2025-05-10T12:04:02.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":122,"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":253514555,"owners_count":21920334,"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-09-24T13:41:01.756Z","updated_at":"2026-02-08T22:10:02.376Z","avatar_url":"https://github.com/SeaQL.png","language":"Rust","funding_links":["https://github.com/sponsors/SeaQL"],"categories":[],"sub_categories":[],"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.\nMS SQL Server Support is available under [SeaORM X](https://www.sea-ql.org/SeaORM-X/).\n\nSeaQuery is written in 100% safe Rust. All workspace crates has `#![forbid(unsafe_code)]`.\n\nSeaQuery is the foundation of [SeaORM](https://github.com/SeaQL/sea-orm), an async \u0026 dynamic ORM for Rust.\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\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 = \"1.0.0-rc.1\"\n```\n\nSeaQuery is very lightweight, all dependencies are optional (except `inherent`).\n\n### Feature flags\n\nMacro: `derive`\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\n### 1. Parameter bindings\n\nOne of the headaches when using raw SQL is parameter binding. With SeaQuery you can inject parameters\nright alongside the expression, and the $N sequencing will be handled for you. No more \"off by one\" errors!\n\n```rust\nassert_eq!(\n    Query::select()\n        .expr(Expr::col(\"size_w\").add(1).mul(2))\n        .from(\"glyph\")\n        .and_where(Expr::col(\"image\").like(\"A\"))\n        .and_where(Expr::col(\"id\").is_in([3, 4, 5]))\n        .build(PostgresQueryBuilder),\n    (\n        r#\"SELECT (\"size_w\" + $1) * $2 FROM \"glyph\" WHERE \"image\" LIKE $3 AND \"id\" IN ($4, $5, $6)\"#\n            .to_owned(),\n        Values(vec![\n            1.into(),\n            2.into(),\n            \"A\".to_owned().into(),\n            3.into(),\n            4.into(),\n            5.into(),\n        ])\n    )\n);\n```\n\nIf you need an \"escape hatch\" to construct complex queries, you can use custom expressions,\nand still have the benefit of sequentially-binded parameters.\n\n```rust\nassert_eq!(\n    Query::select()\n        .columns([\"size_w\", \"size_h\"])\n        .from(\"character\")\n        .and_where(Expr::col(\"id\").eq(1)) // this is $1\n        // custom expressions only need to define local parameter sequence.\n        // its global sequence will be re-written.\n        // here, we flip the order of $2 \u0026 $1 to make it look tricker!\n        .and_where(Expr::cust_with_values(r#\"\"size_w\" = $2 * $1\"#, [3, 2]))\n        .and_where(Expr::col(\"size_h\").gt(4)) // this is $N?\n        .build(PostgresQueryBuilder),\n    (\n        r#\"SELECT \"size_w\", \"size_h\" FROM \"character\" WHERE \"id\" = $1 AND (\"size_w\" = $2 * $3) AND \"size_h\" \u003e $4\"#\n            .to_owned(),\n        Values(vec![1.into(), 2.into(), 3.into(), 4.into()])\n    )\n);\n```\n\n### 2. Dynamic query\n\nYou can construct the query at runtime based on user inputs with a fluent interface,\nso you don't have to append `WHERE` or `AND` conditionally.\n\n```rust\nfn query(a: Option\u003ci32\u003e, b: Option\u003cchar\u003e) -\u003e SelectStatement {\n    Query::select()\n        .column(\"id\")\n        .from(\"character\")\n        .apply_if(a, |q, v| {\n            q.and_where(Expr::col(\"font_id\").eq(v));\n        })\n        .apply_if(b, |q, v| {\n            q.and_where(Expr::col(\"ascii\").like(v));\n        })\n        .take()\n}\n\nassert_eq!(\n    query(Some(5), Some('A')).to_string(MysqlQueryBuilder),\n    \"SELECT `id` FROM `character` WHERE `font_id` = 5 AND `ascii` LIKE 'A'\"\n);\nassert_eq!(\n    query(Some(5), None).to_string(MysqlQueryBuilder),\n    \"SELECT `id` FROM `character` WHERE `font_id` = 5\"\n);\nassert_eq!(\n    query(None, None).to_string(MysqlQueryBuilder),\n    \"SELECT `id` FROM `character`\"\n);\n```\n\nConditions can be arbitrarily complex, thanks to SeaQuery's internal AST:\n\n```rust\nassert_eq!(\n    Query::select()\n        .column(\"id\")\n        .from(\"glyph\")\n        .cond_where(\n            Cond::any()\n                .add(\n                    Cond::all()\n                        .add(Expr::col(\"aspect\").is_null())\n                        .add(Expr::col(\"image\").is_null())\n                )\n                .add(\n                    Cond::all()\n                        .add(Expr::col(\"aspect\").is_in([3, 4]))\n                        .add(Expr::col(\"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 no superfluous parentheses `((((` cluttering the query, because SeaQuery respects\noperator precedence when injecting them.\n\n### 3. Cross database support\n\nWith SeaQuery, you can target multiple database backends while maintaining a single source of query logic.\n\n```rust\nlet query = Query::insert()\n    .into_table(\"glyph\")\n    .columns([\"aspect\", \"image\"])\n    .values_panic([\n        2.into(),\n        3.into(),\n    ])\n    .on_conflict(\n        OnConflict::column(\"id\")\n            .update_columns([\"aspect\", \"image\"])\n            .to_owned(),\n    )\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"INSERT INTO `glyph` (`aspect`, `image`) VALUES (2, 3) ON DUPLICATE KEY UPDATE `aspect` = VALUES(`aspect`), `image` = VALUES(`image`)\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"INSERT INTO \"glyph\" (\"aspect\", \"image\") VALUES (2, 3) ON CONFLICT (\"id\") DO UPDATE SET \"aspect\" = \"excluded\".\"aspect\", \"image\" = \"excluded\".\"image\"\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"INSERT INTO \"glyph\" (\"aspect\", \"image\") VALUES (2, 3) ON CONFLICT (\"id\") DO UPDATE SET \"aspect\" = \"excluded\".\"aspect\", \"image\" = \"excluded\".\"image\"\"#\n);\n```\n\n### 4. Improved raw SQL ergonomics\n\nSeaQuery 1.0 added a new `raw_query!` macro with named parameters, nested field access, array expansion and tuple expansion.\nIt surely will make crafting complex query easier.\n\n```rust\nlet (a, b, c) = (1, 2, \"A\");\nlet d = vec![3, 4, 5];\nlet query = sea_query::raw_query!(\n    PostgresQueryBuilder,\n    r#\"SELECT (\"size_w\" + {a}) * {b} FROM \"glyph\" WHERE \"image\" LIKE {c} AND \"id\" IN ({..d})\"#\n);\n\nassert_eq!(\n    query.sql,\n    r#\"SELECT (\"size_w\" + $1) * $2 FROM \"glyph\" WHERE \"image\" LIKE $3 AND \"id\" IN ($4, $5, $6)\"#\n);\nassert_eq!(\n    query.values,\n    Values(vec![\n        1.into(),\n        2.into(),\n        \"A\".into(),\n        3.into(),\n        4.into(),\n        5.into()\n    ])\n);\n```\n\nInsert with vector-of-tuple expansion.\n\n```rust\nlet values = vec![(2.1345, \"24B\"), (5.15, \"12A\")];\nlet query = sea_query::raw_query!(\n    PostgresQueryBuilder,\n    r#\"INSERT INTO \"glyph\" (\"aspect\", \"image\") VALUES {..(values.0:1),}\"#\n);\n\nassert_eq!(\n    query.sql,\n    r#\"INSERT INTO \"glyph\" (\"aspect\", \"image\") VALUES ($1, $2), ($3, $4)\"#\n);\nassert_eq!(\n    query.values,\n    Values(vec![2.1345.into(), \"24B\".into(), 5.15.into(), \"12A\".into()])\n);\n```\n\nUpdate with nested field access.\n\n```rust\nstruct Character {\n    id: i32,\n    font_size: u16,\n}\nlet c = Character {\n    id: 11,\n    font_size: 22,\n};\nlet query = sea_query::raw_query!(\n    MysqlQueryBuilder,\n    \"UPDATE `character` SET `font_size` = {c.font_size} WHERE `id` = {c.id}\"\n);\n\nassert_eq!(\n    query.sql,\n    \"UPDATE `character` SET `font_size` = ? WHERE `id` = ?\"\n);\nassert_eq!(query.values, Values(vec![22u16.into(), 11i32.into()]));\n```\n\n## Basics\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\nYou can use the `Iden` derive macro to implement it.\n\n```rust\n#[derive(Iden)]\nenum Character {\n    Table,\n    Id,\n    FontId,\n    FontSize,\n}\n\nassert_eq!(Character::Table.to_string(), \"character\");\nassert_eq!(Character::Id.to_string(), \"id\");\nassert_eq!(Character::FontId.to_string(), \"font_id\");\nassert_eq!(Character::FontSize.to_string(), \"font_size\");\n\n#[derive(Iden)]\nstruct Glyph;\nassert_eq!(Glyph.to_string(), \"glyph\");\n```\n\n```rust\nuse sea_query::{Iden, enum_def};\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### Expression\n\nUse [`Expr`] constructors and [`ExprTrait`] methods\nto construct `SELECT`, `JOIN`, `WHERE` and `HAVING` expression in query.\n\n```rust\nassert_eq!(\n    Query::select()\n        .column(\"char_code\")\n        .from(\"character\")\n        .and_where(\n            Expr::col(\"size_w\")\n                .add(1)\n                .mul(2)\n                .eq(Expr::col(\"size_h\").div(2).sub(1))\n        )\n        .and_where(\n            Expr::col(\"size_w\").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_code\")\n                .like(\"D\")\n                .and(Expr::col(\"char_code\").like(\"E\"))\n        )\n        .to_string(PostgresQueryBuilder),\n    [\n        r#\"SELECT \"char_code\" 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 (\"char_code\" LIKE 'D' AND \"char_code\" 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(\"id\")\n        .from(\"glyph\")\n        .cond_where(\n            Cond::any()\n                .add(\n                    Cond::all()\n                        .add(Expr::col(\"aspect\").is_null())\n                        .add(Expr::col(\"image\").is_null())\n                )\n                .add(\n                    Cond::all()\n                        .add(Expr::col(\"aspect\").is_in([3, 4]))\n                        .add(Expr::col(\"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 Statement\n\n### Query Select\n\n```rust\nlet query = Query::select()\n    .column(\"char_code\")\n    .column((\"font\", \"name\"))\n    .from(\"character\")\n    .left_join(\"font\", Expr::col((\"character\", \"font_id\")).equals((\"font\", \"id\")))\n    .and_where(Expr::col(\"size_w\").is_in([3, 4]))\n    .and_where(Expr::col(\"char_code\").like(\"A%\"))\n    .to_owned();\n\nassert_eq!(\n    query.to_string(MysqlQueryBuilder),\n    r#\"SELECT `char_code`, `font`.`name` FROM `character` LEFT JOIN `font` ON `character`.`font_id` = `font`.`id` WHERE `size_w` IN (3, 4) AND `char_code` LIKE 'A%'\"#\n);\nassert_eq!(\n    query.to_string(PostgresQueryBuilder),\n    r#\"SELECT \"char_code\", \"font\".\"name\" FROM \"character\" LEFT JOIN \"font\" ON \"character\".\"font_id\" = \"font\".\"id\" WHERE \"size_w\" IN (3, 4) AND \"char_code\" LIKE 'A%'\"#\n);\nassert_eq!(\n    query.to_string(SqliteQueryBuilder),\n    r#\"SELECT \"char_code\", \"font\".\"name\" FROM \"character\" LEFT JOIN \"font\" ON \"character\".\"font_id\" = \"font\".\"id\" WHERE \"size_w\" IN (3, 4) AND \"char_code\" LIKE 'A%'\"#\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## Advanced\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\", \"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) -\u003e \u0026str {\n        \"MY_FUNCTION\"\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## Schema Statement\n\n### Table Create\n\n```rust\nlet table = Table::create()\n    .table(\"character\")\n    .if_not_exists()\n    .col(ColumnDef::new(\"id\").integer().not_null().auto_increment().primary_key())\n    .col(ColumnDef::new(\"font_size\").integer().not_null())\n    .col(ColumnDef::new(\"character\").string().not_null())\n    .col(ColumnDef::new(\"size_w\").integer().not_null())\n    .col(ColumnDef::new(\"size_h\").integer().not_null())\n    .col(ColumnDef::new(\"font_id\").integer().default(Expr::val(1)))\n    .foreign_key(\n        ForeignKey::create()\n            .name(\"character_fk\")\n            .from(\"character\", \"font_id\")\n            .to(\"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 PRIMARY KEY AUTO_INCREMENT,\"#,\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 1,\"#,\n            r#\"CONSTRAINT `character_fk`\"#,\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\" integer GENERATED BY DEFAULT AS IDENTITY 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 1,\"#,\n            r#\"CONSTRAINT \"character_fk\"\"#,\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 1,\"#,\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(ColumnDef::new(\"new_col\").integer().not_null().default(100))\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().table(Font::Table, \"font_new\").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","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"}