updown/repository/clump.go

97 lines
2.5 KiB
Go

package repository
import (
"errors"
"github.com/google/uuid"
)
// ErrPasteNotInDatabase is returned when one calls PutClump with pastes that are not in the database.
var ErrPasteNotInDatabase = errors.New("repository: given pastes are not in the database")
// Clump represents a group ("clump") of pastes
type Clump struct {
ID int
Title string
Handle uuid.UUID
Pastes []Paste
}
// ClumpRepository puts/gets a clump from the database
type ClumpRepository interface {
// GetClump gets a clump from the database
GetClump(handle uuid.UUID) (Clump, error)
// GetClump gets a clump from the database
PutClump(title string, pastes ...Paste) (Clump, error)
}
// GetClump gets a clump and all of its associated pastes
func (db *DatabaseConnector) GetClump(handle uuid.UUID) (Clump, error) {
pasteRows, err := db.DB.Query("SELECT paste.*, clump.* FROM paste JOIN CLUMP USING (clumpID) WHERE handle = $1", handle.String())
if err != nil {
return Clump{}, err
}
clump := Clump{
Pastes: []Paste{},
}
for pasteRows.Next() {
paste := Paste{}
// Per the docs, "The number of values in dest must be the same as the number of columns in Rows."
// Because the clump result will always be the same, we can just pull it on each row and update the same struct
pasteRows.Scan(&paste.ID, &paste.Filename, &paste.Handle, &paste.ClumpID, &clump.ID, &clump.Title, &clump.Handle)
clump.Pastes = append(clump.Pastes, paste)
}
return clump, pasteRows.Err()
}
// PutClump puts a clump into the database.
// All given pastes must have already been inserted to the database. Returns ErrPasteNotInDatabase if condition isn't met.
func (db *DatabaseConnector) PutClump(title string, pastes ...Paste) (Clump, error) {
handle, err := uuid.NewUUID()
if err != nil {
return Clump{}, err
}
clump := Clump{
Handle: handle,
}
tx, err := db.DB.Begin()
insertResult := tx.QueryRow("INSERT INTO clump VALUES(DEFAULT, $1, $2) RETURNING clumpID", title, handle.String())
err = insertResult.Scan(&clump.ID)
if err != nil {
tx.Rollback()
return Clump{}, err
}
err = db.addPastesToClump(tx, clump.ID, pastes)
if err != nil {
tx.Rollback()
return Clump{}, err
}
return clump, tx.Commit()
}
func (db *DatabaseConnector) addPastesToClump(ex executor, clumpID int, pastes []Paste) error {
for _, paste := range pastes {
paste.ClumpID = clumpID
result, err := db.updatePaste(ex, paste)
if err != nil {
return err
}
numRows, err := result.RowsAffected()
if err != nil {
return err
} else if numRows == 0 {
return ErrPasteNotInDatabase
}
}
return nil
}