Add json_from_sql and json_to_sql macros

This commit is contained in:
silverpill 2022-04-21 22:37:08 +00:00
parent 536c7ecb21
commit a9504de10d
6 changed files with 51 additions and 38 deletions

View file

@ -184,7 +184,7 @@ pub fn get_local_actor(
None => None, None => None,
}; };
let properties = user.profile.extra_fields.clone() let properties = user.profile.extra_fields.clone()
.unpack().into_iter() .into_inner().into_iter()
.map(|field| { .map(|field| {
ActorProperty { ActorProperty {
object_type: PROPERTY_VALUE.to_string(), object_type: PROPERTY_VALUE.to_string(),

View file

@ -19,7 +19,8 @@ macro_rules! int_enum_to_sql {
($t:ty) => { ($t:ty) => {
impl postgres_types::ToSql for $t { impl postgres_types::ToSql for $t {
fn to_sql( fn to_sql(
&self, _: &postgres_types::Type, &self,
_: &postgres_types::Type,
out: &mut postgres_types::private::BytesMut, out: &mut postgres_types::private::BytesMut,
) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> { ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
let int_value: i16 = self.into(); let int_value: i16 = self.into();

View file

@ -0,0 +1,39 @@
/// Implements FromSql trait for any de-serializable type
macro_rules! json_from_sql {
($t:ty) => {
impl<'a> postgres_types::FromSql<'a> for $t {
fn from_sql(
ty: &postgres_types::Type,
raw: &'a [u8],
) -> Result<$t, Box<dyn std::error::Error + Sync + Send>> {
let postgres_types::Json(json_value) =
postgres_types::Json::<serde_json::Value>::from_sql(ty, raw)?;
let value: $t = serde_json::from_value(json_value)?;
Ok(value)
}
postgres_types::accepts!(JSON, JSONB);
}
}
}
/// Implements ToSql trait for any serializable type
macro_rules! json_to_sql {
($t:ty) => {
impl postgres_types::ToSql for $t {
fn to_sql(
&self,
ty: &postgres_types::Type,
out: &mut postgres_types::private::BytesMut,
) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
let value = serde_json::to_value(self)?;
postgres_types::Json(value).to_sql(ty, out)
}
postgres_types::accepts!(JSON, JSONB);
postgres_types::to_sql_checked!();
}
}
}
pub(crate) use {json_from_sql, json_to_sql};

View file

@ -3,6 +3,7 @@ use tokio_postgres::error::{Error as PgError, SqlState};
use crate::errors::DatabaseError; use crate::errors::DatabaseError;
pub mod int_enum; pub mod int_enum;
pub mod json_macro;
pub mod migrate; pub mod migrate;
pub mod query_macro; pub mod query_macro;

View file

@ -59,7 +59,7 @@ impl Account {
.map(|name| get_file_url(instance_url, name)); .map(|name| get_file_url(instance_url, name));
let header_url = profile.banner_file_name.as_ref() let header_url = profile.banner_file_name.as_ref()
.map(|name| get_file_url(instance_url, name)); .map(|name| get_file_url(instance_url, name));
let fields = profile.extra_fields.unpack().into_iter() let fields = profile.extra_fields.into_inner().into_iter()
.map(|field| AccountField { name: field.name, value: field.value }) .map(|field| AccountField { name: field.name, value: field.value })
.collect(); .collect();
Self { Self {
@ -83,7 +83,7 @@ impl Account {
pub fn from_user(user: User, instance_url: &str) -> Self { pub fn from_user(user: User, instance_url: &str) -> Self {
let fields_sources = user.profile.extra_fields.clone() let fields_sources = user.profile.extra_fields.clone()
.unpack().into_iter() .into_inner().into_iter()
.map(|field| AccountField { .map(|field| AccountField {
name: field.name, name: field.name,
value: field.value_source.unwrap_or(field.value), value: field.value_source.unwrap_or(field.value),

View file

@ -1,15 +1,12 @@
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use postgres_types::{ use postgres_types::FromSql;
FromSql, ToSql, IsNull, Type, Json,
accepts, to_sql_checked,
private::BytesMut,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use uuid::Uuid; use uuid::Uuid;
use crate::activitypub::actor::Actor; use crate::activitypub::actor::Actor;
use crate::activitypub::views::get_actor_url; use crate::activitypub::views::get_actor_url;
use crate::database::json_macro::{json_from_sql, json_to_sql};
use crate::errors::ValidationError; use crate::errors::ValidationError;
use super::validators::{ use super::validators::{
validate_username, validate_username,
@ -29,7 +26,7 @@ pub struct ExtraField {
pub struct ExtraFields(pub Vec<ExtraField>); pub struct ExtraFields(pub Vec<ExtraField>);
impl ExtraFields { impl ExtraFields {
pub fn unpack(self) -> Vec<ExtraField> { pub fn into_inner(self) -> Vec<ExtraField> {
let Self(extra_fields) = self; let Self(extra_fields) = self;
extra_fields extra_fields
} }
@ -39,35 +36,10 @@ pub fn get_currency_field_name(currency_code: &str) -> String {
format!("${}", currency_code.to_uppercase()) format!("${}", currency_code.to_uppercase())
} }
type SqlError = Box<dyn std::error::Error + Sync + Send>; json_from_sql!(ExtraFields);
json_to_sql!(ExtraFields);
impl<'a> FromSql<'a> for ExtraFields { json_from_sql!(Actor);
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, SqlError> {
let Json(json_value) = Json::<Value>::from_sql(ty, raw)?;
let fields: Self = serde_json::from_value(json_value)?;
Ok(fields)
}
accepts!(JSON, JSONB);
}
impl ToSql for ExtraFields {
fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, SqlError> {
let value = serde_json::to_value(self)?;
Json(value).to_sql(ty, out)
}
accepts!(JSON, JSONB);
to_sql_checked!();
}
impl<'a> FromSql<'a> for Actor {
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, SqlError> {
let Json(json_value) = Json::<Value>::from_sql(ty, raw)?;
let actor: Self = serde_json::from_value(json_value)?;
Ok(actor)
}
accepts!(JSON, JSONB);
}
#[derive(Clone, FromSql)] #[derive(Clone, FromSql)]
#[postgres(name = "actor_profile")] #[postgres(name = "actor_profile")]