I am developing an app for a desktop application for a gym so as I progress the app grows without focusing on oop and things like that, keeping it as simple as possible and making it work, so I have reached the limit of my knowledge, now I have made my transaction to register a user, There is no authentication or so since the user will register the client so I don’t know if I am handling my transaction correctly or what I can improve. In a few words, it would help me a lot if you gave me some feedback
type userRepository struct {
storage *postgres.PgxStorage
}
func NewUserRepository(storage *postgres.PgxStorage) user.Repository {
return &userRepository{storage: storage}
}
func (ur *userRepository) RegisterUser(ctx context.Context, register *entities.RegisterUsertx) (int32, error) {
tx, err := ur.storage.DBPool.Begin(ctx)
if err != nil {
log.Printf("error beginning transaction: %v", err)
return 0, fmt.Errorf("begin transaction: %w", err)
}
defer func() {
if err != nil {
tx.Rollback(ctx)
log.Printf("transaction rolled back due to error: %v", err)
}
}()
// Registrar usuario
var userID int32
query := "INSERT INTO users (name, lastname1, lastname2, email, phone, created_at) VALUES($1, $2, $3, $4, $5, $6) RETURNING id"
err = tx.QueryRow(ctx, query, register.Name, register.Lastname1, register.Lastname2, register.Email, register.Phone, register.CreatedAt).Scan(&userID)
if err != nil {
log.Printf("error inserting user: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("insert user: %w", err)
}
register.ID = userID
// Crear cuenta
accountID := uuid.New()
var account uuid.UUID
query = "INSERT INTO accounts (user_id, account_id, account_type_id, created_at) VALUES($1, $2, $3, $4) RETURNING account_id"
err = tx.QueryRow(ctx, query, userID, accountID, register.AccountTypeID, time.Now()).Scan(&account)
if err != nil {
log.Printf("error inserting account: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("insert account: %w", err)
}
// Obtener la duracion mediante el id de la suscripcion
var subscriptionDuration int
query = "SELECT subscription_day FROM subscription_costs WHERE id = $1"
err = tx.QueryRow(ctx, query, register.SubscriptionCostID).Scan(&subscriptionDuration)
if err != nil {
log.Printf("error getting subscription duration: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("get subscription duration: %w", err)
}
startDate := time.Now()
endDate := startDate.AddDate(0, 0, subscriptionDuration)
// Crear subscripcion
query = "INSERT INTO subscriptions (account_id, subscription_cost_id, start_date, end_date) VALUES($1, $2, $3, $4) RETURNING id"
err = tx.QueryRow(ctx, query, account, register.SubscriptionCostID, startDate, endDate).Scan(®ister.SubscriptionID)
if err != nil {
log.Printf("error inserting subscription: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("insert subscription: %w", err)
}
// Obtener el monto y comparar con el monto de la suscripcion
var expectedCost float64
query = "SELECT cost from subscription_costs where id = $1"
err = tx.QueryRow(ctx, query, register.SubscriptionCostID).Scan(&expectedCost)
if err != nil {
log.Printf("error getting subscription cost: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("ammount: %w", err)
}
if register.Ammount != expectedCost {
log.Printf("amount incorrect: expected %v, got %v", expectedCost, register.Ammount)
tx.Rollback(ctx)
return 0, fmt.Errorf("amount incorrect: %w", err)
}
query = "INSERT INTO payments (account_id, payment_type_id, cost, payment_date) VALUES($1, $2, $3, $4)"
_, err = tx.Exec(ctx, query, account, register.PaymentTypeID, register.Ammount, time.Now())
if err != nil {
log.Printf("error inserting payment: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("insert payment: %w", err)
}
// Obtener el id del status
var statusPayment, statusAcccount int32
query = `SELECT id FROM STATUS WHERE id = 5 OR id = 1`
rows, err := tx.Query(ctx, query)
if err != nil {
log.Printf("error getting statuses: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("get statuses: %w", err)
}
defer rows.Close()
for rows.Next() {
var id int32
if err := rows.Scan(&id); err != nil {
log.Printf("error scanning status: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("scan status: %w", err)
}
if id == 5 {
statusPayment = id
} else {
statusAcccount = id
}
}
if err := rows.Err(); err != nil {
log.Printf("rows error: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("rows error: %w", err)
}
query = `SELECT id from status where id = 5`
err = tx.QueryRow(ctx, query).Scan(&statusPayment)
if err != nil {
log.Printf("error getting status: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("get status: %w", err)
}
query = "UPDATE payments SET status_id = $1 WHERE account_id = $2"
_, err = tx.Exec(ctx, query, statusPayment, &account)
if err != nil {
log.Printf("error updating payment status: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("insert status: %w", err)
}
query = "UPDATE accounts SET subscription_id = $1, status_id = $2 WHERE account_id = $3"
_, err = tx.Exec(ctx, query, ®ister.SubscriptionID, statusAcccount, &account)
if err != nil {
log.Printf("error updating account status: %v", err)
tx.Rollback(ctx)
return 0, fmt.Errorf("get status: %w", err)
}
err = tx.Commit(ctx)
if err != nil {
log.Printf("error committing transaction: %v", err)
return 0, fmt.Errorf("commit transaction: %w", err)
}
return userID, nil
}