1use ulid::Ulid;
2
3macro_rules! impl_id {
4 ($type:ident) => {
5 #[derive(
6 Clone,
7 Copy,
8 Eq,
9 Hash,
10 Ord,
11 PartialEq,
12 PartialOrd,
13 educe::Educe,
14 serde::Deserialize,
15 serde::Serialize,
16 )]
17 #[educe(Debug)]
18 pub struct $type(#[educe(Debug(method(std::fmt::Display::fmt)))] pub Ulid);
19
20 #[allow(dead_code)]
21 impl $type {
22 pub fn now() -> Self {
23 Self(Ulid::new())
24 }
25
26 #[cfg(feature = "uuid")]
27 pub fn to_uuid(self) -> uuid::Uuid {
28 uuid::Uuid::from_bytes(self.0.to_bytes())
29 }
30
31 #[cfg(feature = "uuid")]
32 pub fn from_uuid(id: uuid::Uuid) -> Self {
33 Self(Ulid::from_bytes(*id.as_bytes()))
34 }
35
36 #[cfg(feature = "indexed-db")]
37 pub fn to_js_string(&self) -> web_sys::js_sys::JsString {
38 web_sys::js_sys::JsString::from(format!("{}", self.0))
39 }
40
41 pub fn from_u128(v: u128) -> Self {
42 Self(Ulid::from_bytes(v.to_be_bytes()))
43 }
44
45 pub fn as_u128(&self) -> u128 {
46 u128::from_be_bytes(self.0.to_bytes())
47 }
48 }
49
50 #[cfg(feature = "sqlx-postgres")]
51 impl<'q> sqlx::encode::Encode<'q, sqlx::Postgres> for $type {
52 fn encode_by_ref(&self, buf: &mut sqlx::postgres::PgArgumentBuffer) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Sync + Send>> {
53 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Postgres>>::encode_by_ref(&self.to_uuid(), buf)
54 }
55 fn encode(self, buf: &mut sqlx::postgres::PgArgumentBuffer) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Sync + Send>> {
56 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Postgres>>::encode(self.to_uuid(), buf)
57 }
58 fn produces(&self) -> Option<sqlx::postgres::PgTypeInfo> {
59 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Postgres>>::produces(&self.to_uuid())
60 }
61 fn size_hint(&self) -> usize {
62 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Postgres>>::size_hint(&self.to_uuid())
63 }
64 }
65
66 #[cfg(feature = "sqlx-postgres")]
67 impl sqlx::Type<sqlx::Postgres> for $type {
68 fn type_info() -> sqlx::postgres::PgTypeInfo {
69 <uuid::Uuid as sqlx::Type<sqlx::Postgres>>::type_info()
70 }
71 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
72 <uuid::Uuid as sqlx::Type<sqlx::Postgres>>::compatible(ty)
73 }
74 }
75
76 #[cfg(feature = "sqlx-postgres")]
77 impl sqlx::postgres::PgHasArrayType for $type {
78 fn array_type_info() -> sqlx::postgres::PgTypeInfo {
79 <uuid::Uuid as sqlx::postgres::PgHasArrayType>::array_type_info()
80 }
81 fn array_compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
82 <uuid::Uuid as sqlx::postgres::PgHasArrayType>::array_compatible(ty)
83 }
84 }
85
86 #[cfg(feature = "sqlx-sqlite")]
87 impl<'q> sqlx::encode::Encode<'q, sqlx::Sqlite> for $type {
88 fn encode_by_ref(&self, buf: &mut Vec<sqlx::sqlite::SqliteArgumentValue<'q>>) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Sync + Send>> {
89 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Sqlite>>::encode_by_ref(&self.to_uuid(), buf)
90 }
91 fn encode(self, buf: &mut Vec<sqlx::sqlite::SqliteArgumentValue<'q>>) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Sync + Send>> {
92 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Sqlite>>::encode(self.to_uuid(), buf)
93 }
94 fn produces(&self) -> Option<sqlx::sqlite::SqliteTypeInfo> {
95 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Sqlite>>::produces(&self.to_uuid())
96 }
97 fn size_hint(&self) -> usize {
98 <uuid::Uuid as sqlx::encode::Encode<'q, sqlx::Sqlite>>::size_hint(&self.to_uuid())
99 }
100 }
101
102 #[cfg(feature = "sqlx-sqlite")]
103 impl sqlx::Type<sqlx::Sqlite> for $type {
104 fn type_info() -> sqlx::sqlite::SqliteTypeInfo {
105 <uuid::Uuid as sqlx::Type<sqlx::Sqlite>>::type_info()
106 }
107 fn compatible(ty: &sqlx::sqlite::SqliteTypeInfo) -> bool {
108 <uuid::Uuid as sqlx::Type<sqlx::Sqlite>>::compatible(ty)
109 }
110 }
111
112 #[cfg(feature = "arbitrary")]
113 impl<'a> arbitrary::Arbitrary<'a> for $type {
114 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
115 Ok(Self(Ulid::from_bytes(u.arbitrary()?)))
116 }
117 }
118
119 deepsize::known_deep_size!(0; $type); };
121}
122
123impl_id!(ObjectId);
124impl_id!(EventId);
125impl_id!(TypeId);
126impl_id!(BinPtr);
127impl_id!(QueryId);
128impl_id!(User);
129impl_id!(SessionRef);
130impl_id!(SessionToken);
131impl_id!(Updatedness);
132
133impl SessionToken {
134 #[cfg(feature = "server")]
135 pub fn new() -> SessionToken {
136 use rand::Rng;
137 SessionToken(ulid::Ulid::from_bytes(rand::rng().random()))
138 }
139}
140
141#[cfg(feature = "server")]
142impl Default for SessionToken {
143 fn default() -> SessionToken {
144 SessionToken::new()
145 }
146}