LINUX.ORG.RU

Релиз Diesel 2.3.0

 diesel, , ,


0

4

Diesel — это безопасный, высокопроизводительный и расширяемый ORM и генератор SQL-запросов для языка Rust. Diesel гарантирует корректность генерируемых SQL-запросов и совместимость между типами, используемыми в коде приложения, и типами в БД. Код, который сгенерировал бы падающий запрос, попросту не скомпилируется. При этом, Diesel является zero-cost абстракцией: производительность кода, использующего Diesel такая же, как производительность кода на C, напрямую вызывающего SQL-запросы.

Основные нововведения в релизе 2.3.0

Новый макрос #[derive(HasQuery)]

Позволяет использовать структуру напрямую для генерации SQL-запроса.

use crate::schema::users;

#[derive(HasQuery)]
struct User {
    id: i32,
    name: String,
}

let users = User::query().load(connection)?

Раньше для в этом случае нужно было применять дерайвы Queryable и Selectable и использовать более громоздкий вызов users::table.select(User::as_select())

Поддержка оконных функций

Наконец-то Diesel поддерживает из коробки генерацию SQL с оконными функциями. Например, код

employees::table
    .select(
        dsl::rank()
            .partition_by(employees::department)
            .window_order(employees::salary.desc())
            .frame_by(dsl::frame::Rows.frame_starts_with(dsl::frame::UnboundedPreceding))
    )

сгенерирует следующий SQL-запрос:

SELECT
   RANK() OVER(PARTITION BY department ORDER BY salary DESC ROWS UNBOUNDED PRECEDING
FROM 
   employees

Разумеется, есть поддержка определений новых оконных функций:

#[declare_sql_function]
extern "SQL" {
    #[window]
    fn row_number() -> BigInt;
}

Поддержка SQLite в WASM

Diesel теперь поддерживает SQLite в любом WASM-рантайме, включая веб-браузеры.

Поддержка дополнительных типов для PostgreSQL

Добавлена поддержка типов RANGE и MULTIRANGE и операций над этими типами.

Поддержка JSON и JSONB для SQLite

Добавлена поддержка типов и функций JSON и JSONB для SQLite.

>>> Подробности

★★★★★

Проверено: CrX ()
Последнее исправление: dataman (всего исправлений: 3)

Код, который сгенерировал бы падающий запрос, попросту не скомпилируется.

Это как?

ya-betmen ★★★★★
()
Ответ на: комментарий от ya-betmen

Ну например, вот такой код из документации (валидный):

#[derive(Insertable)]
#[diesel(table_name = users)]
struct NewUser<'a> {
    name: &'a str,
    hair_color: Option<&'a str>,
}

let new_users = vec![
    NewUser { name: "Sean", hair_color: Some("Black") },
    NewUser { name: "Gordon", hair_color: None },
];

insert_into(users)
    .values(&new_users)
    .execute(&mut connection);

Если тут вместо .values() написать, скажем, .filter(), тогда система типов выдаст ошибку. Или если в NewUser поле name будет интом, тогда тоже система типов выдаст ошибку.

В общем такого рода проверки все реализованы через типы. От этого типы в дизеле километровые, и хоть в коде приложения этого обычно не видно, сообщения об ошибках часто очень пугающие. Но зато в дизеле статические гарантии работают очень хорошо (в отличие от sqlx, где они, по моему мнению, чисто номинальные).

provaton ★★★★★
() автор топика
Ответ на: комментарий от provaton

Писать SQL руками, а автогенерацию использовать только для мапперов (типа sqlx::FromRow) из сырых строк в типы

KivApple ★★★★★
()
Ответ на: комментарий от KivApple

Я очень люблю писать SQL руками, но в некоторых задачах это превращается в ад. Например, вот банальнейшая задачка - есть таблица, в ней 3 поля - строка, инт, дата-время.

Надо написать функцию поиска по этой таблице. Пользователь может искать по любой комбинации полей, для инта и даты-время должна быть возможность указания рейнджа (открытого или закрытого). Для строки нужно искать через LIKE.

Как ты бы реализовывал такое с подходом «писать SQL руками»?

provaton ★★★★★
() автор топика
Ответ на: комментарий от provaton

Не это-то я понимаю, но как он проверит что:

1. Я в запросе не нарушил уникальность ключей?

2. Я буду запускать запрос на нужной субд?

3. Я буду запускать запрос на нужной версии субд?

ya-betmen ★★★★★
()
Ответ на: комментарий от ya-betmen
  1. уникальность ключей - да, это конечно только в рантайме.
  2. в .execute передается структура connection, в ней есть инфа о том, к какой ты субд коннектишься. Вызвать постргес-специфические функции для mysql он тебе не даст.
provaton ★★★★★
() автор топика
Ответ на: комментарий от rukez

А может у них зимняя версия есть?

gns ★★★★★
()
Ответ на: комментарий от provaton

Или прокладывать базу хранимыми процедурами и звать только их, или писать select'ы напрямую.

Очень часто запросы от ORM сводятся к select * from all_tables (tm) и разбору полученного потока вручную в приложении.

gns ★★★★★
()
Ответ на: комментарий от KivApple

А если пишется коробочный продукт, для которого необходима поддержка PostgreSQL, MySQL, Oracle, MSSQL, etc? Писать набор SQL под каждую СУБД отдельно?

static_lab ★★★★★
()
Ответ на: комментарий от gns

селекты напрямую - это по сути генерация SQL через всякие манипуляциями со строками (форматирование, темплейты). Очень error prone, очень небезопасно (проглядеть скл инъекцию - раз плюнуть). Но к сожалению sqlx очень пиарит такой подход, хотя это дебилизм как по мне.

Хранимые процедуры - хорошая штука, но тоже не без недостатков. Больше лок ина на базу данных, гемор с контролем версий и ci/cd. Ну и если говорить о коммерческой разработке, то с таким подходом в команде должен быть хороший ДБА, а их капец как сложно найти.

provaton ★★★★★
() автор топика
Ответ на: комментарий от provaton

Тут я согласен, и SQL плохо (хотя, смотря где, не все задачи сводятся к трансляции URL или JSON в базу напрямую, и хранилки — тот еще геммор...

А версионность в базе — вообще плохо решаемая проблема везде... :( Только дисциплиной решается и регресс-тестами с хорошим покрытием.

Возможно, существуют ORM, которые умеют оптимизировать как-то запросы и учитывать план запроса, который нагенерит база, но я таких не видел. Оно, конечно хорошо, когда перед запросом прогнать select/describe и потом уже писать запрос в синтаксисе ORM, но кто ж знает-то, что ORM там реально сгенерит...

Я, помнится, как-то имел некую халтуру и писал биллинг для некого районного провайдера, так я тогда написал на Си библиотеку, которая брала статистику с ipfilter и пихала ее в базу напрямую. Скорость выросла раза в два по сравнению с опросом интерфейсов и кучей инсертов. Тоже себе подход. Благо хранилки можно писать на чем угодно.

gns ★★★★★
()
Последнее исправление: gns (всего исправлений: 1)
Ответ на: комментарий от static_lab

если необходима поддержка «всего сразу пофигу как» то запросы укладываются в общий синтаксис унифицированного sql
если нужна поддержка со спецификой конкретных бд и движков то под нее пишется собсно специфика - зачем надеяться на то что орм угадает что конкретно требуется если требуется что-то конкретное?

rukez ★★★★★
()
Ответ на: комментарий от static_lab

А если пишется коробочный продукт, для которого необходима поддержка PostgreSQL, MySQL, Oracle, MSSQL, etc? Писать набор SQL под каждую СУБД отдельно?

  1. Вы SQLite здесь забыли в список баз добавить для полноты :) Пример так себе, скажем.
  2. И конечно же ORM сгенерируют для каждой из этих по-разному устроенных Баз Данных и их версий очень производительный и оптимизированный код SQL, который сразу же можно будет выставлять в качестве приложения для какой-либо Лондонской биржи. Верю :)

В общем, вердикт такой (одновременно с rulez написал, но независимо друг от друга :)) - если приложение не напряженное с точки зрения обработки данных, ORM - допустим. Если нет, то SQL в руки и лучше в Хранимках на сервере и вместе с админом БД вылизывать планы.

MichIs
()
Последнее исправление: MichIs (всего исправлений: 3)

Код выглядит как лютейшая дичь. Как обычно бывает с ORM, нужно сначала продумать SQL запрос, потом перевести его на рептилоидный и молиться, чтобы орм сгенерил примерно то, что ожидалось. С листа без мысленной трансляции туда-сюда писать можно только простейшие запросы.

bread
()
Ответ на: комментарий от MichIs

Вполне нормальный список для энтерпрайз-решения. Например, у Джиры так: https://confluence.atlassian.com/adminjiraserver/supported-platforms-938846830.html

Само собой, SQLite никто на продакшене ставить не будет. Но, справедливости ради, для тестовых запусков у Джиры есть встроенная H2, поэтому для решения на Rust может быть и SQLite как встроенная тестовая база.

static_lab ★★★★★
()
Ответ на: комментарий от MichIs

если приложение не напряженное с точки зрения обработки данных, ORM - допустим

А зачем?
Например я хочу выйти за рамки прям самого просто insert и получить id который таблица с auto increment ему назначила - что сгенерит орм? Запрос последнего identity следующим запросом к базе? А если из другого потока/приложения между ними произойдет еще один insert? Или второй строкой в одном запросе?
Или обернет транзакцией?
О муки выбора для орма, догадаться что я вообще пишу, с каким темпом оно будет писать, во сколько потоков и со скольки клиентов 😁

Ну и самый цимус - для легких задач освоить sql можно очень шустро, там даже шишек особо негде набивать и оно всегда пригодится хотя бы в консоле бд посидеть если вдруг чего.
Освоить синтаксис орма? Ну наверное тоже не сложно, только он вроде у всех разных и полностью бестолков если придется общаться с базой напрямую или через анализатор/профайлер запросов

Для сложных запросов я чот не вижу чтоб орм делал что-то проще в сложных запросах сложна сама логика - что куда во что вкладывается, с чем стыкуется и к чему подвязывается - написано оно на sql или на костылях логику проще не сделает, но костыли явно намекают на то что когда результат генерации орма будет «вооон тут вложилось не туда» вариантов исправить что-то будет немного - разве что ждать фикса от разрабов вместо того что бы просто передвинуть скобку в запросе самому 😁

rukez ★★★★★
()
Ответ на: комментарий от rukez

и получить id который таблица с auto increment ему назначила - что сгенерит орм?

дизель поддерживает ретурнинг - https://docs.diesel.rs/2.3.x/diesel/dsl/type.Returning.html

О муки выбора для орма, догадаться что я вообще пишу

Дизель очень близко к СКЛ, в расте ООП как такового нет, поэтому никакой особой там магии не будет. Что пишешь, то и получаешь. Тем более в дизеле, как в любом современном ОРМ, можно юзать квери билдер напрямую, без собственно ОРМа.

Ну и самый цимус - для легких задач освоить sql можно очень шустро,

Я там выше в треде легкую задачу придумал - Релиз Diesel 2.3.0 (комментарий)

Интересно, как ты ее бы реализовал?

provaton ★★★★★
() автор топика
Последнее исправление: provaton (всего исправлений: 1)
Ответ на: комментарий от provaton

Тогда поправь или удали дезинформацию

Код, который сгенерировал бы падающий запрос, попросту не скомпилируется.

ya-betmen ★★★★★
()
Ответ на: комментарий от ya-betmen

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

provaton ★★★★★
() автор топика
Ответ на: комментарий от gns

Ой-ей. Не надо так базу использовать, ей больно. Такой ORM - плохой ORM.

Но даже с хорошими SQL-генераторами, которые дают оптимальный для имеющейся структуры БД и выбранного типа СУБД запрос, программисту очень легко свалиться в ересь.

Просто потому, что конструктор позволяет человеку накидывать всё более и более сложные конструкции, даже не показывая конечного результата. Для программиста всё просто - набрал из готовых кубиков запчастей и DSLем их склеил. А на выходе - CTEшка вызывает CTEшку, вложенные селекты на три-четыре слоя, запросы на несколько экранов текста. Руками, без хелперов, такого не написать. Да, PG справляется, как правило. Но иногда планировщику башню рвёт, или утыкается, например, в плохую производительность CTEшек.

AlexM ★★★★★
()
Ответ на: комментарий от MichIs

При таком подходе, когда логика приложения сосредоточена в хранимых процедурах, судьба всего проекта подвешивается на дорогого и, часто, капризного администратора БД. Случись с ним чего (заболел/запил/уволился) - и вся команда сидит, щелкает клювами.

AlexM ★★★★★
()
Ответ на: комментарий от provaton

Пользователь может искать по любой комбинации полей, для инта и даты-время должна быть возможность указания рейнджа (открытого или закрытого). Для строки нужно искать через LIKE.

Ну и получается, что для каждого случая запросы разные. С ормом тоже будет говнокод, если всё в одну функцию впихнуть.

bread
()
Ответ на: комментарий от gns

А версионность в базе — вообще плохо решаемая проблема везде... :( Только дисциплиной решается и регресс-тестами с хорошим покрытием.

Liquibase? Flyway?

Возможно, существуют ORM, которые умеют оптимизировать как-то запросы и учитывать план запроса, который нагенерит база, но я таких не видел. Оно, конечно хорошо, когда перед запросом прогнать select/describe и потом уже писать запрос в синтаксисе ORM, но кто ж знает-то, что ORM там реально сгенерит...

Типа Hypersistence Optimizer ? (сам не использовал)

X-Pilot ★★★★★
()
Последнее исправление: X-Pilot (всего исправлений: 1)
Ответ на: комментарий от static_lab

Как ты совместишь oracle с mysql если в оракле пустая строка это null а в mysql нет?

Опять Вера в волшебный орм , который обеспечит кроссплатформенность.

Psilocybe ★★★★★
()
Последнее исправление: Psilocybe (всего исправлений: 1)
Ответ на: комментарий от static_lab

коробочных продуктов не делал, но был опыт переезда с MySQL на Oracle. Прходилось вдумчиво тестировать каждый запрос, благо все запросы были объеденены в моделях данных.

Могу предположить, что в коробочном продукте должны быть модели данных с общим интерфейсом. А уже реализация может отличаться.

Psilocybe ★★★★★
()
Ответ на: комментарий от Pierre_Dolle

SQL - не императивный, он декларативный язык. И есть ощущение, что таки да, декларативный язык и ООП неплохо совместимы, но неидеально, как и всё на свете. Шероховатости всегда будут. На то и есть разработчик, чтобы знать, где эти шероховатости есть, и соломки подстелить.

Chiffchaff
()
Ответ на: комментарий от AlexM

При таком подходе, когда логика приложения сосредоточена в хранимых процедурах, судьба всего проекта подвешивается на дорогого и, часто, капризного администратора БД

Если разработчики квалифицированы и хорошо знают БД, то и администратор не нужен - он, так, для понимания разработчиками в особо запущенных случаях того, как настроено админами «железо» (но это очень редко) или для выполнения с теми, полномочиями, которых часто лишают разработчиков в больших компашках, типа «для безопасности».

MichIs
()
Ответ на: комментарий от static_lab

Это к тому, что сейчас, с возрастанием требований к количеству данных, с которым работают приложения, уже давно такая тенденция - писать под конкретную СУБД и выжимать из нее все ее соки с учетом ее особенностей.

Это раньше программы пытались писать под разные СУБД, я помню, тот же SAP якобы мог работать и под MsSQL Server и под Oracle (MySQL и SQLite вроде бы не поддерживал :) ) с его «Open SQL» -диалектом SQL, на котором писали в SAP, а потом он уже в рантайме переводился в диалекты тех СУБД, на которых работал SAP - то же некоторого рода ORM. Но 95% установок было под Oracle DB. А сейчас под свою SAP HANA.

А так, да, были такие ORM для работы с разными БД, и даже сейчас остаются, например, всем нам известный 1С. Он якобы работает с Ms SQL Server, Oracle DB, IBM DB2, PostgreSQL «из каропки». А на самом деле раньше работал хорошо только с Ms SQL Server, а сейчас якобы с PostgreSQL - и статьями по настройкам, изменениям PostgreSQL под 1С, 1С под PostgreSQL и т.д забиты Habr и около 1С-ные сайты уже лет 5, хотя обещали «из каропки» еще лет 10-15 назад.

Ну а Jira - продукт неплохой, но почему-то везде где я работал на нем он сильно тормозил. Я не разбирался почему - то ли админы криворукие, то ли железо слабое, то ли java-ORM там хреновая. Но ассоциия Jira-тормоза у меня прочно засело в голове.

MichIs
()
Ответ на: комментарий от MichIs

ORM позволит перенести проект на другую СУБД не без изменений, но с минимальными изменениями. Изредка это нужно. Хотя я не считаю, что это основной плюс ORM.

В жизни встречал несколько раз проекты, переехавшие с одной СУБД на другую. Хотя, да, наверное, это редкий случай.

Chiffchaff
()
Ответ на: комментарий от MichIs

В контексте переносимости речь идёт скорее о том, что ORM даёт возможность писать переиспользуемые библиотеки, которые можно использовать с любой СУБД. Это уже более весомый плюс.

Chiffchaff
()
Ответ на: комментарий от X-Pilot

Liquibase? Flyway?

Почему-то в большом проекте, к которому я имел отношение это все не использовалось. Не умели, может быть? Спасибо, постараюсь запомнить. Вдруг пригодится когда...

gns ★★★★★
()
Ответ на: комментарий от AlexM

Ой-ей. Не надо так базу использовать, ей больно. Такой ORM - плохой ORM.

Ну вот почему-то hibernate джавайский так и работал в одном большом проекте. Я так и не понял, по другому не умел, или программеры по другому не умели... Трудно сказать.

gns ★★★★★
()
Ответ на: комментарий от Chiffchaff

Правильное разделения своего приложения на слои, при котором работа с БД вынесена в свой слой(модуль) - тоже позволяет с относительно минимальными изменениями переходить с одной СУБД на другую.

Пйсатели ORM не всегда хорошо разбираются в особенностях разных СУБД - это раз, два - трудозатратно поддерживать ORM, чтобы они работали одинаково хорошо с разными СУБД. Это могут позволить себе только относительно большие и финансируемые команды, типа SQLAlchemy, Hibernate и т.д.

И это не говоря о том, что под разные СУБД для одной и той же задачи можно по-разному проектировать структуры и другие вещи. (в общем случае, на относительно простых решениях, структура может быть и одинаковой - но при этом может теряться значительная часть оптимизаций, предоставляемых СУБД, и до 50% и более производительности)

MichIs
()
Ответ на: комментарий от MichIs

Но ассоциия Jira-тормоза у меня прочно засело в голове.

Понапихают всякие Spring’и во все дыры, а потом люди удивляются, что софт тормозит.

WatchCat ★★★★★
()
Ответ на: комментарий от Chiffchaff

Переносимость между СУБД это фантазии. Единственная мотивация для ORM это «не хотим, не умеем писать SQL, пусть оно как-то само». Теперь, когда железяка сама пишет вообще всё, уже пофиг ORM там или что. Что ИИ нагуглит, то и будет, скорей всего какое-то говно в 5 слоеев, как модно было у последних кожаных писателей.

bread
()
Последнее исправление: bread (всего исправлений: 1)
Ответ на: комментарий от gns

Ну, да, тут велик соблазн накидать с широкой лопаты, и до времени незаметно будет, «всё ж работает».

А потом объемы базы дорастают до терабайтов, и SELECT * FROM table начинает выполняться по двадцать-тридцать минут…

AlexM ★★★★★
()
Ответ на: комментарий от MichIs

Это довольно дорого — держать в проекте много людей, хорошо умеющих в PL/SQL и прочие знания,специфичные для DBA. Поскольку в любом живом проекте бизнес-требования меняются с течением времени, то перенос логики в базу неизбежно приводит к тому, что разработка становится дорогой.

Разделение полномочий, так, чтобы исключить или хотя бы уменьшить масштабы и вероятность утечек, — это, в среднем, хорошая практика. Но, опять же, она удорожает проектирование и разработку, поэтому в каждом конкретном случае считать отдельно надо.

AlexM ★★★★★
()
Ответ на: комментарий от gns

В корпоративной разработке (Java/Kotlin), наоборот, используется практически всегда. Обычно Liquibase, довольно редко Flyway, крайне редко самописные DDL. Для Java проектов оно очень просто встраивается в пайплайн: в Spring Boot - нужно прописать конфиг, в Maven - добавить фазу. Для всех остальных проектов (не-Java_based) - используется отдельный клиент.

X-Pilot ★★★★★
()
Последнее исправление: X-Pilot (всего исправлений: 1)
Ответ на: комментарий от bread

почему говнокод? Вообще если у тебя на вполне реальную практическую задачу возникает ответ, что она решается лишь говнокодом, то что-то с тобой не так.

если использовать генератор зарпосов, то решение будет примерно какое-то такое (псевдокод):

fn handle_field1(base_query, search_request) -> query {
    base_query.filter(...)
}

fn handle_field2(base_query, search_request) -> query {
    base_query.filter(...)
}

...

handlers = [handle_field1, handle_field2, ...];

fn execute_search(search_request) -> result {
    let query = table::query();
    for handler in handlers {
         query = handle(query, search_request);
    }
    query.execute()
}

На голом скл по сути будет то же самое, только вручную форматишь кверю. Я видел как некоторые ребята юзают темплейты типа jinja чтоб сформировать sql запрос. ЗАТО НЕ ОРМ!

provaton ★★★★★
() автор топика
Последнее исправление: provaton (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.