package auth import ( "context" "hyapp/pkg/appcode" authdomain "hyapp/services/user-service/internal/domain/auth" ) // UpsertUserDevice 以 (app_code, user_id, device_id) 为主键合并设备档案。 // 合并语义是“非空覆盖”:客户端可能只在部分请求携带设备头(例如 refresh 只带 device_id), // 空值不能抹掉此前已经上报过的型号/厂商/系统版本;last_seen/updated 每次认证成功都必须前移, // 让后台设备列表能按最近活跃排序。写入失败由调用方决定是否忽略,认证主链路不因它失败。 func (r *Repository) UpsertUserDevice(ctx context.Context, device authdomain.UserDevice) error { _, err := r.db.ExecContext(ctx, ` INSERT INTO user_devices (app_code, user_id, device_id, platform, device_model, manufacturer, os_version, imei, app_version, build_number, first_seen_at_ms, last_seen_at_ms, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE platform = IF(VALUES(platform) = '', platform, VALUES(platform)), device_model = IF(VALUES(device_model) = '', device_model, VALUES(device_model)), manufacturer = IF(VALUES(manufacturer) = '', manufacturer, VALUES(manufacturer)), os_version = IF(VALUES(os_version) = '', os_version, VALUES(os_version)), imei = IF(VALUES(imei) = '', imei, VALUES(imei)), app_version = IF(VALUES(app_version) = '', app_version, VALUES(app_version)), build_number = IF(VALUES(build_number) = '', build_number, VALUES(build_number)), last_seen_at_ms = VALUES(last_seen_at_ms), updated_at_ms = VALUES(updated_at_ms) `, appcode.Normalize(device.AppCode), device.UserID, device.DeviceID, device.Platform, device.DeviceModel, device.Manufacturer, device.OSVersion, device.IMEI, device.AppVersion, device.BuildNumber, device.FirstSeenAtMs, device.LastSeenAtMs, device.CreatedAtMs, device.UpdatedAtMs, ) return err }