π We are pleased to release SeaQuery 0.27.0
! Here are some feature highlights π:
Dependency Upgrade
[#356] We have upgraded a major dependency:
- Upgrade
sqlx
to 0.6.1
You might need to upgrade the corresponding dependency in your application as well.
Drivers support
We have reworked the way drivers work in SeaQuery: priori to 0.27.0
, users have to invoke the sea_query_driver_*
macros. Now each driver sqlx
, postgres
& rusqlite
has their own supporting crate, which integrates tightly with the corresponding libraries. Checkout our integration examples below for more details.
[#383] Deprecate sea-query-driver
in favour of sea-query-binder
[#422] Rusqlite support is moved to sea-query-rusqlite
[#433] Postgres support is moved to sea-query-postgres
// before
sea_query::sea_query_driver_postgres!();
use sea_query_driver_postgres::{bind_query, bind_query_as};
let (sql, values) = Query::select()
.from(Character::Table)
.expr(Func::count(Expr::col(Character::Id)))
.build(PostgresQueryBuilder);
let row = bind_query(sqlx::query(&sql), &values)
.fetch_one(&mut pool)
.await
.unwrap();
// now
use sea_query_binder::SqlxBinder;
let (sql, values) = Query::select()
.from(Character::Table)
.expr(Func::count(Expr::col(Character::Id)))
.build_sqlx(PostgresQueryBuilder);
let row = sqlx::query_with(&sql, values)
.fetch_one(&mut pool)
.await
.unwrap();
// You can now make use of SQLx's `query_as_with` nicely:
let rows = sqlx::query_as_with::<_, StructWithFromRow, _>(&sql, values)
.fetch_all(&mut pool)
.await
.unwrap();
Support sub-query operators: EXISTS
, ALL
, ANY
, SOME
[#118] Added sub-query operators: EXISTS
, ALL
, ANY
, SOME
let query = Query::select()
.column(Char::Id)
.from(Char::Table)
.and_where(
Expr::col(Char::Id)
.eq(
Expr::any(
Query::select().column(Char::Id).from(Char::Table).take()
)
)
)
.to_owned();
assert_eq!(
query.to_string(MysqlQueryBuilder),
r#"SELECT `id` FROM `character` WHERE `id` = ANY(SELECT `id` FROM `character`)"#
);
assert_eq!(
query.to_string(PostgresQueryBuilder),
r#"SELECT "id" FROM "character" WHERE "id" = ANY(SELECT "id" FROM "character")"#
);
Support ON CONFLICT WHERE
[#366] Added support to ON CONFLICT WHERE
let query = Query::insert()
.into_table(Glyph::Table)
.columns([Glyph::Aspect, Glyph::Image])
.values_panic(vec![
2.into(),
3.into(),
])
.on_conflict(
OnConflict::column(Glyph::Id)
.update_expr((Glyph::Image, Expr::val(1).add(2)))
.target_and_where(Expr::tbl(Glyph::Table, Glyph::Aspect).is_null())
.to_owned()
)
.to_owned();
assert_eq!(
query.to_string(MysqlQueryBuilder),
r#"INSERT INTO `glyph` (`aspect`, `image`) VALUES (2, 3) ON DUPLICATE KEY UPDATE `image` = 1 + 2"#
);
assert_eq!(
query.to_string(PostgresQueryBuilder),
r#"INSERT INTO "glyph" ("aspect", "image") VALUES (2, 3) ON CONFLICT ("id") WHERE "glyph"."aspect" IS NULL DO UPDATE SET "image" = 1 + 2"#
);
assert_eq!(
query.to_string(SqliteQueryBuilder),
r#"INSERT INTO "glyph" ("aspect", "image") VALUES (2, 3) ON CONFLICT ("id") WHERE "glyph"."aspect" IS NULL DO UPDATE SET "image" = 1 + 2"#
);
Changed cond_where chaining semantics
[#414] Changed cond_where chaining semantics
// Before: will extend current Condition
assert_eq!(
Query::select()
.cond_where(any![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
.cond_where(Expr::col(Glyph::Id).eq(3))
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE "id" = 1 OR "id" = 2 OR "id" = 3"#
);
// Before: confusing, since it depends on the order of invocation:
assert_eq!(
Query::select()
.cond_where(Expr::col(Glyph::Id).eq(3))
.cond_where(any![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE "id" = 3 AND ("id" = 1 OR "id" = 2)"#
);
// Now: will always conjoin with `AND`
assert_eq!(
Query::select()
.cond_where(Expr::col(Glyph::Id).eq(1))
.cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE "id" = 1 AND ("id" = 2 OR "id" = 3)"#
);
// Now: so they are now equivalent
assert_eq!(
Query::select()
.cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
.cond_where(Expr::col(Glyph::Id).eq(1))
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE ("id" = 2 OR "id" = 3) AND "id" = 1"#
);
Added OnConflict::value
and OnConflict::values
[#451] Implementation From<T>
for any Into<Value>
into SimpleExpr
// Before: notice the tuple
OnConflict::column(Glyph::Id).update_expr((Glyph::Image, Expr::val(1).add(2)))
// After: it accepts `Value` as well as `SimpleExpr`
OnConflict::column(Glyph::Id).value(Glyph::Image, Expr::val(1).add(2))
Improvement to ColumnDef::default
[#347] ColumnDef::default
now accepts Into<SimpleExpr>
instead Into<Value>
// Now we can write:
ColumnDef::new(Char::FontId)
.timestamp()
.default(Keyword::CurrentTimestamp)
Breaking Changes
- [#386] Changed
in_tuples
interface to acceptIntoValueTuple
- [#320] Removed deprecated methods
- [#440]
CURRENT_TIMESTAMP
changed from being a function to keyword - [#375] Update SQLite
boolean
type frominteger to
boolean` - [#451] Deprecated
OnConflict::update_value
,OnConflict::update_values
,OnConflict::update_expr
,OnConflict::update_exprs
- [#451] Deprecated
InsertStatement::exprs
,InsertStatement::exprs_panic
- [#451] Deprecated
UpdateStatement::col_expr
,UpdateStatement::value_expr
,UpdateStatement::exprs
- [#451]
UpdateStatement::value
now acceptInto<SimpleExpr>
instead ofInto<Value>
- [#451]
Expr::case
,CaseStatement::case
andCaseStatement::finally
now acceptsInto<SimpleExpr>
instead ofInto<Expr>
- [#460]
InsertStatement::values
,UpdateStatement::values
now acceptsIntoIterator<Item = SimpleExpr>
instead ofIntoIterator<Item = Value>
- [#409] Use native api from SQLx for SQLite to work with time
- [#435] Changed type of
ColumnType::Enum
from(String, Vec<String>)
toEnum { name: DynIden, variants: Vec<DynIden>}
Miscellaneous Enhancements
- [#336] Added support one dimension Postgres array for SQLx
- [#373] Support CROSS JOIN
- [#457] Added support
DROP COLUMN
for SQLite - [#466] Added
YEAR
,BIT
andVARBIT
types - [#338] Handle Postgres schema name for schema statements
- [#418] Added
%
,<<
and>>
binary operators - [#329] Added RAND function
- [#425] Implements
Display
forValue
- [#427] Added
INTERSECT
andEXCEPT
to UnionType - [#448]
OrderedStatement::order_by_customs
,OrderedStatement::order_by_columns
,OverStatement::partition_by_customs
,OverStatement::partition_by_columns
now acceptsIntoIterator<Item = T>
instead ofVec<T>
- [#452]
TableAlterStatement::rename_column
,TableAlterStatement::drop_column
,ColumnDef::new
,ColumnDef::new_with_type
now acceptsIntoIden
instead ofIden
- [#426] Cleanup
IndexBuilder
trait methods - [#436] Introduce
SqlWriter
trait - [#448] Remove unneeded
vec!
from examples
Bug Fixes
- [#449]
distinct_on
properly handlesColumnRef
- [#461] Removed
ON
forDROP INDEX
for SQLite - [#468] Change datetime string format to include microseconds
- [#452]
ALTER TABLE
for PosgreSQL withUNIQUE
constraint
Integration Examples
SeaQuery plays well with the other crates in the rust ecosystem.
- Postgres Example
- Rusqlite Example
- SQLx Any Example
- SQLx Postgres Example
- SQLx MySql Example
- SQLx Sqlite Example
Community
SeaQL is a community driven project. We welcome you to participate, contribute and together build for Rust's future.
Top comments (0)