feat: delete cards #6

Closed
dananglin wants to merge 35 commits from delete-cards into main
4 changed files with 73 additions and 67 deletions
Showing only changes of commit b07ce3f415 - Show all commits

View file

@ -10,16 +10,25 @@ import (
bolt "go.etcd.io/bbolt"
)
// OpenProject reads the project from the database. If no board exists then a new one will be created.
func OpenProject(path string) (*bolt.DB, error) {
type Board struct {
db *bolt.DB
}
// Open reads the board from the database.
// If no board exists then a new one will be created.
func Open(path string) (Board, error) {
db, err := database.OpenDatabase(path)
if err != nil {
return nil, fmt.Errorf("unable to open the database, %w", err)
return Board{}, fmt.Errorf("unable to open the database, %w", err)
}
statusList, err := ReadStatusList(db)
board := Board{
db: db,
}
statusList, err := board.StatusList()
if err != nil {
return nil, err
return Board{}, err
}
if len(statusList) == 0 {
@ -32,16 +41,21 @@ func OpenProject(path string) (*bolt.DB, error) {
}
if _, err := database.WriteMany(db, database.StatusBucket, boltItems); err != nil {
return nil, fmt.Errorf("unable to save the default status list to the database, %w", err)
return Board{}, fmt.Errorf("unable to save the default status list to the database, %w", err)
}
}
return db, nil
return board, nil
}
// ReadStatusList returns the ordered list of statuses from the database.
func ReadStatusList(db *bolt.DB) ([]Status, error) {
data, err := database.ReadAll(db, database.StatusBucket)
func (b *Board) Close() error {
return b.db.Close()
}
// StatusList returns the ordered list of statuses from the database.
func (b *Board) StatusList() ([]Status, error) {
data, err := database.ReadAll(b.db, database.StatusBucket)
if err != nil {
return []Status{}, fmt.Errorf("unable to read the status list, %w", err)
}
@ -68,22 +82,22 @@ func ReadStatusList(db *bolt.DB) ([]Status, error) {
}
// TODO: Finish implementation.
func ReadStatus(db *bolt.DB) (Status, error) {
func (b *Board) ReadStatus() (Status, error) {
return Status{}, nil
}
// TODO: Finish implementation.
func CreateStatus(db *bolt.DB) error {
func (b *Board) NewStatus() error {
return nil
}
// TODO: Finish implementation.
func UpdateStatus(db *bolt.DB) error {
func (b *Board) UpdateStatus() error {
return nil
}
// TODO: Finish implementation.
func DeleteStatus(db *bolt.DB) error {
func (b *Board) DeleteStatus() error {
return nil
}
@ -93,8 +107,8 @@ type CardArgs struct {
}
// CreateCard creates a card in the database.
func CreateCard(db *bolt.DB, args CardArgs) error {
statusList, err := ReadStatusList(db)
func (b *Board) CreateCard(args CardArgs) error {
statusList, err := b.StatusList()
if err != nil {
return fmt.Errorf("unable to read the status list, %w", err)
}
@ -109,7 +123,7 @@ func CreateCard(db *bolt.DB, args CardArgs) error {
Content: args.NewContent,
}
cardID, err := database.Write(db, database.CardBucket, &card)
cardID, err := database.Write(b.db, database.CardBucket, &card)
if err != nil {
return fmt.Errorf("unable to write card to the database, %w", err)
}
@ -118,16 +132,16 @@ func CreateCard(db *bolt.DB, args CardArgs) error {
initialStatus.AddCardID(cardID)
if _, err := database.Write(db, database.StatusBucket, &initialStatus); err != nil {
if _, err := database.Write(b.db, database.StatusBucket, &initialStatus); err != nil {
return fmt.Errorf("unable to write the %s status to the database, %w", initialStatus.Name, err)
}
return nil
}
// ReadCard returns a Card value from the database.
func ReadCard(db *bolt.DB, id int) (Card, error) {
data, err := database.Read(db, database.CardBucket, id)
// Card returns a Card value from the database.
func (b *Board) Card(id int) (Card, error) {
data, err := database.Read(b.db, database.CardBucket, id)
if err != nil {
return Card{}, fmt.Errorf("unable to read card [%d] from the database, %w", id, err)
}
@ -145,10 +159,10 @@ func ReadCard(db *bolt.DB, id int) (Card, error) {
return card, nil
}
// ReadCardList returns a list of Card values from the database.
// CardList returns a list of Card values from the database.
// TODO: function needs testing.
func ReadCardList(db *bolt.DB, ids []int) ([]Card, error) {
data, err := database.ReadMany(db, database.CardBucket, ids)
func (b *Board) CardList(ids []int) ([]Card, error) {
data, err := database.ReadMany(b.db, database.CardBucket, ids)
if err != nil {
return nil, fmt.Errorf("unable to read card list from the database, %w", err)
}
@ -178,8 +192,8 @@ type UpdateCardArgs struct {
}
// UpdateCard modifies an existing card in the database.
func UpdateCard(db *bolt.DB, args UpdateCardArgs) error {
card, err := ReadCard(db, args.CardID)
func (b *Board) UpdateCard(args UpdateCardArgs) error {
card, err := b.Card(args.CardID)
if err != nil {
return err
}
@ -192,7 +206,7 @@ func UpdateCard(db *bolt.DB, args UpdateCardArgs) error {
card.Content = args.NewContent
}
if _, err := database.Write(db, database.CardBucket, &card); err != nil {
if _, err := database.Write(b.db, database.CardBucket, &card); err != nil {
return fmt.Errorf("unable to write card to the database, %w", err)
}
@ -207,12 +221,12 @@ type UpdateCardStatusArgs struct {
// UpdateCardStatus moves a card between statuses.
// TODO: finish implementation.
func UpdateCardStatus(db *bolt.DB, args UpdateCardStatusArgs) error {
func (b *Board) UpdateCardStatus(args UpdateCardStatusArgs) error {
return nil
}
// DeleteCard deletes a card from the database.
// TODO: finish implementation.
func DeleteCard(db *bolt.DB, id int) error {
func (b *Board) DeleteCard(id int) error {
return nil
}

View file

@ -8,7 +8,6 @@ import (
"testing"
"codeflow.dananglin.me.uk/apollo/canal/internal/board"
bolt "go.etcd.io/bbolt"
)
func TestCardLifecycle(t *testing.T) {
@ -22,33 +21,33 @@ func TestCardLifecycle(t *testing.T) {
testDBPath := filepath.Join(projectDir, "test", "databases", "Board_TestCardLifecycle.db")
os.Remove(testDBPath)
db, err := board.OpenProject(testDBPath)
b, err := board.Open(testDBPath)
if err != nil {
t.Fatalf("Unable to open the test database %s, %s.", testDBPath, err)
}
defer func() {
_ = db.Close()
_ = b.Close()
}()
initialCardTitle := "A test card."
initialCardContent := "Ensure that this card is safely stored in the database."
expectedCardID := 1
testCreateCard(t, db, initialCardTitle, initialCardContent, expectedCardID)
testReadCard(t, db, expectedCardID, initialCardTitle, initialCardContent)
testCreateCard(t, b, initialCardTitle, initialCardContent, expectedCardID)
testReadCard(t, b, expectedCardID, initialCardTitle, initialCardContent)
modifiedCardTitle := "Test card updated."
modifiedCardContent1 := "Ensure that this card is safely updated in the database."
testUpdateCard(t, db, expectedCardID, modifiedCardTitle, modifiedCardContent1)
testUpdateCard(t, b, expectedCardID, modifiedCardTitle, modifiedCardContent1)
modifiedCardContent2 := "Updated card content only."
testUpdateCardContent(t, db, expectedCardID, modifiedCardTitle, modifiedCardContent2)
testUpdateCardContent(t, b, expectedCardID, modifiedCardTitle, modifiedCardContent2)
}
func testCreateCard(t *testing.T, db *bolt.DB, title, content string, wantID int) {
func testCreateCard(t *testing.T, b board.Board, title, content string, wantID int) {
t.Helper()
args := board.CardArgs{
@ -56,11 +55,11 @@ func testCreateCard(t *testing.T, db *bolt.DB, title, content string, wantID int
NewContent: content,
}
if err := board.CreateCard(db, args); err != nil {
if err := b.CreateCard(args); err != nil {
t.Fatalf("Unable to create the test card, %s.", err)
}
statusList, err := board.ReadStatusList(db)
statusList, err := b.StatusList()
if err != nil {
t.Fatalf("Unable to run `ReadStatusList`, %s.", err)
}
@ -82,10 +81,10 @@ func testCreateCard(t *testing.T, db *bolt.DB, title, content string, wantID int
}
}
func testReadCard(t *testing.T, db *bolt.DB, cardID int, wantTitle, wantContent string) {
func testReadCard(t *testing.T, b board.Board, cardID int, wantTitle, wantContent string) {
t.Helper()
card, err := board.ReadCard(db, cardID)
card, err := b.Card(cardID)
if err != nil {
t.Fatalf("Unable to read test card, %s.", err)
}
@ -103,7 +102,7 @@ func testReadCard(t *testing.T, db *bolt.DB, cardID int, wantTitle, wantContent
}
}
func testUpdateCard(t *testing.T, db *bolt.DB, cardID int, newTitle, newContent string) {
func testUpdateCard(t *testing.T, b board.Board, cardID int, newTitle, newContent string) {
t.Helper()
args := board.UpdateCardArgs{
@ -114,11 +113,11 @@ func testUpdateCard(t *testing.T, db *bolt.DB, cardID int, newTitle, newContent
},
}
if err := board.UpdateCard(db, args); err != nil {
if err := b.UpdateCard(args); err != nil {
t.Fatalf("Unable to update the test card, %s", err)
}
got, err := board.ReadCard(db, cardID)
got, err := b.Card(cardID)
if err != nil {
t.Fatalf("Unable to read the modified test card, %s", err)
}
@ -136,7 +135,7 @@ func testUpdateCard(t *testing.T, db *bolt.DB, cardID int, newTitle, newContent
}
}
func testUpdateCardContent(t *testing.T, db *bolt.DB, cardID int, expectedTitle, newContent string) {
func testUpdateCardContent(t *testing.T, b board.Board, cardID int, expectedTitle, newContent string) {
t.Helper()
args := board.UpdateCardArgs{
@ -147,11 +146,11 @@ func testUpdateCardContent(t *testing.T, db *bolt.DB, cardID int, expectedTitle,
},
}
if err := board.UpdateCard(db, args); err != nil {
if err := b.UpdateCard(args); err != nil {
t.Fatalf("Unable to update the test card, %s", err)
}
got, err := board.ReadCard(db, cardID)
got, err := b.Card(cardID)
if err != nil {
t.Fatalf("Unable to read the modified test card, %s", err)
}

View file

@ -5,7 +5,6 @@ import (
"codeflow.dananglin.me.uk/apollo/canal/internal/board"
"github.com/rivo/tview"
bolt "go.etcd.io/bbolt"
)
type shiftDirection int
@ -29,34 +28,28 @@ type App struct {
flex *tview.Flex
pages *tview.Pages
focusedColumn int
db *bolt.DB
board board.Board
}
// shutdown shuts down the application.
func (a *App) shutdown() {
a.closeDB()
a.closeBoard()
a.Stop()
}
// closeDB closes the BoltDB database.
func (a *App) closeDB() {
if a.db != nil {
_ = a.db.Close()
}
// closeBoard closes the BoltDB database.
func (a *App) closeBoard() {
_ = a.board.Close()
}
// openProject opens the kanban project.
func (a *App) openProject(path string) error {
if a.db != nil && len(a.db.Path()) > 0 {
a.db.Close()
}
db, err := board.OpenProject(path)
// openBoard opens the kanban project.
func (a *App) openBoard(path string) error {
b, err := board.Open(path)
if err != nil {
return fmt.Errorf("unable to load board, %w", err)
}
a.db = db
a.board = b
if err = a.refresh(); err != nil {
return err
@ -67,7 +60,7 @@ func (a *App) openProject(path string) error {
// refresh refreshes the UI.
func (a *App) refresh() error {
statusList, err := board.ReadStatusList(a.db)
statusList, err := a.board.StatusList()
if err != nil {
return fmt.Errorf("unable to get the status list, %w", err)
}
@ -88,7 +81,7 @@ func (a *App) updateBoard(statusList []board.Status) error {
columns[i] = a.newColumn(statusList[i].ID, statusList[i].Name)
if len(statusList[i].CardIds) > 0 {
cards, err := board.ReadCardList(a.db, statusList[i].CardIds)
cards, err := a.board.CardList(statusList[i].CardIds)
if err != nil {
return fmt.Errorf("unable to get the card list. %w", err)
}
@ -136,7 +129,7 @@ func (a *App) newCard(title, content string) error {
NewContent: content,
}
if err := board.CreateCard(a.db, args); err != nil {
if err := a.board.CreateCard(args); err != nil {
return fmt.Errorf("unable to create card, %w", err)
}

View file

@ -34,7 +34,7 @@ func initApp(a *App) {
a.pages.ShowPage(quitPage)
a.SetFocus(quit)
} else if event.Rune() == 'o' {
a.openProject("")
a.openBoard("")
} else if event.Rune() == 'a' {
a.pages.ShowPage(addPage)
a.SetFocus(add)