2025-09-24 13:47:55 +07:00

113 lines
2.6 KiB
Go

package devices
import (
"context"
"errors"
"time"
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
"gorm.io/gorm"
)
var (
ErrNotFound = gorm.ErrRecordNotFound
ErrInvalidFilter = errors.New("invalid filter")
ErrMoreThanOne = errors.New("more than one record")
)
type repository struct {
db *gorm.DB
}
func (r *repository) Select(filter ...SelectFilter) ([]models.Device, error) {
if len(filter) == 0 {
return nil, ErrInvalidFilter
}
f := newFilter(filter...)
devices := []models.Device{}
return devices, f.apply(r.db).Find(&devices).Error
}
// Exists checks if there exists a device with the given filters.
//
// If the device does not exist, it returns false and nil error. If there is an
// error during the query, it returns false and the error. Otherwise, it returns
// true and nil error.
func (r *repository) Exists(filters ...SelectFilter) (bool, error) {
err := newFilter(filters...).apply(r.db).Take(&models.Device{}).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}
func (r *repository) Get(filter ...SelectFilter) (models.Device, error) {
devices, err := r.Select(filter...)
if err != nil {
return models.Device{}, err
}
if len(devices) == 0 {
return models.Device{}, ErrNotFound
}
if len(devices) > 1 {
return models.Device{}, ErrMoreThanOne
}
return devices[0], nil
}
func (r *repository) Insert(device *models.Device) error {
return r.db.Create(device).Error
}
func (r *repository) UpdatePushToken(id, token string) error {
return r.db.Model(&models.Device{}).Where("id", id).Update("push_token", token).Error
}
func (r *repository) SetLastSeen(ctx context.Context, id string, lastSeen time.Time) error {
if lastSeen.IsZero() {
return nil // ignore zero timestamps
}
res := r.db.WithContext(ctx).
Model(&models.Device{}).
Where("id = ? AND last_seen < ?", id, lastSeen).
Update("last_seen", lastSeen)
if res.Error != nil {
return res.Error
}
// RowsAffected==0 => not found or stale timestamp; treat as no-op.
return nil
}
func (r *repository) Remove(filter ...SelectFilter) error {
if len(filter) == 0 {
return ErrInvalidFilter
}
f := newFilter(filter...)
return f.apply(r.db).Delete(&models.Device{}).Error
}
func (r *repository) removeUnused(ctx context.Context, since time.Time) (int64, error) {
res := r.db.
WithContext(ctx).
Where("updated_at < ?", since).
Delete(&models.Device{})
return res.RowsAffected, res.Error
}
func newDevicesRepository(db *gorm.DB) *repository {
return &repository{
db: db,
}
}