🎉 Мы рады выпустить SeaQuery 0.27.0! Вот некоторые особенности 🌟:


Обновление зависимостей

[#356] Мы обновили основную зависимость:

Возможно, вам также потребуется обновить соответствующую зависимость в вашем приложении.


Поддержка водителей

Мы переработали работу драйверов в SeaQuery: от априори до 0.27.0пользователи должны вызывать sea_query_driver_* макросы. Теперь каждый водитель sqlx, postgres & rusqlite имеет собственный поддерживающий крейт, который тесно интегрируется с соответствующими библиотеками. Ознакомьтесь с нашими примерами интеграции ниже для более подробной информации.

[#383] Устареть sea-query-driver в пользу sea-query-binder

[#422] Поддержка Rusqlite перемещена в sea-query-rusqlite

[#433] Поддержка Postgres перемещена в 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();
Войти в полноэкранный режим

Выйти из полноэкранного режима


Поддержка операторов подзапросов: EXISTS, ALL, ANY, SOME

[#118] Добавлены операторы подзапроса: 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")"#
);
Войти в полноэкранный режим

Выйти из полноэкранного режима


Поддерживать ON CONFLICT WHERE

[#366] Добавлена ​​поддержка 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"#
);
Войти в полноэкранный режим

Выйти из полноэкранного режима


Изменена семантика цепочки cond_where

[#414] Изменена семантика цепочки cond_where

// 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"#
);
Войти в полноэкранный режим

Выйти из полноэкранного режима


Добавлен OnConflict::value а также OnConflict::values

[#451] Реализация From<T> для любого Into<Value> в 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))
Войти в полноэкранный режим

Выйти из полноэкранного режима


Улучшение ColumnDef::default

[#347] ColumnDef::default теперь принимает Into<SimpleExpr> вместо Into<Value>

// Now we can write:
ColumnDef::new(Char::FontId)
    .timestamp()
    .default(Keyword::CurrentTimestamp)
Войти в полноэкранный режим

Выйти из полноэкранного режима


Критические изменения

  • [#386] Измененный in_tuples интерфейс для принятия IntoValueTuple
  • [#320] Удалены устаревшие методы
  • [#440] CURRENT_TIMESTAMP изменено с функции на ключевое слово
  • [#375] Обновить SQLite boolean тип из integer toлогический`
  • [#451] Устаревший OnConflict::update_value, OnConflict::update_values, OnConflict::update_expr, OnConflict::update_exprs
  • [#451] Устаревший InsertStatement::exprs, InsertStatement::exprs_panic
  • [#451] Устаревший UpdateStatement::col_expr, UpdateStatement::value_expr, UpdateStatement::exprs
  • [#451] UpdateStatement::value теперь прими Into<SimpleExpr> вместо Into<Value>
  • [#451] Expr::case, CaseStatement::case а также CaseStatement::finally теперь принимает Into<SimpleExpr> вместо Into<Expr>
  • [#460] InsertStatement::values, UpdateStatement::values теперь принимает IntoIterator<Item = SimpleExpr> вместо IntoIterator<Item = Value>
  • [#409] Используйте собственный API из SQLx для SQLite для работы со временем
  • [#435] Изменен тип ColumnType::Enum из (String, Vec<String>) к Enum { name: DynIden, variants: Vec<DynIden>}


Разные улучшения

  • [#336] Добавлена ​​поддержка одномерного массива Postgres для SQLx.
  • [#373] Поддержка ПЕРЕКРЕСТНОГО СОЕДИНЕНИЯ
  • [#457] Добавлена ​​поддержка DROP COLUMN для SQLite
  • [#466] Добавлен YEAR, BIT а также VARBIT типы
  • [#338] Обрабатывать имя схемы Postgres для операторов схемы
  • [#418] Добавлен %, << а также >> бинарные операторы
  • [#329] Добавлена ​​функция СЛУЧАЙ
  • [#425] Реализует Display за Value
  • [#427] Добавлен INTERSECT а также EXCEPT к UnionType
  • [#448] OrderedStatement::order_by_customs, OrderedStatement::order_by_columns, OverStatement::partition_by_customs, OverStatement::partition_by_columns теперь принимает IntoIterator<Item = T> вместо Vec<T>
  • [#452] TableAlterStatement::rename_column, TableAlterStatement::drop_column, ColumnDef::new, ColumnDef::new_with_type теперь принимает IntoIden вместо Iden
  • [#426] Очистка IndexBuilder методы признаков
  • [#436] Вводить SqlWriter черта
  • [#448] Удалить ненужное vec! из примеров


Исправление ошибок

  • [#449] distinct_on правильно обрабатывает ColumnRef
  • [#461] Удаленный ON за DROP INDEX для SQLite
  • [#468] Измените формат строки даты и времени, чтобы включить микросекунды
  • [#452] ALTER TABLE для PosgreSQL с UNIQUE ограничение


Примеры интеграции

SeaQuery хорошо сочетается с другими крейтами в экосистеме ржавчины.


Сообщество

SeaQL — это проект, управляемый сообществом. Мы приглашаем вас принять участие, внести свой вклад и вместе строить будущее Rust.