summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorD. Scott Boggs <scott@tams.tech>2023-02-12 13:11:21 -0500
committerD. Scott Boggs <scott@tams.tech>2024-04-08 08:56:16 -0400
commitcc6e116823c6bfb67c91913cf21456263a427198 (patch)
tree3c2db1edb46bfb97a0cc61fb6a28f9f345dc800b
parentfb0e434b7ce0ec65fe3408b445f46b77815c5d83 (diff)
Add Admin::Cohort example test; change conversion namespace
-rw-r--r--entities/src/admin/cohort.rs42
-rw-r--r--entities/src/admin/email_domain_block.rs4
-rw-r--r--entities/src/admin/measure.rs6
-rw-r--r--entities/src/conversion.rs163
-rw-r--r--entities/src/instance.rs6
-rw-r--r--entities/src/status/scheduled.rs2
-rw-r--r--entities/src/tag.rs4
7 files changed, 129 insertions, 98 deletions
diff --git a/entities/src/admin/cohort.rs b/entities/src/admin/cohort.rs
index b66787c..14f925a 100644
--- a/entities/src/admin/cohort.rs
+++ b/entities/src/admin/cohort.rs
@@ -1,5 +1,7 @@
+use is_variant::IsVariant;
use serde::{Deserialize, Serialize};
use time::{serde::iso8601, OffsetDateTime};
+use crate::conversion;
/// Represents a retention metric.
///
@@ -18,23 +20,13 @@ pub struct Cohort {
/// The size of the bucket for the returned [`Cohort`] data.
///
/// See also [the API documentation](https://docs.joinmastodon.org/entities/Admin_Cohort/#frequency)
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, IsVariant)]
+#[serde(rename_all = "lowercase")]
pub enum CohortFrequency {
Day,
Month,
}
-impl CohortFrequency {
- #![allow(missing_docs)]
-
- pub fn is_day(&self) -> bool {
- *self == Self::Day
- }
- pub fn is_month(&self) -> bool {
- *self == Self::Month
- }
-}
-
/// Represents a single value from a set of retention metrics.
///
/// See also [the API documentation](https://docs.joinmastodon.org/entities/Admin_Cohort/#CohortData)
@@ -47,5 +39,31 @@ pub struct Data {
/// were active for the given date bucket.
pub rate: f64,
/// How many users registered in the specified period and were active for the given date bucket.
+ #[serde(with = "conversion::string_to::i64")]
pub value: i64,
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_cohort_example() {
+ let example = r#"{
+ "period": "2022-09-01T00:00:00+00:00",
+ "frequency": "month",
+ "data": [
+ {
+ "date": "2022-09-01T00:00:00+00:00",
+ "rate": 1.0,
+ "value": "2"
+ }
+ ]
+ }"#;
+ let subject: Cohort = serde_json::from_str(example).unwrap();
+ assert!(subject.frequency.is_month());
+ let data = &subject.data[0];
+ assert_eq!(data.rate, 1.0);
+ assert_eq!(data.value, 2);
+ }
+}
diff --git a/entities/src/admin/email_domain_block.rs b/entities/src/admin/email_domain_block.rs
index d6b6a73..0fbd333 100644
--- a/entities/src/admin/email_domain_block.rs
+++ b/entities/src/admin/email_domain_block.rs
@@ -25,10 +25,10 @@ pub struct History {
#[serde(with = "conversion::date_from_timestamp")]
pub day: Date,
/// The counted accounts signup attempts using that email domain within that day.
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub accounts: u64,
/// The counted IP signup attempts of that email domain within that day.
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub uses: u64,
}
diff --git a/entities/src/admin/measure.rs b/entities/src/admin/measure.rs
index 08a39bc..3dd95c3 100644
--- a/entities/src/admin/measure.rs
+++ b/entities/src/admin/measure.rs
@@ -11,7 +11,7 @@ pub struct Measure {
/// The units associated with this data item’s value, if applicable.
pub unit: Option<String>,
/// The numeric total associated with the requested measure.
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub total: u64,
/// A human-readable formatted value for this data item.
#[serde(default)]
@@ -20,7 +20,7 @@ pub struct Measure {
/// period. Previous period is calculated by subtracting the start_at and
/// end_at dates, then offsetting both start and end dates backwards by the
/// length of the time period.
- #[serde(with = "conversion::string_to_u64::option")]
+ #[serde(with = "conversion::string_to::u64::option")]
pub previous_total: Option<u64>,
/// The data available for the requested measure, split into daily buckets.
pub data: Vec<Data>,
@@ -33,7 +33,7 @@ pub struct Data {
#[serde(with = "iso8601")]
pub date: OffsetDateTime,
/// The numeric value for the requested measure.
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub value: u64,
}
diff --git a/entities/src/conversion.rs b/entities/src/conversion.rs
index ccfaa81..07320d0 100644
--- a/entities/src/conversion.rs
+++ b/entities/src/conversion.rs
@@ -1,94 +1,107 @@
-pub(crate) mod string_to_u64 {
- use serde::{
- de::{self, Visitor},
- Deserializer, Serializer,
- };
-
- pub(crate) fn serialize<S>(value: &u64, ser: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- ser.serialize_str(&value.to_string())
- }
-
- pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
- where
- D: Deserializer<'de>,
- {
- struct StringToIntVisitor;
-
- impl<'v> Visitor<'v> for StringToIntVisitor {
- type Value = u64;
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(
- formatter,
- "a string which can be parsed as an unsigned, 64-bit integer"
- )
- }
- fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+macro_rules! string_conversion {
+ ($t:ident) => {
+ #[allow(dead_code)]
+ pub(crate) mod $t {
+ use serde::{
+ de::{self, Visitor},
+ Deserializer, Serializer,
+ };
+
+ pub(crate) fn serialize<S>(value: &$t, ser: S) -> Result<S::Ok, S::Error>
where
- E: serde::de::Error,
+ S: Serializer,
{
- v.parse()
- .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &self))
+ ser.serialize_str(&value.to_string())
}
- }
- deserializer.deserialize_str(StringToIntVisitor)
- }
+ pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<$t, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct StringToIntVisitor;
+
+ impl<'v> Visitor<'v> for StringToIntVisitor {
+ type Value = $t;
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(
+ formatter,
+ "a string which can be parsed as an unsigned, 64-bit integer"
+ )
+ }
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ v.parse()
+ .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &self))
+ }
+ }
- pub(crate) mod option {
- use serde::{
- de::{self, Visitor},
- Deserializer, Serializer,
- };
-
- pub(crate) fn serialize<S>(value: &Option<u64>, ser: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- if let Some(value) = value {
- ser.serialize_str(&value.to_string())
- } else {
- ser.serialize_none()
+ deserializer.deserialize_str(StringToIntVisitor)
}
- }
- pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
- where
- D: Deserializer<'de>,
- {
- struct StringToIntVisitor;
-
- impl<'v> Visitor<'v> for StringToIntVisitor {
- type Value = Option<u64>;
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(
- formatter,
- "a string which can be parsed as an unsigned, 64-bit integer"
- )
- }
- fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ pub(crate) mod option {
+ use serde::{
+ de::{self, Visitor},
+ Deserializer, Serializer,
+ };
+
+ pub(crate) fn serialize<S>(value: &Option<$t>, ser: S) -> Result<S::Ok, S::Error>
where
- E: serde::de::Error,
+ S: Serializer,
{
- let v: u64 = v
- .parse()
- .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &self))?;
- Ok(Some(v))
+ if let Some(value) = value {
+ ser.serialize_str(&value.to_string())
+ } else {
+ ser.serialize_none()
+ }
}
- fn visit_none<E>(self) -> Result<Self::Value, E>
+ pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Option<$t>, D::Error>
where
- E: de::Error,
+ D: Deserializer<'de>,
{
- Ok(None)
+ struct StringToIntVisitor;
+
+ impl<'v> Visitor<'v> for StringToIntVisitor {
+ type Value = Option<$t>;
+ fn expecting(
+ &self,
+ formatter: &mut std::fmt::Formatter,
+ ) -> std::fmt::Result {
+ write!(
+ formatter,
+ "a string which can be parsed as an unsigned, 64-bit integer"
+ )
+ }
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ let v: $t = v.parse().map_err(|_| {
+ de::Error::invalid_value(de::Unexpected::Str(v), &self)
+ })?;
+ Ok(Some(v))
+ }
+
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+
+ deserializer.deserialize_any(StringToIntVisitor)
}
}
-
- deserializer.deserialize_any(StringToIntVisitor)
}
- }
+ };
+}
+
+pub(crate) mod string_to {
+ string_conversion!(u64);
+ string_conversion!(i64);
}
pub(crate) mod maybe_empty_url {
diff --git a/entities/src/instance.rs b/entities/src/instance.rs
index 95fb331..16d34d6 100644
--- a/entities/src/instance.rs
+++ b/entities/src/instance.rs
@@ -124,13 +124,13 @@ pub struct Activity {
/// UNIX Timestamp at midnight at the first day of the week.
pub week: String,
/// The number of Statuses created since the week began (cast from an integer)
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub statuses: u64,
/// The number of user logins since the week began (cast from an integer)
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub logins: u64,
/// The number of user registrations since the week began (cast from an integer)
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub registrations: u64,
}
diff --git a/entities/src/status/scheduled.rs b/entities/src/status/scheduled.rs
index 8bae30d..90673f2 100644
--- a/entities/src/status/scheduled.rs
+++ b/entities/src/status/scheduled.rs
@@ -59,7 +59,7 @@ pub struct Poll {
/// The poll options to be used.
pub options: Vec<String>,
/// How many seconds the poll should last before closing.
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub expires_in: u64,
/// Whether the poll allows multiple choices.
pub multiple: Option<bool>,
diff --git a/entities/src/tag.rs b/entities/src/tag.rs
index 30863b9..351ad01 100644
--- a/entities/src/tag.rs
+++ b/entities/src/tag.rs
@@ -26,10 +26,10 @@ pub struct History {
#[serde(with = "conversion::date_from_timestamp")]
pub day: Date,
/// The counted usage of the tag within that day.
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub uses: u64,
/// The total of accounts using the tag within that day.
- #[serde(with = "conversion::string_to_u64")]
+ #[serde(with = "conversion::string_to::u64")]
pub accounts: u64,
}