forked from alemi/upub
feat: improve Node fetching and handling
This commit is contained in:
parent
a73852b3b7
commit
67c3e80cf6
1 changed files with 36 additions and 61 deletions
|
@ -11,7 +11,7 @@ pub enum NodeResolutionError {
|
|||
}
|
||||
|
||||
pub enum Node<T> {
|
||||
Array(Vec<T>),
|
||||
Array(Vec<Node<T>>),
|
||||
Object(T),
|
||||
Link(Box<dyn super::Link>),
|
||||
Empty,
|
||||
|
@ -27,7 +27,7 @@ impl<T> From<Option<T>> for Node<T> {
|
|||
}
|
||||
|
||||
impl<T> Node<T> {
|
||||
pub fn first(&self) -> Option<&T> {
|
||||
pub fn get(&self) -> Option<&T> {
|
||||
match self {
|
||||
Node::Empty | Node::Link(_) => None,
|
||||
Node::Object(x) => Some(x),
|
||||
|
@ -35,7 +35,7 @@ impl<T> Node<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn items(&self) -> Option<Vec<&T>> {
|
||||
pub fn all(&self) -> Option<Vec<&T>> {
|
||||
match self {
|
||||
Node::Empty | Node::Link(_) => None,
|
||||
Node::Object(x) => Some(vec![x]),
|
||||
|
@ -43,46 +43,49 @@ impl<T> Node<T> {
|
|||
Some(v.iter().map(|x| &x).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Node<T>
|
||||
where
|
||||
T : super::Base
|
||||
{
|
||||
pub fn id(&self) -> Option<&str> {
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Node::Array(v) => v.first()?.id(),
|
||||
Node::Link(x) => Some(x.href()),
|
||||
Node::Object(x) => x.id(),
|
||||
Node::Empty => None,
|
||||
Node::Empty => 0,
|
||||
Node::Link(_) => 0,
|
||||
Node::Object(_) => 1,
|
||||
Node::Array(v) => v.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Node<T>
|
||||
where
|
||||
T : Clone + for<'de> serde::Deserialize<'de>,
|
||||
{
|
||||
pub async fn resolve(self) -> Result<T, NodeResolutionError> {
|
||||
match self {
|
||||
Node::Empty => Err(NodeResolutionError::Empty),
|
||||
Node::Object(object) => Ok(object),
|
||||
Node::Array(array) => Ok(
|
||||
array
|
||||
.first()
|
||||
.ok_or(NodeResolutionError::EmptyArray)?
|
||||
.clone()
|
||||
),
|
||||
Node::Link(link) => Ok(
|
||||
reqwest::get(link.href())
|
||||
.await?
|
||||
.json::<T>()
|
||||
.await?
|
||||
impl From<serde_json::Value> for Node<serde_json::Value> {
|
||||
fn from(value: serde_json::Value) -> Self {
|
||||
match value {
|
||||
serde_json::Value::String(uri) => Node::Link(Box::new(uri)),
|
||||
serde_json::Value::Object(_) => match value.get("href") {
|
||||
Some(_) => Node::Object(value),
|
||||
None => Node::Link(Box::new(value)),
|
||||
},
|
||||
serde_json::Value::Array(arr) => Node::Array(
|
||||
arr
|
||||
.into_iter()
|
||||
.filter_map(|x| Self::new(x).ok())
|
||||
.collect()
|
||||
),
|
||||
_ => Node::Empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node<serde_json::Value>{
|
||||
pub async fn fetch(&mut self) -> reqwest::Result<()> {
|
||||
if let Node::Link(link) = self {
|
||||
*self = reqwest::get(link.href())
|
||||
.await?
|
||||
.json::<serde_json::Value>()
|
||||
.await?
|
||||
.into();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeExtractor {
|
||||
fn node(&self, id: &str) -> Node<serde_json::Value>;
|
||||
fn node_vec(&self, id: &str) -> Node<serde_json::Value>;
|
||||
|
@ -110,41 +113,13 @@ impl NodeExtractor for serde_json::Value {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("json object is wrongly structured")]
|
||||
pub struct JsonStructureError;
|
||||
|
||||
impl Node<serde_json::Value> {
|
||||
pub fn new(value: serde_json::Value) -> Result<Self, JsonStructureError> {
|
||||
if !(value.is_string() || value.is_object()) {
|
||||
return Err(JsonStructureError);
|
||||
}
|
||||
if value.is_string() || value.get("href").is_some() {
|
||||
Ok(Self::Link(Box::new(value)))
|
||||
} else {
|
||||
Ok(Self::Object(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn many(value: serde_json::Value) -> Result<Vec<Self>, JsonStructureError> {
|
||||
if let serde_json::Value::Array(arr) = value {
|
||||
Ok(
|
||||
arr
|
||||
.into_iter()
|
||||
.filter_map(|x| Self::new(x.clone()).ok())
|
||||
.collect()
|
||||
)
|
||||
} else {
|
||||
Ok(vec![Self::new(value)?])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue