Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
use sea_query::Iden;
/// Representation of a database table named `BloB`.
///
/// A `Enum` implemented [`Iden`] used in rustdoc and test to demonstrate the library usage.
///
/// [`Iden`]: crate::types::Iden
#[derive(Debug)]
#[allow(dead_code)]
pub enum BinaryType {
Table,
BinaryLen,
Binary,
BlobSize,
TinyBlob,
Blob,
MediumBlob,
LongBlob,
}
impl Iden for BinaryType {
fn unquoted(&self) -> &str {
match self {
Self::Table => "binary_type",
Self::BinaryLen => "binlen",
Self::Binary => "bin",
Self::BlobSize => "defb",
Self::TinyBlob => "tb",
Self::Blob => "b",
Self::MediumBlob => "mb",
Self::LongBlob => "lb",
}
}
}
+79
View File
@@ -0,0 +1,79 @@
use sea_query::*;
#[test]
fn derive_1() {
#[derive(Debug, Iden)]
enum User {
Table,
Id,
FirstName,
LastName,
Email,
}
println!("Default field names");
assert_eq!(Iden::to_string(&User::Table), "user");
assert_eq!(Iden::to_string(&User::Id), "id");
assert_eq!(Iden::to_string(&User::FirstName), "first_name");
assert_eq!(Iden::to_string(&User::LastName), "last_name");
assert_eq!(Iden::to_string(&User::Email), "email");
}
#[test]
fn derive_2() {
#[derive(Debug, Iden)]
// Outer iden attributes overrides what's used for "Table"...
#[iden = "user"]
enum Custom {
Table,
#[iden = "my_id"]
Id,
#[iden = "name"]
FirstName,
#[iden = "surname"]
LastName,
// Custom casing if needed
#[iden = "EMail"]
Email,
}
println!("Custom field names");
assert_eq!(Iden::to_string(&Custom::Table), "user");
assert_eq!(Iden::to_string(&Custom::Id), "my_id");
assert_eq!(Iden::to_string(&Custom::FirstName), "name");
assert_eq!(Iden::to_string(&Custom::LastName), "surname");
assert_eq!(Iden::to_string(&Custom::Email), "EMail");
}
#[test]
fn derive_3() {
#[derive(Debug, Iden)]
enum Something {
// ...the Table can also be overwritten like this
#[iden = "something_else"]
Table,
Id,
AssetName,
UserId,
}
println!("Single custom field name");
assert_eq!(Iden::to_string(&Something::Table), "something_else");
assert_eq!(Iden::to_string(&Something::Id), "id");
assert_eq!(Iden::to_string(&Something::AssetName), "asset_name");
assert_eq!(Iden::to_string(&Something::UserId), "user_id");
}
#[test]
fn derive_4() {
#[derive(Debug, Iden)]
pub struct SomeType;
#[derive(Debug, Iden)]
#[iden = "another_name"]
pub struct CustomName;
println!("Unit structs");
assert_eq!(Iden::to_string(&SomeType), "some_type");
assert_eq!(Iden::to_string(&CustomName), "another_name");
}
+19
View File
@@ -0,0 +1,19 @@
use sea_query::{error::*, tests_cfg::*, *};
#[test]
fn insert_values_1() {
let mut insert = Query::insert();
let result = insert
.into_table(Glyph::Table)
.columns([Glyph::Image, Glyph::Aspect])
.values([String::from("").into()]);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
Error::ColValNumMismatch {
col_len: 2,
val_len: 1,
}
);
}
@@ -0,0 +1,59 @@
use sea_query::{Cond, Expr, ExprTrait, MysqlQueryBuilder, Query, tests_cfg::Glyph};
#[test]
fn test_more_parentheses() {
let query = Query::select()
.column(Glyph::Image)
.from(Glyph::Table)
.cond_where(Cond::all())
.cond_where(Expr::val(1).eq(1))
.cond_where(Expr::val(2).eq(2))
.cond_where(Cond::any().add(Expr::val(3).eq(3)).add(Expr::val(4).eq(4)))
.to_owned();
assert_eq!(
query.to_string(MysqlQueryBuilder),
"SELECT `image` FROM `glyph` WHERE (1 = 1) AND (2 = 2) AND ((3 = 3) OR (4 = 4))"
);
}
#[test]
fn test_more_parentheses_complex() {
// Add pagination
let mut pagination = Cond::all();
let lt_value = Expr::col(Glyph::Aspect)
.lt(1)
.or(Expr::col(Glyph::Aspect).is_null());
let lt_id = Expr::col(Glyph::Aspect)
.is(1)
.and(Expr::col(Glyph::Id).lt(10));
pagination = pagination.add(lt_value.or(lt_id));
// Add filtering
let mut all = Cond::all();
all = all.add(Expr::col(Glyph::Image).eq("png"));
let mut nested = Cond::all();
nested = nested.add(Expr::col(Glyph::Table).gte(5));
nested = nested.add(Expr::col(Glyph::Tokens).lte(3));
all = all.add(nested);
let mut any = Cond::any();
any = any.add(Expr::col(Glyph::Image).like("%.jpg"));
any = any.add(all);
let filtering = any;
// Query
let query = Query::select()
.column(Glyph::Id)
.from(Glyph::Table)
.cond_where(Cond::all())
.cond_where(pagination)
.cond_where(filtering)
.to_owned();
assert_eq!(
query.to_string(MysqlQueryBuilder),
"SELECT `id` FROM `glyph` WHERE ((`aspect` < 1) OR (`aspect` IS NULL) OR ((`aspect` IS 1) AND (`id` < 10))) AND ((`image` LIKE '%.jpg') OR ((`image` = 'png') AND ((`glyph` >= 5) AND (`tokens` <= 3))))"
);
}
+106
View File
@@ -0,0 +1,106 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn explain_mysql_select_with_format() {
assert_eq!(
ExplainStatement::new()
.format(ExplainFormat::Json)
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(MysqlQueryBuilder),
"EXPLAIN FORMAT = JSON SELECT `character` FROM `character`"
);
}
#[test]
fn explain_mysql_analyze_tree() {
assert_eq!(
ExplainStatement::new()
.analyze()
.format(ExplainFormat::Tree)
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(MysqlQueryBuilder),
"EXPLAIN ANALYZE FORMAT = TREE SELECT `character` FROM `character`"
);
}
#[test]
fn explain_mysql_describe_table_column() {
assert_eq!(
ExplainStatement::table_with_column(Char::Table, Char::SizeW).to_string(MysqlQueryBuilder),
"EXPLAIN `character` `size_w`"
);
}
#[test]
fn explain_mysql_for_connection() {
assert_eq!(
ExplainStatement::new()
.for_connection(123)
.to_string(MysqlQueryBuilder),
"EXPLAIN FOR CONNECTION 123"
);
assert_eq!(
ExplainStatement::new()
.format(ExplainFormat::Json)
.into_variable("@foo")
.for_connection(123)
.to_string(MysqlQueryBuilder),
"EXPLAIN FORMAT = JSON INTO @foo FOR CONNECTION 123"
);
}
#[test]
fn explain_mysql_for_schema_database() {
assert_eq!(
ExplainStatement::new()
.for_schema("s1")
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(MysqlQueryBuilder),
"EXPLAIN FOR SCHEMA `s1` SELECT `character` FROM `character`"
);
assert_eq!(
ExplainStatement::new()
.for_database("db1")
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(MysqlQueryBuilder),
"EXPLAIN FOR DATABASE `db1` SELECT `character` FROM `character`"
);
}
#[test]
fn explain_mysql_into_variable() {
assert_eq!(
ExplainStatement::new()
.format(ExplainFormat::Json)
.into_variable("@plan")
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(MysqlQueryBuilder),
"EXPLAIN FORMAT = JSON INTO @plan SELECT `character` FROM `character`"
);
}
@@ -0,0 +1,33 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
ForeignKey::create()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
.to_string(MysqlQueryBuilder),
[
"ALTER TABLE `character`",
"ADD CONSTRAINT `FK_2e303c3a712662f1fc2a4d0aad6`",
"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)",
"ON DELETE CASCADE ON UPDATE CASCADE",
]
.join(" ")
);
}
#[test]
fn drop_1() {
assert_eq!(
ForeignKey::drop()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.table(Char::Table)
.to_string(MysqlQueryBuilder),
"ALTER TABLE `character` DROP FOREIGN KEY `FK_2e303c3a712662f1fc2a4d0aad6`"
);
}
+108
View File
@@ -0,0 +1,108 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
Index::create()
.name("idx-glyph-aspect")
.table(Glyph::Table)
.col(Glyph::Aspect)
.to_string(MysqlQueryBuilder),
"CREATE INDEX `idx-glyph-aspect` ON `glyph` (`aspect`)"
);
}
#[test]
fn create_2() {
assert_eq!(
Index::create()
.unique()
.name("idx-glyph-aspect-image")
.table(Glyph::Table)
.col(Glyph::Aspect)
.col(Glyph::Image)
.to_string(MysqlQueryBuilder),
"CREATE UNIQUE INDEX `idx-glyph-aspect-image` ON `glyph` (`aspect`, `image`)"
);
}
#[test]
fn create_3() {
assert_eq!(
Index::create()
.full_text()
.name("idx-glyph-image")
.table(Glyph::Table)
.col(Glyph::Image)
.to_string(MysqlQueryBuilder),
"CREATE FULLTEXT INDEX `idx-glyph-image` ON `glyph` (`image`)"
);
}
#[test]
fn create_4() {
assert_eq!(
Index::create()
.index_type(IndexType::Hash)
.name("idx-glyph-image")
.table(Glyph::Table)
.col(Glyph::Image)
.to_string(MysqlQueryBuilder),
"CREATE INDEX `idx-glyph-image` ON `glyph` (`image`) USING HASH"
);
}
#[test]
fn create_5() {
assert_eq!(
Index::create()
.name("idx-character-area")
.table(Character::Table)
.col(Expr::col(Character::SizeH).mul(Expr::col(Character::SizeW)))
.to_string(MysqlQueryBuilder),
"CREATE INDEX `idx-character-area` ON `character` ((`size_h` * `size_w`))"
)
}
#[test]
fn create_6() {
assert_eq!(
Index::create()
.name("idx-character-character-area-desc-created_at")
.table(Character::Table)
.col(Func::upper(Expr::col(Character::Character)))
.col((
Expr::col(Character::SizeH).mul(Expr::col(Character::SizeW)),
IndexOrder::Desc,
))
.col(Character::CreatedAt)
.to_string(MysqlQueryBuilder),
"CREATE INDEX `idx-character-character-area-desc-created_at` ON `character` ((UPPER(`character`)), (`size_h` * `size_w`) DESC, `created_at`)"
)
}
#[test]
fn create_7() {
assert_eq!(
Index::create()
.unique()
.name("idx-glyph-image-primary")
.table(Glyph::Table)
.col(Glyph::Image)
.cond_where(Expr::col(Glyph::Aspect).is_not_null())
.to_string(MysqlQueryBuilder),
"CREATE UNIQUE INDEX `idx-glyph-image-primary` ON `glyph` (`image`) WHERE `aspect` IS NOT NULL"
)
}
#[test]
fn drop_1() {
assert_eq!(
Index::drop()
.name("idx-glyph-aspect")
.table(Glyph::Table)
.to_string(MysqlQueryBuilder),
"DROP INDEX `idx-glyph-aspect` ON `glyph`"
);
}
+11
View File
@@ -0,0 +1,11 @@
use sea_query::{extension::mysql::*, tests_cfg::*, *};
mod explain;
mod foreign_key;
mod index;
mod query;
mod table;
#[path = "../common.rs"]
mod common;
use common::*;
File diff suppressed because it is too large Load Diff
+584
View File
@@ -0,0 +1,584 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Glyph::Aspect).double().not_null())
.col(ColumnDef::new(Glyph::Image).text())
.engine("InnoDB")
.character_set("utf8mb4")
.collate("utf8mb4_unicode_ci")
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE `glyph` (",
"`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,",
"`aspect` double NOT NULL,",
"`image` text",
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
]
.join(" ")
);
}
#[test]
fn create_2() {
assert_eq!(
Table::create()
.table(Font::Table)
.col(
ColumnDef::new(Font::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Font::Name).string().not_null())
.col(ColumnDef::new(Font::Variant).string_len(255).not_null())
.col(ColumnDef::new(Font::Language).string_len(1024).not_null())
.engine("InnoDB")
.character_set("utf8mb4")
.collate("utf8mb4_unicode_ci")
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE `font` (",
"`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,",
"`name` varchar(255) NOT NULL,",
"`variant` varchar(255) NOT NULL,",
"`language` varchar(1024) NOT NULL",
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
]
.join(" ")
);
}
#[test]
fn create_3() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string_len(255).not_null())
.col(ColumnDef::new(Char::SizeW).unsigned().not_null())
.col(ColumnDef::new(Char::SizeH).unsigned().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None))
)
.col(
ColumnDef::new(Char::CreatedAt)
.timestamp()
.default(Expr::current_timestamp())
.not_null()
)
.foreign_key(
ForeignKey::create()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Restrict)
)
.engine("InnoDB")
.character_set("utf8mb4")
.collate("utf8mb4_unicode_ci")
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE IF NOT EXISTS `character` (",
"`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,",
"`font_size` int NOT NULL,",
"`character` varchar(255) NOT NULL,",
"`size_w` int UNSIGNED NOT NULL,",
"`size_h` int UNSIGNED NOT NULL,",
"`font_id` int DEFAULT NULL,",
"`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,",
"CONSTRAINT `FK_2e303c3a712662f1fc2a4d0aad6`",
"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)",
"ON DELETE CASCADE ON UPDATE RESTRICT",
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
]
.join(" ")
);
}
#[test]
fn create_4() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.extra("ANYTHING I WANT TO SAY".to_owned())
)
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE `glyph` (",
"`id` int NOT NULL ANYTHING I WANT TO SAY",
")",
]
.join(" ")
);
}
#[test]
fn create_5() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.index(Index::create().unique().name("idx-glyph-id").col(Glyph::Id))
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE `glyph` (",
"`id` int NOT NULL,",
"UNIQUE KEY `idx-glyph-id` (`id`)",
")",
]
.join(" ")
);
}
#[test]
fn create_6() {
assert_eq!(
Table::create()
.table(BinaryType::Table)
.col(ColumnDef::new(BinaryType::BinaryLen).binary_len(32))
.col(ColumnDef::new(BinaryType::Binary).binary())
.col(ColumnDef::new(BinaryType::Blob).blob())
.col(ColumnDef::new(BinaryType::TinyBlob).custom(MySqlType::TinyBlob))
.col(ColumnDef::new(BinaryType::MediumBlob).custom(MySqlType::MediumBlob))
.col(ColumnDef::new(BinaryType::LongBlob).custom(MySqlType::LongBlob))
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE `binary_type` (",
"`binlen` binary(32),",
"`bin` binary(1),",
"`b` blob,",
"`tb` tinyblob,",
"`mb` mediumblob,",
"`lb` longblob",
")",
]
.join(" ")
);
}
#[test]
fn create_7() {
assert_eq!(
Table::create()
.table(Char::Table)
.col(ColumnDef::new(BinaryType::Blob).blob())
.col(ColumnDef::new(Char::Character).binary())
.col(ColumnDef::new(Char::FontSize).binary_len(10))
.col(ColumnDef::new(Char::SizeW).var_binary(10))
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE `character` (",
"`b` blob,",
"`character` binary(1),",
"`font_size` binary(10),",
"`size_w` varbinary(10)",
")",
]
.join(" ")
);
}
#[test]
fn create_8() {
assert_eq!(
Table::create()
.table(Font::Table)
.col(ColumnDef::new(Font::Variant).year())
.to_string(MysqlQueryBuilder),
"CREATE TABLE `font` ( `variant` year )"
);
}
#[test]
fn create_9() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.index(Index::create().name("idx-glyph-id").col(Glyph::Id))
.to_string(MysqlQueryBuilder),
"CREATE TABLE `glyph` ( KEY `idx-glyph-id` (`id`) )"
);
}
#[test]
fn create_10() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).enumeration("tea", ["EverydayTea", "BreakfastTea"]),)
.to_string(MysqlQueryBuilder),
"CREATE TABLE `glyph` ( `id` ENUM('EverydayTea', 'BreakfastTea') )"
);
}
#[test]
fn create_11() {
assert_eq!(
Table::create()
.table(Font::Table)
.temporary()
.col(
ColumnDef::new(Font::Id)
.integer()
.not_null()
.primary_key()
.auto_increment()
)
.col(ColumnDef::new(Font::Name).string().not_null())
.to_string(MysqlQueryBuilder),
[
r#"CREATE TEMPORARY TABLE `font` ("#,
r#"`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,"#,
r#"`name` varchar(255) NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_12() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string_len(255).not_null())
.col(ColumnDef::new(Char::SizeW).unsigned().not_null())
.col(ColumnDef::new(Char::SizeH).unsigned().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.col(
ColumnDef::new(Char::CreatedAt)
.timestamp()
.default(Expr::current_timestamp())
.not_null(),
)
.index(
Index::create()
.name("idx-character-area")
.table(Character::Table)
.col(Expr::col(Character::SizeH).mul(Expr::col(Character::SizeW))),
)
.engine("InnoDB")
.character_set("utf8mb4")
.collate("utf8mb4_unicode_ci")
.to_string(MysqlQueryBuilder),
[
"CREATE TABLE IF NOT EXISTS `character` (",
"`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,",
"`font_size` int NOT NULL,",
"`character` varchar(255) NOT NULL,",
"`size_w` int UNSIGNED NOT NULL,",
"`size_h` int UNSIGNED NOT NULL,",
"`font_id` int DEFAULT NULL,",
"`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,",
"KEY `idx-character-area` ((`size_h` * `size_w`))",
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
]
.join(" ")
);
}
#[test]
fn drop_1() {
assert_eq!(
Table::drop()
.table(Glyph::Table)
.table(Char::Table)
.cascade()
.to_string(MysqlQueryBuilder),
"DROP TABLE `glyph`, `character` CASCADE"
);
}
#[test]
fn truncate_1() {
assert_eq!(
Table::truncate()
.table(Font::Table)
.to_string(MysqlQueryBuilder),
"TRUNCATE TABLE `font`"
);
}
#[test]
fn create_13() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.col(ColumnDef::new(Glyph::Image).string().not_null())
.index(
Index::create()
.unique()
.name("idx-glyph-image-primary")
.col(Glyph::Image)
.cond_where(Expr::col(Glyph::Aspect).is_not_null()),
)
.to_string(MysqlQueryBuilder),
"CREATE TABLE `glyph` ( `id` int NOT NULL, `image` varchar(255) NOT NULL, UNIQUE KEY `idx-glyph-image-primary` (`image`) WHERE `aspect` IS NOT NULL )"
);
}
#[test]
fn alter_1() {
assert_eq!(
Table::alter()
.table(Font::Table)
.add_column(ColumnDef::new("new_col").integer().not_null().default(100))
.to_string(MysqlQueryBuilder),
"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100"
);
}
#[test]
fn alter_2() {
assert_eq!(
Table::alter()
.table(Font::Table)
.modify_column(ColumnDef::new("new_col").big_integer().default(999))
.to_string(MysqlQueryBuilder),
"ALTER TABLE `font` MODIFY COLUMN `new_col` bigint DEFAULT 999"
);
}
#[test]
fn alter_3() {
assert_eq!(
Table::alter()
.table(Font::Table)
.rename_column("new_col", "new_column")
.to_string(MysqlQueryBuilder),
"ALTER TABLE `font` RENAME COLUMN `new_col` TO `new_column`"
);
}
#[test]
fn alter_4() {
assert_eq!(
Table::alter()
.table(Font::Table)
.drop_column("new_column")
.to_string(MysqlQueryBuilder),
"ALTER TABLE `font` DROP COLUMN `new_column`"
);
}
#[test]
fn alter_5() {
assert_eq!(
Table::rename()
.table(Font::Table, "font_new")
.to_string(MysqlQueryBuilder),
"RENAME TABLE `font` TO `font_new`"
);
}
#[test]
#[should_panic(expected = "No alter option found")]
fn alter_6() {
Table::alter().to_string(MysqlQueryBuilder);
}
#[test]
fn alter_7() {
assert_eq!(
Table::alter()
.table(Font::Table)
.drop_column("new_column")
.rename_column(Font::Name, "name_new")
.to_string(MysqlQueryBuilder),
"ALTER TABLE `font` DROP COLUMN `new_column`, RENAME COLUMN `name` TO `name_new`"
);
}
#[test]
fn create_with_check_constraint() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.check(Expr::col(Glyph::Id).gt(10))
)
.check(Expr::col(Glyph::Id).lt(20))
.check(Expr::col(Glyph::Id).ne(15))
.to_string(MysqlQueryBuilder),
r"CREATE TABLE `glyph` ( `id` int NOT NULL CHECK (`id` > 10), CHECK (`id` < 20), CHECK (`id` <> 15) )",
);
}
#[test]
fn create_with_named_check_constraint() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.check(("positive_id", Expr::col(Glyph::Id).gt(10)))
)
.check(("id_range", Expr::col(Glyph::Id).lt(20)))
.check(Expr::col(Glyph::Id).ne(15))
.to_string(MysqlQueryBuilder),
r"CREATE TABLE `glyph` ( `id` int NOT NULL CONSTRAINT `positive_id` CHECK (`id` > 10), CONSTRAINT `id_range` CHECK (`id` < 20), CHECK (`id` <> 15) )",
);
}
#[test]
fn alter_with_check_constraint() {
assert_eq!(
Table::alter()
.table(Glyph::Table)
.add_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.not_null()
.default(101)
.check(Expr::col(Glyph::Aspect).gt(100))
)
.to_string(MysqlQueryBuilder),
r"ALTER TABLE `glyph` ADD COLUMN `aspect` int NOT NULL DEFAULT 101 CHECK (`aspect` > 100)",
);
}
#[test]
fn alter_with_named_check_constraint() {
assert_eq!(
Table::alter()
.table(Glyph::Table)
.add_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.not_null()
.default(101)
.check(("positive_aspect", Expr::col(Glyph::Aspect).gt(100)))
)
.to_string(MysqlQueryBuilder),
r#"ALTER TABLE `glyph` ADD COLUMN `aspect` int NOT NULL DEFAULT 101 CONSTRAINT `positive_aspect` CHECK (`aspect` > 100)"#,
);
}
#[test]
fn create_partition_range() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.partition_by_range([Glyph::Id])
.add_partition(
Alias::new("p0"),
Some(PartitionValues::LessThan(vec![6.into()]))
)
.add_partition(
Alias::new("p1"),
Some(PartitionValues::LessThan(vec![11.into()]))
)
.to_string(MysqlQueryBuilder),
"CREATE TABLE `glyph` ( `id` int NOT NULL ) PARTITION BY RANGE (`id`) ( PARTITION `p0` VALUES LESS THAN (6), PARTITION `p1` VALUES LESS THAN (11) )"
);
}
#[test]
fn create_partition_list() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.partition_by_list([Glyph::Id])
.add_partition(
Alias::new("p0"),
Some(PartitionValues::In(vec![1.into(), 2.into()]))
)
.add_partition(
Alias::new("p1"),
Some(PartitionValues::In(vec![3.into(), 4.into()]))
)
.to_string(MysqlQueryBuilder),
"CREATE TABLE `glyph` ( `id` int NOT NULL ) PARTITION BY LIST (`id`) ( PARTITION `p0` VALUES IN (1, 2), PARTITION `p1` VALUES IN (3, 4) )"
);
}
#[test]
fn create_partition_hash() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.partition_by_hash([Glyph::Id])
.to_string(MysqlQueryBuilder),
"CREATE TABLE `glyph` ( `id` int NOT NULL ) PARTITION BY HASH (`id`)"
);
}
#[test]
fn create_partition_key() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.partition_by_key([Glyph::Id])
.to_string(MysqlQueryBuilder),
"CREATE TABLE `glyph` ( `id` int NOT NULL ) PARTITION BY KEY (`id`)"
);
}
#[test]
#[should_panic(expected = "MySQL does not support VALUES FROM ... TO")]
fn create_partition_values_from_to_panics() {
Table::create()
.table(Glyph::Table)
.values_from_to([1], [10])
.to_string(MysqlQueryBuilder);
}
#[test]
#[should_panic(expected = "MySQL does not support VALUES WITH")]
fn create_partition_values_with_panics() {
Table::create()
.table(Glyph::Table)
.values_with(4, 0)
.to_string(MysqlQueryBuilder);
}
@@ -0,0 +1,77 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn explain_postgres_select_with_options() {
assert_eq!(
ExplainStatement::new()
.analyze()
.verbose(false)
.costs(true)
.settings(false)
.generic_plan(true)
.buffers(true)
.serialize_text()
.wal(true)
.timing(false)
.summary(true)
.memory(true)
.format(ExplainFormat::Json)
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(PostgresQueryBuilder),
r#"EXPLAIN (ANALYZE, VERBOSE 0, COSTS, SETTINGS 0, GENERIC_PLAN, BUFFERS, SERIALIZE TEXT, WAL, TIMING 0, SUMMARY, MEMORY, FORMAT JSON) SELECT "character" FROM "character""#
);
}
#[test]
fn explain_postgres_serialize_text() {
assert_eq!(
ExplainStatement::new()
.serialize_text()
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(PostgresQueryBuilder),
r#"EXPLAIN (SERIALIZE TEXT) SELECT "character" FROM "character""#
);
}
#[test]
fn explain_postgres_serialize_binary() {
assert_eq!(
ExplainStatement::new()
.serialize_binary()
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(PostgresQueryBuilder),
r#"EXPLAIN (SERIALIZE BINARY) SELECT "character" FROM "character""#
);
}
#[test]
fn explain_postgres_serialize_none() {
assert_eq!(
ExplainStatement::new()
.serialize_none()
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(PostgresQueryBuilder),
r#"EXPLAIN (SERIALIZE NONE) SELECT "character" FROM "character""#
);
}
@@ -0,0 +1,62 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
ForeignKey::create()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
.to_string(PostgresQueryBuilder),
[
r#"ALTER TABLE "character" ADD CONSTRAINT "FK_2e303c3a712662f1fc2a4d0aad6""#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
]
.join(" ")
);
}
#[test]
fn create_2() {
assert_eq!(
ForeignKey::create()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.from(("schema", Char::Table), Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
.to_string(PostgresQueryBuilder),
[
r#"ALTER TABLE "schema"."character" ADD CONSTRAINT "FK_2e303c3a712662f1fc2a4d0aad6""#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
]
.join(" ")
);
}
#[test]
fn drop_1() {
assert_eq!(
ForeignKey::drop()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.table(Char::Table)
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "character" DROP CONSTRAINT "FK_2e303c3a712662f1fc2a4d0aad6""#
);
}
#[test]
fn drop_2() {
assert_eq!(
ForeignKey::drop()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.table(("schema", Char::Table))
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "schema"."character" DROP CONSTRAINT "FK_2e303c3a712662f1fc2a4d0aad6""#
);
}
+227
View File
@@ -0,0 +1,227 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
Index::create()
.name("idx-glyph-aspect")
.table(Glyph::Table)
.col(Glyph::Aspect)
.to_string(PostgresQueryBuilder),
r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
);
}
#[test]
fn create_2() {
assert_eq!(
Index::create()
.unique()
.name("idx-glyph-aspect-image")
.table(Glyph::Table)
.col(Glyph::Aspect)
.col(Glyph::Image)
.to_string(PostgresQueryBuilder),
r#"CREATE UNIQUE INDEX "idx-glyph-aspect-image" ON "glyph" ("aspect", "image")"#
);
}
#[test]
fn create_3() {
assert_eq!(
Index::create()
.full_text()
.name("idx-glyph-image")
.table(Glyph::Table)
.col(Glyph::Image)
.to_string(PostgresQueryBuilder),
r#"CREATE INDEX "idx-glyph-image" ON "glyph" USING GIN ("image")"#
);
}
#[test]
fn create_4() {
assert_eq!(
Index::create()
.full_text()
.name("idx-glyph-image")
.concurrently()
.table(Glyph::Table)
.col(Glyph::Image)
.to_string(PostgresQueryBuilder),
r#"CREATE INDEX CONCURRENTLY "idx-glyph-image" ON "glyph" USING GIN ("image")"#
);
}
#[test]
fn create_5() {
assert_eq!(
Index::create()
.if_not_exists()
.full_text()
.name("idx-glyph-image")
.table(Glyph::Table)
.col(Glyph::Image)
.to_string(PostgresQueryBuilder),
r#"CREATE INDEX IF NOT EXISTS "idx-glyph-image" ON "glyph" USING GIN ("image")"#
);
}
#[test]
fn create_6() {
assert_eq!(
Index::create()
.unique()
.name("idx-glyph-aspect-image")
.table(("schema", Glyph::Table))
.col(Glyph::Aspect)
.col(Glyph::Image)
.to_string(PostgresQueryBuilder),
r#"CREATE UNIQUE INDEX "idx-glyph-aspect-image" ON "schema"."glyph" ("aspect", "image")"#
);
}
#[test]
fn create_7() {
assert_eq!(
Index::create()
.unique()
.nulls_not_distinct()
.name("idx-glyph-aspect-image")
.table(Glyph::Table)
.col(Glyph::Aspect)
.col(Glyph::Image)
.to_string(PostgresQueryBuilder),
r#"CREATE UNIQUE INDEX "idx-glyph-aspect-image" ON "glyph" ("aspect", "image") NULLS NOT DISTINCT"#
);
}
#[test]
fn create_8() {
assert_eq!(
Index::create()
.unique()
.nulls_not_distinct()
.name("partial-index-glyph-image-not-null")
.table(Glyph::Table)
.col(Glyph::Image)
.and_where(Expr::col(Glyph::Image).is_not_null())
.to_string(PostgresQueryBuilder),
r#"CREATE UNIQUE INDEX "partial-index-glyph-image-not-null" ON "glyph" ("image") NULLS NOT DISTINCT WHERE "image" IS NOT NULL"#
);
}
#[test]
fn create_9() {
assert_eq!(
Index::create()
.name("idx-font-name-include-id-language")
.table(Font::Table)
.col(Font::Name)
.include(Font::Id)
.include(Font::Language)
.unique()
.nulls_not_distinct()
.to_string(PostgresQueryBuilder),
r#"CREATE UNIQUE INDEX "idx-font-name-include-id-language" ON "font" ("name") INCLUDE ("id", "language") NULLS NOT DISTINCT"#
);
}
#[test]
fn create_10() {
assert_eq!(
Index::create()
.name("idx-character-area")
.table(Character::Table)
.col(Expr::col(Character::SizeH).mul(Expr::col(Character::SizeW)))
.to_string(PostgresQueryBuilder),
r#"CREATE INDEX "idx-character-area" ON "character" (("size_h" * "size_w"))"#
)
}
#[test]
fn create_11() {
assert_eq!(
Index::create()
.name("idx-character-character-area-desc-created_at")
.table(Character::Table)
.col(Func::upper(Expr::col(Character::Character)))
.col((
Expr::col(Character::SizeH).mul(Expr::col(Character::SizeW)),
IndexOrder::Desc,
))
.col(Character::CreatedAt)
.to_string(PostgresQueryBuilder),
r#"CREATE INDEX "idx-character-character-area-desc-created_at" ON "character" ((UPPER("character")), ("size_h" * "size_w") DESC, "created_at")"#
)
}
#[test]
fn create_12() {
assert_eq!(
Index::create()
.if_not_exists()
.name("idx-glyph-image")
.table(Glyph::Table)
.col(
Glyph::Image
.into_index_column()
.with_operator_class("text_pattern_ops")
)
.to_string(PostgresQueryBuilder),
r#"CREATE INDEX IF NOT EXISTS "idx-glyph-image" ON "glyph" ("image" text_pattern_ops)"#
);
}
#[test]
fn drop_1() {
assert_eq!(
Index::drop()
.name("idx-glyph-aspect")
.to_string(PostgresQueryBuilder),
r#"DROP INDEX "idx-glyph-aspect""#
);
}
#[test]
fn drop_2() {
assert_eq!(
Index::drop()
.name("idx-glyph-aspect")
.concurrently()
.to_string(PostgresQueryBuilder),
r#"DROP INDEX CONCURRENTLY "idx-glyph-aspect""#
);
}
#[test]
fn drop_3() {
assert_eq!(
Index::drop()
.name("idx-glyph-aspect")
.table(("schema", Glyph::Table))
.to_string(PostgresQueryBuilder),
r#"DROP INDEX "schema"."idx-glyph-aspect""#
);
}
#[test]
fn drop_4() {
assert_eq!(
Index::drop()
.name("idx-glyph-aspect")
.table(Glyph::Table)
.to_string(PostgresQueryBuilder),
r#"DROP INDEX "idx-glyph-aspect""#
);
}
#[test]
#[should_panic(expected = "Not supported")]
fn drop_5() {
Index::drop()
.name("idx-glyph-aspect")
.table(("database", "schema", Glyph::Table))
.to_string(PostgresQueryBuilder);
}
@@ -0,0 +1,126 @@
use super::*;
use pretty_assertions::assert_eq;
use sea_query::extension::postgres::{PgFunc, json_table as pg_json_table};
#[test]
fn json_table_basic_columns() {
let query = Query::select()
.from_function(
PgFunc::json_table(
Expr::val(r#"[{"name": "John", "age": 30}, {"name": "Jane", "age": 25}]"#),
"$[*]",
)
.for_ordinality("row_number")
.column(pg_json_table::Column::new("name", "text").path("$.name"))
.column(pg_json_table::Column::new("age", "int").path("$.age"))
.build(),
"people",
)
.column("*")
.to_owned();
assert_eq!(
query.to_string(PostgresQueryBuilder),
r#"SELECT "*" FROM JSON_TABLE('[{"name": "John", "age": 30}, {"name": "Jane", "age": 25}]', '$[*]' COLUMNS (row_number FOR ORDINALITY, name "text" PATH '$.name', age "int" PATH '$.age')) AS "people""#
);
}
#[test]
fn json_table_passing_and_error_handling() {
let query = Query::select()
.from_function(
PgFunc::json_table(
Expr::val(r#"{"users": [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]}"#),
"$.users[*] ? (@.id > $min_id)",
)
.passing(0, "min_id")
.column(
pg_json_table::Column::new("user_id", "int")
.path("$.id")
.null_on_error(),
)
.column(
pg_json_table::Column::new("user_name", "text")
.path("$.name")
.default_on_empty(Expr::val("Unknown")),
)
.error_on_error()
.build(),
"filtered_users",
)
.column("*")
.to_owned();
assert_eq!(
query.to_string(PostgresQueryBuilder),
r#"SELECT "*" FROM JSON_TABLE('{"users": [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]}', '$.users[*] ? (@.id > $min_id)' PASSING 0 AS min_id COLUMNS (user_id "int" PATH '$.id' NULL ON ERROR, user_name "text" PATH '$.name' DEFAULT 'Unknown' ON EMPTY) ERROR ON ERROR) AS "filtered_users""#
);
}
#[test]
fn json_table_nested_path() {
let query = Query::select()
.from_function(
PgFunc::json_table(
Expr::val(
r#"{"users": [{"name": "John", "phones": ["123", "456"]}, {"name": "Jane", "phones": ["789"]}]}"#,
),
"$.users[*]",
)
.column(pg_json_table::Column::new("user_name", "text").path("$.name"))
.nested(
pg_json_table::NestedPath::new("$.phones[*]")
.column(pg_json_table::Column::new("phone", "text").path("$")),
)
.build(),
"user_phones",
)
.column("*")
.to_owned();
assert_eq!(
query.to_string(PostgresQueryBuilder),
r#"SELECT "*" FROM JSON_TABLE('{"users": [{"name": "John", "phones": ["123", "456"]}, {"name": "Jane", "phones": ["789"]}]}', '$.users[*]' COLUMNS (user_name "text" PATH '$.name', NESTED PATH '$.phones[*]' COLUMNS (phone "text" PATH '$'))) AS "user_phones""#
);
}
#[test]
fn json_table_nested_path_recursion_and_siblings() {
let query = Query::select()
.from_function(
PgFunc::json_table(
Expr::cust(
r#"'{"favorites":[{"movies":[{"name":"One","director":"John Doe"}],"books":[{"name":"Mystery","authors":[{"name":"Brown Dan"}]}]}]}'::json"#,
),
"$.favorites[*]",
)
.for_ordinality("user_id")
.nested(
pg_json_table::NestedPath::new("$.movies[*]")
.for_ordinality("movie_id")
.column(pg_json_table::Column::new("mname", "text").path("$.name"))
.column(pg_json_table::Column::new("director", "text")),
)
.nested(
pg_json_table::NestedPath::new("$.books[*]")
.for_ordinality("book_id")
.column(pg_json_table::Column::new("bname", "text").path("$.name"))
.nested(
pg_json_table::NestedPath::new("$.authors[*]")
.for_ordinality("author_id")
.column(
pg_json_table::Column::new("author_name", "text").path("$.name"),
),
),
)
.build(),
"jt",
)
.column("*")
.to_owned();
assert_eq!(
query.to_string(PostgresQueryBuilder),
r#"SELECT "*" FROM JSON_TABLE('{"favorites":[{"movies":[{"name":"One","director":"John Doe"}],"books":[{"name":"Mystery","authors":[{"name":"Brown Dan"}]}]}]}'::json, '$.favorites[*]' COLUMNS (user_id FOR ORDINALITY, NESTED PATH '$.movies[*]' COLUMNS (movie_id FOR ORDINALITY, mname "text" PATH '$.name', director "text"), NESTED PATH '$.books[*]' COLUMNS (book_id FOR ORDINALITY, bname "text" PATH '$.name', NESTED PATH '$.authors[*]' COLUMNS (author_id FOR ORDINALITY, author_name "text" PATH '$.name')))) AS "jt""#
);
}
+13
View File
@@ -0,0 +1,13 @@
use sea_query::{tests_cfg::*, *};
mod explain;
mod foreign_key;
mod index;
mod json_table;
mod query;
mod table;
mod types;
#[path = "../common.rs"]
mod common;
use common::*;
File diff suppressed because it is too large Load Diff
+873
View File
@@ -0,0 +1,873 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Glyph::Aspect).double().not_null())
.col(ColumnDef::new(Glyph::Image).text())
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
r#""aspect" double precision NOT NULL,"#,
r#""image" text"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_2() {
assert_eq!(
Table::create()
.table(Font::Table)
.col(
ColumnDef::new(Font::Id)
.integer()
.not_null()
.primary_key()
.auto_increment()
)
.col(ColumnDef::new(Font::Name).string().not_null())
.col(ColumnDef::new(Font::Variant).string_len(255).not_null())
.col(ColumnDef::new(Font::Language).string_len(255).not_null())
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "font" ("#,
r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
r#""name" varchar NOT NULL,"#,
r#""variant" varchar(255) NOT NULL,"#,
r#""language" varchar(255) NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_3() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.primary_key()
.auto_increment()
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string_len(255).not_null())
.col(ColumnDef::new(Char::SizeW).unsigned().not_null())
.col(ColumnDef::new(Char::SizeH).unsigned().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None))
)
.foreign_key(
ForeignKey::create()
.name("FK_2e303c3a712662f1fc2a4d0aad6")
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE IF NOT EXISTS "character" ("#,
r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" varchar(255) NOT NULL,"#,
r#""size_w" bigint NOT NULL,"#,
r#""size_h" bigint NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
r#"CONSTRAINT "FK_2e303c3a712662f1fc2a4d0aad6""#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_4() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Image).custom(Glyph::Aspect))
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "image" aspect )"#
);
}
#[test]
fn create_5() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Image).json())
.col(ColumnDef::new(Glyph::Aspect).json_binary())
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""image" json,"#,
r#""aspect" jsonb"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_6() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.extra("ANYTHING I WANT TO SAY".to_owned())
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""id" integer NOT NULL ANYTHING I WANT TO SAY"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_7() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Aspect)
.interval(None, None)
.not_null()
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""aspect" interval NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_8() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Aspect)
.interval(Some(PgInterval::YearToMonth), None)
.not_null()
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""aspect" interval YEAR TO MONTH NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_9() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Aspect)
.interval(None, Some(42))
.not_null()
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""aspect" interval(42) NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_10() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Aspect)
.interval(Some(PgInterval::Hour), Some(43))
.not_null()
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""aspect" interval HOUR(43) NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_11() {
assert_eq!(
Table::create()
.table(Char::Table)
.col(
ColumnDef::new(Char::CreatedAt)
.timestamp_with_time_zone()
.not_null()
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "character" ("#,
r#""created_at" timestamp with time zone NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_12() {
assert_eq!(
Table::create()
.table(BinaryType::Table)
.col(ColumnDef::new(BinaryType::BinaryLen).binary_len(32))
.col(ColumnDef::new(BinaryType::Binary).binary())
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "binary_type" ("#,
r#""binlen" bytea,"#,
r#""bin" bytea"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_13() {
assert_eq!(
Table::create()
.table(Char::Table)
.col(ColumnDef::new(Char::Character).binary())
.col(ColumnDef::new(Char::FontSize).binary_len(10))
.col(ColumnDef::new(Char::SizeW).var_binary(10))
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "character" ("#,
r#""character" bytea,"#,
r#""font_size" bytea,"#,
r#""size_w" bytea"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_14() {
assert_eq!(
Table::create()
.table(("schema", Glyph::Table))
.col(ColumnDef::new(Glyph::Image).custom(Glyph::Aspect))
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "schema"."glyph" ("#,
r#""image" aspect"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_15() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Image).json())
.col(ColumnDef::new(Glyph::Aspect).json_binary())
.index(
Index::create()
.unique()
.nulls_not_distinct()
.name("idx-glyph-aspect-image")
.table(Glyph::Table)
.col(Glyph::Aspect)
.col(Glyph::Image)
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""image" json,"#,
r#""aspect" jsonb,"#,
r#"CONSTRAINT "idx-glyph-aspect-image" UNIQUE NULLS NOT DISTINCT ("aspect", "image")"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn drop_1() {
assert_eq!(
Table::drop()
.table(Glyph::Table)
.table(Char::Table)
.cascade()
.to_string(PostgresQueryBuilder),
r#"DROP TABLE "glyph", "character" CASCADE"#
);
}
#[test]
fn drop_2() {
assert_eq!(
Table::drop()
.table(("schema1", Glyph::Table))
.table(("schema2", Char::Table))
.cascade()
.to_string(PostgresQueryBuilder),
r#"DROP TABLE "schema1"."glyph", "schema2"."character" CASCADE"#
);
}
#[test]
fn truncate_1() {
assert_eq!(
Table::truncate()
.table(Font::Table)
.to_string(PostgresQueryBuilder),
r#"TRUNCATE TABLE "font""#
);
}
#[test]
fn truncate_2() {
assert_eq!(
Table::truncate()
.table(("schema", Font::Table))
.to_string(PostgresQueryBuilder),
r#"TRUNCATE TABLE "schema"."font""#
);
}
#[test]
fn alter_1() {
assert_eq!(
Table::alter()
.table(Font::Table)
.add_column(ColumnDef::new("new_col").integer().not_null().default(100))
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#
);
}
#[test]
fn alter_2() {
assert_eq!(
Table::alter()
.table(Font::Table)
.modify_column(ColumnDef::new("new_col").big_integer().default(999))
.to_string(PostgresQueryBuilder),
[
r#"ALTER TABLE "font""#,
r#"ALTER COLUMN "new_col" TYPE bigint,"#,
r#"ALTER COLUMN "new_col" SET DEFAULT 999"#,
]
.join(" ")
);
}
#[test]
fn alter_3() {
assert_eq!(
Table::alter()
.table(Font::Table)
.rename_column("new_col", "new_column")
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "font" RENAME COLUMN "new_col" TO "new_column""#
);
}
#[test]
fn alter_4() {
assert_eq!(
Table::alter()
.table(Font::Table)
.drop_column("new_column")
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "font" DROP COLUMN "new_column""#
);
}
#[test]
fn alter_5() {
assert_eq!(
Table::alter()
.table(("schema", Font::Table))
.rename_column("new_col", "new_column")
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "schema"."font" RENAME COLUMN "new_col" TO "new_column""#
);
}
#[test]
#[should_panic(expected = "No alter option found")]
fn alter_6() {
Table::alter().to_string(PostgresQueryBuilder);
}
#[test]
fn alter_7() {
assert_eq!(
Table::alter()
.table(Font::Table)
.add_column(ColumnDef::new("new_col").integer())
.rename_column(Font::Name, "name_new")
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "font" ADD COLUMN "new_col" integer, RENAME COLUMN "name" TO "name_new""#
);
}
#[test]
fn alter_8() {
assert_eq!(
Table::alter()
.table(Font::Table)
.modify_column(ColumnDef::new(Font::Language).null())
.to_string(PostgresQueryBuilder),
[
r#"ALTER TABLE "font""#,
r#"ALTER COLUMN "language" DROP NOT NULL"#,
]
.join(" ")
);
}
#[test]
fn alter_9() {
// https://dbfiddle.uk/98Vd8pmn
assert_eq!(
Table::alter()
.table(Glyph::Table)
.modify_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.auto_increment()
.not_null()
.unique_key()
.primary_key()
)
.to_string(PostgresQueryBuilder),
[
r#"ALTER TABLE "glyph""#,
r#"ALTER COLUMN "aspect" TYPE integer,"#,
r#"ALTER COLUMN "aspect" SET NOT NULL,"#,
r#"ADD UNIQUE ("aspect"),"#,
r#"ADD PRIMARY KEY ("aspect")"#,
]
.join(" ")
);
}
#[test]
fn alter_10() {
// https://dbfiddle.uk/BeiZPvBe
assert_eq!(
Table::alter()
.table(Glyph::Table)
.add_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.auto_increment()
.not_null()
.unique_key()
.primary_key()
)
.to_string(PostgresQueryBuilder),
[
r#"ALTER TABLE "glyph""#,
r#"ADD COLUMN "aspect" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY UNIQUE"#,
]
.join(" ")
);
}
#[test]
fn rename_1() {
assert_eq!(
Table::rename()
.table(Font::Table, "font_new")
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "font" RENAME TO "font_new""#
);
}
#[test]
fn rename_2() {
assert_eq!(
Table::rename()
.table(("schema", Font::Table), ("schema", "font_new"),)
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "schema"."font" RENAME TO "schema"."font_new""#
);
}
#[test]
fn create_with_check_constraint() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.check(Expr::col(Glyph::Id).gt(10))
)
.check(Expr::col(Glyph::Id).lt(20))
.check(Expr::col(Glyph::Id).ne(15))
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL CHECK ("id" > 10), CHECK ("id" < 20), CHECK ("id" <> 15) )"#,
);
}
#[test]
fn create_with_named_check_constraint() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.check(("positive_id", Expr::col(Glyph::Id).gt(10)))
)
.check(("id_range", Expr::col(Glyph::Id).lt(20)))
.check(Expr::col(Glyph::Id).ne(15))
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL CONSTRAINT "positive_id" CHECK ("id" > 10), CONSTRAINT "id_range" CHECK ("id" < 20), CHECK ("id" <> 15) )"#,
);
}
#[test]
fn alter_with_check_constraint() {
assert_eq!(
Table::alter()
.table(Glyph::Table)
.add_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.not_null()
.default(101)
.check(Expr::col(Glyph::Aspect).gt(100))
)
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "glyph" ADD COLUMN "aspect" integer NOT NULL DEFAULT 101 CHECK ("aspect" > 100)"#,
);
}
#[test]
fn alter_with_named_check_constraint() {
assert_eq!(
Table::alter()
.table(Glyph::Table)
.add_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.not_null()
.default(101)
.check(("positive_aspect", Expr::col(Glyph::Aspect).gt(100)))
)
.to_string(PostgresQueryBuilder),
r#"ALTER TABLE "glyph" ADD COLUMN "aspect" integer NOT NULL DEFAULT 101 CONSTRAINT "positive_aspect" CHECK ("aspect" > 100)"#,
);
}
#[test]
fn create_16() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Glyph::Tokens).ltree())
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
r#""tokens" ltree"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_17() {
assert_eq!(
Table::create()
.table(Font::Table)
.col(
ColumnDef::new(Font::Id)
.integer()
.not_null()
.primary_key()
.auto_increment(),
)
.col(ColumnDef::new(Font::Name).string())
.col(ColumnDef::new(Font::Variant).string_len(255).not_null())
.col(ColumnDef::new(Font::Language).string_len(255).not_null())
.index(
Index::create()
.name("idx-font-name-include-language")
.unique()
.nulls_not_distinct()
.col(Font::Name)
.include(Font::Language),
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE "font" ("#,
r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
r#""name" varchar,"#,
r#""variant" varchar(255) NOT NULL,"#,
r#""language" varchar(255) NOT NULL,"#,
r#"CONSTRAINT "idx-font-name-include-language" UNIQUE NULLS NOT DISTINCT ("name") INCLUDE ("language")"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_18() {
assert_eq!(
Table::create()
.table(Font::Table)
.temporary()
.col(
ColumnDef::new(Font::Id)
.integer()
.not_null()
.primary_key()
.auto_increment()
)
.col(ColumnDef::new(Font::Name).string().not_null())
.to_string(PostgresQueryBuilder),
[
r#"CREATE TEMPORARY TABLE "font" ("#,
r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
r#""name" varchar NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_19() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.primary_key()
.auto_increment(),
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string_len(255).not_null())
.col(ColumnDef::new(Char::SizeW).unsigned().not_null())
.col(ColumnDef::new(Char::SizeH).unsigned().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.index(
Index::create()
.name("idx-character-area")
.table(Character::Table)
.col(Expr::col(Character::SizeH).mul(Expr::col(Character::SizeW))),
)
.to_string(PostgresQueryBuilder),
[
r#"CREATE TABLE IF NOT EXISTS "character" ("#,
r#""id" integer GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" varchar(255) NOT NULL,"#,
r#""size_w" bigint NOT NULL,"#,
r#""size_h" bigint NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
r#"CONSTRAINT "idx-character-area" (("size_h" * "size_w"))"#,
r#")"#,
]
.join(" "),
);
}
#[test]
fn create_partition_master_range() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.col(ColumnDef::new(Glyph::Aspect).integer().not_null())
.partition_by_range([Glyph::Aspect])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL, "aspect" integer NOT NULL ) PARTITION BY RANGE ("aspect")"#
);
}
#[test]
fn create_partition_master_range_multiple_columns() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.col(ColumnDef::new(Glyph::Aspect).integer().not_null())
.partition_by_range([Glyph::Id, Glyph::Aspect])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL, "aspect" integer NOT NULL ) PARTITION BY RANGE ("id", "aspect")"#
);
}
#[test]
fn create_partition_child_range() {
assert_eq!(
Table::create()
.table(Alias::new("glyph_1"))
.partition_of(Glyph::Table)
.values_from_to([1], [10])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph_1" PARTITION OF "glyph" FOR VALUES FROM (1) TO (10)"#
);
}
#[test]
fn create_partition_child_range_multiple_columns() {
assert_eq!(
Table::create()
.table(Alias::new("glyph_1"))
.partition_of(Glyph::Table)
.values_from_to([1, 100], [10, 200])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph_1" PARTITION OF "glyph" FOR VALUES FROM (1, 100) TO (10, 200)"#
);
}
#[test]
fn create_partition_master_list() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.partition_by_list([Glyph::Id])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL ) PARTITION BY LIST ("id")"#
);
}
#[test]
fn create_partition_child_list() {
assert_eq!(
Table::create()
.table(Alias::new("glyph_p1"))
.partition_of(Glyph::Table)
.values_in([1, 2, 3])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph_p1" PARTITION OF "glyph" FOR VALUES IN (1, 2, 3)"#
);
}
#[test]
fn create_partition_master_hash() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.partition_by_hash([Glyph::Id])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL ) PARTITION BY HASH ("id")"#
);
}
#[test]
fn create_partition_master_hash_multiple_columns() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.col(ColumnDef::new(Glyph::Aspect).integer().not_null())
.partition_by_hash([Glyph::Id, Glyph::Aspect])
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL, "aspect" integer NOT NULL ) PARTITION BY HASH ("id", "aspect")"#
);
}
#[test]
fn create_partition_child_hash() {
assert_eq!(
Table::create()
.table(Alias::new("glyph_p1"))
.partition_of(Glyph::Table)
.values_with(4, 0)
.to_string(PostgresQueryBuilder),
r#"CREATE TABLE "glyph_p1" PARTITION OF "glyph" FOR VALUES WITH (MODULUS 4, REMAINDER 0)"#
);
}
#[test]
#[should_panic(expected = "Postgres does not support PARTITION BY KEY")]
fn create_partition_key_panics() {
Table::create()
.table(Glyph::Table)
.col(ColumnDef::new(Glyph::Id).integer().not_null())
.partition_by_key([Glyph::Id])
.to_string(PostgresQueryBuilder);
}
#[test]
#[should_panic(expected = "Postgres does not support VALUES LESS THAN")]
fn create_partition_values_less_than_panics() {
Table::create()
.table(Alias::new("glyph_p1"))
.partition_of(Glyph::Table)
.values_less_than([10])
.to_string(PostgresQueryBuilder);
}
+179
View File
@@ -0,0 +1,179 @@
use super::*;
use pretty_assertions::assert_eq;
use sea_query::{PostgresQueryBuilder, extension::postgres::Type};
#[test]
fn create_1() {
assert_eq!(
Type::create()
.as_enum(Font::Table)
.values([Font::Name, Font::Variant, Font::Language])
.to_string(PostgresQueryBuilder),
r#"CREATE TYPE "font" AS ENUM ('name', 'variant', 'language')"#
);
}
#[test]
fn create_2() {
assert_eq!(
Type::create()
.as_enum(("schema", Font::Table))
.values([Font::Name, Font::Variant, Font::Language])
.to_string(PostgresQueryBuilder),
r#"CREATE TYPE "schema"."font" AS ENUM ('name', 'variant', 'language')"#
);
}
#[test]
fn create_3() {
assert_eq!(
Type::create()
.as_enum(Tea::Enum)
.values([Tea::EverydayTea, Tea::BreakfastTea])
.to_string(PostgresQueryBuilder),
r#"CREATE TYPE "tea" AS ENUM ('EverydayTea', 'BreakfastTea')"#
);
enum Tea {
Enum,
EverydayTea,
BreakfastTea,
}
impl sea_query::Iden for Tea {
fn unquoted(&self) -> &str {
match self {
Self::Enum => "tea",
Self::EverydayTea => "EverydayTea",
Self::BreakfastTea => "BreakfastTea",
}
}
}
}
#[test]
fn drop_1() {
assert_eq!(
Type::drop()
.if_exists()
.name(Font::Table)
.restrict()
.to_string(PostgresQueryBuilder),
r#"DROP TYPE IF EXISTS "font" RESTRICT"#
)
}
#[test]
fn drop_2() {
assert_eq!(
Type::drop()
.name(Font::Table)
.to_string(PostgresQueryBuilder),
r#"DROP TYPE "font""#
);
}
#[test]
fn drop_3() {
assert_eq!(
Type::drop()
.if_exists()
.name(Font::Table)
.cascade()
.to_string(PostgresQueryBuilder),
r#"DROP TYPE IF EXISTS "font" CASCADE"#
);
}
#[test]
fn drop_4() {
assert_eq!(
Type::drop()
.name(("schema", Font::Table))
.to_string(PostgresQueryBuilder),
r#"DROP TYPE "schema"."font""#
);
}
#[test]
fn alter_1() {
assert_eq!(
Type::alter()
.name(Font::Table)
.add_value("weight")
.to_string(PostgresQueryBuilder),
r#"ALTER TYPE "font" ADD VALUE 'weight'"#
)
}
#[test]
fn alter_2() {
assert_eq!(
Type::alter()
.name(Font::Table)
.add_value("weight")
.before(Font::Variant)
.to_string(PostgresQueryBuilder),
r#"ALTER TYPE "font" ADD VALUE 'weight' BEFORE 'variant'"#
)
}
#[test]
fn alter_3() {
assert_eq!(
Type::alter()
.name(Font::Table)
.add_value("weight")
.after(Font::Variant)
.to_string(PostgresQueryBuilder),
r#"ALTER TYPE "font" ADD VALUE 'weight' AFTER 'variant'"#
)
}
#[test]
fn alter_4() {
assert_eq!(
Type::alter()
.name(Font::Table)
.rename_to("typeface")
.to_string(PostgresQueryBuilder),
r#"ALTER TYPE "font" RENAME TO "typeface""#
)
}
#[test]
fn alter_5() {
assert_eq!(
Type::alter()
.name(Font::Table)
.rename_value(Font::Variant, Font::Language)
.to_string(PostgresQueryBuilder),
r#"ALTER TYPE "font" RENAME VALUE 'variant' TO 'language'"#
)
}
#[test]
fn alter_6() {
assert_eq!(
Type::alter()
.name(("schema", Font::Table))
.rename_to("typeface")
.to_string(PostgresQueryBuilder),
r#"ALTER TYPE "schema"."font" RENAME TO "typeface""#
)
}
#[test]
fn unsigned_types() {
let query_builder = PostgresQueryBuilder {};
let column_to_string = |column_type| {
let mut out = String::new();
query_builder.prepare_column_type(column_type, &mut out);
out
};
assert_eq!(column_to_string(&ColumnType::TinyUnsigned), "smallint");
assert_eq!(column_to_string(&ColumnType::SmallUnsigned), "integer");
assert_eq!(column_to_string(&ColumnType::Unsigned), "bigint");
assert_eq!(column_to_string(&ColumnType::BigUnsigned), "bigint");
}
+395
View File
@@ -0,0 +1,395 @@
use sea_query::Values;
#[test]
fn test_raw_sql_1() {
struct B {
i: String,
}
fn call_pg(a: i32) {
let b = B {
i: "hello".to_owned(),
};
let c = [1, 2, 3];
let query = sea_query::raw_sql!(
seaql::postgres::query,
r#"SELECT {a}, {b.i} FROM "bar" WHERE "id" in ({..c})"#
);
assert_eq!(
query.sql,
r#"SELECT $1, $2 FROM "bar" WHERE "id" in ($3, $4, $5)"#
);
assert_eq!(
query.values,
Values(vec![
12.into(),
"hello".into(),
1.into(),
2.into(),
3.into(),
])
);
}
call_pg(12);
fn call_sqlite(a: i32) {
let b = B {
i: "hello".to_owned(),
};
let c = [1, 2, 3];
let query = sea_query::raw_sql!(
seaql::sqlite::query,
r#"SELECT {a}, {b.i} FROM "bar" WHERE "id" in ({..c})"#
);
assert_eq!(
query.sql,
r#"SELECT ?, ? FROM "bar" WHERE "id" in (?, ?, ?)"#
);
assert_eq!(
query.values,
Values(vec![
12.into(),
"hello".into(),
1.into(),
2.into(),
3.into(),
])
);
}
call_sqlite(12);
}
#[test]
fn test_raw_sql_1a() {
let a = 1;
struct B {
b: i32,
}
let b = B { b: 2 };
let c = "A";
let d = vec![3, 4, 5];
let query = sea_query::raw_query!(
PostgresQueryBuilder,
r#"SELECT ("size_w" + {a}) * {b.b} FROM "glyph"
WHERE "image" LIKE {c} AND "id" IN ({..d})"#
);
assert_eq!(
query.sql,
r#"SELECT ("size_w" + $1) * $2 FROM "glyph"
WHERE "image" LIKE $3 AND "id" IN ($4, $5, $6)"#
);
assert_eq!(
query.values,
Values(vec![
1.into(),
2.into(),
"A".into(),
3.into(),
4.into(),
5.into()
])
);
}
#[test]
fn test_raw_sql_2() {
struct A {
b: B,
}
struct B {
c: i32,
}
let a = A { b: B { c: 42 } };
let s;
let query = sea_query::raw_sql!(seaql::postgres::query, s = r#"SELECT {a.b.c}"#);
assert_eq!(query.sql, r#"SELECT $1"#);
assert_eq!(query.values, Values(vec![42.into()]));
}
#[test]
fn test_raw_sql_3() {
// this is not real SQL but doesn't matter
let a: i32 = 1;
let b: u8 = 2;
let c = [3u8, 4, 5]; // bytes are bind as 1 item
let c: &[u8] = &c; // sea-query doesn't support [u8] array as value
let d = vec![3u8, 4, 5]; // bytes are bind as 1 item
let e = vec![5i32, 6, 7]; // vec is expanded
let f = &e; // just a borrow
let sql;
let query = sea_query::raw_sql!(
seaql::sqlite::query,
sql = r#"A = {a}, B = {b}, C = {c}, D = ({d}), E = ({..e}), F = ({..f})"#
);
assert_eq!(
sql,
r#"A = ?, B = ?, C = ?, D = (?), E = (?, ?, ?), F = (?, ?, ?)"#
);
assert_eq!(
query.values,
Values(vec![
1i32.into(),
2u8.into(),
vec![3u8, 4, 5].into(), // bytes
vec![3u8, 4, 5].into(), // bytes
5.into(),
6.into(),
7.into(),
5.into(),
6.into(),
7.into(),
])
);
}
#[test]
fn test_raw_sql_4() {
// just to test no-op
let sql;
let query = sea_query::raw_sql!(
seaql::sqlite::query,
sql = r#"SELECT "character".*, "font"."name" FROM "character" INNER JOIN "font" ON "character"."font_id" = "font"."id""#
);
assert_eq!(
query.sql,
r#"SELECT "character".*, "font"."name" FROM "character" INNER JOIN "font" ON "character"."font_id" = "font"."id""#
);
assert_eq!(query.values, Values(vec![]));
}
#[test]
fn test_raw_sql_5() {
// the example in readme
let a = 1;
let b = 2;
let c = "A";
let d = vec![3i32, 4, 5];
let sql;
let query = sea_query::raw_sql!(
seaql::sqlite::query,
sql = r#"SELECT ("size_w" + {a}) * {b} FROM "glyph" WHERE "image" LIKE {c} AND "id" IN ({..d})"#
);
assert_eq!(
sql,
r#"SELECT ("size_w" + ?) * ? FROM "glyph" WHERE "image" LIKE ? AND "id" IN (?, ?, ?)"#
);
assert_eq!(
query.values,
Values(vec![
1.into(),
2.into(),
"A".into(),
3.into(),
4.into(),
5.into()
])
);
let query = sea_query::raw_sql!(
seaql::postgres::query,
r#"SELECT ("size_w" + {a}) * {b} FROM "glyph" WHERE "image" LIKE {c} AND "id" IN ({..d})"#
);
assert_eq!(
query.sql,
r#"SELECT ("size_w" + $1) * $2 FROM "glyph" WHERE "image" LIKE $3 AND "id" IN ($4, $5, $6)"#
);
assert_eq!(
query.values,
Values(vec![
1.into(),
2.into(),
"A".into(),
3.into(),
4.into(),
5.into()
])
);
}
#[test]
fn test_raw_sql_6() {
let a = Some(1);
let b = Option::<i32>::None;
let c = Some("c".to_owned());
let d = Option::<String>::None;
let query = sea_query::raw_sql!(seaql::sqlite::query, r#"SELECT {a}, {b}, {c}, {d}"#);
assert_eq!(query.sql, r#"SELECT ?, ?, ?, ?"#);
assert_eq!(
query.values,
Values(vec![
1.into(),
Option::<i32>::None.into(),
"c".into(),
Option::<String>::None.into(),
])
);
}
#[test]
fn test_raw_sql_7() {
let var = (1, "2".to_owned(), 3);
let query = sea_query::raw_sql!(
seaql::postgres::query,
r#"SELECT {var.0}, {var.1}, {var.2}, {var.0:2}"#
);
assert_eq!(query.sql, r#"SELECT $1, $2, $3, $4, $5, $6"#);
assert_eq!(
query.values,
Values(vec![
1.into(),
"2".into(),
3.into(),
1.into(),
"2".into(),
3.into(),
])
);
}
#[test]
fn test_raw_sql_8() {
let values = (1, "2");
let query = sea_query::raw_sql!(
seaql::mysql::query,
"INSERT INTO `glyph` (`aspect`, `image`) VALUES ({values.0:1})"
);
assert_eq!(
query.sql,
"INSERT INTO `glyph` (`aspect`, `image`) VALUES (?, ?)"
);
assert_eq!(query.values, Values(vec![1.into(), "2".into()]));
}
#[test]
fn test_raw_sql_9() {
// test vector of tuple expansion
let values = vec![(1, "2", 3), (4, "5", 6)];
let z = 42;
let query = sea_query::raw_sql!(
seaql::postgres::query,
r#"INSERT INTO "glyph" ("aspect", "image", "font_size") VALUES {..(values.0:2),} SELECT {z}"#
);
assert_eq!(
query.sql,
r#"INSERT INTO "glyph" ("aspect", "image", "font_size") VALUES ($1, $2, $3), ($4, $5, $6) SELECT $7"#
);
assert_eq!(
query.values,
Values(vec![
1.into(),
"2".into(),
3.into(),
4.into(),
"5".into(),
6.into(),
42.into(),
])
);
}
#[test]
fn test_raw_sql_10() {
// array expansion, but without tuple expansion
let values = vec![(1, "2", 3), (4, "5", 6)];
let z = 42;
let query = sea_query::raw_sql!(
seaql::postgres::query,
r#"INSERT INTO "glyph" ("aspect", "image") VALUES {..(values.0, values.1, values.2),} SELECT {z}"#
);
assert_eq!(
query.sql,
r#"INSERT INTO "glyph" ("aspect", "image") VALUES ($1, $2, $3), ($4, $5, $6) SELECT $7"#
);
assert_eq!(
query.values,
Values(vec![
1.into(),
"2".into(),
3.into(),
4.into(),
"5".into(),
6.into(),
42.into(),
])
);
let query = sea_query::raw_sql!(
seaql::postgres::query,
r#"INSERT INTO "glyph" ("aspect", "image")
-- inline comment'
VALUES {..(values.0, values.1, values.2),} SELECT {z}"#
);
assert_eq!(
query.sql,
r#"INSERT INTO "glyph" ("aspect", "image")
-- inline comment'
VALUES ($1, $2, $3), ($4, $5, $6) SELECT $7"#
);
}
#[test]
fn test_raw_sql_11() {
struct Item {
a: i32,
b: String,
c: u16,
}
// array expansion, but without tuple expansion
let values = vec![
Item {
a: 11,
b: "1b".to_owned(),
c: 13,
},
Item {
a: 21,
b: "2b".to_owned(),
c: 23,
},
];
let z = 42;
let query = sea_query::raw_sql!(
seaql::postgres::query,
r#"INSERT INTO "glyph" ("aspect", "image") VALUES {..(values.a, values.b, values.c),} SELECT {z}"#
);
assert_eq!(
query.sql,
r#"INSERT INTO "glyph" ("aspect", "image") VALUES ($1, $2, $3), ($4, $5, $6) SELECT $7"#
);
assert_eq!(
query.values,
Values(vec![
11.into(),
"1b".into(),
13u16.into(),
21.into(),
"2b".into(),
23u16.into(),
42.into(),
])
);
}
#[test]
fn test_raw_sql_12() {
let v = 12i32;
let query = sea_query::raw_query!(PostgresQueryBuilder, r#"SELECT {v} + {v}::int"#);
assert_eq!(query.sql, r#"SELECT $1 + $2::int"#);
assert_eq!(query.values, Values(vec![12i32.into(), 12i32.into()]));
}
+33
View File
@@ -0,0 +1,33 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn explain_sqlite_select() {
assert_eq!(
ExplainStatement::new()
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(SqliteQueryBuilder),
r#"EXPLAIN SELECT "character" FROM "character""#
);
}
#[test]
fn explain_sqlite_query_plan() {
assert_eq!(
ExplainStatement::new()
.query_plan()
.statement(
Query::select()
.column(Char::Character)
.from(Char::Table)
.to_owned(),
)
.to_string(SqliteQueryBuilder),
r#"EXPLAIN QUERY PLAN SELECT "character" FROM "character""#
);
}
@@ -0,0 +1 @@
// Sqlite does not support modification of foreign key constraints to existing tables
+69
View File
@@ -0,0 +1,69 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
Index::create()
.name("idx-glyph-aspect")
.table(Glyph::Table)
.col(Glyph::Aspect)
.to_string(SqliteQueryBuilder),
r#"CREATE INDEX "idx-glyph-aspect" ON "glyph" ("aspect")"#
);
}
#[test]
fn create_2() {
assert_eq!(
Index::create()
.unique()
.name("idx-glyph-aspect-image")
.table(Glyph::Table)
.col(Glyph::Aspect)
.col(Glyph::Image)
.to_string(SqliteQueryBuilder),
r#"CREATE UNIQUE INDEX "idx-glyph-aspect-image" ON "glyph" ("aspect", "image")"#
);
}
#[test]
fn create_3() {
assert_eq!(
Index::create()
.if_not_exists()
.unique()
.name("idx-glyph-aspect-image")
.table(Glyph::Table)
.col(Glyph::Aspect)
.col(Glyph::Image)
.to_string(SqliteQueryBuilder),
r#"CREATE UNIQUE INDEX IF NOT EXISTS "idx-glyph-aspect-image" ON "glyph" ("aspect", "image")"#
);
}
#[test]
fn create_4() {
assert_eq!(
Index::create()
.if_not_exists()
.unique()
.name("partial-index-glyph-image-not-null")
.table(Glyph::Table)
.col(Glyph::Image)
.and_where(Expr::col(Glyph::Image).is_not_null())
.to_string(SqliteQueryBuilder),
r#"CREATE UNIQUE INDEX IF NOT EXISTS "partial-index-glyph-image-not-null" ON "glyph" ("image") WHERE "image" IS NOT NULL"#
);
}
#[test]
fn drop_1() {
assert_eq!(
Index::drop()
.name("idx-glyph-aspect")
.table(Glyph::Table)
.to_string(SqliteQueryBuilder),
r#"DROP INDEX "idx-glyph-aspect""#
);
}
+11
View File
@@ -0,0 +1,11 @@
use sea_query::{tests_cfg::*, *};
mod explain;
mod foreign_key;
mod index;
mod query;
mod table;
#[path = "../common.rs"]
mod common;
use common::*;
File diff suppressed because it is too large Load Diff
+748
View File
@@ -0,0 +1,748 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn create_1() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Glyph::Aspect).double().not_null())
.col(ColumnDef::new(Glyph::Image).text())
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE "glyph" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""aspect" double NOT NULL,"#,
r#""image" text"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_2() {
assert_eq!(
Table::create()
.table(Font::Table)
.col(
ColumnDef::new(Font::Id)
.integer()
.not_null()
.primary_key()
.auto_increment()
)
.col(ColumnDef::new(Font::Name).string().not_null())
.col(ColumnDef::new(Font::Variant).string().not_null())
.col(ColumnDef::new(Font::Language).string().not_null())
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE "font" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""name" varchar NOT NULL,"#,
r#""variant" varchar NOT NULL,"#,
r#""language" varchar NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_3() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Char::FontSize).big_integer().not_null())
.col(ColumnDef::new(Char::Character).string().not_null())
.col(ColumnDef::new(Char::SizeW).unsigned().not_null())
.col(ColumnDef::new(Char::SizeH).unsigned().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None))
)
.foreign_key(
ForeignKey::create()
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE IF NOT EXISTS "character" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" varchar NOT NULL,"#,
r#""size_w" integer NOT NULL,"#,
r#""size_h" integer NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_4() {
assert_eq!(
Table::create()
.table(BinaryType::Table)
.col(ColumnDef::new(BinaryType::BinaryLen).binary_len(32))
.col(ColumnDef::new(BinaryType::Binary).binary())
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE "binary_type" ("#,
r#""binlen" blob(32),"#,
r#""bin" blob(1)"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_5() {
assert_eq!(
Table::create()
.table(Char::Table)
.col(ColumnDef::new(Char::Character).binary())
.col(ColumnDef::new(Char::FontSize).binary_len(10))
.col(ColumnDef::new(Char::SizeW).var_binary(10))
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE "character" ("#,
r#""character" blob(1),"#,
r#""font_size" blob(10),"#,
r#""size_w" varbinary_blob(10)"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_6() {
assert_eq!(
Table::create()
.table(Task::Table)
.col(
ColumnDef::new(Task::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Task::IsDone).boolean().not_null())
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE "task" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""is_done" boolean NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_7() {
assert_eq!(
Table::create()
.table(Task::Table)
.col(
ColumnDef::new(Task::Id)
.big_integer()
.not_null()
.auto_increment()
.primary_key()
)
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE "task" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_8() {
assert_eq!(
Table::create()
.table(Font::Table)
.temporary()
.col(
ColumnDef::new(Font::Id)
.integer()
.not_null()
.primary_key()
.auto_increment()
)
.col(ColumnDef::new(Font::Name).string().not_null())
.to_string(SqliteQueryBuilder),
[
r#"CREATE TEMPORARY TABLE "font" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""name" varchar NOT NULL"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_with_unique_index() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string().not_null())
.col(ColumnDef::new(Char::SizeW).integer().not_null())
.col(ColumnDef::new(Char::SizeH).integer().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None))
)
.foreign_key(
ForeignKey::create()
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.index(Index::create().unique().col(Char::SizeH).col(Char::SizeW))
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE IF NOT EXISTS "character" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" varchar NOT NULL,"#,
r#""size_w" integer NOT NULL,"#,
r#""size_h" integer NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
r#"UNIQUE ("size_h", "size_w"),"#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_with_primary_unique_index() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string().not_null())
.col(ColumnDef::new(Char::SizeW).integer().not_null())
.col(ColumnDef::new(Char::SizeH).integer().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None))
)
.foreign_key(
ForeignKey::create()
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.index(Index::create().unique().primary().col(Char::SizeH).col(Char::SizeW))
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE IF NOT EXISTS "character" ("#,
r#""id" integer NOT NULL,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" varchar NOT NULL,"#,
r#""size_w" integer NOT NULL,"#,
r#""size_h" integer NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
r#"PRIMARY KEY ("size_h", "size_w"),"#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
r#")"#,
]
.join(" ")
);
}
#[test]
fn create_with_unique_index_constraint() {
assert_eq!(
Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string().not_null())
.col(ColumnDef::new(Char::SizeW).integer().not_null())
.col(ColumnDef::new(Char::SizeH).integer().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.foreign_key(
ForeignKey::create()
.from(Char::Table, Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.index(
Index::create()
.name("idx-sizehw")
.table(Char::Table)
.col(Char::SizeH)
.col(Char::SizeW)
.unique(),
)
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE IF NOT EXISTS "character" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" varchar NOT NULL,"#,
r#""size_w" integer NOT NULL,"#,
r#""size_h" integer NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
r#"CONSTRAINT "idx-sizehw" UNIQUE ("size_h", "size_w"),"#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
r#")"#,
].join(" ")
);
}
#[test]
fn create_in_schema_with_unique_index_constraint_and_foreign_key() {
assert_eq!(
Table::create()
.table(("schema", Char::Table))
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Char::FontSize).integer().not_null())
.col(ColumnDef::new(Char::Character).string().not_null())
.col(ColumnDef::new(Char::SizeW).integer().not_null())
.col(ColumnDef::new(Char::SizeH).integer().not_null())
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.foreign_key(
ForeignKey::create()
.from(("schema", Char::Table), Char::FontId)
.to(("schema", Font::Table), Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.index(
Index::create()
.name("idx-sizehw")
.table(Char::Table)
.col(Char::SizeH)
.col(Char::SizeW)
.unique(),
)
.to_string(SqliteQueryBuilder),
[
r#"CREATE TABLE IF NOT EXISTS "schema"."character" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" varchar NOT NULL,"#,
r#""size_w" integer NOT NULL,"#,
r#""size_h" integer NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
r#"CONSTRAINT "idx-sizehw" UNIQUE ("size_h", "size_w"),"#,
r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
r#")"#,
].join(" ")
);
}
#[test]
fn create_source_only_schema_foreign_key_fails() {
let _ = Table::create()
.table(("schema", Char::Table))
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.foreign_key(
ForeignKey::create()
.from(("schema", Char::Table), Char::FontId)
.to(Font::Table, Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.to_string(SqliteQueryBuilder);
}
#[test]
fn create_target_only_schema_foreign_key_fails() {
let _ = Table::create()
.table(Char::Table)
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.foreign_key(
ForeignKey::create()
.from(Char::Table, Char::FontId)
.to(("schema", Font::Table), Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.to_string(SqliteQueryBuilder);
}
#[test]
fn create_cross_schema_foreign_key_fails() {
let _ = Table::create()
.table(("schema1", Char::Table))
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.foreign_key(
ForeignKey::create()
.from(("schema1", Char::Table), Char::FontId)
.to(("schema2", Font::Table), Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.to_string(SqliteQueryBuilder);
}
#[test]
fn create_fully_qualified_db_schema_table_fails() {
let _ = Table::create()
.table(("db", "schema", Char::Table))
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.to_string(SqliteQueryBuilder);
}
#[test]
fn foreign_key_to_fully_qualified_db_schema_table_fails() {
let _ = Table::create()
.table(("schema", Char::Table))
.if_not_exists()
.col(
ColumnDef::new(Char::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(
ColumnDef::new(Char::FontId)
.integer()
.default(Value::Int(None)),
)
.foreign_key(
ForeignKey::create()
.from(("db", "schema", Char::Table), Char::FontId)
.to(("db", "schema", Font::Table), Font::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.to_string(SqliteQueryBuilder);
}
#[test]
fn drop_1() {
assert_eq!(
Table::drop()
.table(Glyph::Table)
.table(Char::Table)
.cascade()
.to_string(SqliteQueryBuilder),
r#"DROP TABLE "glyph", "character""#
);
}
#[test]
fn drop_with_schemas() {
assert_eq!(
Table::drop()
.table(("schema1", Glyph::Table))
.table(("schema2", Char::Table))
.cascade()
.to_string(SqliteQueryBuilder),
r#"DROP TABLE "schema1"."glyph", "schema2"."character""#
);
}
#[test]
#[should_panic(expected = "Sqlite doesn't support TRUNCATE statement")]
fn truncate_1() {
assert_eq!(
Table::truncate()
.table(Font::Table)
.to_string(SqliteQueryBuilder),
r#"TRUNCATE TABLE "font""#
);
}
#[test]
fn alter_1() {
assert_eq!(
Table::alter()
.table(Font::Table)
.add_column(ColumnDef::new("new_col").integer().not_null().default(99))
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 99"#
);
}
#[test]
#[should_panic(expected = "Sqlite not support modifying table column")]
fn alter_2() {
Table::alter()
.table(Font::Table)
.modify_column(ColumnDef::new("new_col").double())
.to_string(SqliteQueryBuilder);
}
#[test]
fn alter_3() {
assert_eq!(
Table::alter()
.table(Font::Table)
.rename_column("new_col", "new_column")
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "font" RENAME COLUMN "new_col" TO "new_column""#
);
}
#[test]
fn alter_4() {
assert_eq!(
Table::alter()
.table(Font::Table)
.drop_column("new_column")
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "font" DROP COLUMN "new_column""#
);
}
#[test]
fn alter_5() {
assert_eq!(
Table::rename()
.table(Font::Table, "font_new")
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "font" RENAME TO "font_new""#
);
}
#[test]
fn alter_add_column_schema() {
assert_eq!(
Table::alter()
.table(("schema", Font::Table))
.add_column(ColumnDef::new("new_col").integer().not_null().default(99))
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "schema"."font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 99"#
);
}
#[test]
fn alter_rename_column_schema() {
assert_eq!(
Table::alter()
.table(("schema", Font::Table))
.rename_column("new_col", "new_column")
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "schema"."font" RENAME COLUMN "new_col" TO "new_column""#
);
}
#[test]
fn alter_drop_column_schema() {
assert_eq!(
Table::alter()
.table(("schema", Font::Table))
.drop_column("new_column")
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "schema"."font" DROP COLUMN "new_column""#
);
}
#[test]
fn alter_rename_table_schema() {
assert_eq!(
Table::rename()
.table(("schema", Font::Table), "font_new")
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "schema"."font" RENAME TO "font_new""#
);
}
#[test]
#[should_panic(expected = "No alter option found")]
fn alter_6() {
Table::alter().to_string(SqliteQueryBuilder);
}
#[test]
#[should_panic(expected = "Sqlite doesn't support multiple alter options")]
fn alter_7() {
let _ = Table::alter()
.table(Font::Table)
.add_column(ColumnDef::new("new_col").integer())
.rename_column(Font::Name, "name_new")
.drop_column("name_new")
.to_string(SqliteQueryBuilder);
}
#[test]
fn create_with_check_constraint() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.check(Expr::col(Glyph::Id).gt(10))
)
.check(Expr::col(Glyph::Id).lt(20))
.check(Expr::col(Glyph::Id).ne(15))
.to_string(SqliteQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL CHECK ("id" > 10), CHECK ("id" < 20), CHECK ("id" <> 15) )"#,
);
}
#[test]
fn create_with_named_check_constraint() {
assert_eq!(
Table::create()
.table(Glyph::Table)
.col(
ColumnDef::new(Glyph::Id)
.integer()
.not_null()
.check(("positive_id", Expr::col(Glyph::Id).gt(10)))
)
.check(("id_range", Expr::col(Glyph::Id).lt(20)))
.check(Expr::col(Glyph::Id).ne(15))
.to_string(SqliteQueryBuilder),
r#"CREATE TABLE "glyph" ( "id" integer NOT NULL CONSTRAINT "positive_id" CHECK ("id" > 10), CONSTRAINT "id_range" CHECK ("id" < 20), CHECK ("id" <> 15) )"#,
);
}
#[test]
fn alter_with_check_constraint() {
assert_eq!(
Table::alter()
.table(Glyph::Table)
.add_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.not_null()
.default(101)
.check(Expr::col(Glyph::Aspect).gt(100))
)
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "glyph" ADD COLUMN "aspect" integer NOT NULL DEFAULT 101 CHECK ("aspect" > 100)"#,
);
}
#[test]
fn alter_with_named_check_constraint() {
assert_eq!(
Table::alter()
.table(Glyph::Table)
.add_column(
ColumnDef::new(Glyph::Aspect)
.integer()
.not_null()
.default(101)
.check(("positive_aspect", Expr::col(Glyph::Aspect).gt(100)))
)
.to_string(SqliteQueryBuilder),
r#"ALTER TABLE "glyph" ADD COLUMN "aspect" integer NOT NULL DEFAULT 101 CONSTRAINT "positive_aspect" CHECK ("aspect" > 100)"#,
);
}