Комментарии 13
Hola si quieres pueda darte el codigo si lo ncesitas ?
Идея может и интересная академически, но всё ещё непонятно, зачем оно нужно, например, в продакшене? Чтобы увеличить время отработки запроса за счёт парсинга SQL и построения запроса? Чтобы усложнить себе работу за счёт изобретения сферических велосипедов в вакууме? В данном конкретном сценарии запросы простые, и вполне можно обойтись передачей условий как параметров и на стороне backend билдить из них SQL запрос, либо вообще использовать ORM (при желании). Для сколько нибудь сложных запросов придется сюда затащить аналог целого движка SQL и ещё строго проверять, что в этом подзапросе не запросят что-нибудь лишнего из других таблиц, что позволит например методом наблюдения (прошло условие или нет) узнать структуру БД или что-то о данных в этой самой базе. В общем, не вижу практических примеров того, где это реально могло бы помочь и при этом показать себя лучше, чем взять банально тот же GraphQL.
«Просто, элегантно и почти без лишнего кода» - ну такое себе. Себя не похвалишь, никто не похвалит. Это имеется в виду две этих функции - processSqlValue и processSqlExpr? Сама по себе задача то простая. Это даже не полноценный sqlParser/sqlBuilder. Простенький where/between/and/or реализуется.
«Реализовать валидатор SQL-условий WHERE на Go довольно просто — почти тривиально» - как бы и так очевидно. Любой джун конкретно с указанной в статье задачей справится. Если копнуть глубже, вроде условий IN, подстроки или select с join - чем более функционально, тем более сложно будет, придется также учитывать, как обрабатывают SQL конкретные субд/движки.
Ну то есть если кому - то действительно нужно написать много апи, где используется простейший where/and/or, то вместо кучи однообразных апи с преобразованием в Sql через dbx можно использовать такое решение. Или использовать кодогенерацию. Но на практике чаще сразу используют graphql - и более функционален и полно готовых надстроек для контроля доступа
Есть же sqlc который генерит репозиторий на основе запроса SQL , вот он экономит время
А как graphql помогает решать подобную задачу с произвольными фильтрами? Насколько помню в стандарте не было ничего об универсальном языке запросов.
Есть squirrel, который отлично подходит для таких задач.
У меня есть личная аллергия на формирование SQL запроса через принты.
Только мне в обработке строк чудится заготовка под инъекции?
Допустим, вы ищете велосипед из стали весом от 10 до 20 килограммов.
// GET /api/products?material=steel&weightFrom=10&weightTo=20
$qb = $this->productRepository->createQueryBuilder();
if ($queryParams->get('material')) {
$qb->andWhere('material', '=', $queryParams->get('material'));
}
if ($queryParams->get('weightFrom')) {
$qb->andWhere('weight', '>=', $queryParams->get('weightFrom'));
}
if ($queryParams->get('weightTo')) {
$qb->andWhere('weight', '<=', $queryParams->get('weightTo'));
}
$results = $this->productRepository->findByQuery($qb);
10 строк кода без всяких парсеров.
А это точно Golang?)
P.S Аналогичный код на Go + ORM будет не шибко сложнее:
package main
import (
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"strconv"
)
type Product struct {
gorm.Model
Material string
Weight float64
}
func GetProducts(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
query := db.Model(&Product{})
if material := c.Query("material"); material != "" {
query = query.Where("material = ?", material)
}
if weightFrom := c.Query("weightFrom"); weightFrom != "" {
if wf, err := strconv.ParseFloat(weightFrom, 64); err == nil {
query = query.Where("weight >= ?", wf)
}
}
if weightTo := c.Query("weightTo"); weightTo != "" {
if wt, err := strconv.ParseFloat(weightTo, 64); err == nil {
query = query.Where("weight <= ?", wt)
}
}
var products []Product
if err := query.Find(&products).Error; err != nil {
c.JSON(500, gin.H{"error": "Failed to fetch products"})
return
}
c.JSON(200, products)
}
}
Это просто пример, его можно сделать на любом языке. Можно считать его псевдокодом.
Как превратить SQL в API на Go?