Skip to main content
Glama
macros.rs17.1 kB
/// The primary macro used for creating IDs for SI. macro_rules! id { ( $(#[$($attrs:tt)*])* $name:ident ) => { do_not_use_directly_id_inner!( $(#[$($attrs)*])* $name ); }; } /// Provides PostgreSQL type conversion implementations in addition to standard [`id!`] functionality. macro_rules! id_with_pg_types { ( $(#[$($attrs:tt)*])* $name:ident ) => { do_not_use_directly_id_inner!( $(#[$($attrs)*])* $name ); impl<'a> postgres_types::FromSql<'a> for $name { fn from_sql( ty: &postgres_types::Type, raw: &'a [u8], ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> { let id: String = postgres_types::FromSql::from_sql(ty, raw)?; Ok(Self(::ulid::Ulid::from_string(&id)?)) } fn accepts(ty: &postgres_types::Type) -> bool { ty == &postgres_types::Type::BPCHAR || ty.kind() == &postgres_types::Kind::Domain(postgres_types::Type::BPCHAR) } } impl postgres_types::ToSql for $name { fn to_sql( &self, ty: &postgres_types::Type, out: &mut postgres_types::private::BytesMut, ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> where Self: Sized, { postgres_types::ToSql::to_sql(&self.0.to_string(), ty, out) } fn accepts(ty: &postgres_types::Type) -> bool where Self: Sized, { ty == &postgres_types::Type::BPCHAR || ty.kind() == &postgres_types::Kind::Domain(postgres_types::Type::BPCHAR) } fn to_sql_checked( &self, ty: &postgres_types::Type, out: &mut postgres_types::private::BytesMut, ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> { postgres_types::ToSql::to_sql(&self.0.to_string(), ty, out) } } }; } /// Provides PostgreSQL type conversion and SeaORM implementations in addition to standard [`id!`] functionality. macro_rules! id_with_pg_and_sea_orm_types { ( $(#[$($attrs:tt)*])* $name:ident ) => { do_not_use_directly_id_inner!( $(#[$($attrs)*])* $name ); impl<'a> postgres_types::FromSql<'a> for $name { fn from_sql( ty: &postgres_types::Type, raw: &'a [u8], ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> { let id: String = postgres_types::FromSql::from_sql(ty, raw)?; Ok(Self(::ulid::Ulid::from_string(&id)?)) } fn accepts(ty: &postgres_types::Type) -> bool { ty == &postgres_types::Type::BPCHAR || ty.kind() == &postgres_types::Kind::Domain(postgres_types::Type::BPCHAR) } } impl postgres_types::ToSql for $name { fn to_sql( &self, ty: &postgres_types::Type, out: &mut postgres_types::private::BytesMut, ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> where Self: Sized, { postgres_types::ToSql::to_sql(&self.0.to_string(), ty, out) } fn accepts(ty: &postgres_types::Type) -> bool where Self: Sized, { ty == &postgres_types::Type::BPCHAR || ty.kind() == &postgres_types::Kind::Domain(postgres_types::Type::BPCHAR) } fn to_sql_checked( &self, ty: &postgres_types::Type, out: &mut postgres_types::private::BytesMut, ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> { postgres_types::ToSql::to_sql(&self.0.to_string(), ty, out) } } impl From<$name> for sea_orm::Value { fn from(source: $name) -> Self { sea_orm::Value::String(Some(Box::new(source.0.to_string()))) } } impl TryFrom<String> for $name { type Error = sea_orm::DbErr; fn try_from(s: String) -> Result<Self, Self::Error> { Ok($name( ::ulid::Ulid::from_string(&s).map_err(|err| sea_orm::DbErr::Type(err.to_string()))?, )) } } impl sea_orm::TryFromU64 for $name { fn try_from_u64(_: u64) -> Result<Self, sea_orm::DbErr> { Err(sea_orm::DbErr::Exec(sea_orm::RuntimeErr::Internal( format!("{} cannot be converted from u64", stringify!($name)), ))) } } impl sea_orm::sea_query::Nullable for $name { fn null() -> sea_orm::Value { sea_orm::Value::String(None) } } impl sea_orm::TryGetable for $name { fn try_get_by<I: sea_orm::ColIdx>(res: &sea_orm::QueryResult, idx: I) -> Result<Self, sea_orm::TryGetError> { let json_str: String = res.try_get_by(idx) .map_err(sea_orm::TryGetError::DbErr) .and_then(|opt: Option<String>| { opt.ok_or(sea_orm::TryGetError::Null("null".to_string())) })?; ::ulid::Ulid::from_string(&json_str) .map_err(|e| sea_orm::TryGetError::DbErr(sea_orm::DbErr::Type(e.to_string()))) .map($name) } } impl sea_orm::sea_query::ValueType for $name { fn try_from(v: sea_orm::Value) -> Result<Self, sea_orm::sea_query::ValueTypeErr> { match v { sea_orm::Value::String(Some(x)) => Ok($name( ::ulid::Ulid::from_string(&x).map_err(|_| sea_orm::sea_query::ValueTypeErr)?, )), _ => Err(sea_orm::sea_query::ValueTypeErr), } } fn type_name() -> String { stringify!($name).to_owned() } fn array_type() -> sea_orm::sea_query::ArrayType { sea_orm::sea_query::ArrayType::String } fn column_type() -> sea_orm::sea_query::ColumnType { sea_orm::sea_query::ColumnType::String(sea_orm::entity::prelude::StringLen::None) } } }; } /// **Deprecated:** this macro provides additional functionality for using the "nil" ID on top of the standard `id!` /// macro. It also adds support for SeaORM type conversions. /// /// This absolutely should not be used for any new IDs. Nick will be mad. No, I'm not writing this in third /// person, why do you ask? macro_rules! id_with_none_and_sea_orm_types { ( $(#[$($attrs:tt)*])* $name:ident ) => { do_not_use_directly_id_inner!( $(#[$($attrs)*])* $name ); impl Default for $name { fn default() -> Self { Self::NONE } } impl $name { /// The "nil" value for this ID. pub const NONE: Self = Self(::ulid::Ulid::nil()); } impl From<$name> for sea_orm::Value { fn from(source: $name) -> Self { sea_orm::Value::String(Some(Box::new(source.0.to_string()))) } } impl TryFrom<String> for $name { type Error = sea_orm::DbErr; fn try_from(s: String) -> Result<Self, Self::Error> { Ok($name( ::ulid::Ulid::from_string(&s).map_err(|err| sea_orm::DbErr::Type(err.to_string()))?, )) } } impl sea_orm::TryFromU64 for $name { fn try_from_u64(_: u64) -> Result<Self, sea_orm::DbErr> { Err(sea_orm::DbErr::Exec(sea_orm::RuntimeErr::Internal( format!("{} cannot be converted from u64", stringify!($name)), ))) } } impl sea_orm::sea_query::Nullable for $name { fn null() -> sea_orm::Value { sea_orm::Value::String(None) } } impl sea_orm::TryGetable for $name { fn try_get_by<I: sea_orm::ColIdx>(res: &sea_orm::QueryResult, idx: I) -> Result<Self, sea_orm::TryGetError> { let json_str: String = res.try_get_by(idx) .map_err(sea_orm::TryGetError::DbErr) .and_then(|opt: Option<String>| { opt.ok_or(sea_orm::TryGetError::Null("null".to_string())) })?; ::ulid::Ulid::from_string(&json_str) .map_err(|e| sea_orm::TryGetError::DbErr(sea_orm::DbErr::Type(e.to_string()))) .map($name) } } impl sea_orm::sea_query::ValueType for $name { fn try_from(v: sea_orm::Value) -> Result<Self, sea_orm::sea_query::ValueTypeErr> { match v { sea_orm::Value::String(Some(x)) => Ok($name( ::ulid::Ulid::from_string(&x).map_err(|_| sea_orm::sea_query::ValueTypeErr)?, )), _ => Err(sea_orm::sea_query::ValueTypeErr), } } fn type_name() -> String { stringify!($name).to_owned() } fn array_type() -> sea_orm::sea_query::ArrayType { sea_orm::sea_query::ArrayType::String } fn column_type() -> sea_orm::sea_query::ColumnType { sea_orm::sea_query::ColumnType::String(sea_orm::entity::prelude::StringLen::None) } } }; } /// **Deprecated:** this macro provides additional functionality for using the "nil" ID on top of the standard `id!` /// macro. It also adds support for PostgreSQL type conversions. /// /// This absolutely should not be used for any new IDs. Nick will be mad. No, I'm not writing this in third person, why /// do you ask? macro_rules! id_with_none_and_pg_types { ( $(#[$($attrs:tt)*])* $name:ident ) => { do_not_use_directly_id_inner!( $(#[$($attrs)*])* $name ); impl Default for $name { fn default() -> Self { Self::NONE } } impl $name { /// The "nil" value for this ID. pub const NONE: Self = Self(::ulid::Ulid::nil()); } impl<'a> postgres_types::FromSql<'a> for $name { fn from_sql( ty: &postgres_types::Type, raw: &'a [u8], ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> { let id: String = postgres_types::FromSql::from_sql(ty, raw)?; Ok(Self(::ulid::Ulid::from_string(&id)?)) } fn accepts(ty: &postgres_types::Type) -> bool { ty == &postgres_types::Type::BPCHAR || ty.kind() == &postgres_types::Kind::Domain(postgres_types::Type::BPCHAR) } } impl postgres_types::ToSql for $name { fn to_sql( &self, ty: &postgres_types::Type, out: &mut postgres_types::private::BytesMut, ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> where Self: Sized, { postgres_types::ToSql::to_sql(&self.0.to_string(), ty, out) } fn accepts(ty: &postgres_types::Type) -> bool where Self: Sized, { ty == &postgres_types::Type::BPCHAR || ty.kind() == &postgres_types::Kind::Domain(postgres_types::Type::BPCHAR) } fn to_sql_checked( &self, ty: &postgres_types::Type, out: &mut postgres_types::private::BytesMut, ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> { postgres_types::ToSql::to_sql(&self.0.to_string(), ty, out) } } }; } // NOTE(nick,jacob): this is a bit messy, but it would be complicated/tricky to scope this properly until stable // Rust provides the ability to use normal visibility modifiers in front of a "macro_rules!" definition. Some escape // hatches include, but are not limited to, creating a "si-id-macros" crate with mixed usages of "macro_export" and // "macro_use"... or using the "macro-vis" crate (https://github.com/kestrer/macro-vis). At the time of writing, // pursuing an escape hatch or different solution is unlikely to be worth it. #[allow(missing_docs)] macro_rules! do_not_use_directly_id_inner { ( $(#[$($attrss:tt)*])* $name:ident ) => { $(#[$($attrss)*])* #[allow(missing_docs)] #[derive( Eq, PartialEq, PartialOrd, Ord, Copy, Clone, Hash, derive_more::From, derive_more::Into, derive_more::Display, serde::Serialize, serde::Deserialize, )] pub struct $name(::ulid::Ulid); impl std::fmt::Debug for $name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple(stringify!($name)).field(&self.0.to_string()).finish() } } impl $name { /// Length of a string-encoded ID in bytes. pub const ID_LEN: usize = ::ulid::ULID_LEN; /// Generates a new key which is virtually guaranteed to be unique. pub fn generate() -> Self { Self(::ulid::Ulid::new()) } /// Calls [`Self::generate`]. #[allow(clippy::new_without_default)] pub fn new() -> Self { Self::generate() } /// Converts type into inner [`Ulid`](::ulid::Ulid). pub fn into_inner(self) -> ::ulid::Ulid { self.0 } /// Creates a Crockford Base32 encoded string that represents this Ulid. pub fn array_to_str<'buf>(&self, buf: &'buf mut [u8; ::ulid::ULID_LEN]) -> &'buf mut str { self.0.array_to_str(buf) } /// Converts the ID into a byte array. pub fn array_to_str_buf() -> [u8; ::ulid::ULID_LEN] { [0; ::ulid::ULID_LEN] } /// Constructs a new instance of Self from the given raw identifier. /// /// This function is typically used to consume ownership of the specified identifier. pub fn from_raw_id(value: ::ulid::Ulid) -> Self { Self(value) } /// Extracts the raw identifier. /// /// This function is typically used to borrow an owned idenfier. pub fn as_raw_id(&self) -> ::ulid::Ulid { self.0 } /// Consumes this object, returning the raw underlying identifier. /// /// This function is typically used to transfer ownership of the underlying identifier /// to the caller. pub fn into_raw_id(self) -> ::ulid::Ulid { self.0 } } impl From<$name> for String { fn from(id: $name) -> Self { ::ulid::Ulid::from(id.0).into() } } impl<'a> From<&'a $name> for ::ulid::Ulid { fn from(id: &'a $name) -> Self { id.0 } } impl From<$name> for crate::ulid::Ulid { fn from(id: $name) -> Self { id.0.into() } } impl<'a> From<&'a $name> for crate::ulid::Ulid { fn from(id: &'a $name) -> Self { id.0.into() } } impl From<crate::ulid::Ulid> for $name { fn from(ulid: crate::ulid::Ulid) -> Self { ulid.inner().into() } } impl<'a> From<&'a $name> for $name { fn from(id: &'a $name) -> Self { *id } } impl std::str::FromStr for $name { type Err = ::ulid::DecodeError; fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Self(::ulid::Ulid::from_string(s)?)) } } // impl si_id::SiId for $name {} }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server