package bundb import ( "context" "database/sql" "errors" "fmt" "gitea.dwysokinski.me/twhelp/dcbot/internal/bundb/internal/model" "gitea.dwysokinski.me/twhelp/dcbot/internal/domain" "github.com/google/uuid" "github.com/jackc/pgerrcode" "github.com/uptrace/bun" "github.com/uptrace/bun/driver/pgdriver" ) type Monitor struct { db *bun.DB } func NewMonitor(db *bun.DB) *Monitor { return &Monitor{db: db} } func (m *Monitor) Create(ctx context.Context, params domain.CreateMonitorParams) (domain.Monitor, error) { groupID, err := uuid.Parse(params.GroupID()) if err != nil { return domain.Monitor{}, domain.GroupDoesNotExistError{ ID: params.GroupID(), } } monitor := model.Monitor{ GroupID: groupID, TribeID: params.TribeID(), } if _, err = m.db.NewInsert(). Model(&monitor). Returning("*"). Exec(ctx); err != nil { return domain.Monitor{}, fmt.Errorf( "something went wrong while inserting monitor into the db: %w", mapCreateMonitorError(err, params), ) } return monitor.ToDomain(), nil } func (m *Monitor) List(ctx context.Context, groupID string) ([]domain.Monitor, error) { if _, err := uuid.Parse(groupID); err != nil { return nil, nil } var monitors []model.Monitor if err := m.db.NewSelect(). Model(&monitors). Order("created_at ASC"). Where("group_id = ?", groupID). Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) { return nil, fmt.Errorf("couldn't select monitors from the db: %w", err) } result := make([]domain.Monitor, 0, len(monitors)) for _, monitor := range monitors { result = append(result, monitor.ToDomain()) } return result, nil } func (m *Monitor) Get(ctx context.Context, id string) (domain.Monitor, error) { if _, err := uuid.Parse(id); err != nil { return domain.Monitor{}, domain.MonitorNotFoundError{ID: id} } var monitor model.Monitor err := m.db.NewSelect(). Model(&monitor). Where("id = ?", id). Scan(ctx) if err != nil { if errors.Is(err, sql.ErrNoRows) { return domain.Monitor{}, domain.MonitorNotFoundError{ID: id} } return domain.Monitor{}, fmt.Errorf("couldn't select monitor from the db (id=%s): %w", id, err) } return monitor.ToDomain(), nil } func (m *Monitor) Delete(ctx context.Context, id string) error { if _, err := uuid.Parse(id); err != nil { return domain.MonitorNotFoundError{ID: id} } res, err := m.db.NewDelete(). Model(&model.Monitor{}). Returning("NULL"). Where("id = ?", id). Exec(ctx) if err != nil && !errors.Is(err, sql.ErrNoRows) { return fmt.Errorf("couldn't delete monitor (id=%s): %w", id, err) } if affected, _ := res.RowsAffected(); affected == 0 { return domain.MonitorNotFoundError{ID: id} } return nil } func mapCreateMonitorError(err error, params domain.CreateMonitorParams) error { var pgError pgdriver.Error if !errors.As(err, &pgError) { return err } code := pgError.Field('C') constraint := pgError.Field('n') switch { case code == pgerrcode.ForeignKeyViolation && constraint == "monitors_group_id_fkey": return domain.GroupDoesNotExistError{ ID: params.GroupID(), } case code == pgerrcode.UniqueViolation && constraint == "monitors_group_id_tribe_id_key": return domain.MonitorAlreadyExistsError{ TribeID: params.TribeID(), GroupID: params.GroupID(), } default: return err } }