package board import ( "bytes" "encoding/gob" "fmt" "sort" "codeflow.dananglin.me.uk/apollo/canal/internal/database" 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) } statusList, err := ReadStatusList(db) if err != nil { return nil, err } if len(statusList) == 0 { newStatusList := defaultStatusList() boltItems := make([]database.BoltItem, len(newStatusList)) for i := range newStatusList { boltItems[i] = &newStatusList[i] } 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 db, 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) if err != nil { return []Status{}, fmt.Errorf("unable to read the status list, %w", err) } statuses := make([]Status, len(data)) for i, d := range data { buf := bytes.NewBuffer(d) decoder := gob.NewDecoder(buf) var s Status if err := decoder.Decode(&s); err != nil { return []Status{}, fmt.Errorf("unable to decode data, %w", err) } statuses[i] = s } sort.Sort(ByStatusOrder(statuses)) return statuses, nil } // TODO: Finish implementation. func ReadStatus(db *bolt.DB) (Status, error) { return Status{}, nil } // TODO: Finish implementation. func CreateStatus(db *bolt.DB) error { return nil } // TODO: Finish implementation. func UpdateStatus(db *bolt.DB) error { return nil } // TODO: Finish implementation. func DeleteStatus(db *bolt.DB) error { return nil } type CardArgs struct { NewTitle string NewContent string } // CreateCard creates a card in the database. func CreateCard(db *bolt.DB, args CardArgs) error { statusList, err := ReadStatusList(db) if err != nil { return fmt.Errorf("unable to read the status list, %w", err) } if len(statusList) == 0 { return statusListEmptyError{} } card := Card{ ID: -1, Title: args.NewTitle, Content: args.NewContent, } cardID, err := database.Write(db, database.CardBucket, &card) if err != nil { return fmt.Errorf("unable to write card to the database, %w", err) } initialStatus := statusList[0] initialStatus.AddCardID(cardID) if _, err := database.Write(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) if err != nil { return Card{}, fmt.Errorf("unable to read card [%d] from the database, %w", id, err) } var card Card buf := bytes.NewBuffer(data) decoder := gob.NewDecoder(buf) if err := decoder.Decode(&card); err != nil { return Card{}, fmt.Errorf("unable to decode data, %w", err) } return card, nil } // ReadCardList 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) if err != nil { return nil, fmt.Errorf("unable to read card list from the database, %w", err) } cards := make([]Card, len(data)) for i, d := range data { buf := bytes.NewBuffer(d) decoder := gob.NewDecoder(buf) var c Card if err := decoder.Decode(&c); err != nil { return nil, fmt.Errorf("unable to decode data, %w", err) } cards[i] = c } return cards, nil } type UpdateCardArgs struct { CardID int CardArgs } // UpdateCard modifies an existing card in the database. func UpdateCard(db *bolt.DB, args UpdateCardArgs) error { card, err := ReadCard(db, args.CardID) if err != nil { return err } if len(args.NewTitle) > 0 { card.Title = args.NewTitle } if len(args.NewContent) > 0 { card.Content = args.NewContent } if _, err := database.Write(db, database.CardBucket, &card); err != nil { return fmt.Errorf("unable to write card to the database, %w", err) } return nil } type UpdateCardStatusArgs struct { CardID int OldStatusID int NewStatusID int } // UpdateCardStatus moves a card between statuses. // TODO: finish implementation. func UpdateCardStatus(db *bolt.DB, args UpdateCardStatusArgs) error { return nil } // DeleteCard deletes a card from the database. // TODO: finish implementation. func DeleteCard(db *bolt.DB, id int) error { return nil }