Hypercode/alex/hypercodePublic

Code

  1. hypercode
  2. database
  3. repositories
  4. users_repository.go
users_repository.go270 lines
package repositories

import (
	"database/sql"
	"errors"

	"github.com/hypercodehq/hypercode/database/models"
)

type UsersRepository interface {
	Create(username, email, displayName, password string) (*models.User, error)
	CreateFromGitHub(username, email, displayName, githubUserID string) (*models.User, error)
	FindByID(id int64) (*models.User, error)
	FindByUsername(username string) (*models.User, error)
	FindByEmail(email string) (*models.User, error)
	FindByGitHubUserID(githubUserID string) (*models.User, error)
	FindAll() ([]*models.User, error)
	Update(user *models.User) error
	Delete(id int64) error
}

type usersRepository struct {
	db *sql.DB
}

func NewUsersRepository(db *sql.DB) UsersRepository {
	return &usersRepository{db: db}
}

func (r *usersRepository) Create(username, email, displayName, password string) (*models.User, error) {
	query := `
		INSERT INTO users (username, email, display_name, password)
		VALUES (?, ?, ?, ?)
		RETURNING id, username, email, display_name, password, github_user_id, created_at, updated_at
	`

	user := &models.User{}
	err := r.db.QueryRow(query, username, email, displayName, password).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.DisplayName,
		&user.Password,
		&user.GitHubUserID,
		&user.CreatedAt,
		&user.UpdatedAt,
	)
	if err != nil {
		return nil, err
	}

	return user, nil
}

func (r *usersRepository) CreateFromGitHub(username, email, displayName, githubUserID string) (*models.User, error) {
	query := `
		INSERT INTO users (username, email, display_name, github_user_id)
		VALUES (?, ?, ?, ?)
		RETURNING id, username, email, display_name, password, github_user_id, created_at, updated_at
	`

	user := &models.User{}
	err := r.db.QueryRow(query, username, email, displayName, githubUserID).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.DisplayName,
		&user.Password,
		&user.GitHubUserID,
		&user.CreatedAt,
		&user.UpdatedAt,
	)
	if err != nil {
		return nil, err
	}

	return user, nil
}

func (r *usersRepository) FindByID(id int64) (*models.User, error) {
	query := `
		SELECT id, username, email, display_name, password, github_user_id, created_at, updated_at
		FROM users
		WHERE id = ?
	`

	user := &models.User{}
	err := r.db.QueryRow(query, id).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.DisplayName,
		&user.Password,
		&user.GitHubUserID,
		&user.CreatedAt,
		&user.UpdatedAt,
	)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, nil
		}
		return nil, err
	}

	return user, nil
}

func (r *usersRepository) FindByUsername(username string) (*models.User, error) {
	query := `
		SELECT id, username, email, display_name, password, github_user_id, created_at, updated_at
		FROM users
		WHERE username = ?
	`

	user := &models.User{}
	err := r.db.QueryRow(query, username).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.DisplayName,
		&user.Password,
		&user.GitHubUserID,
		&user.CreatedAt,
		&user.UpdatedAt,
	)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, nil
		}
		return nil, err
	}

	return user, nil
}

func (r *usersRepository) FindByEmail(email string) (*models.User, error) {
	query := `
		SELECT id, username, email, display_name, password, github_user_id, created_at, updated_at
		FROM users
		WHERE email = ?
	`

	user := &models.User{}
	err := r.db.QueryRow(query, email).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.DisplayName,
		&user.Password,
		&user.GitHubUserID,
		&user.CreatedAt,
		&user.UpdatedAt,
	)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, nil
		}
		return nil, err
	}

	return user, nil
}

func (r *usersRepository) FindByGitHubUserID(githubUserID string) (*models.User, error) {
	query := `
		SELECT id, username, email, display_name, password, github_user_id, created_at, updated_at
		FROM users
		WHERE github_user_id = ?
	`

	user := &models.User{}
	err := r.db.QueryRow(query, githubUserID).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.DisplayName,
		&user.Password,
		&user.GitHubUserID,
		&user.CreatedAt,
		&user.UpdatedAt,
	)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, nil
		}
		return nil, err
	}

	return user, nil
}

func (r *usersRepository) Update(user *models.User) error {
	query := `
		UPDATE users
		SET username = ?, email = ?, display_name = ?, password = ?, github_user_id = ?
		WHERE id = ?
	`

	result, err := r.db.Exec(query, user.Username, user.Email, user.DisplayName, user.Password, user.GitHubUserID, user.ID)
	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rows == 0 {
		return sql.ErrNoRows
	}

	return nil
}

func (r *usersRepository) FindAll() ([]*models.User, error) {
	query := `
		SELECT id, username, email, display_name, password, github_user_id, created_at, updated_at
		FROM users
		ORDER BY id ASC
	`

	rows, err := r.db.Query(query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var users []*models.User
	for rows.Next() {
		user := &models.User{}
		err := rows.Scan(
			&user.ID,
			&user.Username,
			&user.Email,
			&user.DisplayName,
			&user.Password,
			&user.GitHubUserID,
			&user.CreatedAt,
			&user.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		users = append(users, user)
	}

	return users, nil
}

func (r *usersRepository) Delete(id int64) error {
	query := `DELETE FROM users WHERE id = ?`

	result, err := r.db.Exec(query, id)
	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rows == 0 {
		return sql.ErrNoRows
	}

	return nil
}