package repository import ( "time" "gorm.io/gorm" "dating-app/internal/models" ) type UserRepository struct { db *gorm.DB } func NewUserRepository(db *gorm.DB) *UserRepository { return &UserRepository{db: db} } func (r *UserRepository) FindByPhone(phone string) (*models.User, error) { var user models.User err := r.db.Where("phone = ?", phone).First(&user).Error if err != nil { return nil, err } return &user, nil } func (r *UserRepository) FindByID(id uint) (*models.User, error) { var user models.User err := r.db.First(&user, id).Error if err != nil { return nil, err } return &user, nil } // FindByIDs چند کاربر رو با هم در یک کوئری برمی‌گردونه (به‌جای یک FindByID // جدا به‌ازای هر id)؛ برای لیست‌هایی مثل مچ‌ها که باید اطلاعات طرف مقابل // چندین مچ رو یک‌جا نشون بدن. func (r *UserRepository) FindByIDs(ids []uint) ([]models.User, error) { var users []models.User if len(ids) == 0 { return users, nil } err := r.db.Where("id IN ?", ids).Find(&users).Error return users, err } // GetOrCreateByPhone کاربر را با شماره‌ی داده‌شده پیدا می‌کند یا در صورت نبود می‌سازد. func (r *UserRepository) GetOrCreateByPhone(phone string) (*models.User, bool, error) { var user models.User err := r.db.Where("phone = ?", phone).First(&user).Error if err == nil { return &user, false, nil } if err != gorm.ErrRecordNotFound { return nil, false, err } user = models.User{ Phone: phone, State: models.UserStateInactive, IsActive: true, CurrentStep: models.StepBasicInfo, } if err := r.db.Create(&user).Error; err != nil { return nil, false, err } return &user, true, nil } // ListPendingApproval کاربرانی که آنبوردینگ رو تکمیل کردن و منتظر بررسی ادمین‌اند // رو به ترتیب قدیمی‌ترین اول برمی‌گردونه. func (r *UserRepository) ListPendingApproval() ([]models.User, error) { var users []models.User err := r.db. Where("is_onboarded = ? AND approval_status = ?", true, models.ApprovalPending). Order("updated_at asc"). Find(&users).Error return users, err } // ListDiscoverable کاندیداهای بخش دوستیابی رو برمی‌گردونه: تاییدشده، فعال، // جنسیت مخالف کاربر (به‌عنوان ساده‌ترین فرض پیش‌فرض؛ فیلد ترجیح جنسیتی/گرایش // هنوز توی سیستم وجود نداره) و کسایی که قبلاً روشون سواپ نزده. // چون فاصله باید توی Go محاسبه بشه (haversine)، یک batch بزرگ‌تر از حد // نهایی برمی‌گردونه تا بعد از فیلتر فاصله همچنان گزینه‌ی کافی بمونه. func (r *UserRepository) ListDiscoverable(currentUserID uint, oppositeGender models.Gender, minAge, maxAge int, batchSize int) ([]models.User, error) { var users []models.User now := time.Now() minBirth := now.AddDate(-maxAge-1, 0, 1) maxBirth := now.AddDate(-minAge, 0, 0) err := r.db. Where("id != ?", currentUserID). Where("is_onboarded = ? AND approval_status = ? AND is_active = ?", true, models.ApprovalApproved, true). Where("gender = ?", oppositeGender). Where("birth_date BETWEEN ? AND ?", minBirth, maxBirth). Where("NOT EXISTS (SELECT 1 FROM swipes s WHERE s.swiper_id = ? AND s.swiped_id = users.id)", currentUserID). Order("id asc"). Limit(batchSize). Find(&users).Error return users, err } func (r *UserRepository) Save(user *models.User) error { return r.db.Save(user).Error } func (r *UserRepository) UpdateFields(user *models.User, fields map[string]interface{}) error { return r.db.Model(user).Updates(fields).Error } func (r *UserRepository) DB() *gorm.DB { return r.db }