8c6250f0/todo/todo-repository_gen.go
2025-02-20 16:48:07 +01:00

334 lines
7.1 KiB
Go

package todo
// 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"
"time"
"todo/crud"
)
type TodoRepository struct {
connPool *pgxpool.Pool
dialect goqu.DialectWrapper
}
func NewTodoRepository(connPool *pgxpool.Pool) *TodoRepository {
return &TodoRepository{
connPool: connPool,
dialect: goqu.Dialect("postgres"),
}
}
func (r *TodoRepository) Create(todo Todo) (int, error) {
sql, args, err := r.dialect.Insert("todo").
Prepared(true).
Rows(goqu.Record{
"updated_at": time.Now(),
"name": todo.Name,
"completed": todo.Completed,
"due": r.jsonToString(todo.Due),
"user_id": todo.UserId,
}).
Returning("id").
ToSQL()
if err != nil {
crud.LogError("error creating create Todo sql: %v", err)
return -1, err
}
rows, err := r.connPool.Query(context.Background(), sql, args...)
if err != nil {
crud.LogError("error creating Todo: %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("Todo already exists")
return -1, TodoAlreadyExistsError{Todo: todo}
}
return id, nil
}
type TodoAlreadyExistsError struct {
Todo Todo
}
func (e TodoAlreadyExistsError) Error() string {
return fmt.Sprint("Todo ", e.Todo, " already exists")
}
func (r *TodoRepository) getSelectColumns() []any {
return []any{"id", "created_at", "updated_at",
"name", "completed", "due", "user_id",
}
}
func (r *TodoRepository) Read(userId int, id int) (Todo, error) {
crud.Debug("Getting Todo by id ", id)
sql, args, _ := r.dialect.From("todo").
Prepared(true).
Select(r.getSelectColumns()...).
Where(goqu.Ex{
"id": id,
"user_id": userId,
}).
ToSQL()
rows, err := r.connPool.Query(context.Background(), sql, args...)
if err != nil {
crud.Error("Failed to get Todo: ", err)
}
defer rows.Close()
if rows.Next() {
item, _, err := r.rowToItem(rows, false)
return item, err
}
return Todo{}, errors.New("no rows found")
}
type TodoItemScan struct {
Todo
RowId int
Count int
}
func (r *TodoRepository) rowToItem(rows pgx.Rows, rowId bool) (Todo, int, error) {
var item TodoItemScan
if rowId {
err := rows.Scan(
&item.RowId,
&item.Count,
&item.Id,
&item.CreatedAt,
&item.UpdatedAt,
&item.Name,
&item.Completed,
&item.Due,
&item.UserId,
)
if err != nil {
return Todo{}, -1, err
}
} else {
err := rows.Scan(
&item.Id,
&item.CreatedAt,
&item.UpdatedAt,
&item.Name,
&item.Completed,
&item.Due,
&item.UserId,
)
if err != nil {
return Todo{}, -1, err
}
}
return Todo{
Id: item.Id,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
Name: item.Name,
Completed: item.Completed,
Due: item.Due,
UserId: item.UserId,
}, item.Count, nil
}
func (r *TodoRepository) Update(userId int, todo Todo) error {
sql, args, err := r.dialect.Update("todo").
Prepared(true).
Set(goqu.Record{
"updated_at": time.Now(),
"name": todo.Name,
"completed": todo.Completed,
"due": r.jsonToString(todo.Due),
"user_id": todo.UserId,
}).
Where(goqu.Ex{
"id": todo.Id,
"user_id": userId,
}).
ToSQL()
if err != nil {
crud.LogError("error creating update Todo sql: %v", err)
return err
}
_, err = r.connPool.Exec(context.Background(), sql, args...)
if err != nil {
crud.LogError("error updating Todo: %v", err)
return err
}
return nil
}
func (r *TodoRepository) Delete(userId int, id int) error {
sql, args, err := r.dialect.Delete("todo").
Prepared(true).
Where(goqu.Ex{
"id": id,
"user_id": userId,
}).
ToSQL()
if err != nil {
crud.LogError("error creating delete Todo sql: %v", err)
return err
}
_, err = r.connPool.Exec(context.Background(), sql, args...)
if err != nil {
crud.LogError("error deleting Todo: %v", err)
return err
}
return nil
}
type TodoField string
const (
TodoFieldName TodoField = "name"
TodoFieldCompleted TodoField = "completed"
TodoFieldDue TodoField = "due"
)
type TodoNameFilter struct {
Active bool
Value string
}
type TodoCompletedFilter struct {
Active bool
Value bool
}
type TodoOrderDirection string
const (
TodoOrderDirectionAsc TodoOrderDirection = "asc"
TodoOrderDirectionDesc TodoOrderDirection = "desc"
)
type TodoReferences struct {
UserId int
}
type TodoPaginationParams struct {
RowId int
PageSize int
OrderBy TodoField
OrderDirection TodoOrderDirection
NameFilter TodoNameFilter
CompletedFilter TodoCompletedFilter
References TodoReferences
}
func (r *TodoRepository) GetPage(params TodoPaginationParams) ([]Todo, int, error) {
var orderByWindow exp.WindowExpression
if params.OrderDirection == TodoOrderDirectionAsc {
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{
"user_id": params.References.UserId,
},
}
whereExpressions = r.addPageFilters(params, whereExpressions)
var colOrder exp.OrderedExpression
if params.OrderDirection == TodoOrderDirectionAsc {
colOrder = goqu.C(string(params.OrderBy)).Asc()
} else {
colOrder = goqu.C(string(params.OrderBy)).Desc()
}
dialect := goqu.Dialect("postgres")
innerFrom := dialect.From("todo").
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([]Todo, 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 *TodoRepository) addPageFilters(params TodoPaginationParams, whereExpressions []goqu.Expression) []goqu.Expression {
if params.NameFilter.Active {
whereExpressions = append(whereExpressions, goqu.Ex{
"name": goqu.Op{"like": fmt.Sprint("%", params.NameFilter.Value, "%")},
})
}
if params.CompletedFilter.Active {
whereExpressions = append(whereExpressions, goqu.Ex{
"completed": params.CompletedFilter.Value,
})
}
return whereExpressions
}
func (r *TodoRepository) jsonToString(jsonData any) string {
bytes, err := json.Marshal(jsonData)
if err != nil {
return "{}"
}
return string(bytes)
}