dry some stuff. also lot of yelling at the compiler
This commit is contained in:
Generated
+1
@@ -2714,6 +2714,7 @@ dependencies = [
|
|||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
"rand 0.8.3",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ pub(crate) struct ObjectModelForm {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
// #[serde(with="serde_with::rust::default_on_error")] // This is because "" can be selected
|
// #[serde(with="serde_with::rust::default_on_error")] // This is because "" can be selected
|
||||||
#[serde(with="my_string_empty_as_none")]
|
#[serde(with = "my_string_empty_as_none")]
|
||||||
pub name_property: Option<ID>,
|
pub name_property: Option<ID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ pub(crate) async fn create(
|
|||||||
match wg.define_object(ObjectModel {
|
match wg.define_object(ObjectModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
name: form.name.clone(),
|
name: form.name.clone(),
|
||||||
name_property: form.name_property
|
name_property: form.name_property,
|
||||||
}) {
|
}) {
|
||||||
Ok(_id) => {
|
Ok(_id) => {
|
||||||
wg.persist().err_to_500()?;
|
wg.persist().err_to_500()?;
|
||||||
@@ -96,10 +96,13 @@ pub(crate) async fn update_form(
|
|||||||
context.insert("model", &model);
|
context.insert("model", &model);
|
||||||
} else {
|
} else {
|
||||||
context.insert("model", model);
|
context.insert("model", model);
|
||||||
context.insert("old", &ObjectModelForm {
|
context.insert(
|
||||||
name: model.name.to_string(),
|
"old",
|
||||||
name_property: model.name_property
|
&ObjectModelForm {
|
||||||
});
|
name: model.name.to_string(),
|
||||||
|
name_property: model.name_property,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let properties = rg.get_property_models_for_parent(*model_id).collect_vec();
|
let properties = rg.get_property_models_for_parent(*model_id).collect_vec();
|
||||||
@@ -162,30 +165,29 @@ pub(crate) async fn delete(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub mod my_string_empty_as_none {
|
pub mod my_string_empty_as_none {
|
||||||
use serde::{Deserializer, Serializer, Serialize};
|
use serde::de::{Error, Visitor};
|
||||||
use std::str::FromStr;
|
use serde::{Deserializer, Serialize, Serializer};
|
||||||
use std::fmt::{Display, Write};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use serde::de::{Visitor, Error};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::str::FromStr;
|
||||||
use yopa::ID;
|
use yopa::ID;
|
||||||
|
|
||||||
// FIXME largely copied from serde_with
|
// FIXME largely copied from serde_with
|
||||||
|
|
||||||
/// Deserialize an `Option<T>` from a string using `FromStr`
|
/// Deserialize an `Option<T>` from a string using `FromStr`
|
||||||
pub fn deserialize<'de, D, S>(deserializer: D) -> Result<Option<S>, D::Error>
|
pub fn deserialize<'de, D, S>(deserializer: D) -> Result<Option<S>, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
S: FromStr,
|
S: FromStr,
|
||||||
S::Err: Display,
|
S::Err: Display,
|
||||||
{
|
{
|
||||||
struct OptionStringEmptyNone<S>(PhantomData<S>);
|
struct OptionStringEmptyNone<S>(PhantomData<S>);
|
||||||
impl<'de, S> Visitor<'de> for OptionStringEmptyNone<S>
|
impl<'de, S> Visitor<'de> for OptionStringEmptyNone<S>
|
||||||
where
|
where
|
||||||
S: FromStr,
|
S: FromStr,
|
||||||
S::Err: Display,
|
S::Err: Display,
|
||||||
{
|
{
|
||||||
type Value = Option<S>;
|
type Value = Option<S>;
|
||||||
|
|
||||||
@@ -194,8 +196,8 @@ pub mod my_string_empty_as_none {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
match value {
|
match value {
|
||||||
"" => Ok(None),
|
"" => Ok(None),
|
||||||
@@ -204,8 +206,8 @@ pub mod my_string_empty_as_none {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
|
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
match &*value {
|
match &*value {
|
||||||
"" => Ok(None),
|
"" => Ok(None),
|
||||||
@@ -215,16 +217,16 @@ pub mod my_string_empty_as_none {
|
|||||||
|
|
||||||
// TODO remove?
|
// TODO remove?
|
||||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
self.visit_str(&v.to_string())
|
self.visit_str(&v.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles the `null` case
|
// handles the `null` case
|
||||||
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@@ -235,8 +237,8 @@ pub mod my_string_empty_as_none {
|
|||||||
|
|
||||||
/// Serialize a string from `Option<T>` using `AsRef<str>` or using the empty string if `None`.
|
/// Serialize a string from `Option<T>` using `AsRef<str>` or using the empty string if `None`.
|
||||||
pub fn serialize<S>(option: &Option<ID>, serializer: S) -> Result<S::Ok, S::Error>
|
pub fn serialize<S>(option: &Option<ID>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
option.serialize(serializer)
|
option.serialize(serializer)
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use actix_session::Session;
|
use actix_session::Session;
|
||||||
use actix_web::{HttpResponse, Responder, web};
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
use heck::TitleCase;
|
use heck::TitleCase;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use json_dotpath::DotPaths;
|
use json_dotpath::DotPaths;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use yopa::{data, ID, model, Storage};
|
use yopa::{data, model, Storage, ID};
|
||||||
use yopa::data::Object;
|
|
||||||
use yopa::insert::InsertObj;
|
use yopa::insert::InsertObj;
|
||||||
use yopa::model::{ObjectModel, PropertyModel, RelationModel};
|
use yopa::model::{ObjectModel, PropertyModel, RelationModel};
|
||||||
use yopa::update::UpdateObj;
|
use yopa::update::UpdateObj;
|
||||||
|
|
||||||
use crate::session_ext::SessionExt;
|
use crate::session_ext::SessionExt;
|
||||||
use crate::TERA;
|
|
||||||
use crate::tera_ext::TeraExt;
|
use crate::tera_ext::TeraExt;
|
||||||
use crate::utils::{redirect, StorageErrorIntoResponseError};
|
use crate::utils::{redirect, StorageErrorIntoResponseError};
|
||||||
|
use crate::TERA;
|
||||||
|
use yopa::helpers::GroupByModel;
|
||||||
|
|
||||||
// we only need references here, Context serializes everything to Value.
|
// we only need references here, Context serializes everything to Value.
|
||||||
// cloning would be a waste of cycles
|
// cloning would be a waste of cycles
|
||||||
@@ -97,13 +98,14 @@ fn prepare_object_create_data(rg: &Storage, model_id: ID) -> actix_web::Result<O
|
|||||||
.get_property_models_for_parents(prop_object_ids)
|
.get_property_models_for_parents(prop_object_ids)
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
objects: rg.get_objects_of_types(related_ids).map(|o| {
|
objects: rg
|
||||||
ObjectDisplay {
|
.get_objects_of_types(related_ids)
|
||||||
|
.map(|o| ObjectDisplay {
|
||||||
id: o.id,
|
id: o.id,
|
||||||
model: o.model,
|
model: o.model,
|
||||||
name: rg.get_object_name(o),
|
name: rg.get_object_name(o),
|
||||||
}
|
})
|
||||||
}).collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,13 +164,16 @@ pub(crate) async fn list_inner(
|
|||||||
.sorted_by_key(|m| &m.name)
|
.sorted_by_key(|m| &m.name)
|
||||||
.map(|model| {
|
.map(|model| {
|
||||||
let objects = objects_by_model.remove(&model.id).unwrap_or_default();
|
let objects = objects_by_model.remove(&model.id).unwrap_or_default();
|
||||||
let mut objects = objects.into_iter().map(|o| {
|
let mut objects = objects
|
||||||
ObjectDisplay {
|
.into_iter()
|
||||||
id: o.id,
|
.map(|o| {
|
||||||
model: o.model,
|
ObjectDisplay {
|
||||||
name: rg.get_object_name(o), // TODO optimize
|
id: o.id,
|
||||||
}
|
model: o.model,
|
||||||
}).collect_vec();
|
name: rg.get_object_name(o), // TODO optimize
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
objects.sort_by(|a, b| a.name.cmp(&b.name));
|
objects.sort_by(|a, b| a.name.cmp(&b.name));
|
||||||
ModelWithObjects { model, objects }
|
ModelWithObjects { model, objects }
|
||||||
@@ -223,11 +228,14 @@ pub(crate) async fn detail(
|
|||||||
.get_object_model(object.model)
|
.get_object_model(object.model)
|
||||||
.ok_or_else(|| actix_web::error::ErrorNotFound("No such model"))?;
|
.ok_or_else(|| actix_web::error::ErrorNotFound("No such model"))?;
|
||||||
|
|
||||||
context.insert("object", &ObjectDisplay {
|
context.insert(
|
||||||
id: object_id,
|
"object",
|
||||||
model: object.model,
|
&ObjectDisplay {
|
||||||
name: rg.get_object_name(object),
|
id: object_id,
|
||||||
});
|
model: object.model,
|
||||||
|
name: rg.get_object_name(object),
|
||||||
|
},
|
||||||
|
);
|
||||||
context.insert("model", model);
|
context.insert("model", model);
|
||||||
context.insert("kind", &rg.get_model_name(object.model));
|
context.insert("kind", &rg.get_model_name(object.model));
|
||||||
|
|
||||||
@@ -248,8 +256,7 @@ pub(crate) async fn detail(
|
|||||||
let object_values_by_model = grouped_values
|
let object_values_by_model = grouped_values
|
||||||
.remove(&object_id)
|
.remove(&object_id)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.into_iter()
|
.group_by_model();
|
||||||
.into_group_map_by(|value| value.model);
|
|
||||||
|
|
||||||
let mut view_object_properties = vec![];
|
let mut view_object_properties = vec![];
|
||||||
for (prop_model_id, values) in object_values_by_model {
|
for (prop_model_id, values) in object_values_by_model {
|
||||||
@@ -268,7 +275,7 @@ pub(crate) async fn detail(
|
|||||||
{
|
{
|
||||||
let grouped_relations = relations
|
let grouped_relations = relations
|
||||||
.iter()
|
.iter()
|
||||||
.into_group_map_by(|relation| relation.model);
|
.group_by_model();
|
||||||
|
|
||||||
let mut relation_views = vec![];
|
let mut relation_views = vec![];
|
||||||
for (model_id, relations) in grouped_relations {
|
for (model_id, relations) in grouped_relations {
|
||||||
@@ -283,8 +290,7 @@ pub(crate) async fn detail(
|
|||||||
let rel_values_by_model = grouped_values
|
let rel_values_by_model = grouped_values
|
||||||
.remove(&rel.id)
|
.remove(&rel.id)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.into_iter()
|
.group_by_model();
|
||||||
.into_group_map_by(|value| value.model);
|
|
||||||
|
|
||||||
let mut view_rel_properties = vec![];
|
let mut view_rel_properties = vec![];
|
||||||
for (prop_model_id, values) in rel_values_by_model {
|
for (prop_model_id, values) in rel_values_by_model {
|
||||||
@@ -327,7 +333,7 @@ pub(crate) async fn detail(
|
|||||||
{
|
{
|
||||||
let grouped_relations = reci_relations
|
let grouped_relations = reci_relations
|
||||||
.iter()
|
.iter()
|
||||||
.into_group_map_by(|relation| relation.model);
|
.group_by_model();
|
||||||
|
|
||||||
let mut relation_views = vec![];
|
let mut relation_views = vec![];
|
||||||
for (model_id, relations) in grouped_relations {
|
for (model_id, relations) in grouped_relations {
|
||||||
@@ -342,8 +348,7 @@ pub(crate) async fn detail(
|
|||||||
let rel_values_by_model = grouped_values
|
let rel_values_by_model = grouped_values
|
||||||
.remove(&rel.id)
|
.remove(&rel.id)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.into_iter()
|
.group_by_model();
|
||||||
.into_group_map_by(|value| value.model);
|
|
||||||
|
|
||||||
let mut view_rel_properties = vec![];
|
let mut view_rel_properties = vec![];
|
||||||
for (prop_model_id, values) in rel_values_by_model {
|
for (prop_model_id, values) in rel_values_by_model {
|
||||||
@@ -428,11 +433,14 @@ pub(crate) async fn update_form(
|
|||||||
|
|
||||||
// maybe its useful,idk
|
// maybe its useful,idk
|
||||||
context.insert("model", &model);
|
context.insert("model", &model);
|
||||||
context.insert("object", &ObjectDisplay {
|
context.insert(
|
||||||
id: object.id,
|
"object",
|
||||||
model: object.model,
|
&ObjectDisplay {
|
||||||
name: rg.get_object_name(object),
|
id: object.id,
|
||||||
});
|
model: object.model,
|
||||||
|
name: rg.get_object_name(object),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let create_data = prepare_object_create_data(&rg, model.id)?;
|
let create_data = prepare_object_create_data(&rg, model.id)?;
|
||||||
|
|
||||||
@@ -448,7 +456,8 @@ pub(crate) async fn update_form(
|
|||||||
.map(|p| p.id)
|
.map(|p| p.id)
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
let mut values_grouped = rg.get_values_for_object(*id).into_group_map_by(|v| v.model);
|
let mut values_grouped = rg.get_values_for_object(*id)
|
||||||
|
.group_by_model();
|
||||||
|
|
||||||
prop_ids.into_iter().for_each(|id| {
|
prop_ids.into_iter().for_each(|id| {
|
||||||
value_map.insert(
|
value_map.insert(
|
||||||
@@ -472,7 +481,7 @@ pub(crate) async fn update_form(
|
|||||||
|
|
||||||
let mut relations_grouped_by_model = relations
|
let mut relations_grouped_by_model = relations
|
||||||
.iter()
|
.iter()
|
||||||
.into_group_map_by(|relation| relation.model);
|
.group_by_model();
|
||||||
|
|
||||||
let mut property_models_grouped_by_parent =
|
let mut property_models_grouped_by_parent =
|
||||||
rg.get_grouped_prop_models_for_parents(relation_model_ids.clone());
|
rg.get_grouped_prop_models_for_parents(relation_model_ids.clone());
|
||||||
@@ -497,8 +506,7 @@ pub(crate) async fn update_form(
|
|||||||
let mut rel_values = relation_values_grouped_by_instance
|
let mut rel_values = relation_values_grouped_by_instance
|
||||||
.remove(&rel.id)
|
.remove(&rel.id)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.into_iter()
|
.group_by_model();
|
||||||
.into_group_map_by(|relation| relation.model);
|
|
||||||
|
|
||||||
prop_models_for_relation.iter().for_each(|prop_model| {
|
prop_models_for_relation.iter().for_each(|prop_model| {
|
||||||
relation_values_map.insert(
|
relation_values_map.insert(
|
||||||
@@ -525,7 +533,7 @@ pub(crate) async fn update_form(
|
|||||||
let object = EnrichedObject {
|
let object = EnrichedObject {
|
||||||
id: object.id,
|
id: object.id,
|
||||||
model: object.model,
|
model: object.model,
|
||||||
name: rg.get_object_name_by_id(object.id),
|
name: rg.get_object_name(object),
|
||||||
values: value_map,
|
values: value_map,
|
||||||
relations: relation_map,
|
relations: relation_map,
|
||||||
};
|
};
|
||||||
@@ -558,7 +566,11 @@ pub(crate) async fn update(
|
|||||||
Ok(_id) => {
|
Ok(_id) => {
|
||||||
wg.persist().err_to_500()?;
|
wg.persist().err_to_500()?;
|
||||||
debug!("Object created, redirecting to root");
|
debug!("Object created, redirecting to root");
|
||||||
session.flash_success(format!("{} \"{}\" updated.", model_name, wg.get_object_name_by_id(id)));
|
session.flash_success(format!(
|
||||||
|
"{} \"{}\" updated.",
|
||||||
|
model_name,
|
||||||
|
wg.get_object_name_by_id(id)
|
||||||
|
));
|
||||||
Ok(HttpResponse::Ok().finish())
|
Ok(HttpResponse::Ok().finish())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ itertools = "0.10.0"
|
|||||||
#lazy_static = "1.4.0"
|
#lazy_static = "1.4.0"
|
||||||
bincode = "1.3.1"
|
bincode = "1.3.1"
|
||||||
atomic = "0.5.0"
|
atomic = "0.5.0"
|
||||||
|
rand = "0.8.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
+3
-5
@@ -40,18 +40,16 @@ impl<K, V> KVVecToKeysOrValues<K, V> for Vec<(K, V)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait IsNoneOrElse<T> : Sized {
|
pub(crate) trait IsNoneOrElse<T>: Sized {
|
||||||
//noinspection RsSelfConvention
|
//noinspection RsSelfConvention
|
||||||
fn is_none_or_else(&self, test : impl FnOnce(&T) -> bool) -> bool;
|
fn is_none_or_else(&self, test: impl FnOnce(&T) -> bool) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IsNoneOrElse<T> for Option<T> {
|
impl<T> IsNoneOrElse<T> for Option<T> {
|
||||||
fn is_none_or_else(&self, test: impl FnOnce(&T) -> bool) -> bool {
|
fn is_none_or_else(&self, test: impl FnOnce(&T) -> bool) -> bool {
|
||||||
match self {
|
match self {
|
||||||
None => true,
|
None => true,
|
||||||
Some(value) => {
|
Some(value) => test(value),
|
||||||
test(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
//! Data value structs
|
//! Data value structs
|
||||||
|
|
||||||
use std::borrow::{Cow, Borrow};
|
use std::borrow::{Borrow, Cow};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
//! Helper traits and stuff for working with lists and iterators of objects
|
||||||
|
|
||||||
|
// Re-export itertools for convenience
|
||||||
|
pub use itertools;
|
||||||
|
|
||||||
|
use crate::{data, insert, model, update, ID};
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub trait GetParent {
|
||||||
|
fn get_parent(&self) -> ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_get_parent {
|
||||||
|
($($struct:ty),+) => {
|
||||||
|
$(
|
||||||
|
impl GetParent for $struct {
|
||||||
|
fn get_parent(&self) -> ID { self.object }
|
||||||
|
}
|
||||||
|
impl GetParent for &$struct {
|
||||||
|
fn get_parent(&self) -> ID { self.object }
|
||||||
|
}
|
||||||
|
impl GetParent for &&$struct {
|
||||||
|
fn get_parent(&self) -> ID { self.object }
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_get_parent!(
|
||||||
|
data::Value, data::Relation,
|
||||||
|
model::RelationModel, model::PropertyModel);
|
||||||
|
|
||||||
|
pub trait GetModelID {
|
||||||
|
fn get_model_id(&self) -> ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_get_model_id {
|
||||||
|
($($struct:ty),+) => {
|
||||||
|
$(
|
||||||
|
impl GetModelID for $struct {
|
||||||
|
fn get_model_id(&self) -> ID { self.model }
|
||||||
|
}
|
||||||
|
impl GetModelID for &$struct {
|
||||||
|
fn get_model_id(&self) -> ID { self.model }
|
||||||
|
}
|
||||||
|
impl GetModelID for &&$struct {
|
||||||
|
fn get_model_id(&self) -> ID { self.model }
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_get_model_id!(
|
||||||
|
data::Object, data::Value, data::Relation,
|
||||||
|
insert::InsertRel, insert::InsertValue, insert::InsertObj,
|
||||||
|
update::UpsertRelation, update::UpsertValue);
|
||||||
|
|
||||||
|
// This would be nice, but doesn't work
|
||||||
|
|
||||||
|
//
|
||||||
|
// pub struct FilterOfParent<'a, S: 'a> { iter: S, parent: ID, marker : std::marker::PhantomData<&'a S> }
|
||||||
|
//
|
||||||
|
// // impl<'a, V: GetParent + 'a, S: Iterator<Item=&'a V>> Iterator for FilterOfParent<S> {
|
||||||
|
// // type Item = &'a V;
|
||||||
|
// //
|
||||||
|
// // #[inline]
|
||||||
|
// // fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
// // let parent = self.parent;
|
||||||
|
// // self.iter.find(|x| x.get_parent() == parent)
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// impl<'a, V: GetParent + 'a, S: Iterator<Item=V>> Iterator for FilterOfParent<'a, S> {
|
||||||
|
// type Item = V;
|
||||||
|
//
|
||||||
|
// #[inline]
|
||||||
|
// fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
// let parent = self.parent;
|
||||||
|
// self.iter.find(|x| x.get_parent() == parent)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub trait WhereParent<'a>: Sized {
|
||||||
|
// fn where_parent(self, id: ID) -> FilterOfParent<'a, Self>;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// impl<'a, V : 'a, S : 'a + Iterator<Item=V>> WhereParent<'a> for S {
|
||||||
|
// fn where_parent(self, id: ID) -> FilterOfParent<'a, Self> {
|
||||||
|
// FilterOfParent { iter: self, parent: id, marker: std::marker::PhantomData }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub trait GroupByParent<'a, T: 'a + GetParent>: Sized {
|
||||||
|
fn group_by_parent(self) -> HashMap<ID, Vec<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a + GetParent, S: IntoIterator<Item = T>> GroupByParent<'a, T> for S {
|
||||||
|
#[inline]
|
||||||
|
fn group_by_parent(self) -> HashMap<ID, Vec<T>> {
|
||||||
|
self.into_iter().into_group_map_by(|v| v.get_parent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GroupByModel<'a, T: 'a + GetModelID>: Sized {
|
||||||
|
fn group_by_model(self) -> HashMap<ID, Vec<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a + GetModelID, S: IntoIterator<Item = T>> GroupByModel<'a, T> for S {
|
||||||
|
#[inline]
|
||||||
|
fn group_by_model(self) -> HashMap<ID, Vec<T>> {
|
||||||
|
self.into_iter().into_group_map_by(|v| v.get_model_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::helpers::{GetParent, GroupByParent};
|
||||||
|
use crate::id::random_id;
|
||||||
|
use crate::ID;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct Child(ID, &'static str);
|
||||||
|
|
||||||
|
impl GetParent for Child {
|
||||||
|
fn get_parent(&self) -> ID {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn group_vec() {
|
||||||
|
let parent1 = random_id();
|
||||||
|
let parent2 = random_id();
|
||||||
|
|
||||||
|
let vec = vec![
|
||||||
|
Child(parent1, "A"),
|
||||||
|
Child(parent2, "C"),
|
||||||
|
Child(parent1, "B"),
|
||||||
|
Child(parent2, "D"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut grouped = vec.group_by_parent();
|
||||||
|
|
||||||
|
assert_eq!(2, grouped.len());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
grouped.remove(&parent1).unwrap(),
|
||||||
|
vec![Child(parent1, "A"), Child(parent1, "B"),]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
grouped.remove(&parent2).unwrap(),
|
||||||
|
vec![Child(parent2, "C"), Child(parent2, "D"),]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn group_iter() {
|
||||||
|
let parent1 = random_id();
|
||||||
|
let parent2 = random_id();
|
||||||
|
|
||||||
|
let vec = vec![
|
||||||
|
Child(parent1, "A"),
|
||||||
|
Child(parent2, "C"),
|
||||||
|
Child(parent1, "B"),
|
||||||
|
Child(parent2, "D"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut grouped = vec.into_iter().group_by_parent();
|
||||||
|
|
||||||
|
assert_eq!(2, grouped.len());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
grouped.remove(&parent1).unwrap(),
|
||||||
|
vec![Child(parent1, "A"), Child(parent1, "B"),]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
grouped.remove(&parent2).unwrap(),
|
||||||
|
vec![Child(parent2, "C"), Child(parent2, "D"),]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn count_where_parent() {
|
||||||
|
// let parent1 = random_id();
|
||||||
|
// let parent2 = random_id();
|
||||||
|
//
|
||||||
|
// let vec = vec![
|
||||||
|
// Child(parent1, "A"),
|
||||||
|
// Child(parent2, "C"),
|
||||||
|
// Child(parent1, "B"),
|
||||||
|
// Child(parent2, "D"),
|
||||||
|
// ];
|
||||||
|
//
|
||||||
|
// let _ = vec.iter().where_parent(parent2).next();
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -17,3 +17,16 @@ pub type ID = u32;
|
|||||||
pub trait HaveId {
|
pub trait HaveId {
|
||||||
fn get_id(&self) -> ID;
|
fn get_id(&self) -> ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "uuid-ids")]
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn random_id() -> ID {
|
||||||
|
ID::new_v4()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "uuid-ids"))]
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn random_id() -> ID {
|
||||||
|
use rand::Rng;
|
||||||
|
rand::thread_rng().gen()
|
||||||
|
}
|
||||||
|
|||||||
+1
-5
@@ -48,11 +48,7 @@ pub struct InsertObj {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InsertObj {
|
impl InsertObj {
|
||||||
pub fn new(
|
pub fn new(model_id: ID, values: Vec<InsertValue>, relations: Vec<InsertRel>) -> Self {
|
||||||
model_id: ID,
|
|
||||||
values: Vec<InsertValue>,
|
|
||||||
relations: Vec<InsertRel>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
model: model_id,
|
model: model_id,
|
||||||
values,
|
values,
|
||||||
|
|||||||
+42
-42
@@ -1,7 +1,8 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
// #[macro_use]
|
#[cfg(test)]
|
||||||
// extern crate serde_json;
|
#[macro_use]
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -21,10 +22,11 @@ use insert::InsertValue;
|
|||||||
pub use model::DataType;
|
pub use model::DataType;
|
||||||
use model::ObjectModel;
|
use model::ObjectModel;
|
||||||
|
|
||||||
|
use crate::cool::IsNoneOrElse;
|
||||||
|
use crate::data::Object;
|
||||||
|
use crate::helpers::{GroupByModel, GroupByParent};
|
||||||
use crate::model::{PropertyModel, RelationModel};
|
use crate::model::{PropertyModel, RelationModel};
|
||||||
use crate::update::{UpdateObj, UpsertValue};
|
use crate::update::{UpdateObj, UpsertValue};
|
||||||
use crate::cool::IsNoneOrElse;
|
|
||||||
use crate::data::{Object, Value};
|
|
||||||
|
|
||||||
mod cool;
|
mod cool;
|
||||||
pub mod data;
|
pub mod data;
|
||||||
@@ -33,6 +35,8 @@ pub mod insert;
|
|||||||
pub mod model;
|
pub mod model;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
|
|
||||||
|
pub mod helpers;
|
||||||
|
|
||||||
mod serde_atomic_id;
|
mod serde_atomic_id;
|
||||||
mod serde_map_as_list;
|
mod serde_map_as_list;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -40,8 +44,8 @@ mod tests;
|
|||||||
|
|
||||||
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
pub const YOPA_MAGIC : &[u8; 4] = b"YOPA";
|
pub const YOPA_MAGIC: &[u8; 4] = b"YOPA";
|
||||||
pub const BINARY_FORMAT : u8 = 1;
|
pub const BINARY_FORMAT: u8 = 1;
|
||||||
|
|
||||||
/// Stupid storage with naive inefficient file persistence
|
/// Stupid storage with naive inefficient file persistence
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
@@ -62,7 +66,7 @@ pub struct Storage {
|
|||||||
|
|
||||||
#[cfg(not(feature = "uuid-ids"))]
|
#[cfg(not(feature = "uuid-ids"))]
|
||||||
#[serde(with = "serde_atomic_id")]
|
#[serde(with = "serde_atomic_id")]
|
||||||
next_id : atomic::Atomic<ID>,
|
next_id: atomic::Atomic<ID>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
opts: StoreOpts,
|
opts: StoreOpts,
|
||||||
@@ -180,7 +184,7 @@ impl Storage {
|
|||||||
let parsed: Self = match self.opts.file_format {
|
let parsed: Self = match self.opts.file_format {
|
||||||
FileEncoding::JSON => serde_json::from_reader(reader)?,
|
FileEncoding::JSON => serde_json::from_reader(reader)?,
|
||||||
FileEncoding::BINCODE => {
|
FileEncoding::BINCODE => {
|
||||||
let mut magic : [u8; 5] = [0; 5];
|
let mut magic: [u8; 5] = [0; 5];
|
||||||
reader.read_exact(&mut magic)?;
|
reader.read_exact(&mut magic)?;
|
||||||
|
|
||||||
if &magic[0..4] != YOPA_MAGIC {
|
if &magic[0..4] != YOPA_MAGIC {
|
||||||
@@ -193,7 +197,7 @@ impl Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bincode::deserialize_from(reader)?
|
bincode::deserialize_from(reader)?
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let opts = std::mem::replace(&mut self.opts, StoreOpts::default());
|
let opts = std::mem::replace(&mut self.opts, StoreOpts::default());
|
||||||
@@ -231,7 +235,7 @@ impl Storage {
|
|||||||
writer.write_all(YOPA_MAGIC)?;
|
writer.write_all(YOPA_MAGIC)?;
|
||||||
writer.write_all(&[BINARY_FORMAT])?;
|
writer.write_all(&[BINARY_FORMAT])?;
|
||||||
bincode::serialize_into(writer, self)?
|
bincode::serialize_into(writer, self)?
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,7 +257,7 @@ impl Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get object name, or the ID as string if no name is configured
|
/// Get object name, or the ID as string if no name is configured
|
||||||
pub fn get_object_name_by_id<'a>(&'a self, id : ID) -> Cow<'a, str> {
|
pub fn get_object_name_by_id<'a>(&'a self, id: ID) -> Cow<'a, str> {
|
||||||
if let Some(o) = self.get_object(id) {
|
if let Some(o) = self.get_object(id) {
|
||||||
return self.get_object_name(o);
|
return self.get_object_name(o);
|
||||||
}
|
}
|
||||||
@@ -261,9 +265,17 @@ impl Storage {
|
|||||||
return id.to_string().into();
|
return id.to_string().into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_object_name<'b, 'a: 'b>(&'a self, object : &'a Object) -> Cow<'b, str> {
|
pub fn get_object_name<'b, 'a: 'b>(&'a self, object: &'a Object) -> Cow<'b, str> {
|
||||||
if let Some(ObjectModel{ name_property: Some(name_property), .. }) = self.get_object_model(object.model) {
|
if let Some(ObjectModel {
|
||||||
if let Some(v) = self.values.values().find(|v| v.object == object.id && &v.model == name_property) {
|
name_property: Some(name_property),
|
||||||
|
..
|
||||||
|
}) = self.get_object_model(object.model)
|
||||||
|
{
|
||||||
|
if let Some(v) = self
|
||||||
|
.values
|
||||||
|
.values()
|
||||||
|
.find(|v| v.object == object.id && &v.model == name_property)
|
||||||
|
{
|
||||||
return v.value.to_cow();
|
return v.value.to_cow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -293,7 +305,9 @@ impl Storage {
|
|||||||
|
|
||||||
/// Iterate object models with given IDs
|
/// Iterate object models with given IDs
|
||||||
pub fn get_object_models_by_ids(&self, ids: Vec<ID>) -> impl Iterator<Item = &ObjectModel> {
|
pub fn get_object_models_by_ids(&self, ids: Vec<ID>) -> impl Iterator<Item = &ObjectModel> {
|
||||||
self.obj_models.values().filter(move |m| ids.contains(&m.id))
|
self.obj_models
|
||||||
|
.values()
|
||||||
|
.filter(move |m| ids.contains(&m.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an object model by ID
|
/// Get an object model by ID
|
||||||
@@ -313,9 +327,7 @@ impl Storage {
|
|||||||
|
|
||||||
/// Get all property models grouped by the parent object ID.
|
/// Get all property models grouped by the parent object ID.
|
||||||
pub fn get_grouped_prop_models(&self) -> HashMap<ID, Vec<&PropertyModel>> {
|
pub fn get_grouped_prop_models(&self) -> HashMap<ID, Vec<&PropertyModel>> {
|
||||||
self.prop_models
|
self.prop_models.values().group_by_parent()
|
||||||
.values()
|
|
||||||
.into_group_map_by(|model| model.object)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get property models belonging to a group of parent IDs,
|
/// Get property models belonging to a group of parent IDs,
|
||||||
@@ -327,7 +339,7 @@ impl Storage {
|
|||||||
self.prop_models
|
self.prop_models
|
||||||
.values()
|
.values()
|
||||||
.filter(|p| parent_model_ids.contains(&p.object))
|
.filter(|p| parent_model_ids.contains(&p.object))
|
||||||
.into_group_map_by(|model| model.object)
|
.group_by_parent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate relation models attached to an object model
|
/// Iterate relation models attached to an object model
|
||||||
@@ -362,9 +374,7 @@ impl Storage {
|
|||||||
|
|
||||||
/// Get all relation models, grouped by their source object model ID
|
/// Get all relation models, grouped by their source object model ID
|
||||||
pub fn get_grouped_relation_models(&self) -> HashMap<ID, Vec<&RelationModel>> {
|
pub fn get_grouped_relation_models(&self) -> HashMap<ID, Vec<&RelationModel>> {
|
||||||
self.rel_models
|
self.rel_models.values().group_by_parent()
|
||||||
.values()
|
|
||||||
.into_group_map_by(|model| model.object)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get reciprocal relation models, grouped by their destination model ID
|
/// Get reciprocal relation models, grouped by their destination model ID
|
||||||
@@ -411,7 +421,7 @@ impl Storage {
|
|||||||
self.values
|
self.values
|
||||||
.values()
|
.values()
|
||||||
.filter(move |prop| parents.contains(&prop.object))
|
.filter(move |prop| parents.contains(&prop.object))
|
||||||
.into_group_map_by(|model| model.object)
|
.group_by_parent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all objects belonging to a model.
|
/// Get all objects belonging to a model.
|
||||||
@@ -432,9 +442,7 @@ impl Storage {
|
|||||||
|
|
||||||
/// Get all objects, grouped by their model ID
|
/// Get all objects, grouped by their model ID
|
||||||
pub fn get_grouped_objects(&self) -> HashMap<ID, Vec<&data::Object>> {
|
pub fn get_grouped_objects(&self) -> HashMap<ID, Vec<&data::Object>> {
|
||||||
self.objects
|
self.objects.values().group_by_model()
|
||||||
.values()
|
|
||||||
.into_group_map_by(|object| object.model)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get object by ID
|
/// Get object by ID
|
||||||
@@ -830,7 +838,7 @@ impl Storage {
|
|||||||
parent_id: ID,
|
parent_id: ID,
|
||||||
parent_model_id: ID|
|
parent_model_id: ID|
|
||||||
-> Result<Vec<data::Value>, StorageError> {
|
-> Result<Vec<data::Value>, StorageError> {
|
||||||
let mut values_by_id = values.into_iter().into_group_map_by(|iv| iv.model);
|
let mut values_by_id = values.group_by_model();
|
||||||
let mut values_to_insert = vec![];
|
let mut values_to_insert = vec![];
|
||||||
|
|
||||||
for (prop_model_id, prop) in self
|
for (prop_model_id, prop) in self
|
||||||
@@ -873,7 +881,7 @@ impl Storage {
|
|||||||
first.value,
|
first.value,
|
||||||
self.get_model_name(*prop_model_id),
|
self.get_model_name(*prop_model_id),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -908,10 +916,7 @@ impl Storage {
|
|||||||
let mut values_to_insert = find_values_to_insert(insobj.values, object_id, obj_model_id)?;
|
let mut values_to_insert = find_values_to_insert(insobj.values, object_id, obj_model_id)?;
|
||||||
|
|
||||||
// And now ..... relations!
|
// And now ..... relations!
|
||||||
let mut relations_by_id = insobj
|
let mut relations_by_id = insobj.relations.group_by_model();
|
||||||
.relations
|
|
||||||
.into_iter()
|
|
||||||
.into_group_map_by(|ir| ir.model);
|
|
||||||
let mut relations_to_insert = vec![];
|
let mut relations_to_insert = vec![];
|
||||||
|
|
||||||
for (relation_model_id, relation_model) in self
|
for (relation_model_id, relation_model) in self
|
||||||
@@ -1020,7 +1025,7 @@ impl Storage {
|
|||||||
),
|
),
|
||||||
StorageError,
|
StorageError,
|
||||||
> {
|
> {
|
||||||
let mut values_by_model = values.into_iter().into_group_map_by(|iv| iv.model);
|
let mut values_by_model = values.group_by_model();
|
||||||
let mut values_to_insert = vec![];
|
let mut values_to_insert = vec![];
|
||||||
let mut ids_to_delete = vec![];
|
let mut ids_to_delete = vec![];
|
||||||
|
|
||||||
@@ -1028,7 +1033,7 @@ impl Storage {
|
|||||||
.values
|
.values
|
||||||
.values()
|
.values()
|
||||||
.filter(|v| v.object == parent_id)
|
.filter(|v| v.object == parent_id)
|
||||||
.into_group_map_by(|v| v.model);
|
.group_by_model();
|
||||||
|
|
||||||
for (prop_model_id, prop) in self
|
for (prop_model_id, prop) in self
|
||||||
.prop_models
|
.prop_models
|
||||||
@@ -1071,7 +1076,7 @@ impl Storage {
|
|||||||
first.value,
|
first.value,
|
||||||
self.get_model_name(*prop_model_id),
|
self.get_model_name(*prop_model_id),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1113,10 +1118,7 @@ impl Storage {
|
|||||||
find_values_to_change(updobj.values, updated_object_id, updated_object_model_id)?;
|
find_values_to_change(updobj.values, updated_object_id, updated_object_model_id)?;
|
||||||
|
|
||||||
// And now ..... relations!
|
// And now ..... relations!
|
||||||
let mut relations_by_model = updobj
|
let mut relations_by_model = updobj.relations.group_by_model();
|
||||||
.relations
|
|
||||||
.into_iter()
|
|
||||||
.into_group_map_by(|ir| ir.model);
|
|
||||||
let mut relations_to_insert = vec![];
|
let mut relations_to_insert = vec![];
|
||||||
let mut relations_to_delete = vec![];
|
let mut relations_to_delete = vec![];
|
||||||
|
|
||||||
@@ -1124,7 +1126,7 @@ impl Storage {
|
|||||||
.relations
|
.relations
|
||||||
.values()
|
.values()
|
||||||
.filter(|v| v.object == updated_object_id)
|
.filter(|v| v.object == updated_object_id)
|
||||||
.into_group_map_by(|v| v.model);
|
.group_by_model();
|
||||||
|
|
||||||
let rel_models_by_id = self
|
let rel_models_by_id = self
|
||||||
.rel_models
|
.rel_models
|
||||||
@@ -1196,8 +1198,6 @@ impl Storage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let obj_mut = self.objects.get_mut(&updated_object_id).unwrap();
|
|
||||||
|
|
||||||
debug!("Add {} new object relations", relations_to_insert.len());
|
debug!("Add {} new object relations", relations_to_insert.len());
|
||||||
for rel in relations_to_insert {
|
for rel in relations_to_insert {
|
||||||
self.relations.insert(rel.id, rel);
|
self.relations.insert(rel.id, rel);
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
//! Serialize atomic ID by fetching its value
|
//! Serialize atomic ID by fetching its value
|
||||||
|
|
||||||
use crate::id::ID;
|
use crate::id::ID;
|
||||||
use serde::{Serialize, Deserializer, Deserialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
pub fn serialize<S>(x: &atomic::Atomic<ID>, s: S) -> Result<S::Ok, S::Error>
|
pub fn serialize<S>(x: &atomic::Atomic<ID>, s: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
x.load(atomic::Ordering::Relaxed)
|
x.load(atomic::Ordering::Relaxed).serialize(s)
|
||||||
.serialize(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<atomic::Atomic<ID>, D::Error>
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<atomic::Atomic<ID>, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let id : ID = ID::deserialize(deserializer)?;
|
let id: ID = ID::deserialize(deserializer)?;
|
||||||
Ok(atomic::Atomic::new(id))
|
Ok(atomic::Atomic::new(id))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ fn test1() {
|
|||||||
let model = crate::model::ObjectModel {
|
let model = crate::model::ObjectModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
name: "Name".to_string(),
|
name: "Name".to_string(),
|
||||||
|
name_property: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{}", serde_json::to_string_pretty(&model).unwrap());
|
println!("{}", serde_json::to_string_pretty(&model).unwrap());
|
||||||
|
|||||||
Reference in New Issue
Block a user