package repository import ( "context" "database/sql" "errors" "tailly_back_v2/internal/domain" "time" ) var ( ErrUserNotFound = errors.New("user not found") ) type UserRepository interface { Create(ctx context.Context, user *domain.User) error GetByID(ctx context.Context, id int) (*domain.User, error) GetAll(ctx context.Context, id int) ([]*domain.User, error) GetByEmail(ctx context.Context, email string) (*domain.User, error) GetByConfirmationToken(ctx context.Context, token string) (*domain.User, error) Update(ctx context.Context, user *domain.User) error Delete(ctx context.Context, id int) error } type userRepository struct { db *sql.DB } func NewUserRepository(db *sql.DB) UserRepository { return &userRepository{db: db} } func (r *userRepository) Create(ctx context.Context, user *domain.User) error { query := ` INSERT INTO users (username, email, password, email_confirmation_token, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id ` err := r.db.QueryRowContext(ctx, query, user.Username, user.Email, user.Password, user.EmailConfirmationToken, user.CreatedAt, user.UpdatedAt, ).Scan(&user.ID) return err } func (r *userRepository) GetByID(ctx context.Context, id int) (*domain.User, error) { query := ` SELECT id, username, email, password, email_confirmation_token, email_confirmed_at, created_at, updated_at, avatar FROM users WHERE id = $1 ` user := &domain.User{} var confirmedAt sql.NullTime err := r.db.QueryRowContext(ctx, query, id).Scan( &user.ID, &user.Username, &user.Email, &user.Password, &user.EmailConfirmationToken, &confirmedAt, &user.CreatedAt, &user.UpdatedAt, &user.Avatar, ) if err == sql.ErrNoRows { return nil, ErrUserNotFound } if confirmedAt.Valid { user.EmailConfirmedAt = &confirmedAt.Time } return user, err } func (r *userRepository) GetByEmail(ctx context.Context, email string) (*domain.User, error) { query := ` SELECT id, username, email, password, email_confirmation_token, email_confirmed_at, created_at, updated_at, avatar FROM users WHERE email = $1 ` user := &domain.User{} var confirmedAt sql.NullTime err := r.db.QueryRowContext(ctx, query, email).Scan( &user.ID, &user.Username, &user.Email, &user.Password, &user.EmailConfirmationToken, &confirmedAt, &user.CreatedAt, &user.UpdatedAt, &user.Avatar, ) if err == sql.ErrNoRows { return nil, ErrUserNotFound } if confirmedAt.Valid { user.EmailConfirmedAt = &confirmedAt.Time } return user, err } func (r *userRepository) GetByConfirmationToken(ctx context.Context, token string) (*domain.User, error) { query := ` SELECT id, username, email, password, email_confirmation_token, email_confirmed_at, created_at, updated_at, avatar FROM users WHERE email_confirmation_token = $1 ` user := &domain.User{} var confirmedAt sql.NullTime err := r.db.QueryRowContext(ctx, query, token).Scan( &user.ID, &user.Username, &user.Email, &user.Password, &user.EmailConfirmationToken, &confirmedAt, &user.CreatedAt, &user.UpdatedAt, &user.Avatar, ) if err == sql.ErrNoRows { return nil, ErrUserNotFound } if confirmedAt.Valid { user.EmailConfirmedAt = &confirmedAt.Time } return user, err } func (r *userRepository) Update(ctx context.Context, user *domain.User) error { query := ` UPDATE users SET username = $1, email = $2, password = $3, email_confirmation_token = $4, email_confirmed_at = $5, avatar = $6, updated_at = $7 WHERE id = $8 ` var confirmedAt interface{} if user.EmailConfirmedAt != nil { confirmedAt = *user.EmailConfirmedAt } else { confirmedAt = nil } _, err := r.db.ExecContext(ctx, query, user.Username, user.Email, user.Password, user.EmailConfirmationToken, confirmedAt, &user.Avatar, time.Now(), // Обновляем updated_at user.ID, ) return err } func (r *userRepository) Delete(ctx context.Context, id int) error { query := `DELETE FROM users WHERE id = $1` _, err := r.db.ExecContext(ctx, query, id) return err } func (r *userRepository) GetAll(ctx context.Context, id int) ([]*domain.User, error) { query := ` SELECT id, username, avatar FROM users WHERE id != $1 ` rows, err := r.db.QueryContext(ctx, query, id) if err != nil { return nil, err } defer rows.Close() var users []*domain.User for rows.Next() { user := &domain.User{} err := rows.Scan( &user.ID, &user.Username, &user.Avatar, ) if err != nil { return nil, err } users = append(users, user) } return users, nil }