Дизайн билдера для динамических sql запросов для golang?
Столкнулся с такой проблемой, что не могу найти билдер для запросов sql для го, который будет уметь принимать список нужных колонок и нужных фильтров для последующей генерации запроса. например есть таблица users с колонками (id,name,creation_date,password,last seen) в функцию мы передадим, что хотим увидеть поля (name,password,creation_date), а в качестве условий/фильтров поле name != 'user' и last_seen > 15.07.2023. И соотвественно чтобы функция выглядела примерно так NewSQL(fields,filters), которая возвращала бы уже sql запрос, т.е. билдер на основании этих двух параметров уже всё делает для произвольных полей.
Билдеры которые уже есть, частично реализуют вопросы с автоматическим генерацией запроса, но поверх них равно нужно писать много своего кода, чтобы сделать динамический фильтр и по сути для каждоый таблицы нужно будет писать много своего кода.
Если возможно, то было круто увидеть пример такого билдера конкретно для го и получить информацию по тому как правильно задизайнить такой фильтр. Возможно мой подход в целом является неправильным в этом случае хотелось бы услышать критику
Фильтры как вы хотите будет реализовать сложнее, так как там три аргумента получается, поле знак и значение, опять же там могут быть варианты с И и ИЛИ
Чисто функцию конкретно для задачи возможно будет сделать не сложно. Так же обычно делают плэйсхолдеры и сам запрос для подготовки
Александр Павлюк, это полезная штука, но она не подходит в том плане, что каждый запрос нужно вручную писать, т.е. не получится просто туда передать список колонок и условий которые нужно будет выполнить, всю эту логику придётся самому писать
В filters я думал сделать в виде большой структуры/класса, в которой уже будет вся нужная инфа, т.е. например там хранится limit, offset, список нужных полей, и в ней же хранится ConditionFilter, в котором указаны поле, значение, тип операции и т.д.
Чисто функцию конкретно для задачи возможно будет сделать не сложно.
Я сделал урезанный вариант для одной таблицы в целом это работает нормально, но перед тем как делать более полный и общий вариант, я хотел бы дизайн улучшить
Так же обычно делают плэйсхолдеры и сам запрос для подготовки
Можете пж конкретный пример привести? Я возможно не совсем понял, но например можно будет написать 1 такой запрос, которого хватит для того, чтобы получить фильтр, который сможет искать по 20+ параметрам, как например на озоне или в днс?
Александр Павлюк, в сквирел заранее нужно прописать, что в запросе будет where/offset. Т.е. программист напишет свой запрос заранее. Допустим у меня будет фильтр для поиска по 3 параметрам дата, возраст, имя, чтобы фильтр работал мне нужно будет написать отдельную функцию конкретно под него. Типа такого (пример не мой а со страницы squirell"
import sq "github.com/Masterminds/squirrel"
users := sq.Select("*").From("users").Join("emails USING (email_id)")
active := users.Where(sq.Eq{"deleted_at": nil})
sql, args, err := active.ToSql()
sql == "SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL"
, условно если в фильтр добавится несколько параметров, то мне придется переписывать код. Я же хочу, чтобы вся информация поступала уже в фильтре, т.е. передаю в функцию информацию о том, какие условия должны быть, какое значение должно быть больше/меньше, при этом если бы я добавил лишнее поле, то мне не пришлось бы переписывать код фильтра
Squirrel makes conditional query building a breeze:
if len(q) > 0 {
users = users.Where("name LIKE ?", fmt.Sprint("%", q, "%"))
}
Вот более наглядный пример, в их же примере пишут, как они предлагают решать ситуацию с доп. условиями, т.е. если хочешь добавить дополнительное поле, то пиши лишний if под него
calculator212, нет же, в сквирел запрос билдился динамически на рантайме, вы можете его по частям билдить и добавлять или не добавлять какие-то поля или условия в зависимости от логики вашего кода.
просто надо написать тонкую обертку над сквирелом, которая подгонит логику под нужную вам
Я как раз и хочу написать либу, которая сможет избегать написания прослоек, и вместо прослоек данные будут браться из фильтров, которые передаёт пользователь
Я примерно сейчас так и делаю, это достаточно удобный подход, но я хотел попробовать перейти к более общему подходу и не привязывать либу к конкретным билдерам
calculator212, как по мне, функция Where(sq.And{}) у сквирела это и есть "фильтры, которые передает пользователь", так и не понял, чем отличается от этого то, что вы хотите. Там sq.And это как раз массив предикатов.
как по мне, функция Where(sq.And{}) у сквирела это и есть "фильтры, которые передает пользователь", так и не понял, чем отличается от этого то, что вы хотите.
Думаю ваш вариант рабочий и в целом можно написать про то, что я говорил, думаю пару идей точно возьму из него. Если хотите могу как ответ отметить