use crate::{Result, RideWithGpsClient};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum ItemType {
Route,
Trip,
Event,
Collection,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SyncItem {
pub id: u64,
pub item_type: ItemType,
pub updated_at: DateTime<Utc>,
pub deleted: Option<bool>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SyncResponse {
pub items: Vec<SyncItem>,
pub server_datetime: DateTime<Utc>,
}
impl RideWithGpsClient {
pub fn sync(&self, since: &DateTime<Utc>) -> Result<SyncResponse> {
let since_str = since.to_rfc3339();
let url = format!(
"/api/v1/sync.json?since={}",
urlencoding::encode(&since_str)
);
self.get(&url)
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::TimeZone;
#[test]
fn test_sync_item_deserialization() {
let json = r#"{
"id": 123,
"item_type": "route",
"updated_at": "2025-01-15T10:30:00Z",
"deleted": false
}"#;
let item: SyncItem = serde_json::from_str(json).unwrap();
assert_eq!(item.id, 123);
assert_eq!(item.item_type, ItemType::Route);
assert_eq!(item.deleted, Some(false));
}
#[test]
fn test_sync_response_deserialization() {
let json = r#"{
"items": [
{
"id": 123,
"item_type": "route",
"updated_at": "2025-01-15T10:30:00Z",
"deleted": false
},
{
"id": 456,
"item_type": "trip",
"updated_at": "2025-01-15T11:00:00Z",
"deleted": true
}
],
"server_datetime": "2025-01-15T12:00:00Z"
}"#;
let response: SyncResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.items.len(), 2);
assert_eq!(response.items[0].item_type, ItemType::Route);
assert_eq!(response.items[1].item_type, ItemType::Trip);
assert_eq!(
response.server_datetime,
Utc.with_ymd_and_hms(2025, 1, 15, 12, 0, 0).unwrap()
);
}
#[test]
fn test_item_type_serialization() {
assert_eq!(
serde_json::to_string(&ItemType::Route).unwrap(),
r#""route""#
);
assert_eq!(serde_json::to_string(&ItemType::Trip).unwrap(), r#""trip""#);
}
}