fix: add restrictions when setting IDs.
All checks were successful
/ test (pull_request) Successful in 40s
/ lint (pull_request) Successful in 43s

Main change:

Add restrictions when adding IDs for cards and statuses. Errors are
returned when an attempt is made to set an ID lower than 1, or an
attempt is made to set an ID that has already been set.

Additional changes:

- Error types in the board packages are now defined in errors.go.
- Small formatting to error messages.
This commit is contained in:
Dan Anglin 2024-01-21 15:39:51 +00:00
parent d532c86475
commit 4e7eb77583
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
4 changed files with 108 additions and 61 deletions

View file

@ -1,15 +1,5 @@
package board
import "fmt"
type CardNotExistError struct {
ID int
}
func (e CardNotExistError) Error() string {
return fmt.Sprintf("card ID '%d' does not exist in the database", e.ID)
}
// Card represents a card on a Kanban board.
type Card struct {
ID int
@ -18,12 +8,23 @@ type Card struct {
Created string
}
// UpdateId updates the ID of the Card value.
func (c *Card) UpdateId(id int) {
// SetID updates the ID of the Card value only if
// the ID is < 1 (i.e. unset).
func (c *Card) SetID(id int) error {
if id < 1 {
return InvalidIDError{id}
}
if c.ID > 0 {
return IDAlreadySetError{}
}
c.ID = id
return nil
}
// Id returns the ID of the Card value.
func (c *Card) Id() int {
// GetID returns the ID of the Card value.
func (c *Card) GetID() int {
return c.ID
}

53
internal/board/errors.go Normal file
View file

@ -0,0 +1,53 @@
package board
import "fmt"
// CardNotExistError is returned when a card does not exist in the database.
type CardNotExistError struct {
ID int
}
func (e CardNotExistError) Error() string {
return fmt.Sprintf("card ID '%d' does not exist in the database", e.ID)
}
// InvalidIDError is an error for when an attempt to set an ID lower than 1 is made.
type InvalidIDError struct {
ID int
}
func ( e InvalidIDError) Error() string {
return fmt.Sprintf("'%d' is an invalid ID", e.ID)
}
// IDAlreadySetError is an error for when an attempt is made to set an ID that has already been set.
type IDAlreadySetError struct {}
func (e IDAlreadySetError) Error() string {
return "the item's ID is already set"
}
// StatusListEmptyError is an error for unexpected empty list of statuses.
type StatusListEmptyError struct{}
func (e StatusListEmptyError) Error() string {
return "the status list must not be empty"
}
// StatusNotExistError is an error for when a status cannot be found in the database.
type StatusNotExistError struct {
ID int
}
func (e StatusNotExistError) Error() string {
return fmt.Sprintf("status ID '%d' does not exist in the database", e.ID)
}
// StatusNotEmptyError is an error for when an attempt is made to delete non-empty statuses.
type StatusNotEmptyError struct {
ID int
}
func (e StatusNotEmptyError) Error() string {
return fmt.Sprintf("status ID '%d' must contain no cards before deletion", e.ID)
}

View file

@ -1,32 +1,9 @@
package board
import (
"fmt"
"sort"
)
type StatusListEmptyError struct{}
func (e StatusListEmptyError) Error() string {
return "the status list must not be empty"
}
type StatusNotExistError struct {
ID int
}
func (e StatusNotExistError) Error() string {
return fmt.Sprintf("status ID '%d' does not exist in the database", e.ID)
}
type StatusNotEmptyError struct {
ID int
}
func (e StatusNotEmptyError) Error() string {
return fmt.Sprintf("status ID '%d' must contain no cards before deletion", e.ID)
}
// Status represents the status of the Kanban board.
type Status struct {
ID int
@ -36,12 +13,22 @@ type Status struct {
}
// UpdateID updates the ID of the Status value.
func (s *Status) UpdateId(id int) {
func (s *Status) SetID(id int) error {
if id < 1 {
return InvalidIDError{id}
}
if s.ID > 0 {
return IDAlreadySetError{}
}
s.ID = id
return nil
}
// Id returns the ID of the Status value.
func (s *Status) Id() int {
// GetID returns the ID of the Status value.
func (s *Status) GetID() int {
return s.ID
}

View file

@ -18,8 +18,8 @@ const (
)
type BoltItem interface {
UpdateId(int)
Id() int
SetID(int) error
GetID() int
}
// OpenDatabase opens the database, at a given path, for reading and writing.
@ -65,7 +65,7 @@ func Read(db *bolt.DB, bucketName string, itemID int) ([]byte, error) {
return nil
}); err != nil {
return nil, fmt.Errorf("error while reading the Bolt item from the database, %w", err)
return nil, fmt.Errorf("error while reading the Bolt item from the database; %w", err)
}
return data, nil
@ -116,13 +116,13 @@ func ReadAll(db *bolt.DB, bucketName string) ([][]byte, error) {
return nil
}); err != nil {
return fmt.Errorf("unable to load status, %w", err)
return fmt.Errorf("unable to load the Bolt item; %w", err)
}
return nil
})
if err != nil {
return nil, fmt.Errorf("error while loading statuses from the database, %w", err)
return nil, fmt.Errorf("error while loading the Bolt items from the database; %w", err)
}
return output, nil
@ -140,12 +140,15 @@ func Write(db *bolt.DB, bucketName string, item BoltItem) (int, error) {
return bucketNotExistError{bucket: string(bucketNameBytes)}
}
if item.Id() < 1 {
if item.GetID() < 1 {
var id uint64
if id, err = bucket.NextSequence(); err != nil {
return fmt.Errorf("unable to generate an ID for the card, %w", err)
return fmt.Errorf("unable to generate an ID for the Bolt item; %w", err)
}
if err = item.SetID(int(id)); err != nil {
return fmt.Errorf("unable to set the generated ID to the Bolt item; %w", err)
}
item.UpdateId(int(id))
}
buf := new(bytes.Buffer)
@ -154,17 +157,17 @@ func Write(db *bolt.DB, bucketName string, item BoltItem) (int, error) {
return fmt.Errorf("unable to encode data, %w", err)
}
if err = bucket.Put([]byte(strconv.Itoa(item.Id())), buf.Bytes()); err != nil {
return fmt.Errorf("unable to write the card to the bucket, %w", err)
if err = bucket.Put([]byte(strconv.Itoa(item.GetID())), buf.Bytes()); err != nil {
return fmt.Errorf("unable to write the Bolt item to the bucket; %w", err)
}
return nil
})
if err != nil {
return 0, fmt.Errorf("error while saving the card to the database, %w", err)
return 0, fmt.Errorf("error while saving the Bolt item to the database; %w", err)
}
return item.Id(), nil
return item.GetID(), nil
}
// WriteMany saves one or more Bolt items to the status bucket.
@ -187,12 +190,15 @@ func WriteMany(database *bolt.DB, bucketName string, items []BoltItem) ([]int, e
for ind, item := range items {
var err error
if item.Id() < 1 {
if item.GetID() < 1 {
var id uint64
if id, err = bucket.NextSequence(); err != nil {
return fmt.Errorf("unable to generate ID, %w", err)
}
item.UpdateId(int(id))
if err = item.SetID(int(id)); err != nil {
return fmt.Errorf("unable to set the generated ID to the Bolt item; %w", err)
}
}
buf := new(bytes.Buffer)
@ -201,11 +207,11 @@ func WriteMany(database *bolt.DB, bucketName string, items []BoltItem) ([]int, e
return fmt.Errorf("unable to encode data, %w", err)
}
if err = bucket.Put([]byte(strconv.Itoa(item.Id())), buf.Bytes()); err != nil {
if err = bucket.Put([]byte(strconv.Itoa(item.GetID())), buf.Bytes()); err != nil {
return fmt.Errorf("unable to add the Bolt Item to the %s bucket, %w", bucketName, err)
}
ids[ind] = item.Id()
ids[ind] = item.GetID()
}
return nil
@ -229,12 +235,12 @@ func Delete(db *bolt.DB, bucketName string, itemID int) error {
}
if err := bucket.Delete([]byte(strconv.Itoa(itemID))); err != nil {
return fmt.Errorf("an error occurred when deleting Bolt item '%d', %w", itemID, err)
return fmt.Errorf("an error occurred when deleting Bolt item '%d'; %w", itemID, err)
}
return nil
}); err != nil {
return fmt.Errorf("error deleting data from the '%s' bucket, %w", bucketName, err)
return fmt.Errorf("error deleting data from the '%s' bucket; %w", bucketName, err)
}
return nil
@ -245,7 +251,7 @@ func mkDataDir(path string) error {
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0o700); err != nil {
return fmt.Errorf("error while making directory %s, %w", dir, err)
return fmt.Errorf("error while making directory %s; %w", dir, err)
}
return nil
@ -258,14 +264,14 @@ func ensureBuckets(db *bolt.DB) error {
err := db.Update(func(tx *bolt.Tx) error {
for _, v := range buckets {
if _, err := tx.CreateBucketIfNotExists([]byte(v)); err != nil {
return fmt.Errorf("unable to ensure that %s bucket is created in the database, %w", v, err)
return fmt.Errorf("unable to ensure that %s bucket is created in the database; %w", v, err)
}
}
return nil
})
if err != nil {
return fmt.Errorf("error while ensuring buckets exist in the database, %w", err)
return fmt.Errorf("error while ensuring buckets exist in the database; %w", err)
}
return nil