1use std::any::type_name;
16use std::collections::{BTreeMap, HashMap};
17use std::fmt::Formatter;
18use std::num::TryFromIntError;
19use std::ops::{Add, AddAssign};
20use std::str::FromStr;
21
22use sea_orm::sea_query::{ArrayType, ValueTypeErr};
23use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryGetError};
24use serde::{Deserialize, Deserializer, Serialize, Serializer};
25use thiserror_ext::AsReport;
26use tracing::warn;
27
28use crate::catalog::source::OptionalAssociatedTableId;
29use crate::catalog::table::OptionalAssociatedSourceId;
30
31pub const OBJECT_ID_PLACEHOLDER: u32 = u32::MAX - 1;
32
33#[derive(Clone, Copy, Default, Hash, PartialOrd, PartialEq, Eq, Ord)]
34#[repr(transparent)]
35pub struct TypedId<const N: usize>(pub(crate) u32);
36
37impl<const N: usize> std::fmt::Debug for TypedId<N> {
38 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39 <u32 as std::fmt::Debug>::fmt(&self.0, f)
40 }
41}
42
43impl<const N: usize> std::fmt::Display for TypedId<N> {
44 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
45 <u32 as std::fmt::Display>::fmt(&self.0, f)
46 }
47}
48
49impl<const N: usize> PartialEq<u32> for TypedId<N> {
50 fn eq(&self, other: &u32) -> bool {
51 self.0 == *other
52 }
53}
54
55impl<const N: usize> FromStr for TypedId<N> {
56 type Err = <u32 as FromStr>::Err;
57
58 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 Ok(Self(<u32 as FromStr>::from_str(s)?))
60 }
61}
62
63impl<const N: usize> TypedId<N> {
64 pub const fn new(inner: u32) -> Self {
65 TypedId(inner)
66 }
67
68 pub fn as_raw_id(self) -> u32 {
69 self.0
70 }
71
72 pub fn as_i32_id(self) -> i32 {
73 self.to_i32()
74 }
75
76 pub const fn placeholder() -> Self {
77 Self(OBJECT_ID_PLACEHOLDER)
78 }
79
80 pub fn is_placeholder(&self) -> bool {
81 self.0 == OBJECT_ID_PLACEHOLDER
82 }
83
84 fn from_i32(inner: i32) -> Self {
85 Self(inner.try_into().unwrap_or_else(|e: TryFromIntError| {
86 if cfg!(debug_assertions) {
87 panic!(
88 "invalid i32 id {} for {}: {:?}",
89 inner,
90 type_name::<Self>(),
91 e.as_report()
92 );
93 } else {
94 warn!(
95 "invalid i32 id {} for {}: {:?}",
96 inner,
97 type_name::<Self>(),
98 e.as_report()
99 );
100 inner as _
101 }
102 }))
103 }
104
105 fn to_i32(self) -> i32 {
106 self.0.try_into().unwrap_or_else(|e: TryFromIntError| {
107 if cfg!(debug_assertions) {
108 panic!(
109 "invalid u32 id {} for {}: {:?}",
110 self.0,
111 type_name::<Self>(),
112 e.as_report()
113 );
114 } else {
115 warn!(
116 "invalid u32 id {} for {}: {:?}",
117 self.0,
118 type_name::<Self>(),
119 e.as_report()
120 );
121 self.0 as _
122 }
123 })
124 }
125
126 pub fn raw_slice(slice: &[Self]) -> &[u32] {
127 unsafe { std::mem::transmute(slice) }
129 }
130
131 pub fn mut_raw_vec(vec: &mut Vec<Self>) -> &mut Vec<u32> {
132 unsafe { std::mem::transmute(vec) }
134 }
135
136 pub fn raw_hash_map_ref<V>(map: &HashMap<Self, V>) -> &HashMap<u32, V> {
137 unsafe { std::mem::transmute(map) }
139 }
140
141 pub fn raw_hash_map_mut_ref<V>(map: &mut HashMap<Self, V>) -> &mut HashMap<u32, V> {
142 unsafe { std::mem::transmute(map) }
144 }
145
146 pub fn raw_btree_map_ref<V>(map: &BTreeMap<Self, V>) -> &BTreeMap<u32, V> {
147 unsafe { std::mem::transmute(map) }
149 }
150
151 pub fn raw_btree_map_mut_ref<V>(map: &mut BTreeMap<Self, V>) -> &mut BTreeMap<u32, V> {
152 unsafe { std::mem::transmute(map) }
154 }
155}
156
157impl<const N: usize> From<u32> for TypedId<N> {
158 fn from(id: u32) -> Self {
159 Self::new(id)
160 }
161}
162
163impl<const N: usize> From<TypedId<N>> for sea_orm::Value {
164 fn from(value: TypedId<N>) -> Self {
165 sea_orm::Value::from(value.to_i32())
166 }
167}
168
169impl<const N: usize> sea_orm::sea_query::ValueType for TypedId<N> {
170 fn try_from(v: sea_orm::Value) -> Result<Self, ValueTypeErr> {
171 let inner = <i32 as sea_orm::sea_query::ValueType>::try_from(v)?;
172 Ok(Self::from_i32(inner))
173 }
174
175 fn type_name() -> String {
176 <i32 as sea_orm::sea_query::ValueType>::type_name()
177 }
178
179 fn array_type() -> ArrayType {
180 <i32 as sea_orm::sea_query::ValueType>::array_type()
181 }
182
183 fn column_type() -> ColumnType {
184 <i32 as sea_orm::sea_query::ValueType>::column_type()
185 }
186}
187
188impl<const N: usize> sea_orm::sea_query::Nullable for TypedId<N> {
189 fn null() -> sea_orm::Value {
190 <i32 as sea_orm::sea_query::Nullable>::null()
191 }
192}
193
194impl<const N: usize> sea_orm::TryGetable for TypedId<N> {
195 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
196 let inner = <i32 as sea_orm::TryGetable>::try_get_by(res, index)?;
197 Ok(Self::from_i32(inner))
198 }
199}
200
201impl<const N: usize> sea_orm::TryFromU64 for TypedId<N> {
202 fn try_from_u64(n: u64) -> Result<Self, DbErr> {
203 let inner = <i32 as sea_orm::TryFromU64>::try_from_u64(n)?;
204 Ok(Self::from_i32(inner))
205 }
206}
207
208impl<const N: usize> Serialize for TypedId<N> {
209 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
210 where
211 S: Serializer,
212 {
213 <u32 as Serialize>::serialize(&self.0, serializer)
214 }
215}
216
217impl<'de, const N: usize> Deserialize<'de> for TypedId<N> {
218 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
219 where
220 D: Deserializer<'de>,
221 {
222 Ok(Self(<u32 as Deserialize>::deserialize(deserializer)?))
223 }
224}
225
226impl<const N: usize> Add<u32> for TypedId<N> {
227 type Output = Self;
228
229 fn add(self, rhs: u32) -> Self::Output {
230 Self(self.0.checked_add(rhs).unwrap())
231 }
232}
233
234impl<const N: usize> AddAssign<u32> for TypedId<N> {
235 fn add_assign(&mut self, rhs: u32) {
236 self.0 = self.0.checked_add(rhs).unwrap()
237 }
238}
239
240pub type TableId = TypedId<1>;
241pub type JobId = TypedId<2>;
242pub type DatabaseId = TypedId<3>;
243pub type SchemaId = TypedId<4>;
244pub type FragmentId = TypedId<5>;
245pub type ActorId = TypedId<6>;
246pub type WorkerId = TypedId<7>;
247pub type SinkId = TypedId<8>;
248pub type SourceId = TypedId<9>;
249
250pub type SubscriptionId = TypedId<10>;
251pub type IndexId = TypedId<11>;
252pub type ViewId = TypedId<12>;
253pub type FunctionId = TypedId<13>;
254pub type ConnectionId = TypedId<14>;
255pub type SecretId = TypedId<15>;
256pub type SubscriberId = TypedId<16>;
257
258pub type ObjectId = TypedId<256>;
259
260macro_rules! impl_as {
261 (@func $target_id_name:ident, $alias_name:ident) => {
262 paste::paste! {
263 pub fn [< as_ $alias_name >](self) -> $target_id_name {
264 $target_id_name::new(self.0)
265 }
266 }
267 };
268 (@func $target_id_name:ident) => {
269 paste::paste! {
270 impl_as! { @func $target_id_name, [< $target_id_name:snake >] }
271 }
272 };
273 ($src_id_name:ident $(,$target_id_name:ident)* $(,{$orig_target_id_name:ident , $alias_name:ident})*) => {
274 impl $src_id_name {
275 $(
276 impl_as! { @func $target_id_name }
277 )*
278 $(
279 impl_as! { @func $orig_target_id_name, $alias_name }
280 )*
281 }
282 }
283}
284
285impl JobId {
286 pub fn is_mv_table_id(self, table_id: TableId) -> bool {
287 self.0 == table_id.0
288 }
289}
290
291impl_as!(JobId, SinkId, IndexId, SubscriberId, {TableId, mv_table_id}, {SourceId, shared_source_id});
292impl_as!(TableId, JobId);
293
294impl From<OptionalAssociatedTableId> for TableId {
295 fn from(value: OptionalAssociatedTableId) -> Self {
296 let OptionalAssociatedTableId::AssociatedTableId(table_id) = value;
297 Self(table_id)
298 }
299}
300
301impl From<TableId> for OptionalAssociatedTableId {
302 fn from(value: TableId) -> Self {
303 OptionalAssociatedTableId::AssociatedTableId(value.0)
304 }
305}
306
307impl_as!(SinkId, JobId);
308impl_as!(IndexId, JobId);
309impl_as!(SourceId, {JobId, share_source_job_id}, {TableId, cdc_table_id});
310impl_as!(SubscriptionId, SubscriberId);
311
312impl From<OptionalAssociatedSourceId> for SourceId {
313 fn from(value: OptionalAssociatedSourceId) -> Self {
314 let OptionalAssociatedSourceId::AssociatedSourceId(source_id) = value;
315 Self(source_id)
316 }
317}
318
319impl From<SourceId> for OptionalAssociatedSourceId {
320 fn from(value: SourceId) -> Self {
321 OptionalAssociatedSourceId::AssociatedSourceId(value.0)
322 }
323}
324
325macro_rules! impl_into_object {
326 ($mod_prefix:ty, $($type_name:ident),+) => {
327 $(
328 impl From<$type_name> for $mod_prefix {
329 fn from(value: $type_name) -> Self {
330 <$mod_prefix>::$type_name(value.0)
331 }
332 }
333 )+
334 };
335}
336
337impl_into_object!(
338 crate::user::grant_privilege::Object,
339 DatabaseId,
340 TableId,
341 SchemaId,
342 SinkId,
343 SourceId,
344 SubscriptionId,
345 ViewId,
346 FunctionId,
347 ConnectionId,
348 SecretId
349);
350
351impl_into_object!(
352 crate::ddl_service::alter_name_request::Object,
353 DatabaseId,
354 TableId,
355 SchemaId,
356 SinkId,
357 SourceId,
358 SubscriptionId,
359 IndexId,
360 ViewId
361);
362
363impl_into_object!(
364 crate::ddl_service::alter_owner_request::Object,
365 DatabaseId,
366 TableId,
367 SchemaId,
368 SinkId,
369 SourceId,
370 SubscriptionId,
371 ViewId,
372 ConnectionId
373);
374
375impl_into_object!(
376 crate::ddl_service::alter_set_schema_request::Object,
377 TableId,
378 ViewId,
379 SourceId,
380 SinkId,
381 SubscriptionId,
382 FunctionId,
383 ConnectionId
384);
385
386macro_rules! impl_into_rename_object {
387 ($($type_name:ident),+) => {
388 paste::paste! {
389 $(
390 impl From<([<$type_name Id>], [<$type_name Id>])> for crate::ddl_service::alter_swap_rename_request::Object {
391 fn from((src_object_id, dst_object_id): ([<$type_name Id>], [<$type_name Id>])) -> Self {
392 crate::ddl_service::alter_swap_rename_request::Object::$type_name(crate::ddl_service::alter_swap_rename_request::ObjectNameSwapPair {
393 src_object_id: src_object_id.as_object_id(),
394 dst_object_id: dst_object_id.as_object_id(),
395 })
396 }
397 }
398 )+
399 }
400 };
401}
402
403impl_into_rename_object!(Table, View, Source, Sink, Subscription);
404
405macro_rules! impl_object_id_conversion {
406 ($($type_name:ident),+) => {
407 $(
408 impl From<$type_name> for ObjectId {
409 fn from(value: $type_name) -> Self {
410 Self::new(value.0)
411 }
412 }
413
414 impl $type_name {
415 pub fn as_object_id(self) -> ObjectId {
416 ObjectId::new(self.0)
417 }
418 }
419 )+
420
421 paste::paste! {
422 impl ObjectId {
423 $(
424 pub fn [< as_ $type_name:snake>](self) -> $type_name {
425 $type_name::new(self.0)
426 }
427 )+
428 }
429 }
430 };
431}
432
433impl_object_id_conversion!(
434 DatabaseId,
435 TableId,
436 SchemaId,
437 SinkId,
438 SourceId,
439 JobId,
440 SubscriptionId,
441 IndexId,
442 ViewId,
443 FunctionId,
444 ConnectionId,
445 SecretId
446);