implement Serialize/Deserialize for Entry, Address, remove as_json

+ cosmetics (to_str -> to_string)
feat/vaults
Tomáš Mládek 2021-02-19 21:45:33 +01:00
parent 99f6c6c052
commit dc71bec67a
4 changed files with 62 additions and 52 deletions

View File

@ -1,14 +1,15 @@
use crate::hash::{decode, encode, Hash};
use anyhow::{anyhow, Result};
use serde::de::Visitor;
use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
use std::convert::TryInto;
use std::fmt;
use std::io::prelude::*;
use std::io::Cursor;
use anyhow::{anyhow, Result};
use unsigned_varint::encode;
use uuid::Uuid;
use crate::hash::{encode, Hash};
use std::str::FromStr;
use thiserror::private::DisplayAsDisplay;
use unsigned_varint::encode;
use uuid::Uuid;
#[derive(Clone, PartialEq)]
pub enum Address {
@ -57,6 +58,42 @@ impl Address {
}
}
impl Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
{
serializer.serialize_str(encode(self.encode().map_err(ser::Error::custom)?).as_str())
}
}
struct AddressVisitor;
impl<'de> Visitor<'de> for AddressVisitor {
type Value = Address;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid UpEnd address (hash/UUID) as a multi-hashed string")
}
fn visit_str<E>(self, str: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let bytes = decode(str).map_err(de::Error::custom)?;
Ok(Address::decode(bytes.as_ref()).map_err(de::Error::custom)?)
}
}
impl<'de> Deserialize<'de> for Address {
fn deserialize<D>(deserializer: D) -> Result<Address, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(AddressVisitor)
}
}
impl FromStr for Address {
type Err = anyhow::Error;

View File

@ -14,6 +14,7 @@ use lexpr::value::Value::Symbol;
use lexpr::Value::Cons;
use log::{debug, trace};
use nonempty::NonEmpty;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::borrow::Borrow;
use std::convert::TryFrom;
@ -23,34 +24,20 @@ use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Duration;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entry {
pub target: Address,
pub key: String,
pub value: EntryValue,
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum EntryValue {
Value(serde_json::Value),
Address(Address),
Invalid,
}
impl Entry {
pub fn as_json(&self) -> serde_json::Value {
json!({
"target": self.target.to_string(),
"key": self.key,
"value": match &self.value {
EntryValue::Value(value) => ("VALUE", value.clone()),
EntryValue::Address(address) => ("ADDR", json!(address.to_string())),
EntryValue::Invalid => ("INVALID", json!("INVALID")),
}
})
}
}
impl TryFrom<models::Entry> for Entry {
type Error = anyhow::Error;
@ -74,13 +61,13 @@ impl Hashable for Entry {
let mut result = Cursor::new(vec![0u8; 0]);
result.write_all(self.target.encode()?.as_slice())?;
result.write_all(self.key.as_bytes())?;
result.write_all(self.value.to_str()?.as_bytes())?;
result.write_all(self.value.to_string()?.as_bytes())?;
Ok(hash(result.get_ref()))
}
}
impl EntryValue {
pub fn to_str(&self) -> Result<String> {
pub fn to_string(&self) -> Result<String> {
let (type_char, content) = match self {
EntryValue::Value(value) => ('J', serde_json::to_string(value)?),
EntryValue::Address(address) => ('O', address.to_string()),
@ -193,7 +180,7 @@ pub fn retrieve_object<C: Connection<Backend = Sqlite>>(
let matches = data
.filter(target.eq(object_address.encode()?))
.or_filter(value.eq(EntryValue::Address(object_address).to_str()?))
.or_filter(value.eq(EntryValue::Address(object_address).to_string()?))
.load::<models::Entry>(connection)?;
let entries = matches
.into_iter()
@ -239,7 +226,7 @@ pub fn remove_object<C: Connection<Backend = Sqlite>>(
let matches = data
.filter(target.eq(object_address.encode()?))
.or_filter(value.eq(EntryValue::Address(object_address).to_str()?));
.or_filter(value.eq(EntryValue::Address(object_address).to_string()?));
Ok(diesel::delete(matches).execute(connection)?)
}
@ -499,11 +486,11 @@ fn query_to_sqlite(query: &Query) -> Result<Box<Predicate>> {
match &eq.value {
QueryComponent::Exact(q_value) => {
subqueries.push(Box::new(data::value.eq(q_value.to_str()?)))
subqueries.push(Box::new(data::value.eq(q_value.to_string()?)))
}
QueryComponent::In(q_values) => {
let values: Result<Vec<_>, _> =
q_values.iter().map(|v| v.to_str()).collect();
q_values.iter().map(|v| v.to_string()).collect();
subqueries.push(Box::new(data::value.eq_any(values?)))
}
QueryComponent::Contains(q_value) => {
@ -583,9 +570,9 @@ pub fn query_entries<C: Connection<Backend = Sqlite>>(
};
query = match entry_query.value {
QueryComponent::Exact(q_value) => query.filter(value.eq(q_value.to_str()?)),
QueryComponent::Exact(q_value) => query.filter(value.eq(q_value.to_string()?)),
QueryComponent::In(q_values) => {
let values: Result<Vec<_>, _> = q_values.into_iter().map(|v| v.to_str()).collect();
let values: Result<Vec<_>, _> = q_values.into_iter().map(|v| v.to_string()).collect();
query.filter(value.eq_any(values?))
}
QueryComponent::Contains(q_value_string) => {
@ -617,7 +604,7 @@ pub fn insert_entry<C: Connection<Backend = Sqlite>>(
identity: entry.hash()?.0,
target: entry.target.encode()?,
key: entry.key,
value: entry.value.to_str()?,
value: entry.value.to_string()?,
};
Ok(diesel::insert_into(data::table)

View File

@ -1,10 +1,11 @@
use actix::prelude::*;
use anyhow::{anyhow, Result};
use filebuffer::FileBuffer;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tiny_keccak::{Hasher, KangarooTwelve};
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Hash(pub Vec<u8>);
impl AsRef<[u8]> for Hash {

View File

@ -53,11 +53,11 @@ pub async fn get_object(
debug!("{:?}", response);
let mut result: HashMap<String, serde_json::Value> = HashMap::new();
let mut result: HashMap<String, Entry> = HashMap::new();
for entry in response.map_err(error::ErrorInternalServerError)? {
result.insert(
encode(entry.hash().map_err(ErrorInternalServerError)?),
entry.as_json(),
entry,
);
}
Ok(HttpResponse::Ok().json(result))
@ -90,12 +90,7 @@ pub async fn list_hier(
.await
.map_err(ErrorNotFound)?; // todo: 500 if actual error occurs
Ok(HttpResponse::Ok().json(
entries
.iter()
.map(Entry::as_json)
.collect::<serde_json::Value>(),
))
Ok(HttpResponse::Ok().json(entries))
}
#[derive(Deserialize)]
@ -111,12 +106,7 @@ pub async fn get_lookup(
let connection = state.db_pool.get().map_err(ErrorInternalServerError)?;
let response = lookup_by_filename(&connection, info.query).map_err(ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(
response
.iter()
.map(Entry::as_json)
.collect::<serde_json::Value>(),
))
Ok(HttpResponse::Ok().json(response))
}
#[derive(Deserialize)]
@ -135,12 +125,7 @@ pub async fn get_query(
let in_query = Query::from_sexp(&sexp).map_err(ErrorInternalServerError)?;
let result = query(&connection, in_query).map_err(ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(
result
.iter()
.map(Entry::as_json)
.collect::<serde_json::Value>(),
))
Ok(HttpResponse::Ok().json(result))
}
#[post("/api/refresh")]