Add ClumpRepository with implementations

master
Nick Krichevsky 2019-03-18 22:41:19 -04:00
parent 19b591e48b
commit d88bf493de
2 changed files with 106 additions and 2 deletions

96
repository/clump.go Normal file
View File

@ -0,0 +1,96 @@
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
}

View File

@ -1,6 +1,10 @@
package repository
import "github.com/google/uuid"
import (
"database/sql"
"github.com/google/uuid"
)
// Paste represents a paste that the user has stored in the database
type Paste struct {
@ -55,7 +59,11 @@ func (db *DatabaseConnector) PutPaste(filename string) (Paste, error) {
// UpdatePaste allows for a paste to be updated.
// Currently, only the filename and clump id can be updated
func (db *DatabaseConnector) UpdatePaste(paste Paste) error {
_, err := db.DB.Exec("UPDATE paste SET filename = $1, clumpID = $2 WHERE pasteID = $3", paste.Filename, paste.ClumpID, paste.ID)
_, err := db.updatePaste(db.DB, paste)
return err
}
func (db *DatabaseConnector) updatePaste(ex executor, paste Paste) (sql.Result, error) {
return db.DB.Exec("UPDATE paste SET filename = $1, clumpID = $2 WHERE pasteID = $3", paste.Filename, paste.ClumpID, paste.ID)
}