diff --git a/Cargo.lock b/Cargo.lock index 20e7d9c..47196b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -468,6 +468,10 @@ dependencies = [ [[package]] name = "whoareyou-server" version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] [[package]] name = "windows-link" diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 207243b..4d5d24c 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -5,5 +5,7 @@ edition.workspace = true authors.workspace = true [dependencies] +serde = { version = "1", features = ["derive"] } [dev-dependencies] +serde_json = "1" diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs index 272b9e3..65880be 100644 --- a/crates/server/src/lib.rs +++ b/crates/server/src/lib.rs @@ -1 +1 @@ -// modules added as they are implemented +pub mod model; diff --git a/crates/server/src/model.rs b/crates/server/src/model.rs new file mode 100644 index 0000000..aa7a8dd --- /dev/null +++ b/crates/server/src/model.rs @@ -0,0 +1,87 @@ +use std::collections::BTreeMap; + +use serde::Serialize; + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Entry { + pub messages: Vec, + pub history: Vec, + pub comments: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Comment { + /// Unix epoch seconds, UTC. + pub timestamp: Option, + pub title: Option, + pub message: String, +} + +/// Per-provider outcome as exposed in the API (and cached). +#[derive(Debug, Clone, PartialEq, Serialize)] +#[serde(tag = "status", rename_all = "snake_case")] +pub enum ProviderResult { + Ok { entry: Entry }, + NoData, + FetchFailed, + ParseFailed, +} + +/// A fetched HTTP response handed to a provider's `parse`. +#[derive(Debug, Clone)] +pub struct FetchedResponse { + pub status: u16, + pub body: String, +} + +/// Outcome of a provider's `parse` call, before API mapping. +#[derive(Debug)] +pub enum ParseOutcome { + Ok(Entry), + NoData, + Failed(String), +} + +#[derive(Debug, Serialize)] +pub struct LookupResponse { + pub number: String, + pub results: BTreeMap, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn provider_result_serializes_to_api_shape() { + let ok = ProviderResult::Ok { + entry: Entry { + messages: vec![], + history: vec!["42 andra".to_string()], + comments: vec![Comment { + timestamp: Some(1547746162), + title: None, + message: "Varmsälj".to_string(), + }], + }, + }; + + let json = serde_json::to_value(&ok).unwrap(); + assert_eq!(json["status"], "ok"); + assert_eq!(json["entry"]["history"][0], "42 andra"); + assert_eq!(json["entry"]["comments"][0]["timestamp"], 1547746162); + + assert_eq!( + serde_json::to_value(&ProviderResult::NoData).unwrap()["status"], + "no_data" + ); + assert_eq!( + serde_json::to_value(&ProviderResult::FetchFailed).unwrap()["status"], + "fetch_failed" + ); + assert_eq!( + serde_json::to_value(&ProviderResult::ParseFailed).unwrap()["status"], + "parse_failed" + ); + } +}