package repository import ( "context" "github.com/jackc/pgx/v5/pgxpool" "financeiro-carvalho/internal/model" ) type AccountRepository struct { pool *pgxpool.Pool } func NewAccountRepository(pool *pgxpool.Pool) *AccountRepository { return &AccountRepository{pool: pool} } func (r *AccountRepository) List(ctx context.Context) ([]model.Account, error) { rows, err := r.pool.Query(ctx, ` SELECT a.id, a.name, a.type, a.initial_balance, a.created_at::text, a.updated_at::text, a.initial_balance + COALESCE(SUM(CASE WHEN t.type = 'income' THEN t.amount ELSE 0 END), 0) - COALESCE(SUM(CASE WHEN t.type = 'expense' THEN t.amount ELSE 0 END), 0) AS balance FROM accounts a LEFT JOIN transactions t ON t.account_id = a.id GROUP BY a.id ORDER BY a.created_at `) if err != nil { return nil, err } defer rows.Close() var out []model.Account for rows.Next() { var a model.Account if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.InitialBalance, &a.CreatedAt, &a.UpdatedAt, &a.Balance); err != nil { return nil, err } out = append(out, a) } return out, rows.Err() } func (r *AccountRepository) GetByID(ctx context.Context, id int) (*model.Account, error) { var a model.Account err := r.pool.QueryRow(ctx, ` SELECT a.id, a.name, a.type, a.initial_balance, a.created_at::text, a.updated_at::text, a.initial_balance + COALESCE(SUM(CASE WHEN t.type = 'income' THEN t.amount ELSE 0 END), 0) - COALESCE(SUM(CASE WHEN t.type = 'expense' THEN t.amount ELSE 0 END), 0) AS balance FROM accounts a LEFT JOIN transactions t ON t.account_id = a.id WHERE a.id = $1 GROUP BY a.id `, id).Scan(&a.ID, &a.Name, &a.Type, &a.InitialBalance, &a.CreatedAt, &a.UpdatedAt, &a.Balance) if err != nil { return nil, err } return &a, nil } func (r *AccountRepository) Create(ctx context.Context, in model.AccountInput) (*model.Account, error) { var a model.Account err := r.pool.QueryRow(ctx, ` INSERT INTO accounts (name, type, initial_balance) VALUES ($1, $2, $3) RETURNING id, name, type, initial_balance, created_at::text, updated_at::text `, in.Name, in.Type, in.InitialBalance). Scan(&a.ID, &a.Name, &a.Type, &a.InitialBalance, &a.CreatedAt, &a.UpdatedAt) if err != nil { return nil, err } a.Balance = a.InitialBalance return &a, nil } func (r *AccountRepository) Update(ctx context.Context, id int, in model.AccountInput) (*model.Account, error) { row := r.pool.QueryRow(ctx, ` UPDATE accounts SET name=$1, type=$2, initial_balance=$3, updated_at=NOW() WHERE id=$4 RETURNING id, name, type, initial_balance, created_at::text, updated_at::text `, in.Name, in.Type, in.InitialBalance, id) var a model.Account if err := row.Scan(&a.ID, &a.Name, &a.Type, &a.InitialBalance, &a.CreatedAt, &a.UpdatedAt); err != nil { return nil, err } // recalculate balance full, err := r.GetByID(ctx, a.ID) if err != nil { return nil, err } return full, nil } func (r *AccountRepository) Delete(ctx context.Context, id int) error { _, err := r.pool.Exec(ctx, `DELETE FROM accounts WHERE id = $1`, id) return err } func (r *AccountRepository) TotalPatrimony(ctx context.Context) (float64, error) { var total float64 err := r.pool.QueryRow(ctx, ` SELECT COALESCE(SUM( a.initial_balance + COALESCE(( SELECT SUM(CASE WHEN type='income' THEN amount ELSE -amount END) FROM transactions WHERE account_id = a.id ), 0) ), 0) FROM accounts a `).Scan(&total) return total, err }