inline_postgres_impl/
untyped_key.rs

1use tokio_postgres::types::{FromSql, ToSql, self, to_sql_checked, IsNull};
2use ulid::Ulid;
3use bytes::{Buf, BufMut};
4
5/// A type that is suitable for keys in the database.
6/// 
7/// Internally it uses an [`Ulid`].
8/// It is randomly generated and contains 80 bits of entropy.
9/// The first 48 bits encode a timestamp such that the keys are ordered by time of insertion
10/// 
11/// Chance of collision is negligible - `4e-7` if a billion keys are generated in the same millisecond.
12#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct Key(pub(crate) Ulid);
14
15impl Key {
16    pub fn new() -> Self {
17        Self(Ulid::new())
18    }
19    pub(crate) fn accepts_impl(ty: &types::Type) -> bool {
20       matches!(ty, &types::Type::UUID)
21    }
22}
23
24impl FromSql<'_> for Key {
25    fn from_sql(_ty: &types::Type, mut raw: &[u8]) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> {
26        let mut bytes = [0u8; 16];
27        for b in bytes.iter_mut() {
28            *b = raw.get_u8();
29        }
30        Ok(Key(Ulid(u128::from_be_bytes(bytes))))
31    }
32
33    fn accepts(ty: &types::Type) -> bool {
34        Key::accepts_impl(ty)
35    }
36}
37
38impl ToSql for Key {
39    fn to_sql(&self, _ty: &types::Type, out: &mut types::private::BytesMut) -> Result<types::IsNull, Box<dyn std::error::Error + Sync + Send>>
40    where
41        Self: Sized {
42            let bytes = self.0.0.to_be_bytes();
43            for b in bytes.into_iter() {
44                out.put_u8(b);
45            }
46            Ok(IsNull::No)
47    }
48
49    fn accepts(ty: &types::Type) -> bool
50    where
51        Self: Sized {
52        Key::accepts_impl(ty)
53    }
54
55    to_sql_checked!();
56}