DEV Community

SeaQL
SeaQL

Posted on • Originally published at sea-ql.org

What's new in SeaQuery 0.28.0

🎉 We are pleased to release SeaQuery 0.28.0! Here are some feature highlights 🌟:

New IdenStatic trait for static identifier

[#508] Representing a identifier with &'static str. The IdenStatic trait looks like this:

pub trait IdenStatic: Iden + Copy + 'static {
    fn as_str(&self) -> &'static str;
}
Enter fullscreen mode Exit fullscreen mode

You can derive it easily for your existing Iden. Just changing the #[derive(Iden)] into #[derive(IdenStatic)].

#[derive(IdenStatic)]
enum User {
    Table,
    Id,
    FirstName,
    LastName,
    #[iden = "_email"]
    Email,
}

assert_eq!(User::Email.as_str(), "_email");
Enter fullscreen mode Exit fullscreen mode

New PgExpr and SqliteExpr traits for backend specific expressions

[#519] Postgres specific and SQLite specific expressions are being moved into its corresponding trait. You need to import the trait into scope before construct the expression with those backend specific methods.

// Importing `PgExpr` trait before constructing Postgres expression
use sea_query::{extension::postgres::PgExpr, tests_cfg::*, *};

let query = Query::select()
    .columns([Font::Name, Font::Variant, Font::Language])
    .from(Font::Table)
    .and_where(Expr::val("a").concatenate("b").concat("c").concat("d"))
    .to_owned();

assert_eq!(
    query.to_string(PostgresQueryBuilder),
    r#"SELECT "name", "variant", "language" FROM "font" WHERE 'a' || 'b' || 'c' || 'd'"#
);
Enter fullscreen mode Exit fullscreen mode
// Importing `SqliteExpr` trait before constructing SQLite expression
 use sea_query::{extension::sqlite::SqliteExpr, tests_cfg::*, *};

 let query = Query::select()
    .column(Font::Name)
    .from(Font::Table)
    .and_where(Expr::col(Font::Name).matches("a"))
    .to_owned();

 assert_eq!(
    query.to_string(SqliteQueryBuilder),
    r#"SELECT "name" FROM "font" WHERE "name" MATCH 'a'"#
 );
Enter fullscreen mode Exit fullscreen mode

Bug Fixes

// given
let (statement, values) = sea_query::Query::select()
    .column(Glyph::Id)
    .from(Glyph::Table)
    .cond_where(Cond::any()
        .add(Cond::all()) // empty all() => TRUE
        .add(Cond::any()) // empty any() => FALSE
    )
    .build(sea_query::MysqlQueryBuilder);

// old behavior
assert_eq!(statement, r#"SELECT `id` FROM `glyph`"#);

// new behavior
assert_eq!(
    statement,
    r#"SELECT `id` FROM `glyph` WHERE (TRUE) OR (FALSE)"#
);

// a complex example
let (statement, values) = Query::select()
    .column(Glyph::Id)
    .from(Glyph::Table)
    .cond_where(
        Cond::all()
            .add(Cond::all().not())
            .add(Cond::any().not())
            .not(),
    )
    .build(MysqlQueryBuilder);

assert_eq!(
    statement,
    r#"SELECT `id` FROM `glyph` WHERE NOT ((NOT TRUE) AND (NOT FALSE))"#
);
Enter fullscreen mode Exit fullscreen mode

Breaking Changes

  • [#535] MSRV is up to 1.62
# Make sure you're running SeaQuery with Rust 1.62+ 🦀
$ rustup update
Enter fullscreen mode Exit fullscreen mode
  • [#492] ColumnType::Array definition changed from Array(SeaRc<Box<ColumnType>>) to Array(SeaRc<ColumnType>)
  • [#475] Func::* now returns FunctionCall instead of SimpleExpr
  • [#475] Func::coalesce now accepts IntoIterator<Item = SimpleExpr> instead of IntoIterator<Item = Into<SimpleExpr>
  • [#475] Removed Expr::arg and Expr::args - these functions are no longer needed
  • [#507] Moved all Postgres specific operators to PgBinOper
  • [#476] Expr methods used to accepts Into<Value> now accepts Into<SimpleExpr>
  • [#476] Expr::is_in, Expr::is_not_in now accepts Into<SimpleExpr> instead of Into<Value> and convert it to SimpleExpr::Tuple instead of SimpleExpr::Values
  • [#475] Expr::expr now accepts Into<SimpleExpr> instead of SimpleExpr
  • [#519] Moved Postgres specific Expr methods to new trait PgExpr
  • [#528] Expr::equals now accepts C: IntoColumnRef instead of T: IntoIden, C: IntoIden
use sea_query::{*, tests_cfg::*};

let query = Query::select()
    .columns([Char::Character, Char::SizeW, Char::SizeH])
    .from(Char::Table)
    .and_where(
        Expr::col((Char::Table, Char::FontId))
-           .equals(Font::Table, Font::Id)
+           .equals((Font::Table, Font::Id))
    )
    .to_owned();

assert_eq!(
    query.to_string(MysqlQueryBuilder),
    r#"SELECT `character`, `size_w`, `size_h` FROM `character` WHERE `character`.`font_id` = `font`.`id`"#
);
Enter fullscreen mode Exit fullscreen mode
  • [#525] Removed integer and date time column types' display length / precision option

API Additions

  • [#475] Added SelectStatement::from_function
use sea_query::{tests_cfg::*, *};

let query = Query::select()
    .column(ColumnRef::Asterisk)
    .from_function(Func::random(), Alias::new("func"))
    .to_owned();

assert_eq!(
    query.to_string(MysqlQueryBuilder),
    r#"SELECT * FROM RAND() AS `func`"#
);
Enter fullscreen mode Exit fullscreen mode
  • [#486] Added binary operators from the Postgres pg_trgm extension
use sea_query::extension::postgres::PgBinOper;

assert_eq!(
    Query::select()
        .expr(Expr::col(Font::Name).binary(PgBinOper::WordSimilarity, Expr::value("serif")))
        .from(Font::Table)
        .to_string(PostgresQueryBuilder),
    r#"SELECT "name" <% 'serif' FROM "font""#
);
Enter fullscreen mode Exit fullscreen mode
  • [#473] Added ILIKE and NOT ILIKE operators
  • [#510] Added the mul and div methods for SimpleExpr
  • [#513] Added the MATCH, -> and ->> operators for SQLite
use sea_query::extension::sqlite::SqliteBinOper;

assert_eq!(
    Query::select()
        .column(Char::Character)
        .from(Char::Table)
        .and_where(Expr::col(Char::Character).binary(SqliteBinOper::Match, Expr::val("test")))
        .build(SqliteQueryBuilder),
    (
        r#"SELECT "character" FROM "character" WHERE "character" MATCH ?"#.to_owned(),
        Values(vec!["test".into()])
    )
);
Enter fullscreen mode Exit fullscreen mode
  • [#497] Added the FULL OUTER JOIN
  • [#530] Added PgFunc::get_random_uuid
  • [#528] Added SimpleExpr::eq, SimpleExpr::ne, Expr::not_equals
  • [#529] Added PgFunc::starts_with
  • [#535] Added Expr::custom_keyword and SimpleExpr::not
use sea_query::*;

let query = Query::select()
    .expr(Expr::custom_keyword(Alias::new("test")))
    .to_owned();

assert_eq!(query.to_string(MysqlQueryBuilder), r#"SELECT test"#);
assert_eq!(query.to_string(PostgresQueryBuilder), r#"SELECT test"#);
assert_eq!(query.to_string(SqliteQueryBuilder), r#"SELECT test"#);
Enter fullscreen mode Exit fullscreen mode
  • [#539] Added SimpleExpr::like, SimpleExpr::not_like and Expr::cast_as
  • [#532] Added support for NULLS NOT DISTINCT clause for Postgres
  • [#531] Added Expr::cust_with_expr and Expr::cust_with_exprs
use sea_query::{tests_cfg::*, *};

let query = Query::select()
    .expr(Expr::cust_with_expr("data @? ($1::JSONPATH)", "hello"))
    .to_owned();

assert_eq!(
    query.to_string(PostgresQueryBuilder),
    r#"SELECT data @? ('hello'::JSONPATH)"#
);
Enter fullscreen mode Exit fullscreen mode
  • [#538] Added support for converting &String to Value

Miscellaneous Enhancements

  • [#475] New struct FunctionCall which hold function and arguments
  • [#503] Support BigDecimal, IpNetwork and MacAddress for sea-query-postgres
  • [#511] Made value::with_array module public and therefore making NotU8 trait public
  • [#524] Drop the Sized requirement on implementers of SchemaBuilders

Integration Examples

SeaQuery plays well with the other crates in the rust ecosystem.

Community

SeaQL is a community driven project. We welcome you to participate, contribute and together build for Rust's future.

Top comments (0)