В процессе разработки на Go нередко встаёт вопрос о создании удобного уровня абстракции для работы с базой данных: хочется иметь и простую генерацию миграций, и гибкий Query Builder. Проект Gormite был создан как раз для решения этих задач. Он предлагает облегчённый подход к ORM, при этом сохраняя гибкость при формировании SQL-запросов.
Знакомство с Gormite
Gormite – это CLI-инструмент, которая не нуждается в прямой интеграции в go.mod. Она читает конфигурацию (mapping) из YAML-файла и по указанным в нём entities генерирует миграции для базы данных. Дополнительно в Gormite входит полноценный Query Builder, позволяющий динамически формировать запросы к базе данных.
Главная идея Gormite – разделить ответствености генерации миграций и прикладного кода, чтобы разработчики могли:
Легко описывать структуру таблиц через Go-структуры и теги.
Генерировать SQL-миграции по этим структурам, вводя вручную SQL-код.
Формировать сложные запросы в Go-коде за счёт выразительного Query Builder’а.
Установка и настройка генератора миграций
Шаг 1. Установить Gormite
go install github.com/KoNekoD/gormite/cmd/gormite@latest
Шаг 2. Создать конфигурационный файл gormite.yaml
Gormite ищет настройки по умолчанию в директории resources.
resources/gormite.yaml
gormite:
orm:
mapping:
Entities:
dir: pkg/entities
dir – указывает, где хранятся ваши Go-сущности.
Шаг 3. Подготовить сущности
Внутри pkg/entities создавайте файлы со структурами, описывающими таблицы БД.
user.go
package entities
import "github.com/KoNekoD/gormite/test/docs_example/pkg/enums"
// User "app_user"
type User struct {
ID int `db:"id" pk:"true"`
Email string `db:"email" uniq:"email" length:"180" uniq_cond:"email:(identity_type = 'email')"`
Phone string `db:"phone" uniq:"phone" length:"10" uniq_cond:"phone:(identity_type = 'phone')"`
IdentityType enums.IdentityType `db:"identity_type" type:"varchar"`
Code *string `db:"code" nullable:"true"`
FullName *string `db:"full_name" default:"'Anonymous'" index:"index_full_name" index_cond:"index_full_name:(is_active = true)"`
IsActive bool `db:"is_active"`
}
type UserProfile struct {
ID int `db:"id" pk:"true"`
User *User `db:"user_id"`
Age int `db:"age"`
}
После того как вы подготовили сущности и YAML-файл, Gormite анализирует структуры и генерирует SQL-миграции, учитывая все настройки из тегов структур, например:
db – название столбца
pk – первичный ключ
nullable – допускается значение NULL
Подробнее можно ознакомиться в документации.
Query Builder
Вторая составляющая Gormite — это высокоуровневый Query Builder, призванный упростить работу с SQL. Он предоставляет полноценный функционал для построения запросов, помогающих строить запросы различной сложности.
Пример использования:
qb := gormite.NewQueryBuilder[entities.User]()
qb.Select("u.id", "u.email").
From("app_user u").
Where("u.is_active = :active").
SetParameter("active", true).
OrderBy("u.id DESC").
SetMaxResults(10)
rows, err := qb.GetResult()
if err != nil {
log.Fatal(err)
}
// rows будет содержать список *entities.User, заполненных из полей "u.id" и "u.email".
Заключение
Gormite подойдёт тем, кто ищет лёгкий способ автоматизировать миграции и гибко формировать SQL — без лишних обвязок и глубокой интеграции в проект.
Комментарии (4)
starwalkn
11.02.2025 10:45разделить ответствености генерации миграций и прикладного кода
И чем описание миграций на "сыром" SQL в отдельной директории будет лучше описания ямлика и добавления большого количества тегов в структуры?
В процессе разработки на Go нередко встаёт вопрос о создании удобного уровня абстракции
Гораздо реже чем где-либо еще. Обмазываться абстракциями ради абстракций может и принято, например, в Java, но точно не в Go.
это CLI-инструмент, которая не нуждается в прямой интеграции в go.mod
Но потребует дополнительной установки бинарника в контейнеры.
SetMaxResults(10)
А чем вам слово LIMIT не угодило? ИМХО, когда разработчик использует query builder, то он интуитивно ищет методы, схожие по названию с операциями в SQL.
И так же я не понял, в чем смысл объединения генератора миграций и query builder.
tuxi
11.02.2025 10:45Начинать на таком одно удовольствие. Главное вовремя соскочить, чтобы развивать, тюнить и поддерживать - кто то другой был должен.
paramtamtam
Прошу не считать этот коментарий слишком токсичным (а он будет токсичным), но:
Каждый разработчик должен написать свой фреймворк, ровно как и то, что он должен его никому не показывать
Документации считаем что нет
Ровно как и юнит тестов
Контекста (
context.Context
) тоже нет - только по этому критерию сразу мимо кассыАвтоматические миграции имеют свою цену, и платить ее придется (по закону Мерфи) вот ровно тогда, когда на это совсем не будет бюджета
Constrains, returning, etc...
Вы проделали классную исследовательскую работу, но собирать фидбэк таким образом - стоит ли?