forked from alemi/upub
feat: improved Node API
This commit is contained in:
parent
67c3e80cf6
commit
106380d3b7
2 changed files with 59 additions and 26 deletions
|
@ -1,14 +1,4 @@
|
||||||
#[derive(Debug, thiserror::Error)]
|
use super::Object;
|
||||||
pub enum NodeResolutionError {
|
|
||||||
#[error("error fetching object: {0}")]
|
|
||||||
FetchError(#[from] reqwest::Error),
|
|
||||||
|
|
||||||
#[error("empty array")]
|
|
||||||
EmptyArray,
|
|
||||||
|
|
||||||
#[error("field not present")]
|
|
||||||
Empty,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Node<T> {
|
pub enum Node<T> {
|
||||||
Array(Vec<Node<T>>),
|
Array(Vec<Node<T>>),
|
||||||
|
@ -31,7 +21,13 @@ impl<T> Node<T> {
|
||||||
match self {
|
match self {
|
||||||
Node::Empty | Node::Link(_) => None,
|
Node::Empty | Node::Link(_) => None,
|
||||||
Node::Object(x) => Some(x),
|
Node::Object(x) => Some(x),
|
||||||
Node::Array(v) => v.first(),
|
Node::Array(v) => match v.iter().find_map(|x| match x {
|
||||||
|
Node::Object(x) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
}) {
|
||||||
|
Some(x) => Some(x),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +36,17 @@ impl<T> Node<T> {
|
||||||
Node::Empty | Node::Link(_) => None,
|
Node::Empty | Node::Link(_) => None,
|
||||||
Node::Object(x) => Some(vec![x]),
|
Node::Object(x) => Some(vec![x]),
|
||||||
Node::Array(v) =>
|
Node::Array(v) =>
|
||||||
Some(v.iter().map(|x| &x).collect()),
|
Some(v.iter().filter_map(|x| match x {
|
||||||
|
Node::Object(x) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
}).collect()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Node::Empty | Node::Link(_) => true,
|
||||||
|
Node::Object(_) | Node::Array(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +60,35 @@ impl<T> Node<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Node<T>
|
||||||
|
where
|
||||||
|
T : Object
|
||||||
|
{
|
||||||
|
pub fn id(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Node::Empty => None,
|
||||||
|
Node::Link(uri) => Some(uri.href()),
|
||||||
|
Node::Object(obj) => obj.id(),
|
||||||
|
Node::Array(arr) => arr.first()?.id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<&str>> for Node<serde_json::Value> {
|
||||||
|
fn from(value: Option<&str>) -> Self {
|
||||||
|
match value {
|
||||||
|
Some(x) => Node::Link(Box::new(x.to_string())),
|
||||||
|
None => Node::Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Node<serde_json::Value> {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
Node::Link(Box::new(value.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<serde_json::Value> for Node<serde_json::Value> {
|
impl From<serde_json::Value> for Node<serde_json::Value> {
|
||||||
fn from(value: serde_json::Value) -> Self {
|
fn from(value: serde_json::Value) -> Self {
|
||||||
match value {
|
match value {
|
||||||
|
@ -65,7 +100,7 @@ impl From<serde_json::Value> for Node<serde_json::Value> {
|
||||||
serde_json::Value::Array(arr) => Node::Array(
|
serde_json::Value::Array(arr) => Node::Array(
|
||||||
arr
|
arr
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|x| Self::new(x).ok())
|
.map(Self::from)
|
||||||
.collect()
|
.collect()
|
||||||
),
|
),
|
||||||
_ => Node::Empty,
|
_ => Node::Empty,
|
||||||
|
@ -86,7 +121,12 @@ impl Node<serde_json::Value>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait NodeExtractor {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) trait NodeExtractor {
|
||||||
fn node(&self, id: &str) -> Node<serde_json::Value>;
|
fn node(&self, id: &str) -> Node<serde_json::Value>;
|
||||||
fn node_vec(&self, id: &str) -> Node<serde_json::Value>;
|
fn node_vec(&self, id: &str) -> Node<serde_json::Value>;
|
||||||
}
|
}
|
||||||
|
@ -95,26 +135,18 @@ impl NodeExtractor for serde_json::Value {
|
||||||
fn node(&self, id: &str) -> Node<serde_json::Value> {
|
fn node(&self, id: &str) -> Node<serde_json::Value> {
|
||||||
match self.get(id) {
|
match self.get(id) {
|
||||||
None => Node::Empty,
|
None => Node::Empty,
|
||||||
Some(x) => match Node::new(x.clone()) {
|
Some(x) => Node::from(x.clone()),
|
||||||
Err(e) => Node::Empty,
|
|
||||||
Ok(x) => x,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_vec(&self, id: &str) -> Node<serde_json::Value> {
|
fn node_vec(&self, id: &str) -> Node<serde_json::Value> {
|
||||||
match self.get(id) {
|
match self.get(id) {
|
||||||
None => Node::Empty,
|
None => Node::Empty,
|
||||||
Some(x) => match Node::many(x.clone()) {
|
Some(x) => Node::from(x.clone()),
|
||||||
Err(e) => Node::Empty,
|
|
||||||
Ok(x) => x,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub(crate) trait InsertStr {
|
pub(crate) trait InsertStr {
|
||||||
fn insert_str(&mut self, k: &str, v: Option<&str>);
|
fn insert_str(&mut self, k: &str, v: Option<&str>);
|
||||||
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>);
|
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>);
|
||||||
|
@ -133,7 +165,7 @@ impl InsertStr for serde_json::Map<String, serde_json::Value> {
|
||||||
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>) {
|
fn insert_timestr(&mut self, k: &str, t: Option<chrono::DateTime<chrono::Utc>>) {
|
||||||
if let Some(published) = t {
|
if let Some(published) = t {
|
||||||
self.insert(
|
self.insert(
|
||||||
"published".to_string(),
|
k.to_string(),
|
||||||
serde_json::Value::String(published.to_rfc3339()),
|
serde_json::Value::String(published.to_rfc3339()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ pub trait Object : super::Base {
|
||||||
|
|
||||||
impl Object for serde_json::Value {
|
impl Object for serde_json::Value {
|
||||||
fn object_type(&self) -> Option<ObjectType> {
|
fn object_type(&self) -> Option<ObjectType> {
|
||||||
|
use super::Base;
|
||||||
match self.base_type() {
|
match self.base_type() {
|
||||||
Some(super::BaseType::Object(o)) => Some(o),
|
Some(super::BaseType::Object(o)) => Some(o),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
Loading…
Reference in a new issue