use sqlx::{ColumnIndex, Decode, FromRow, Row, Type};
use std::ops::{Deref, DerefMut};
pub struct WithId<E> {
inner: E,
id: i64,
}
impl<E> WithId<E> {
pub fn new(inner: E, id: i64) -> Self {
WithId { inner, id }
}
pub fn into_inner(self) -> E {
self.inner
}
pub fn inner(&self) -> &E {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut E {
&mut self.inner
}
pub fn id(&self) -> i64 {
self.id
}
}
impl<E> Deref for WithId<E> {
type Target = E;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<E> DerefMut for WithId<E> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<'a, R: Row, E> FromRow<'a, R> for WithId<E>
where
R: Row,
E: FromRow<'a, R>,
&'a str: ColumnIndex<R>,
i64: Decode<'a, R::Database>,
i64: Type<R::Database>,
{
fn from_row(row: &'a R) -> ::sqlx::Result<Self> {
let inner = E::from_row(row)?;
let id = row.try_get("id")?;
Ok(Self { inner, id })
}
}
impl<E: Clone> Clone for WithId<E> {
fn clone(&self) -> Self {
Self {
id: self.id,
inner: self.inner.clone(),
}
}
}
impl<E: PartialEq> PartialEq for WithId<E> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.inner == other.inner
}
}
impl<E: Eq> Eq for WithId<E> {}
impl<E: std::fmt::Debug> std::fmt::Debug for WithId<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WithId").field("id", &self.id).field("inner", &self.inner).finish()
}
}
#[cfg(feature = "serde")]
mod with_serde {
use super::WithId;
use serde::{
de::{self, MapAccess, SeqAccess, Visitor},
Deserialize,
};
use std::marker::PhantomData;
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
pub(crate) enum WithIdFields {
Inner,
Id,
}
pub(crate) struct WithIdVisitor<E> {
inner: PhantomData<E>,
}
impl<E> WithIdVisitor<E> {
pub(crate) fn new() -> Self {
WithIdVisitor { inner: PhantomData }
}
}
impl<'de, E: Deserialize<'de>> Visitor<'de> for WithIdVisitor<E> {
type Value = WithId<E>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("struct WithId")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let id = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let inner = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
Ok(Self::Value::new(inner, id))
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut inner = None;
let mut id = None;
while let Some(key) = map.next_key()? {
match key {
WithIdFields::Inner => {
if inner.is_some() {
return Err(de::Error::duplicate_field("inner"));
}
inner = Some(map.next_value()?);
}
WithIdFields::Id => {
if id.is_some() {
return Err(de::Error::duplicate_field("nanos"));
}
id = Some(map.next_value()?);
}
}
}
let inner = inner.ok_or_else(|| de::Error::missing_field("inner"))?;
let id = id.ok_or_else(|| de::Error::missing_field("id"))?;
Ok(Self::Value::new(inner, id))
}
}
}
#[cfg(feature = "serde")]
impl<E: serde::Serialize> serde::Serialize for WithId<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::ser::Serializer,
{
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("WithId", 2)?;
s.serialize_field("id", &self.id)?;
s.serialize_field("inner", &self.inner)?;
s.end()
}
}
#[cfg(feature = "serde")]
impl<'de, E: serde::Deserialize<'de>> serde::Deserialize<'de> for WithId<E> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &["inner", "id"];
deserializer.deserialize_struct("WithId", FIELDS, with_serde::WithIdVisitor::<E>::new())
}
}
#[cfg(test)]
mod test {
use crate::WithId;
#[test]
fn is_clone_if_inner_is_clone() {
#[derive(Clone)]
struct Foo;
let foo = WithId::new(Foo, 10);
let _ = foo.clone();
}
#[test]
fn is_eq_if_inner_is_eq_and_debug_if_inner_is_debug() {
#[derive(Eq, PartialEq, Debug)]
struct Foo(u8);
let left = WithId::new(Foo(1), 10);
let right = WithId::new(Foo(1), 10);
assert_eq!(left, right);
let right = WithId::new(Foo(1), 11);
assert_ne!(left, right);
let right = WithId::new(Foo(2), 10);
assert_ne!(left, right);
}
#[cfg(feature = "serde")]
mod serde {
use crate::WithId;
use serde::{Deserialize, Serialize};
#[test]
fn is_serialize_if_inner_is_serialize() {
#[derive(Serialize)]
struct Foo {
x: u32,
}
let with_id = WithId::new(Foo { x: 420 }, 69);
assert_eq!(serde_json::to_string(&with_id).unwrap(), r#"{"id":69,"inner":{"x":420}}"#);
}
#[test]
fn is_deserialize_if_inner_is_deserialize() {
#[derive(Deserialize)]
struct Foo(u32);
let with_id: WithId<Foo> = serde_json::from_str(r#"{"id":69,"inner":420}"#).unwrap();
assert_eq!(with_id.inner.0, 420);
assert_eq!(with_id.id, 69);
}
}
}