Documentation
¶
Overview ¶
Package data_base предоставляет типобезопасные, расширяемые и производительные компоненты для работы с реляционными базами данных в Go.
Основные возможности:
- Универсальные компоненты для CRUD операций: Finder, Saver, Deleter и др.
- Типобезопасные фильтры и сортировка с поддержкой распространённых операторов.
- Поддержка пагинации через компонент Pager.
- Гибкое преобразование между моделями и SQL-записями через функции-мапперы.
Все компоненты используют стандартный интерфейс dbClient.Client, что упрощает тестирование и позволяет легко подменять реализацию хранения данных.
Index ¶
- Variables
- func NewFilter(filter *repository.Filter) (goqu.Expression, error)
- func NewSort(sort *repository.Sort) exp.OrderedExpression
- type BulkInserter
- type BulkInserterOption
- type BulkUpdater
- type BulkUpdaterOption
- type Client
- type Counter
- type Deleter
- type DeleterOption
- type Finder
- type GetIdentifier
- type Hook
- type HookManager
- type Inserter
- type InserterOption
- type Mapper
- type Pager
- type Saver
- type SaverOption
- type Scanner
- type SetIdentifier
- type Updater
- type UpdaterOption
Constants ¶
This section is empty.
Variables ¶
var Component = compogo.Component{ Dependencies: compogo.Components{ &dbClient.Component, &sqlGenerator.Component, &dbMigrator.Component, }, }
var FilterTypeUndefined = errors.New("undefined")
var IdNotBeZeroError = errors.New("id must not be null")
IdNotBeZeroError возвращается компонентом Updater (и другими операциями обновления), если переданная модель имеет нулевой идентификатор (GetId() == 0).
Такая проверка позволяет избежать случайного обновления всех записей в таблице (например, при WHERE id = 0) и даёт явный сигнал о некорректном вызове.
Пример:
user := &User{Name: "Alice"} // ID не установлен
_, err := updater.Update(ctx, user)
if errors.Is(err, data_base.IdNotBeZeroError) {
// Обработка ошибки: ID обязателен для обновления
}
Functions ¶
func NewFilter ¶
func NewFilter(filter *repository.Filter) (goqu.Expression, error)
NewFilter преобразует Filter из пакета repository в goqu.Expression, который можно использовать для построения SQL-запросов. Поддерживает операторы: =, !=, >, >=, <, <=, LIKE, IN.
Возвращает ошибку FilterTypeUndefined, если переданный оператор не поддерживается.
Пример:
filter := repository.NewFilter("name", "Alice", repository.Eq)
expr, err := data_base.NewFilter(filter)
func NewSort ¶
func NewSort(sort *repository.Sort) exp.OrderedExpression
NewSort преобразует Sort из пакета repository в goqu.OrderedExpression для сортировки результатов запроса.
Поддерживает направления: ASC (по умолчанию) и DESC.
Пример:
sort := &repository.Sort{ColumnName: "created_at", Direction: repository.DESC}
expr := data_base.NewSort(sort)
Types ¶
type BulkInserter ¶
type BulkInserter[T any] struct { // contains filtered or unexported fields }
BulkInserter предназначен для массовой вставки записей (INSERT) одной операцией. Принимает срез указателей на модели и преобразует их в записи с помощью Mapper.
Значительно повышает производительность при вставке большого количества записей, сокращая количество сетевых вызовов к базе данных.
Пример:
bulk := &data_base.BulkInserter[User]{
tableName: "users",
mapper: toRecord,
db: db,
gen: gen,
}
users := []*User{&User{Name: "A"}, &User{Name: "B"}}
err := bulk.BulkInsert(ctx, users...)
func NewBulkInserter ¶ added in v0.0.7
func NewBulkInserter[T any]( db dbClient.Client, gen *goqu.DialectWrapper, modelToRecord Mapper[T], tableName string, options ...BulkInserterOption[T], ) *BulkInserter[T]
func (*BulkInserter[T]) BulkInsert ¶
func (b *BulkInserter[T]) BulkInsert(ctx context.Context, models ...*T) error
type BulkInserterOption ¶ added in v0.0.9
type BulkInserterOption[T any] func(u *BulkInserter[T])
func AddPostHookBulkInserterOption ¶ added in v0.0.9
func AddPostHookBulkInserterOption[T any](hooks ...Hook[T]) BulkInserterOption[T]
func AddPreHookBulkInserterOption ¶ added in v0.0.9
func AddPreHookBulkInserterOption[T any](hooks ...Hook[T]) BulkInserterOption[T]
type BulkUpdater ¶ added in v0.0.5
type BulkUpdater struct {
// contains filtered or unexported fields
}
func NewBulkUpdater ¶ added in v0.0.5
func NewBulkUpdater( db dbClient.Client, gen *goqu.DialectWrapper, tableName string, options ...BulkUpdaterOption, ) *BulkUpdater
func (*BulkUpdater) BulkUpdate ¶ added in v0.0.5
func (b *BulkUpdater) BulkUpdate(ctx context.Context, pairs map[string]any, filters ...*repository.Filter) error
type BulkUpdaterOption ¶ added in v0.0.9
type BulkUpdaterOption func(u *BulkUpdater)
func AddPostHookBulkUpdaterOption ¶ added in v0.0.9
func AddPostHookBulkUpdaterOption(hooks ...Hook[repository.Filter]) BulkUpdaterOption
func AddPreHookBulkUpdaterOption ¶ added in v0.0.9
func AddPreHookBulkUpdaterOption(hooks ...Hook[repository.Filter]) BulkUpdaterOption
type Counter ¶
type Counter struct {
// contains filtered or unexported fields
}
Counter предназначен для подсчёта количества записей в таблице, удовлетворяющих переданным фильтрам.
Игнорирует значения NULL в указанной колонке для подсчёта. Для nil-фильтров возвращает общее количество записей в таблице.
Пример:
counter := data_base.NewCounter(db, gen, "users", "id")
filters := []*repository.Filter{repository.NewFilter("active", "true", repository.Eq)}
count, err := counter.Count(ctx, filters...)
func NewCounter ¶
type Deleter ¶
type Deleter struct {
// contains filtered or unexported fields
}
Deleter предназначен для удаления записей из таблицы по переданным фильтрам. Для выполнения физического удаления (DELETE) используйте фильтры. Для мягкого удаления рекомендуется использовать Updater.
Возвращает ошибку, если удаление не удалось выполнить.
Пример:
deleter := data_base.NewDeleter(db, gen, "users")
filters := []*repository.Filter{repository.NewFilter("id", 123, repository.Eq)}
err := deleter.Delete(ctx, filters...)
func NewDeleter ¶
func NewDeleter( db dbClient.Client, gen *goqu.DialectWrapper, tableName string, options ...DeleterOption, ) *Deleter
type DeleterOption ¶ added in v0.0.9
type DeleterOption func(u *Deleter)
func AddPostHookDeleterOption ¶ added in v0.0.9
func AddPostHookDeleterOption(hooks ...Hook[repository.Filter]) DeleterOption
func AddPreHookDeleterOption ¶ added in v0.0.9
func AddPreHookDeleterOption(hooks ...Hook[repository.Filter]) DeleterOption
type Finder ¶
type Finder[T any] struct { // contains filtered or unexported fields }
Finder предназначен для поиска записей в базе данных с поддержкой фильтрации и сортировки. Возвращает срез указателей на модели типа T.
Нулевое значение структуры использовать нельзя. Для создания экземпляра используйте функцию NewFinder, передавая в неё экземпляр клиента БД, генератор SQL, функцию для маппинга строки результата в модель и название таблицы.
Пример:
rowMapper := func(rows *sql.Rows) (*User, error) {
var u User
err := rows.Scan(&u.ID, &u.Name, &u.Email)
return &u, err
}
finder := data_base.NewFinder[User](db, goqu.Dialect("postgres"), rowMapper, "users", "id", "name", "email")
filters := []*repository.Filter{repository.NewFilter("name", "Alice", repository.Eq)}
users, err := finder.Find(ctx, nil, filters...)
func (*Finder[T]) Find ¶
func (f *Finder[T]) Find(ctx context.Context, sorts []*repository.Sort, filters ...*repository.Filter) ([]*T, error)
type GetIdentifier ¶ added in v0.0.4
GetIdentifier — сигнатура функции для извлечения числового идентификатора из модели.
Используется компонентами Saver и Updater для определения, является ли модель новой (ID == 0) или уже существующей (ID != 0).
Пример:
getID := func(m *User) uint64 { return m.ID }
id := getID(user) // 12345
Обычно такой хелпер передаётся в конструктор:
saver := data_base.NewSaver(
db, gen,
mapper,
getID,
setID,
"users", "id",
)
type HookManager ¶ added in v0.0.9
type HookManager[T any] struct { // contains filtered or unexported fields }
func NewHookManager ¶ added in v0.0.9
func NewHookManager[T any](hooks ...Hook[T]) *HookManager[T]
func (*HookManager[T]) Count ¶ added in v0.0.9
func (m *HookManager[T]) Count() int
func (*HookManager[T]) Fire ¶ added in v0.0.9
func (m *HookManager[T]) Fire(ctx context.Context, c Client, ts ...*T) (err error)
func (*HookManager[T]) RegisterHook ¶ added in v0.0.9
func (m *HookManager[T]) RegisterHook(hook Hook[T])
func (*HookManager[T]) RegisterHooks ¶ added in v0.0.9
func (m *HookManager[T]) RegisterHooks(hooks ...Hook[T])
type Inserter ¶
type Inserter[T any] struct { // contains filtered or unexported fields }
Inserter предназначен только для вставки новых записей (INSERT). После успешной вставки автоматически устанавливает сгенерированный ID модели через SetId().
В отличие от Saver, не выполняет обновление при наличии ID. Полезен для сценариев, где нужно гарантировать создание новой записи.
Пример:
inserter := data_base.NewInserter[User](db, gen, toRecord, "users")
user := &User{Name: "Bob", Email: "bob@example.com"}
insertedUser, err := inserter.Insert(ctx, user)
func NewInserter ¶
func NewInserter[T any]( db dbClient.Client, gen *goqu.DialectWrapper, mapper Mapper[T], setIdentifier SetIdentifier[T], tableName string, options ...InserterOption[T], ) *Inserter[T]
type InserterOption ¶ added in v0.0.9
func AddPostHookInserterOption ¶ added in v0.0.9
func AddPostHookInserterOption[T any](hooks ...Hook[T]) InserterOption[T]
func AddPreHookInserterOption ¶ added in v0.0.9
func AddPreHookInserterOption[T any](hooks ...Hook[T]) InserterOption[T]
type Mapper ¶ added in v0.0.4
Mapper — сигнатура функции для преобразования указателя на модель, используется в запись для SQL-запроса (goqu.Record). Используется компонентами Saver, Inserter, Updater и BulkInserter.
Позволяет гибко контролировать, какие поля и как сохраняются в базе данных.
type Pager ¶
type Pager[T any] struct { // contains filtered or unexported fields }
Pager предназначен для постраничного получения данных с фильтрацией и сортировкой. Является расширением Finder и использует тот же механизм маппинга строк в модели.
Поддерживает все виды фильтров и сортировок из пакета repository. Для работы с пагинацией используйте структуру repository.Page.
Пример:
pager := data_base.NewPager(db, gen, rowMapper, "users", "id", "name")
page := &repository.Page{Number: 0, Limit: 10}
users, err := pager.Page(ctx, page, sorts, filters...)
func (*Pager[T]) Page ¶
func (p *Pager[T]) Page(ctx context.Context, page *repository.Page, sorts []*repository.Sort, filters ...*repository.Filter) ([]*T, error)
type Saver ¶
type Saver[T any] struct { // contains filtered or unexported fields }
Saver реализует паттерн "сохранить или обновить" (UPSERT), автоматически определяя операцию по значению идентификатора модели.
Если GetId() возвращает 0, выполняется вставка (INSERT) новой записи, после чего модели автоматически устанавливается сгенерированный ID через SetId(). Если GetId() не равен 0, выполняется обновление (UPDATE) существующей записи.
Требует, чтобы тип T реализовывал интерфейс Identifier. Для работы необходима функция, преобразующая модель в goqu.Record.
Пример:
toRecord := func(u *User) goqu.Record {
return goqu.Record{"name": u.Name, "email": u.Email}
}
saver := data_base.NewSaver[User](db, gen, toRecord, "users", "id")
user := &User{Name: "Alice", Email: "alice@example.com"}
savedUser, err := saver.Save(ctx, user) // user.ID будет установлен после вставки
func NewSaver ¶
func NewSaver[T any]( db dbClient.Client, gen *goqu.DialectWrapper, mapper Mapper[T], getIdentifier GetIdentifier[T], setIdentifier SetIdentifier[T], tableName string, idColName string, options ...SaverOption[T], ) *Saver[T]
type SaverOption ¶ added in v0.0.9
func AddPostHookSaverOption ¶ added in v0.0.9
func AddPostHookSaverOption[T any](hooks ...Hook[T]) SaverOption[T]
func AddPreHookSaverOption ¶ added in v0.0.9
func AddPreHookSaverOption[T any](hooks ...Hook[T]) SaverOption[T]
type Scanner ¶ added in v0.0.4
Scanner — сигнатура функции для преобразования строки результата SQL-запроса (*sql.Rows), используется в экземпляр модели типа T. Используется компонентами Finder и Pager.
Возвращает указатель на модель и ошибку, если сканирование не удалось.
type SetIdentifier ¶ added in v0.0.4
SetIdentifier — сигнатура функции для установки числового идентификатора в модель.
Используется компонентами Saver и Inserter для проставления сгенерированного базой данных ID (например, после INSERT с auto_increment или serial колонкой).
Важно: функция должна изменять переданную модель (принимает указатель), а не возвращать новое значение.
Пример:
setID := func(m *User, id uint64) { m.ID = id }
setID(user, 12345)
Обычно такой хелпер передаётся в конструктор:
inserter := data_base.NewInserter(
db, gen,
mapper,
setID,
"users",
)
type Updater ¶
type Updater[T any] struct { // contains filtered or unexported fields }
Updater предназначен для обновления существующих записей в таблице. В отличие от Saver, Updater не выполняет вставку новых записей и требует, чтобы переданная модель имела заполненный идентификатор (GetId() != 0).
Если идентификатор модели равен 0, метод Update возвращает ошибку IdNotBeZeroError. Это предотвращает случайное выполнение UPDATE без условия WHERE.
Компонент использует функцию Mapper для преобразования модели в запись (goqu.Record) и выполняет обновление по указанному полю идентификатора.
Пример использования:
toRecord := func(u *User) goqu.Record {
return goqu.Record{"name": u.Name, "email": u.Email}
}
updater := data_base.NewUpdater(
db,
goqu.Dialect("postgres"),
toRecord,
"users",
"id",
)
user := &User{Id: 123, Name: "Updated Name"}
updatedUser, err := updater.Update[User](ctx, user)
if err != nil {
// Обработка ошибки
}
func NewUpdater ¶
func NewUpdater[T any]( db dbClient.Client, gen *goqu.DialectWrapper, mapper Mapper[T], getIdentifier GetIdentifier[T], tableName string, idColName string, options ...UpdaterOption[T], ) *Updater[T]
type UpdaterOption ¶ added in v0.0.9
func AddPostHookUpdaterOption ¶ added in v0.0.9
func AddPostHookUpdaterOption[T any](hooks ...Hook[T]) UpdaterOption[T]
func AddPreHookUpdaterOption ¶ added in v0.0.9
func AddPreHookUpdaterOption[T any](hooks ...Hook[T]) UpdaterOption[T]