userver
userver copied to clipboard
Реализация конструктора запросов QueryBuilder
Часто приходится реализовывать запросы к БД, которые в зависимости от переданных параметров должны добавлять в запрос к БД дополнительные условия - фильтры.
Например, если передали строковый параметр, то нужно поискать в строковых полях, если передали коллекцию идентификаторов, то поискать с вхождением какого-то поля в эту коллекцию( массив).
Для этих целей удобно использовать QueryBuilder по типу такого:
https://docs.rs/sqlx/latest/sqlx/struct.QueryBuilder.html
Фактически он просто склеивает запрос, позволяя вставлять аргументы с эскейпингом для защиты от иньекций.
Добавляет escaped значение фильтра: builder.bind(filter) Вставляет строку в запрос как есть: buidler.bind(" AND value IN ")
ну и другие удобные методы.
Есть ли что-то подобное в userver? Я не нашел. Если нет, было бы классно реализовать
У нас есть данный функционал 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
- параметры отделены от запроса - нет возможности получить уязвимость
Это отлично! А для кликхауса?
А вот для кликхауса подобный функционал не выставлен наружу, при том что эскейпинг и формирование запросов реализованы :(
Надо будет нам добавить класс storages::clickhouse::ParameterStore и документацию по использованию.
Добавить можно, и это должно быть относительно просто, т.к. параметры в драйвере кликхауса сериализуются в строки, из которых собирается итоговый запрос буквально через fmt::format(...)
:
https://github.com/userver-framework/userver/blob/d0c4578727d8ff2e0b889f2872c2632ecd314b23/clickhouse/include/userver/storages/clickhouse/query.hpp#L51-L56
Думаю ParameterStore может быть обёрткой над вектором строк, например