feat: move a card between statuses #3
4 changed files with 73 additions and 67 deletions
|
@ -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) {
|
||||
db, err := database.OpenDatabase(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open the database, %w", err)
|
||||
type Board struct {
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
statusList, err := ReadStatusList(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, err
|
||||
return Board{}, fmt.Errorf("unable to open the database, %w", err)
|
||||
}
|
||||
|
||||
board := Board{
|
||||
db: db,
|
||||
}
|
||||
|
||||
statusList, err := board.StatusList()
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue