forked from alemi/upub
feat: macros for getters/setters, refactored
This commit is contained in:
parent
863ea0408d
commit
35f85695ba
3 changed files with 339 additions and 135 deletions
339
src/activitystream/macros.rs
Normal file
339
src/activitystream/macros.rs
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
use super::Node;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[error("invalid type value")]
|
||||||
|
pub struct TypeValueError;
|
||||||
|
|
||||||
|
impl From<TypeValueError> for sea_orm::sea_query::ValueTypeErr {
|
||||||
|
fn from(_: TypeValueError) -> Self {
|
||||||
|
sea_orm::sea_query::ValueTypeErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TypeValueError> for sea_orm::TryGetError {
|
||||||
|
fn from(_: TypeValueError) -> Self {
|
||||||
|
sea_orm::TryGetError::Null("value is not a valid type".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! strenum {
|
||||||
|
( $(pub enum $enum_name:ident { $($flat:ident),* ; $($deep:ident($inner:ident)),* };)+ ) => {
|
||||||
|
$(
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
|
pub enum $enum_name {
|
||||||
|
$($flat,)*
|
||||||
|
$($deep($inner),)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for $enum_name {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
$(Self::$flat => stringify!($flat),)*
|
||||||
|
$(Self::$deep(x) => x.as_ref(),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for $enum_name {
|
||||||
|
type Error = $crate::activitystream::macros::TypeValueError;
|
||||||
|
|
||||||
|
fn try_from(value:&str) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
$(stringify!($flat) => Ok(Self::$flat),)*
|
||||||
|
_ => {
|
||||||
|
$(
|
||||||
|
if let Ok(x) = $inner::try_from(value) {
|
||||||
|
return Ok(Self::$deep(x));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
Err($crate::activitystream::macros::TypeValueError)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$enum_name> for sea_orm::Value {
|
||||||
|
fn from(value: $enum_name) -> sea_orm::Value {
|
||||||
|
sea_orm::Value::String(Some(Box::new(value.as_ref().to_string())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sea_orm::sea_query::ValueType for $enum_name {
|
||||||
|
fn try_from(v: sea_orm::Value) -> Result<Self, sea_orm::sea_query::ValueTypeErr> {
|
||||||
|
match v {
|
||||||
|
sea_orm::Value::String(Some(x)) =>
|
||||||
|
Ok(<Self as TryFrom<&str>>::try_from(x.as_str())?),
|
||||||
|
_ => Err(sea_orm::sea_query::ValueTypeErr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_name() -> String {
|
||||||
|
stringify!($enum_name).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_type() -> sea_orm::sea_query::ArrayType {
|
||||||
|
sea_orm::sea_query::ArrayType::String
|
||||||
|
}
|
||||||
|
|
||||||
|
fn column_type() -> sea_orm::sea_query::ColumnType {
|
||||||
|
sea_orm::sea_query::ColumnType::String(Some(24))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sea_orm::TryGetable for $enum_name {
|
||||||
|
fn try_get_by<I: sea_orm::ColIdx>(res: &sea_orm::prelude::QueryResult, index: I) -> Result<Self, sea_orm::TryGetError> {
|
||||||
|
let x : String = res.try_get_by(index)?;
|
||||||
|
Ok(Self::try_from(x.as_str())?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! getter {
|
||||||
|
($name:ident -> type $t:ty) => {
|
||||||
|
fn $name(&self) -> Option<$t> {
|
||||||
|
self.get("type")?.as_str()?.try_into().ok()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident -> &str) => {
|
||||||
|
fn $name(&self) -> Option<&str> {
|
||||||
|
self.get(stringify!($name))?.as_str()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident::$rename:ident -> &str) => {
|
||||||
|
fn $name(&self) -> Option<&str> {
|
||||||
|
self.get(stringify!($rename))?.as_str()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident -> f64) => {
|
||||||
|
fn $name(&self) -> Option<f64> {
|
||||||
|
self.get(stringify!($name))?.as_f64()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident::$rename:ident -> f64) => {
|
||||||
|
fn $name(&self) -> Option<f64> {
|
||||||
|
self.get(stringify!($rename))?.as_f64()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident -> chrono::DateTime<chrono::Utc>) => {
|
||||||
|
fn $name(&self) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||||
|
Some(
|
||||||
|
chrono::DateTime::parse_from_rfc3339(
|
||||||
|
self
|
||||||
|
.get(stringify!($name))?
|
||||||
|
.as_str()?
|
||||||
|
)
|
||||||
|
.ok()?
|
||||||
|
.with_timezone(&chrono::Utc)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident::$rename:ident -> chrono::DateTime<chrono::Utc>) => {
|
||||||
|
fn $name(&self) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||||
|
Some(
|
||||||
|
chrono::DateTime::parse_from_rfc3339(
|
||||||
|
self
|
||||||
|
.get(stringify!($rename))?
|
||||||
|
.as_str()?
|
||||||
|
)
|
||||||
|
.ok()?
|
||||||
|
.with_timezone(&chrono::Utc)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident -> node $t:ty) => {
|
||||||
|
fn $name(&self) -> $crate::activitystream::Node<$t> {
|
||||||
|
match self.get(stringify!($name)) {
|
||||||
|
Some(x) => $crate::activitystream::Node::from(x.clone()),
|
||||||
|
None => $crate::activitystream::Node::Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident::$rename:ident -> node $t:ty) => {
|
||||||
|
fn $name(&self) -> $crate::activitystream::Node<$t> {
|
||||||
|
match self.get(stringify!($rename)) {
|
||||||
|
Some(x) => $crate::activitystream::Node::from(x.clone()),
|
||||||
|
None => $crate::activitystream::Node::Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! setter {
|
||||||
|
($name:ident -> &str) => {
|
||||||
|
paste::item! {
|
||||||
|
fn [< set_$name >](&mut self, val: Option<&str>) -> &mut Self {
|
||||||
|
$crate::activitystream::macros::set_maybe_value(
|
||||||
|
self, stringify!($name), val.map(|x| serde_json::Value::String(x.to_string()))
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident -> chrono::DateTime<chrono::Utc>) => {
|
||||||
|
paste::item! {
|
||||||
|
fn [< set_$name >](&mut self, val: Option<chrono::DateTime<chrono::Utc>>) -> &mut Self {
|
||||||
|
$crate::activitystream::macros::set_maybe_value(
|
||||||
|
self, stringify!($name), val.map(|x| serde_json::Value::String(x.to_rfc3339()))
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident::$rename:ident -> chrono::DateTime<chrono::Utc>) => {
|
||||||
|
paste::item! {
|
||||||
|
fn [< set_$name >](&mut self, val: Option<chrono::DateTime<chrono::Utc>>) -> &mut Self {
|
||||||
|
$crate::activitystream::macros::set_maybe_value(
|
||||||
|
self, stringify!($rename), val.map(|x| serde_json::Value::String(x.to_rfc3339()))
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident -> node $t:ty ) => {
|
||||||
|
paste::item! {
|
||||||
|
fn [< set_$name >](&mut self, val: $crate::activitystream::Node<$t>) -> &mut Self {
|
||||||
|
$crate::activitystream::macros::set_maybe_node(
|
||||||
|
self, stringify!($name), val
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident::$rename:ident -> node $t:ty ) => {
|
||||||
|
paste::item! {
|
||||||
|
fn [< set_$name >](&mut self, val: $crate::activitystream::Node<$t>) -> &mut Self {
|
||||||
|
$crate::activitystream::macros::set_maybe_node(
|
||||||
|
self, stringify!($rename), val
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident -> type $t:ty ) => {
|
||||||
|
paste::item! {
|
||||||
|
fn [< set_$name >](&mut self, val: Option<$t>) -> &mut Self {
|
||||||
|
$crate::activitystream::macros::set_maybe_value(
|
||||||
|
self, "type", val.map(|x| serde_json::Value::String(x.as_ref().to_string()))
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_maybe_node<T : super::Base>(obj: &mut serde_json::Value, key: &str, node: super::Node<T>) {
|
||||||
|
match node {
|
||||||
|
super::Node::Object(x) => {
|
||||||
|
set_maybe_value(
|
||||||
|
obj, key, Some(x.underlying_json_object()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
super::Node::Link(l) => {
|
||||||
|
set_maybe_value(
|
||||||
|
obj, key, Some(serde_json::Value::String(l.href().to_string())),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
super::Node::Array(_) => {
|
||||||
|
set_maybe_value(
|
||||||
|
obj, key, Some(serde_json::Value::Array(node.flat())),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
super::Node::Empty => {
|
||||||
|
set_maybe_value(
|
||||||
|
obj, key, None,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_maybe_value(obj: &mut serde_json::Value, key: &str, value: Option<serde_json::Value>) {
|
||||||
|
if let Some(map) = obj.as_object_mut() {
|
||||||
|
match value {
|
||||||
|
Some(x) => map.insert(key.to_string(), x),
|
||||||
|
None => map.remove(key),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
tracing::error!("error setting '{key}' on json Value: not an object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait InsertValue {
|
||||||
|
fn insert_node(&mut self, k: &str, v: Node<serde_json::Value>);
|
||||||
|
fn insert_str(&mut self, k: &str, v: Option<&str>);
|
||||||
|
fn insert_float(&mut self, k: &str, f: Option<f64>);
|
||||||
|
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InsertValue for serde_json::Map<String, serde_json::Value> {
|
||||||
|
fn insert_node(&mut self, k: &str, node: Node<serde_json::Value>) {
|
||||||
|
match node {
|
||||||
|
Node::Object(x) => {
|
||||||
|
self.insert(
|
||||||
|
k.to_string(),
|
||||||
|
*x,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Node::Array(ref _arr) => {
|
||||||
|
self.insert(
|
||||||
|
k.to_string(),
|
||||||
|
serde_json::Value::Array(node.flat()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Node::Link(l) => {
|
||||||
|
self.insert(
|
||||||
|
k.to_string(),
|
||||||
|
serde_json::Value::String(l.href().to_string()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Node::Empty => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_str(&mut self, k: &str, v: Option<&str>) {
|
||||||
|
if let Some(v) = v {
|
||||||
|
self.insert(
|
||||||
|
k.to_string(),
|
||||||
|
serde_json::Value::String(v.to_string()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_float(&mut self, k: &str, v: Option<f64>) {
|
||||||
|
if let Some(v) = v {
|
||||||
|
if let Some(n) = serde_json::Number::from_f64(v) {
|
||||||
|
self.insert(
|
||||||
|
k.to_string(),
|
||||||
|
serde_json::Value::Number(n),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>) {
|
||||||
|
if let Some(published) = t {
|
||||||
|
self.insert(
|
||||||
|
k.to_string(),
|
||||||
|
serde_json::Value::String(published.to_rfc3339()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -129,48 +129,3 @@ impl Node<serde_json::Value>{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub(crate) trait NodeExtractor {
|
|
||||||
fn node(&self, id: &str) -> Node<serde_json::Value>;
|
|
||||||
fn node_vec(&self, id: &str) -> Node<serde_json::Value>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeExtractor for serde_json::Value {
|
|
||||||
fn node(&self, id: &str) -> Node<serde_json::Value> {
|
|
||||||
match self.get(id) {
|
|
||||||
None => Node::Empty,
|
|
||||||
Some(x) => Node::from(x.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn node_vec(&self, id: &str) -> Node<serde_json::Value> {
|
|
||||||
match self.get(id) {
|
|
||||||
None => Node::Empty,
|
|
||||||
Some(x) => Node::from(x.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait InsertStr {
|
|
||||||
fn insert_str(&mut self, k: &str, v: Option<&str>);
|
|
||||||
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InsertStr for serde_json::Map<String, serde_json::Value> {
|
|
||||||
fn insert_str(&mut self, k: &str, v: Option<&str>) {
|
|
||||||
if let Some(v) = v {
|
|
||||||
self.insert(
|
|
||||||
k.to_string(),
|
|
||||||
serde_json::Value::String(v.to_string()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>) {
|
|
||||||
if let Some(published) = t {
|
|
||||||
self.insert(
|
|
||||||
k.to_string(),
|
|
||||||
serde_json::Value::String(published.to_rfc3339()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
#[error("invalid type value")]
|
|
||||||
pub struct TypeValueError;
|
|
||||||
|
|
||||||
impl From<TypeValueError> for sea_orm::sea_query::ValueTypeErr {
|
|
||||||
fn from(_: TypeValueError) -> Self {
|
|
||||||
sea_orm::sea_query::ValueTypeErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TypeValueError> for sea_orm::TryGetError {
|
|
||||||
fn from(_: TypeValueError) -> Self {
|
|
||||||
sea_orm::TryGetError::Null("value is not a valid type".into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! strenum {
|
|
||||||
( $(pub enum $enum_name:ident { $($flat:ident),* ; $($deep:ident($inner:ident)),* };)+ ) => {
|
|
||||||
$(
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
|
||||||
pub enum $enum_name {
|
|
||||||
$($flat,)*
|
|
||||||
$($deep($inner),)*
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<str> for $enum_name {
|
|
||||||
fn as_ref(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
$(Self::$flat => stringify!($flat),)*
|
|
||||||
$(Self::$deep(x) => x.as_ref(),)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&str> for $enum_name {
|
|
||||||
type Error = $crate::activitystream::types::TypeValueError;
|
|
||||||
|
|
||||||
fn try_from(value:&str) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
$(stringify!($flat) => Ok(Self::$flat),)*
|
|
||||||
_ => {
|
|
||||||
$(
|
|
||||||
if let Ok(x) = $inner::try_from(value) {
|
|
||||||
return Ok(Self::$deep(x));
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
Err($crate::activitystream::types::TypeValueError)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$enum_name> for sea_orm::Value {
|
|
||||||
fn from(value: $enum_name) -> sea_orm::Value {
|
|
||||||
sea_orm::Value::String(Some(Box::new(value.as_ref().to_string())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl sea_orm::sea_query::ValueType for $enum_name {
|
|
||||||
fn try_from(v: sea_orm::Value) -> Result<Self, sea_orm::sea_query::ValueTypeErr> {
|
|
||||||
match v {
|
|
||||||
sea_orm::Value::String(Some(x)) =>
|
|
||||||
Ok(<Self as TryFrom<&str>>::try_from(x.as_str())?),
|
|
||||||
_ => Err(sea_orm::sea_query::ValueTypeErr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_name() -> String {
|
|
||||||
stringify!($enum_name).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn array_type() -> sea_orm::sea_query::ArrayType {
|
|
||||||
sea_orm::sea_query::ArrayType::String
|
|
||||||
}
|
|
||||||
|
|
||||||
fn column_type() -> sea_orm::sea_query::ColumnType {
|
|
||||||
sea_orm::sea_query::ColumnType::String(Some(24))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl sea_orm::TryGetable for $enum_name {
|
|
||||||
fn try_get_by<I: sea_orm::ColIdx>(res: &sea_orm::prelude::QueryResult, index: I) -> Result<Self, sea_orm::TryGetError> {
|
|
||||||
let x : String = res.try_get_by(index)?;
|
|
||||||
Ok(Self::try_from(x.as_str())?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in a new issue