1use crate::resources::{IDUnknown, TSIDResource};
2use anyhow::anyhow;
3use std::{
4 fmt::{Debug, Display},
5 marker::PhantomData,
6 ops::Deref,
7};
8use tsid::{create_tsid, TSID};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
19#[cfg_attr(feature = "ts-rs", ts(type = "string", concrete(Resource = IDUnknown)))]
20#[cfg_attr(
21 feature = "diesel",
22 derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
23)]
24#[cfg_attr(feature = "diesel", diesel(sql_type = diesel::sql_types::BigInt))]
25pub struct TSIDDatabaseID<Resource: TSIDResource> {
26 pub(crate) id: TSID,
27 resource: PhantomData<Resource>,
28}
29
30impl<Resource: TSIDResource> TSIDDatabaseID<Resource> {
31 pub fn from_raw_number(number: u64) -> Self {
34 Self {
35 id: TSID::from(number),
36 resource: PhantomData,
37 }
38 }
39
40 pub fn from_integer(number: i64) -> Self {
41 Self {
42 id: TSID::from(number as u64),
43 resource: PhantomData,
44 }
45 }
46
47 pub fn random() -> Self {
49 Self {
50 id: create_tsid(),
51 resource: PhantomData,
52 }
53 }
54
55 pub fn to_raw_number(&self) -> u64 {
58 self.id.number()
59 }
60
61 pub fn into_unknown(&self) -> TSIDDatabaseID<IDUnknown> {
62 TSIDDatabaseID::<IDUnknown> {
63 id: self.id,
64 resource: PhantomData,
65 }
66 }
67
68 pub fn from_str(v: &str) -> Result<TSIDDatabaseID<Resource>, anyhow::Error> {
75 let tsid_only = if let Some(prefix) = Resource::prefix() {
76 v.strip_prefix(&format!("{}_", prefix))
77 .ok_or(anyhow!("missing prefix {}_", prefix))?
78 } else {
79 v
80 };
81
82 let tsid = TSID::try_from(tsid_only).map_err(|_| anyhow!("invalid tsid"))?;
83 Ok(TSIDDatabaseID::<Resource>::from(tsid))
84 }
85}
86
87impl<Resource: TSIDResource> Display for TSIDDatabaseID<Resource> {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 if let Some(prefix) = Resource::prefix() {
90 write!(f, "{}_{}", prefix, self.id.to_string())
91 } else {
92 write!(f, "{}", self.id.to_string())
93 }
94 }
95}
96
97impl<Resource: TSIDResource> Deref for TSIDDatabaseID<Resource> {
98 type Target = TSID;
99 fn deref(&self) -> &Self::Target {
100 &self.id
101 }
102}
103
104impl<Resource: TSIDResource> From<TSID> for TSIDDatabaseID<Resource> {
105 fn from(value: TSID) -> Self {
106 Self {
107 id: value,
108 resource: PhantomData,
109 }
110 }
111}