Files
lti-api/internal/modules/users/repositories/user.repository.go
T

120 lines
2.9 KiB
Go

package repository
import (
"context"
"errors"
"time"
"github.com/jackc/pgconn"
commonrepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type UserRepository interface {
commonrepo.BaseRepository[entity.User]
IdExists(ctx context.Context, id uint) (bool, error)
GetByIdUser(ctx context.Context, idUser int64, modifier func(*gorm.DB) *gorm.DB) (*entity.User, error)
UpsertByIdUser(ctx context.Context, user *entity.User) error
SoftDeleteByIdUser(ctx context.Context, idUser int64) error
}
type UserRepositoryImpl struct {
*commonrepo.BaseRepositoryImpl[entity.User]
db *gorm.DB
}
func NewUserRepository(db *gorm.DB) UserRepository {
return &UserRepositoryImpl{
BaseRepositoryImpl: commonrepo.NewBaseRepository[entity.User](db),
db: db,
}
}
func (r *UserRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) {
return commonrepo.Exists[entity.User](ctx, r.db, id)
}
func (r *UserRepositoryImpl) GetByIdUser(
ctx context.Context,
idUser int64,
modifier func(*gorm.DB) *gorm.DB,
) (*entity.User, error) {
return r.BaseRepositoryImpl.First(ctx, func(db *gorm.DB) *gorm.DB {
return db.Where("id_user = ?", idUser)
})
}
func (r *UserRepositoryImpl) UpsertByIdUser(ctx context.Context, user *entity.User) error {
if user == nil {
return gorm.ErrInvalidData
}
return r.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
now := time.Now()
user.DeletedAt = gorm.DeletedAt{}
user.UpdatedAt = now
err := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id_user"}},
UpdateAll: true,
}).Omit("id", "created_at").Create(user).Error
if err == nil {
return nil
}
if !isUniqueViolation(err, "users_email_unique") {
return err
}
var existing entity.User
lockQuery := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("email = ?", user.Email)
if err := lockQuery.First(&existing).Error; err != nil {
return err
}
user.Id = existing.Id
updates := map[string]any{
"id_user": user.IdUser,
"email": user.Email,
"name": user.Name,
"updated_at": now,
"deleted_at": gorm.DeletedAt{},
}
if err := tx.Model(&entity.User{}).Where("id = ?", existing.Id).Updates(updates).Error; err != nil {
return err
}
return nil
})
}
func (r *UserRepositoryImpl) SoftDeleteByIdUser(ctx context.Context, idUser int64) error {
query := r.DB().WithContext(ctx).Where("id_user = ?", idUser)
result := query.Delete(&entity.User{})
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}
return nil
}
func isUniqueViolation(err error, constraint string) bool {
var pgErr *pgconn.PgError
if !errors.As(err, &pgErr) {
return false
}
if pgErr.Code != "23505" {
return false
}
if constraint == "" {
return true
}
return pgErr.ConstraintName == constraint
}