// File: backend/internal/database/user_repository.go package database import ( "context" "database/sql" "errors" "gitea.mrixs.me/minecraft-platform/backend/internal/models" ) var ( ErrUserExists = errors.New("user with this username or email already exists") ) type UserRepository struct { DB *sql.DB } // CreateUserTx создает нового пользователя и его профиль в рамках одной транзакции func (r *UserRepository) CreateUserTx(ctx context.Context, user *models.User) error { tx, err := r.DB.BeginTx(ctx, nil) if err != nil { return err } // Гарантируем откат транзакции в случае любой ошибки defer tx.Rollback() // Шаг 4 из ТЗ: Проверка уникальности var exists bool err = tx.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM users WHERE username = $1 OR email = $2)", user.Username, user.Email).Scan(&exists) if err != nil { return err } if exists { return ErrUserExists } // Шаг 7 из ТЗ: INSERT в таблицу users. Получаем ID нового пользователя. var newUserID int err = tx.QueryRowContext(ctx, "INSERT INTO users (uuid, username, email, password_hash, role) VALUES ($1, $2, $3, $4, $5) RETURNING id", user.UUID, user.Username, user.Email, user.PasswordHash, user.Role, ).Scan(&newUserID) if err != nil { return err } // Шаг 9 из ТЗ: INSERT в таблицу profiles _, err = tx.ExecContext(ctx, "INSERT INTO profiles (user_id) VALUES ($1)", newUserID) if err != nil { return err } // Шаг 10 из ТЗ: Коммитим транзакцию return tx.Commit() }