Add diesel feature

This can simplify Lemmy code and avoid converting back and forth
to DbUrl type all the time.
This commit is contained in:
Felix Ableitner 2023-11-30 12:34:44 +01:00
parent 69b80aa6e1
commit ca42d891b1
2 changed files with 105 additions and 13 deletions

View file

@ -8,6 +8,12 @@ license = "AGPL-3.0"
repository = "https://github.com/LemmyNet/activitypub-federation-rust"
documentation = "https://docs.rs/activitypub_federation/"
[features]
default = ["actix-web", "axum"]
actix-web = ["dep:actix-web"]
axum = ["dep:axum", "dep:tower", "dep:hyper"]
diesel = ["dep:diesel"]
[dependencies]
chrono = { version = "0.4.31", features = ["clock"], default-features = false }
serde = { version = "1.0.189", features = ["derive"] }
@ -44,6 +50,7 @@ tokio = { version = "1.33.0", features = [
"rt-multi-thread",
"time",
] }
diesel = { version = "2.1.4", features = ["postgres"], default-features = false, optional = true }
# Actix-web
actix-web = { version = "4.4.0", default-features = false, optional = true }
@ -58,11 +65,6 @@ hyper = { version = "0.14", optional = true }
futures = "0.3.28"
moka = { version = "0.11.3", features = ["future"] }
[features]
default = ["actix-web", "axum"]
actix-web = ["dep:actix-web"]
axum = ["dep:axum", "dep:tower", "dep:hyper"]
[dev-dependencies]
anyhow = "1.0.75"
rand = "0.8.5"

View file

@ -57,12 +57,12 @@ where
pub struct ObjectId<Kind>(Box<Url>, PhantomData<Kind>)
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>;
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>;
impl<Kind> ObjectId<Kind>
where
Kind: Object + Send + Debug + 'static,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
/// Construct a new objectid instance
pub fn parse(url: &str) -> Result<Self, url::ParseError> {
@ -163,7 +163,7 @@ where
impl<Kind> Clone for ObjectId<Kind>
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
fn clone(&self) -> Self {
ObjectId(self.0.clone(), self.1)
@ -190,7 +190,7 @@ fn should_refetch_object(last_refreshed: DateTime<Utc>) -> bool {
impl<Kind> Display for ObjectId<Kind>
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.as_str())
@ -200,7 +200,7 @@ where
impl<Kind> Debug for ObjectId<Kind>
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.as_str())
@ -210,7 +210,7 @@ where
impl<Kind> From<ObjectId<Kind>> for Url
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
fn from(id: ObjectId<Kind>) -> Self {
*id.0
@ -220,7 +220,7 @@ where
impl<Kind> From<Url> for ObjectId<Kind>
where
Kind: Object + Send + 'static,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
fn from(url: Url) -> Self {
ObjectId(Box::new(url), PhantomData::<Kind>)
@ -230,13 +230,103 @@ where
impl<Kind> PartialEq for ObjectId<Kind>
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0) && self.1 == other.1
}
}
//#[cfg(feature = "diesel")]
const _IMPL_DIESEL_NEW_TYPE_FOR_OBJECT_ID: () = {
use diesel::{
backend::Backend,
deserialize::{FromSql, FromStaticSqlRow},
expression::AsExpression,
internal::derives::as_expression::Bound,
pg::Pg,
query_builder::QueryId,
serialize,
serialize::{Output, ToSql},
sql_types::{HasSqlType, SingleValue, Text},
Expression,
Queryable,
};
// TODO: this impl only works for Postgres db because of to_string() call which requires reborrow
impl<Kind, ST> ToSql<ST, Pg> for ObjectId<Kind>
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
String: ToSql<ST, Pg>,
{
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
let v = self.0.to_string();
<String as ToSql<Text, Pg>>::to_sql(&v, &mut out.reborrow())
}
}
impl<'expr, Kind, ST> AsExpression<ST> for &'expr ObjectId<Kind>
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
Bound<ST, String>: Expression<SqlType = ST>,
ST: SingleValue,
{
type Expression = Bound<ST, &'expr str>;
fn as_expression(self) -> Self::Expression {
Bound::new(self.0.as_str())
}
}
impl<Kind, ST> AsExpression<ST> for ObjectId<Kind>
where
Kind: Object,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
Bound<ST, String>: Expression<SqlType = ST>,
ST: SingleValue,
{
type Expression = Bound<ST, String>;
fn as_expression(self) -> Self::Expression {
// TODO: deprecated in favor of `.into()` but that fails to compile
Bound::new(self.0.into_string())
}
}
impl<Kind, ST, DB> FromSql<ST, DB> for ObjectId<Kind>
where
Kind: Object + Send + 'static,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
String: FromSql<ST, DB>,
DB: Backend,
DB: HasSqlType<ST>,
{
fn from_sql(
raw: DB::RawValue<'_>,
) -> Result<Self, Box<dyn ::std::error::Error + Send + Sync>> {
let string: String = FromSql::<ST, DB>::from_sql(raw)?;
Ok(ObjectId::parse(&string)?)
}
}
impl<Kind, ST, DB> Queryable<ST, DB> for ObjectId<Kind>
where
Kind: Object + Send + 'static,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
String: FromStaticSqlRow<ST, DB>,
DB: Backend,
DB: HasSqlType<ST>,
{
type Row = String;
fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
Ok(ObjectId::parse(&row)?)
}
}
impl<Kind> QueryId for ObjectId<Kind>
where
Kind: Object + 'static,
for<'de2> <Kind as Object>::Kind: Deserialize<'de2>,
{
type QueryId = Self;
}
};
#[cfg(test)]
pub mod tests {
use super::*;