Why this question exists?
I am writing rabbithole-rs, which is a JSON:API implementation based on Rust. But while designing the sorting/pagination features, I meet a big problem on on designing the attribute
fields.
Intro JSON:API soring/pagination briefly
There is a attributes
fields in JSON:API's resource
object, which is a HashMap<String, serde_json::Value>
or HashMap<String, Box<Any>>
, where the key is attribute name, and the value is the attribute's value.
And Vec<Resource>
object has a sort(attribute_name: &str)
method, which can sort a bunch of Resource
based on one of the attribute.
A brief layout of Resource
pub struct Resource {
pub ty: String, // The type of `Resource`, `sort` method can only effect on the same type of resources
pub id: String, // Every `Resource` has an unique id
pub attr1: dyn Ord + Serialize + Deserialize,
... <more attrs>
}
Where:
- Each
attr
should implement at least three traits:Ord
to compareSerialize
to convert intoserde_json::Value
Deserialize
to convert fromserde_json::Value
What the problem is?
When getting a Resource
, I have to extract all of the attribute
fields and put them into a HashMap
, like: HashMap<String, serde_json::Value>
or HashMap<String, Box<Any>>
. But both of them lose the trait info of the attributes, so I cannot compare two attribute item with the same name.
A brief demo, please!
Sure! Here you go!
#[macro_use]
extern crate serde_derive;
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::collections::HashMap;
/// This is a struct field
#[derive(Debug, Serialize, Deserialize, Ord, PartialOrd, PartialEq, Eq)]
pub struct Name {
pub first_name: String,
pub last_name: String,
}
/// Resource object
#[derive(Debug, Serialize, Deserialize, Ord, PartialOrd, PartialEq, Eq)]
pub struct Resource {
pub ty: String,
pub id: String,
pub age: i32, // attr 1
pub name: Name, // another attr
}
fn main() {
let item1 = Resource {
ty: "human".into(),
id: "id1".to_string(),
age: 1,
name: Name {
first_name: "first1".to_string(),
last_name: "last1".to_string(),
},
};
// **This is the first attributes HashMap**
let mut map_item1: HashMap<&str, (&str, Box<dyn Any>)> = Default::default();
map_item1.insert("age", ("i32", Box::new(item1.age)));
map_item1.insert("name", ("Name", Box::new(item1.name)));
let item2 = Resource {
ty: "human".into(),
id: "id2".to_string(),
age: 2,
name: Name {
first_name: "first2".to_string(),
last_name: "last2".to_string(),
},
};
// **This is the second attributes HashMap**
let mut map_item2: HashMap<&str, (&str, Box<dyn Any>)> = Default::default();
map_item2.insert("age", ("i32", Box::new(item2.age)));
map_item2.insert("name", ("Name", Box::new(item2.name)));
// TODO: NEED TO BE IMPLEMENTED
for k in map_item1.keys() {
println!(
"key: {key}, item1.{key} < item2.{key}? {res}",
key = k,
res = map_item1.get(k).unwrap().1.cmp(map_item2.get(k).unwrap().1)
)
}
}
Aucun commentaire:
Enregistrer un commentaire