Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions models/databasehelper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package models

import (
// "database/sql"
"errors"
"github.com/lib/pq"
)

// UniqueConstraintError is returned when a uniqueness constraint is violated during an insert.
var UniqueConstraintError = errors.New("postgres: unique constraint violation")

// QueryResultContainedMultipleRowsError is returned when a query unexpectedly returns more than one row.
var QueryResultContainedMultipleRowsError = errors.New("query result unexpectedly contained multiple rows")

// QueryResultContainedNoRowsError is returned when a query unexpectedly returns no rows.
var QueryResultContainedNoRowsError = errors.New("query result unexpectedly contained no rows")

func convertPostgresError(err error) error {
const uniqueConstraintErrorCode = "23505"

if postgresErr, ok := err.(*pq.Error); ok {
if postgresErr.Code == uniqueConstraintErrorCode {
return UniqueConstraintError
}
}

return err
}

func (db *DB) execOneResult(sqlQuery string, object interface{}, args ...interface{}) error {

rows, err := db.Query(sqlQuery, args...)
if err != nil {
return convertPostgresError(err)
}
defer rows.Close()

foundResult := false
for rows.Next() {

if foundResult {
return QueryResultContainedMultipleRowsError
}

if err := rows.Scan(object); err != nil {
return convertPostgresError(err)
}

foundResult = true
}

if !foundResult {
return QueryResultContainedNoRowsError
}

if err := rows.Err(); err != nil {
return convertPostgresError(err)
}

return nil
}

func (db *DB) execNoResults(sqlQuery string, args ...interface{}) (int64, error) {

res, err := db.Exec(sqlQuery, args...)
if err != nil {
return 0, convertPostgresError(err)
}

numAffected, err := res.RowsAffected()
if err != nil {
return 0, convertPostgresError(err)
}

return numAffected, nil
}
24 changes: 0 additions & 24 deletions models/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,8 @@ package models

import (
"database/sql"
"errors"

"github.com/lib/pq"
)

// UniqueConstraintError is returned when a uniqueness constraint is violated during an insert.
var UniqueConstraintError = errors.New("postgres: unique constraint violation")

// QueryResultContainedMultipleRowsError is returned when a query unexpectedly returns more than one row.
var QueryResultContainedMultipleRowsError = errors.New("query result unexpectedly contained multiple rows")

// QueryResultContainedNoRowsError is returned when a query unexpectedly returns no rows.
var QueryResultContainedNoRowsError = errors.New("query result unexpectedly contained no rows")

// ConnectToDatabase also pings the database to ensure a working connection.
func ConnectToDatabase(databaseUrl string) (*DB, error) {
tempDb, err := sql.Open("postgres", databaseUrl)
Expand All @@ -41,15 +29,3 @@ type Datastore interface {
type DB struct {
*sql.DB
}

func convertPostgresError(err error) error {
const uniqueConstraintErrorCode = "23505"

if postgresErr, ok := err.(*pq.Error); ok {
if postgresErr.Code == uniqueConstraintErrorCode {
return UniqueConstraintError
}
}

return err
}
26 changes: 2 additions & 24 deletions models/note.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,9 @@ func (db *DB) StoreNewNote(
VALUES ($1, $2, $3)
RETURNING id`

rows, err := db.Query(sqlQuery, authorId, content, creationTime)
if err != nil {
return 0, convertPostgresError(err)
}
defer rows.Close()

var noteId int64 = 0
for rows.Next() {

if noteId != 0 {
return 0, QueryResultContainedMultipleRowsError
}

if err := rows.Scan(&noteId); err != nil {
return 0, convertPostgresError(err)
}
if err := db.execOneResult(sqlQuery, &noteId, authorId, content, creationTime); err != nil {
return 0, err
}

if noteId == 0 {
return 0, QueryResultContainedNoRowsError
}

if err := rows.Err(); err != nil {
return 0, convertPostgresError(err)
}

return NoteId(noteId), nil
}
14 changes: 6 additions & 8 deletions models/note_category.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var categoryStrings = [...]string{
}

var CannotDeserializeNoteCategoryStringError = errors.New("String does not correspond to a Note Category")
var NoteAlreadyContainsCategoryError = errors.New("NoteId already has a category stored for it")

func DeserializeNoteCategory(input string) (NoteCategory, error) {
for i := 0; i < len(categoryStrings); i++ {
Expand Down Expand Up @@ -48,14 +49,11 @@ func (db *DB) StoreNewNoteCategoryRelationship(
INSERT INTO note_to_category_relationship (note_id, category)
VALUES ($1, $2)`

rows, err := db.Query(sqlQuery, int64(noteId), category.String())
if err != nil {
return convertPostgresError(err)
}
defer rows.Close()

if err := rows.Err(); err != nil {
return convertPostgresError(err)
if _, err := db.execNoResults(sqlQuery, int64(noteId), category.String()); err != nil {
if err == UniqueConstraintError {
return NoteAlreadyContainsCategoryError
}
return err
}

return nil
Expand Down
52 changes: 11 additions & 41 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,12 @@ func (db *DB) StoreNewUser(
INSERT INTO app_user (display_name, email_address, password, creation_time)
VALUES ($1, $2, $3, $4)`

rows, err := db.Query(sqlQuery, displayName, emailAddress.String(), hashedPassword, creationTime)
if err != nil {
return convertPostgresError(err)
}
defer rows.Close()
if _, err := db.execNoResults(sqlQuery, displayName, emailAddress.String(), hashedPassword, creationTime); err != nil {
if err == UniqueConstraintError {
return EmailAddressAlreadyInUseError
}

if err := rows.Err(); err != nil {
return convertPostgresError(err)
return err
}

return nil
Expand All @@ -69,25 +67,10 @@ func (db *DB) AuthenticateUserCredentials(emailAddress *EmailAddress, password s
SELECT password FROM app_user
WHERE email_address = $1`

rows, err := db.Query(sqlQuery, emailAddress.String())
if err != nil {
return convertPostgresError(err)
}
defer rows.Close()

var storedHashedPassword []byte
for rows.Next() {
if storedHashedPassword != nil {
return QueryResultContainedMultipleRowsError
}

if err := rows.Scan(&storedHashedPassword); err != nil {
return err
}
}

if storedHashedPassword == nil {
return QueryResultContainedNoRowsError
if err := db.execOneResult(sqlQuery, &storedHashedPassword, emailAddress.String()); err != nil {
return err
}

if err := bcrypt.CompareHashAndPassword(
Expand All @@ -109,25 +92,12 @@ func (db *DB) GetIdForUserWithEmailAddress(emailAddress *EmailAddress) (UserId,
SELECT id FROM app_user
WHERE email_address = $1`

rows, err := db.Query(sqlQuery, emailAddress.String())
if err != nil {
return 0, convertPostgresError(err)
}
defer rows.Close()

var userId int64
for rows.Next() {
if userId != 0 {
return 0, QueryResultContainedMultipleRowsError
if err := db.execOneResult(sqlQuery, &userId, emailAddress.String()); err != nil {
if err == QueryResultContainedNoRowsError {
return 0, CredentialsNotAuthorizedError
}

if err := rows.Scan(&userId); err != nil {
return 0, err
}
}

if userId == 0 {
return 0, QueryResultContainedNoRowsError
return 0, err
}

return UserId(userId), nil
Expand Down