You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
3.7 KiB

package services
import (
"context"
"database/sql"
"fmt"
"log"
"time"
"github.com/lib/pq"
_ "github.com/lib/pq"
)
var dbConn *sql.DB
type DB interface {
// VerifyEmail(email string) error
// ResetPassword(email string) (string, error)
// RegisterUser(email, username, password string) (User, error)
GetLog(int64, time.Time, time.Time, []LogType) ([]StatLog, error)
AddLog(int64, StatLog) error
UpdateProfile(int64, User) error
GetProfileByID(int64) (User, error)
GetProfileByEmail(string) (User, error)
}
func Connect(host, user, password string) (DB, error) {
psqlconn := fmt.Sprintf("host=%s port=5432 user=%s password=%s dbname=bodytrack sslmode=disable", host, user, password)
pgClient, err := sql.Open("postgres", psqlconn)
if err != nil {
return nil, err
}
if err := pgClient.Ping(); err != nil {
return nil, err
}
return pgdb{DB: pgClient}, nil
}
type pgdb struct{ *sql.DB }
func (db pgdb) GetLog(id int64, start, end time.Time, lt []LogType) ([]StatLog, error) {
getLogSql := `
SELECT
value, logType, recordedTs
FROM stats.log
WHERE
userId = $1 AND recordedTs >= $2 AND recordedTs <= $3
AND logType = ANY($4)
ORDER BY recordedTs DESC;`
var results []StatLog
rows, err := db.Query(getLogSql, id, start, end, pq.Array(lt))
if err != nil {
return nil, err
}
defer rows.Close()
if err := rows.Err(); err != nil {
return nil, err
}
for rows.Next() {
var sl StatLog
if err := rows.Scan(&sl.Value, &sl.Type, &sl.RecordedTS); err != nil {
log.Printf("could not scan value for statlog: %v", err)
}
results = append(results, sl)
}
return results, nil
}
func (db pgdb) AddLog(id int64, sl StatLog) error {
statLogInsertSql := `
INSERT INTO stats.log (userId, value, logType, recordedTs)
VALUES ($1, $2, $3, $4);
`
tx, err := db.BeginTx(context.Background(), nil)
if err != nil {
return err
}
defer tx.Commit()
if _, err := tx.Exec(statLogInsertSql, id, sl.Value, sl.Type, sl.RecordedTS); err != nil {
tx.Rollback()
return err
}
return nil
}
func (db pgdb) UpdateProfile(id int64, u User) error {
updateProfileSql := `
UPDATE accounts.profile SET
username = $2, displayunit = $3, birthdate = $4, height = $5
WHERE userId = $1;
`
updateUserSql := `
UPDATE accounts.users SET
email = $2, passwordHash = $3
WHERE id = $1;
`
tx, err := db.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelReadCommitted})
if err != nil {
return err
}
defer tx.Commit()
if _, err := tx.Exec(updateProfileSql, id, u.Username, u.DisplayUnit, u.Birthdate, u.Height); err != nil {
tx.Rollback()
return fmt.Errorf("could not update profile: %w", err)
}
if _, err := tx.Exec(updateUserSql, id, u.Email, u.PasswordHash); err != nil {
tx.Rollback()
return fmt.Errorf("could not update user: %w", err)
}
return nil
}
func (db pgdb) GetProfileByID(id int64) (User, error) {
sql := `SELECT
u.id, u.email, u.passwordhash, p.username, p.displayunit, p.birthdate, p.height
FROM Accounts.Users u JOIN Accounts.Profile p on u.id = p.userId
WHERE u.id = $1 LIMIT 1;
`
var u User
if err := db.QueryRow(sql, id).Scan(
&u.ID,
&u.Email,
&u.PasswordHash,
&u.Username,
&u.DisplayUnit,
&u.Birthdate,
&u.Height,
); err != nil {
return u, err
}
return u, nil
}
func (db pgdb) GetProfileByEmail(email string) (User, error) {
sql := `SELECT
u.id, u.email, u.passwordhash, p.username, p.displayunit, p.birthdate, p.height
FROM Accounts.Users u JOIN Accounts.Profile p on u.id = p.userId
WHERE u.email = $1 LIMIT 1;
`
var u User
if err := db.QueryRow(sql, email).Scan(
&u.ID,
&u.Email,
&u.PasswordHash,
&u.Username,
&u.DisplayUnit,
&u.Birthdate,
&u.Height,
); err != nil {
return u, err
}
return u, nil
}