package units import ( "context" "errors" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgconn" "gorm.io/gorm" ) var ( ErrNotFound = errors.New("unit not found") ErrSymbolTaken = errors.New("symbol already in use") ErrInUse = errors.New("unit is referenced by existing price tiers") ) type Repository interface { Create(ctx context.Context, u *Unit) error FindByID(ctx context.Context, id uuid.UUID) (*Unit, error) List(ctx context.Context) ([]*Unit, error) Update(ctx context.Context, u *Unit) error Delete(ctx context.Context, id uuid.UUID) error } type gormRepository struct { db *gorm.DB } func NewRepository(db *gorm.DB) Repository { return &gormRepository{db: db} } func (r *gormRepository) Create(ctx context.Context, u *Unit) error { if err := r.db.WithContext(ctx).Create(u).Error; err != nil { if isUniqueViolation(err) { return ErrSymbolTaken } return err } return nil } func (r *gormRepository) FindByID(ctx context.Context, id uuid.UUID) (*Unit, error) { var u Unit err := r.db.WithContext(ctx).Where("id = ?", id).First(&u).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrNotFound } if err != nil { return nil, err } return &u, nil } func (r *gormRepository) List(ctx context.Context) ([]*Unit, error) { var list []*Unit if err := r.db.WithContext(ctx).Order("name asc").Find(&list).Error; err != nil { return nil, err } return list, nil } func (r *gormRepository) Update(ctx context.Context, u *Unit) error { err := r.db.WithContext(ctx).Save(u).Error if isUniqueViolation(err) { return ErrSymbolTaken } return err } func (r *gormRepository) Delete(ctx context.Context, id uuid.UUID) error { res := r.db.WithContext(ctx).Delete(&Unit{}, "id = ?", id) if res.Error != nil { if isForeignKeyViolation(res.Error) { return ErrInUse } return res.Error } if res.RowsAffected == 0 { return ErrNotFound } return nil } func isUniqueViolation(err error) bool { var pgErr *pgconn.PgError return errors.As(err, &pgErr) && pgErr.Code == "23505" } func isForeignKeyViolation(err error) bool { var pgErr *pgconn.PgError return errors.As(err, &pgErr) && pgErr.Code == "23503" }