package db import ( "context" "database/sql" "github.com/pkg/errors" "github.com/uptrace/bun" ) type listgetter[T any] struct { q *bun.SelectQuery items *[]*T pageOpts *PageOpts defaults *PageOpts } type List[T any] struct { Items []*T Total int PageOpts PageOpts } type Filter struct { Field string Value any } func GetList[T any](tx bun.Tx, pageOpts, defaults *PageOpts) *listgetter[T] { l := &listgetter[T]{ items: new([]*T), pageOpts: pageOpts, defaults: defaults, } l.q = tx.NewSelect(). Model(l.items) return l } func (l *listgetter[T]) Relation(name string, apply ...func(*bun.SelectQuery) *bun.SelectQuery) *listgetter[T] { l.q = l.q.Relation(name, apply...) return l } func (l *listgetter[T]) Filter(filters ...Filter) *listgetter[T] { for _, filter := range filters { l.q = l.q.Where("? = ?", bun.Ident(filter.Field), filter.Value) } return l } func (l *listgetter[T]) GetAll(ctx context.Context) (*List[T], error) { if l.defaults == nil { return nil, errors.New("default pageopts is nil") } total, err := l.q.Count(ctx) if err != nil { return nil, errors.Wrap(err, "query.Count") } l.q, l.pageOpts = setPageOpts(l.q, l.pageOpts, l.defaults, total) err = l.q.Scan(ctx) if err != nil && errors.Is(err, sql.ErrNoRows) { return nil, errors.Wrap(err, "query.Scan") } list := &List[T]{ Items: *l.items, Total: total, PageOpts: *l.pageOpts, } return list, nil }