The route will now display real, live data from the DB! Errors are not handled very well, just returned as JSON for now. Need to implement an error page for states when errors occur. This commit also includes lots of documentation for the various service/repository methods. I am trying to not let docs fall through the cracks, but I am not perfect lol.
148 lines
3.8 KiB
Go
148 lines
3.8 KiB
Go
package repository
|
|
|
|
import (
|
|
"database/sql"
|
|
|
|
domain "github.com/haydenhargreaves/Potion/internal/domain/user"
|
|
_ "github.com/lib/pq"
|
|
)
|
|
|
|
type UserRepository struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
// Compile-time check to ensure the UserRepository implements domain.UserRepository
|
|
var _ domain.UserRepository = (*UserRepository)(nil)
|
|
|
|
// NewUserRepository creates a user repository object which is used by the user service to access
|
|
// the database. Any user related database operations will take place in this repository.
|
|
func NewUserRepository(db *sql.DB) domain.UserRepository {
|
|
return &UserRepository{db: db}
|
|
}
|
|
|
|
// CreateGoogleUser creates a user entry in the users table. The refresh token is required along
|
|
// with the Google user info, in order to complete the database schema. Currently, Google login is
|
|
// the only support method of authentication, if this changes, this repository may need updates to
|
|
// match an updated table schema.
|
|
//
|
|
// This function will NOT check if the user already exists, if they do, it will return an error. For
|
|
// best results, pair this function with the GetGoogleUser which will return the user if it can find
|
|
// it.
|
|
func (r *UserRepository) CreateGoogleUser(googleUserInfo *domain.GoogleUserInfo, googleRefreshToken string) (domain.User, error) {
|
|
tx, err := r.db.Begin()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return domain.User{}, err
|
|
}
|
|
|
|
var user domain.User
|
|
query := `INSERT INTO users
|
|
(GoogleId, Name, Email, ImageUrl, GoogleRefreshToken)
|
|
VALUES ($1, $2, $3, $4, $5) RETURNING *;`
|
|
|
|
if err := tx.QueryRow(
|
|
query,
|
|
googleUserInfo.Id,
|
|
googleUserInfo.Name,
|
|
googleUserInfo.Email,
|
|
googleUserInfo.Picture,
|
|
googleRefreshToken,
|
|
).Scan(
|
|
&user.Id,
|
|
&user.GoogleId,
|
|
&user.Name,
|
|
&user.Email,
|
|
&user.ImageUrl,
|
|
&user.GoogleRefreshToken,
|
|
&user.Created,
|
|
); err != nil {
|
|
tx.Rollback()
|
|
return domain.User{}, err
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
tx.Rollback()
|
|
return domain.User{}, err
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// GetGoogleUser attempts to find a user in the database via its Google ID, not the database ID. This
|
|
// function is used when a user logs in with Google to prevent duplicate entries from being made. If
|
|
// no user is found, this function will return a null pointer but not an error.
|
|
func (r *UserRepository) GetGoogleUser(googleId string) (*domain.User, error) {
|
|
tx, err := r.db.Begin()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
var user domain.User
|
|
query := `SELECT * FROM users WHERE GoogleId = $1`
|
|
|
|
if err := tx.QueryRow(query, googleId).Scan(
|
|
&user.Id,
|
|
&user.GoogleId,
|
|
&user.Name,
|
|
&user.Email,
|
|
&user.ImageUrl,
|
|
&user.GoogleRefreshToken,
|
|
&user.Created,
|
|
); err != nil {
|
|
// If no user was found, don't error, just return
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
return &user, nil
|
|
}
|
|
|
|
// GetUser gets a user from the database via its ID. The operation is wrapped in a transaction
|
|
// for added safety. The repository will not check for a nil result, instead the service will.
|
|
// Callers are responsible for protecting against double nil results. Any errors will be bubbled
|
|
// to the caller.
|
|
func (r *UserRepository) GetUser(id int) (*domain.User, error) {
|
|
tx, err := r.db.Begin()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
query := "SELECT * FROM users WHERE id = $1"
|
|
|
|
var user domain.User
|
|
if err := tx.QueryRow(query, id).Scan(
|
|
&user.Id,
|
|
&user.GoogleId,
|
|
&user.Name,
|
|
&user.Email,
|
|
&user.ImageUrl,
|
|
&user.GoogleRefreshToken,
|
|
&user.Created,
|
|
); err != nil {
|
|
// If no user was found, don't error, just return
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
return &user, nil
|
|
|
|
}
|