userver icon indicating copy to clipboard operation
userver copied to clipboard

Реализация конструктора запросов QueryBuilder

Open MikhailNazarov opened this issue 2 years ago • 4 comments

Часто приходится реализовывать запросы к БД, которые в зависимости от переданных параметров должны добавлять в запрос к БД дополнительные условия - фильтры.

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

Для этих целей удобно использовать QueryBuilder по типу такого:

https://docs.rs/sqlx/latest/sqlx/struct.QueryBuilder.html

Фактически он просто склеивает запрос, позволяя вставлять аргументы с эскейпингом для защиты от иньекций.

Добавляет escaped значение фильтра: builder.bind(filter) Вставляет строку в запрос как есть: buidler.bind(" AND value IN ")

ну и другие удобные методы.

Есть ли что-то подобное в userver? Я не нашел. Если нет, было бы классно реализовать

MikhailNazarov avatar Jul 04 '22 15:07 MikhailNazarov

У нас есть данный функционал https://userver.tech/da/dd0/classstorages_1_1postgres_1_1ParameterStore.html . Но вот документации и примеров использования катострафически не хватает. Добавлю в ближайшее время.

По поводу свободной функции escape истоирия интереснее. Escape нет и не планируется:

  • такое API провоцирует появление уязвимостей в коде
  • такое API ведёт к деградации производительности

Драйвер PostgreSql у нас работает следующим образом. Когда SQL query встречается в первый раз, драйвер превращает его в prepared statement. После этого используется только prepared statement, все параметры посылаются отдельно в бинарном виде без эскейпинга.

В результате получаем следующие плюсы:

  • по сети каждый раз не шлётся текст запроса - экономится сетевой трафик
  • база данных работает с prepared statement - у неё больше возможностей для оптимизации плана запроса
  • параметры запроса шлются в бинарном виде - экономится CPU
  • параметры отделены от запроса - нет возможности получить уязвимость

apolukhin avatar Jul 05 '22 09:07 apolukhin

Это отлично! А для кликхауса?

MikhailNazarov avatar Jul 05 '22 09:07 MikhailNazarov

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

Надо будет нам добавить класс storages::clickhouse::ParameterStore и документацию по использованию.

apolukhin avatar Jul 06 '22 08:07 apolukhin

Добавить можно, и это должно быть относительно просто, т.к. параметры в драйвере кликхауса сериализуются в строки, из которых собирается итоговый запрос буквально через fmt::format(...): https://github.com/userver-framework/userver/blob/d0c4578727d8ff2e0b889f2872c2632ecd314b23/clickhouse/include/userver/storages/clickhouse/query.hpp#L51-L56


Думаю ParameterStore может быть обёрткой над вектором строк, например

itrofimow avatar Oct 26 '23 04:10 itrofimow