1use std::any::type_name;
16use std::num::TryFromIntError;
17
18use parse_display::Display;
19use sea_orm::sea_query::{ArrayType, ValueTypeErr};
20use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryGetError};
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22use thiserror_ext::AsReport;
23use tracing::warn;
24
25#[derive(Clone, Copy, Debug, Display, Default, Hash, PartialOrd, PartialEq, Eq, Ord)]
26#[display("{inner}")]
27pub struct TypedId<const N: usize> {
28    pub(crate) inner: u32,
29}
30
31impl<const N: usize> TypedId<N> {
32    pub const fn new(inner: u32) -> Self {
33        TypedId { inner }
34    }
35
36    pub fn as_raw_id(&self) -> u32 {
37        self.inner
38    }
39
40    fn from_i32(inner: i32) -> Self {
41        Self {
42            inner: inner.try_into().unwrap_or_else(|e: TryFromIntError| {
43                if cfg!(debug_assertions) {
44                    panic!(
45                        "invalid i32 id {} for {}: {:?}",
46                        inner,
47                        type_name::<Self>(),
48                        e.as_report()
49                    );
50                } else {
51                    warn!(
52                        "invalid i32 id {} for {}: {:?}",
53                        inner,
54                        type_name::<Self>(),
55                        e.as_report()
56                    );
57                    inner as _
58                }
59            }),
60        }
61    }
62}
63
64impl<const N: usize> From<u32> for TypedId<N> {
65    fn from(id: u32) -> Self {
66        Self::new(id)
67    }
68}
69
70impl<const N: usize> From<&u32> for TypedId<N> {
71    fn from(id: &u32) -> Self {
72        Self::new(*id)
73    }
74}
75
76impl<const N: usize> From<TypedId<N>> for u32 {
77    fn from(id: TypedId<N>) -> Self {
78        id.inner
79    }
80}
81
82impl<const N: usize> From<&TypedId<N>> for u32 {
83    fn from(id: &TypedId<N>) -> Self {
84        id.inner
85    }
86}
87
88impl<const N: usize> From<TypedId<N>> for sea_orm::Value {
89    fn from(value: TypedId<N>) -> Self {
90        let inner: i32 = value.inner.try_into().unwrap_or_else(|e: TryFromIntError| {
91            if cfg!(debug_assertions) {
92                panic!(
93                    "invalid u32 id {} for {}: {:?}",
94                    value.inner,
95                    type_name::<Self>(),
96                    e.as_report()
97                );
98            } else {
99                warn!(
100                    "invalid u32 id {} for {}: {:?}",
101                    value.inner,
102                    type_name::<Self>(),
103                    e.as_report()
104                );
105                value.inner as _
106            }
107        });
108        sea_orm::Value::from(inner)
109    }
110}
111
112impl<const N: usize> sea_orm::sea_query::ValueType for TypedId<N> {
113    fn try_from(v: sea_orm::Value) -> Result<Self, ValueTypeErr> {
114        let inner = <i32 as sea_orm::sea_query::ValueType>::try_from(v)?;
115        Ok(Self::from_i32(inner))
116    }
117
118    fn type_name() -> String {
119        <i32 as sea_orm::sea_query::ValueType>::type_name()
120    }
121
122    fn array_type() -> ArrayType {
123        <i32 as sea_orm::sea_query::ValueType>::array_type()
124    }
125
126    fn column_type() -> ColumnType {
127        <i32 as sea_orm::sea_query::ValueType>::column_type()
128    }
129}
130
131impl<const N: usize> sea_orm::sea_query::Nullable for TypedId<N> {
132    fn null() -> sea_orm::Value {
133        <i32 as sea_orm::sea_query::Nullable>::null()
134    }
135}
136
137impl<const N: usize> sea_orm::TryGetable for TypedId<N> {
138    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
139        let inner = <i32 as sea_orm::TryGetable>::try_get_by(res, index)?;
140        Ok(Self::from_i32(inner))
141    }
142}
143
144impl<const N: usize> sea_orm::TryFromU64 for TypedId<N> {
145    fn try_from_u64(n: u64) -> Result<Self, DbErr> {
146        let inner = <i32 as sea_orm::TryFromU64>::try_from_u64(n)?;
147        Ok(Self::from_i32(inner))
148    }
149}
150
151impl<const N: usize> Serialize for TypedId<N> {
152    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
153    where
154        S: Serializer,
155    {
156        <u32 as Serialize>::serialize(&self.inner, serializer)
157    }
158}
159
160impl<'de, const N: usize> Deserialize<'de> for TypedId<N> {
161    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
162    where
163        D: Deserializer<'de>,
164    {
165        Ok(Self {
166            inner: <u32 as Deserialize>::deserialize(deserializer)?,
167        })
168    }
169}
170
171pub type TableId = TypedId<1>;
172pub type JobId = TypedId<2>;
173
174impl JobId {
175    pub fn is_mv_table_id(self, table_id: TableId) -> bool {
176        self.inner == table_id.inner
177    }
178
179    pub fn as_mv_table_id(self) -> TableId {
180        TableId::new(self.inner)
181    }
182}
183
184impl TableId {
185    pub fn as_job_id(self) -> JobId {
186        JobId::new(self.inner)
187    }
188}