package crud import ( "context" "errors" "github.com/uptrace/bun" "github.com/uptrace/bun/driver/pgdriver" ) var ErrRecordAlreadyExists = errors.New("record already exists") type Service[T any] struct { db *bun.DB } func NewService[T any](db *bun.DB) *Service[T] { return &Service[T]{ db: db, } } func (s *Service[T]) Insert(ctx context.Context, model *T) error { if _, err := s.db.NewInsert().Model(model).Returning("*").Exec(ctx); err != nil { pqErr := pgdriver.Error{} if errors.As(err, &pqErr) { if pqErr.Field('C') == "23505" { return ErrRecordAlreadyExists } } return err } return nil } func (s *Service[T]) UpdatePk(ctx context.Context, model *T, columns []string) error { if _, err := s.db.NewUpdate().Model(model).WherePK(columns...).Column(columns...).Exec(ctx); err != nil { pqErr := pgdriver.Error{} if errors.As(err, &pqErr) { if pqErr.Field('C') == "23505" { return ErrRecordAlreadyExists } } return err } return nil } //nolint:revive func (s *Service[T]) Update(ctx context.Context, model *T, columns []string, query string, args ...any) error { if _, err := s.db.NewUpdate().Model(model).Where(query, args...).Column(columns...).Exec(ctx); err != nil { pqErr := pgdriver.Error{} if errors.As(err, &pqErr) { if pqErr.Field('C') == "23505" { return ErrRecordAlreadyExists } } return err } return nil } func (s *Service[T]) FindOne(ctx context.Context, query string, args ...any) (*T, error) { m := new(T) return m, s.db.NewSelect().Model(m).Where(query, args...).Scan(ctx, m) } //nolint:revive func (s *Service[T]) Find(ctx context.Context, query string, args ...any) ([]T, int, error) { m := make([]T, 0) c, err := s.db.NewSelect().Model(m).Where(query, args...).ScanAndCount(ctx, &m) return m, c, err } func (s *Service[T]) Delete(ctx context.Context, query string, args ...any) error { _, err := s.db.NewDelete().Model((*T)(nil)).Where(query, args...).Exec(ctx) return err }