diff --git a/internal/board/card.go b/internal/board/card.go index 944ddf8..9913489 100644 --- a/internal/board/card.go +++ b/internal/board/card.go @@ -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 } diff --git a/internal/board/errors.go b/internal/board/errors.go new file mode 100644 index 0000000..387ee25 --- /dev/null +++ b/internal/board/errors.go @@ -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) +} diff --git a/internal/board/status.go b/internal/board/status.go index 6ac1d64..2a38fc0 100644 --- a/internal/board/status.go +++ b/internal/board/status.go @@ -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 } diff --git a/internal/db/database.go b/internal/db/database.go index 6f54980..57e1b60 100644 --- a/internal/db/database.go +++ b/internal/db/database.go @@ -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