risingwave_pb/
id.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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        // SAFETY: transparent repr
128        unsafe { std::mem::transmute(slice) }
129    }
130
131    pub fn mut_raw_vec(vec: &mut Vec<Self>) -> &mut Vec<u32> {
132        // SAFETY: transparent repr
133        unsafe { std::mem::transmute(vec) }
134    }
135
136    pub fn raw_hash_map_ref<V>(map: &HashMap<Self, V>) -> &HashMap<u32, V> {
137        // SAFETY: transparent repr
138        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        // SAFETY: transparent repr
143        unsafe { std::mem::transmute(map) }
144    }
145
146    pub fn raw_btree_map_ref<V>(map: &BTreeMap<Self, V>) -> &BTreeMap<u32, V> {
147        // SAFETY: transparent repr
148        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        // SAFETY: transparent repr
153        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);