package user // GENERATED FILE // DO NOT EDIT import ( "context" "encoding/json" "errors" "fmt" "github.com/doug-martin/goqu/v9" _ "github.com/doug-martin/goqu/v9/dialect/postgres" "github.com/doug-martin/goqu/v9/exp" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" "strings" "test/crud" "time" ) type UserRepository struct { connPool *pgxpool.Pool dialect goqu.DialectWrapper } func NewUserRepository(connPool *pgxpool.Pool) *UserRepository { return &UserRepository{ connPool: connPool, dialect: goqu.Dialect("postgres"), } } func (r *UserRepository) Create(user User) (int, error) { sql, args, err := r.dialect.Insert("user"). Prepared(true). Rows(goqu.Record{ "updated_at": time.Now(), "email": user.Email, "password": user.Password, }). Returning("id"). ToSQL() if err != nil { crud.LogError("error creating create User sql: %v", err) return -1, err } rows, err := r.connPool.Query(context.Background(), sql, args...) if err != nil { crud.LogError("error creating User: %v", err) return -1, err } defer rows.Close() var id int if rows.Next() { err = rows.Scan(&id) if err != nil { crud.LogError("error scanning User: %v", err) return -1, err } } else { crud.Error("User already exists") return -1, UserAlreadyExistsError{User: user} } return id, nil } type UserAlreadyExistsError struct { User User } func (e UserAlreadyExistsError) Error() string { return fmt.Sprint("User ", e.User, " already exists") } func (r *UserRepository) getSelectColumns() []any { return []any{"id", "created_at", "updated_at", "email", "password", } } func (r *UserRepository) Read(id int) (User, error) { crud.Debug("Getting User by id ", id) sql, args, _ := r.dialect.From("user"). Prepared(true). Select(r.getSelectColumns()...). Where(goqu.Ex{ "id": id, }). ToSQL() rows, err := r.connPool.Query(context.Background(), sql, args...) if err != nil { crud.Error("Failed to get User: ", err) } defer rows.Close() if rows.Next() { item, _, err := r.rowToItem(rows, false) return item, err } return User{}, errors.New("no rows found") } type UserItemScan struct { User RowId int Count int } func (r *UserRepository) rowToItem(rows pgx.Rows, rowId bool) (User, int, error) { var item UserItemScan if rowId { err := rows.Scan( &item.RowId, &item.Count, &item.Id, &item.CreatedAt, &item.UpdatedAt, &item.Email, &item.Password, ) if err != nil { return User{}, -1, err } } else { err := rows.Scan( &item.Id, &item.CreatedAt, &item.UpdatedAt, &item.Email, &item.Password, ) if err != nil { return User{}, -1, err } } return User{ Id: item.Id, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, Email: item.Email, Password: item.Password, }, item.Count, nil } func (r *UserRepository) Update(user User) error { sql, args, err := r.dialect.Update("user"). Prepared(true). Set(goqu.Record{ "updated_at": time.Now(), "email": user.Email, "password": user.Password, }). Where(goqu.Ex{ "id": user.Id, }). ToSQL() if err != nil { crud.LogError("error creating update User sql: %v", err) return err } _, err = r.connPool.Exec(context.Background(), sql, args...) if err != nil { crud.LogError("error updating User: %v", err) return err } return nil } func (r *UserRepository) Delete(id int) error { sql, args, err := r.dialect.Delete("user"). Prepared(true). Where(goqu.Ex{ "id": id, }). ToSQL() if err != nil { crud.LogError("error creating delete User sql: %v", err) return err } _, err = r.connPool.Exec(context.Background(), sql, args...) if err != nil { crud.LogError("error deleting User: %v", err) return err } return nil } type UserField string const ( UserFieldEmail UserField = "email" UserFieldPassword UserField = "password" ) type UserEmailFilter struct { Active bool Value string } type PasswordFilter struct { Active bool Value string } type UserOrderDirection string const ( UserOrderDirectionAsc UserOrderDirection = "asc" UserOrderDirectionDesc UserOrderDirection = "desc" ) type UserPaginationParams struct { RowId int PageSize int OrderBy UserField OrderDirection UserOrderDirection EmailFilter UserEmailFilter PasswordFilter PasswordFilter } func (r *UserRepository) GetPage(params UserPaginationParams) ([]User, int, error) { var orderByWindow exp.WindowExpression if params.OrderDirection == UserOrderDirectionAsc { orderByWindow = goqu.W().OrderBy(goqu.C(string(params.OrderBy)).Asc()) } else { orderByWindow = goqu.W().OrderBy(goqu.C(string(params.OrderBy)).Desc()) } selectColumns := []any{ goqu.ROW_NUMBER().Over(orderByWindow).As("row_id"), goqu.COUNT("*"), } selectColumns = append(selectColumns, r.getSelectColumns()...) whereExpressions := []goqu.Expression{ goqu.Ex{}, } whereExpressions = r.addPageFilters(params, whereExpressions) var colOrder exp.OrderedExpression if params.OrderDirection == UserOrderDirectionAsc { colOrder = goqu.C(string(params.OrderBy)).Asc() } else { colOrder = goqu.C(string(params.OrderBy)).Desc() } dialect := goqu.Dialect("postgres") innerFrom := dialect.From("user"). Prepared(true). Select(selectColumns...). Where(whereExpressions...). Order(colOrder) sql, args, _ := dialect.From(innerFrom). Prepared(true). Where(goqu.Ex{"row_id": goqu.Op{"gt": params.RowId}}). Limit(uint(params.PageSize)). ToSQL() sql = strings.Replace(sql, "COUNT(*)", "COUNT(*) over()", 1) rows, err := r.connPool.Query(context.Background(), sql, args...) if err != nil { crud.LogError("failed to run sql query: %v", err) return nil, -1, err } defer rows.Close() results := make([]User, 0) totalCount := 0 for rows.Next() { parsed, count, err := r.rowToItem(rows, true) if err != nil { return nil, -1, err } totalCount = count results = append(results, parsed) } return results, totalCount, nil } func (r *UserRepository) addPageFilters(params UserPaginationParams, whereExpressions []goqu.Expression) []goqu.Expression { if params.EmailFilter.Active { whereExpressions = append(whereExpressions, goqu.Ex{ "email": goqu.Op{"like": fmt.Sprint("%", params.EmailFilter.Value, "%")}, }) } if params.PasswordFilter.Active { whereExpressions = append(whereExpressions, goqu.Ex{ "password": goqu.Op{"like": fmt.Sprint("%", params.PasswordFilter.Value, "%")}, }) } return whereExpressions } func (r *UserRepository) jsonToString(jsonData any) string { bytes, err := json.Marshal(jsonData) if err != nil { return "{}" } return string(bytes) } func (r *UserRepository) FirstLetterToUpper(name string) string { return strings.ToUpper(name[:1]) + name[1:] } func (u *UserRepository) DoesUserEmailExist(email string) (bool, error) { sql, args, _ := u.dialect.From("user"). Prepared(true). Select(goqu.COUNT("email")). Where(goqu.Ex{"email": email}). ToSQL() rows, err := u.connPool.Query(context.Background(), sql, args...) if err != nil { crud.LogError("failed to run sql query: %v", err) return false, err } defer rows.Close() if rows.Next() { var count int err = rows.Scan(&count) if err != nil { return false, err } return count == 1, nil } return false, nil } func (u *UserRepository) GetUserId(email string) (int, error) { sql, args, _ := u.dialect.From("user"). Prepared(true). Select("id"). Where(goqu.Ex{"email": email}). ToSQL() rows, err := u.connPool.Query(context.Background(), sql, args...) if err != nil { crud.LogError("failed to run sql query: %v", err) return -1, err } defer rows.Close() if rows.Next() { var id int err = rows.Scan(&id) if err != nil { return -1, err } return id, nil } return -1, nil } func (r *UserRepository) VerifyPassword(email string, password string) (bool, int, error) { userId, err := r.GetUserId(email) if err != nil { return false, -1, err } user, err := r.Read(userId) if err != nil { return false, -1, err } return crud.VerifyPassword(password, user.Password), userId, nil }