More ergonomic DeriveActiveEnum
derive macro
This commit is contained in:
parent
2f7c9ccda7
commit
bb78a1d709
@ -1,3 +1,4 @@
|
||||
use heck::CamelCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{punctuated::Punctuated, token::Comma, Lit, LitInt, LitStr, Meta};
|
||||
@ -10,6 +11,7 @@ enum Error {
|
||||
|
||||
struct ActiveEnum {
|
||||
ident: syn::Ident,
|
||||
enum_name: String,
|
||||
rs_type: TokenStream,
|
||||
db_type: TokenStream,
|
||||
is_string: bool,
|
||||
@ -27,6 +29,7 @@ impl ActiveEnum {
|
||||
let ident_span = input.ident.span();
|
||||
let ident = input.ident;
|
||||
|
||||
let mut enum_name = ident.to_string().to_camel_case();
|
||||
let mut rs_type = Err(Error::TT(quote_spanned! {
|
||||
ident_span => compile_error!("Missing macro attribute `rs_type`");
|
||||
}));
|
||||
@ -52,8 +55,22 @@ impl ActiveEnum {
|
||||
}
|
||||
} else if name == "db_type" {
|
||||
if let Lit::Str(litstr) = &nv.lit {
|
||||
db_type = syn::parse_str::<TokenStream>(&litstr.value())
|
||||
.map_err(Error::Syn);
|
||||
let s = litstr.value();
|
||||
match s.as_ref() {
|
||||
"Enum" => {
|
||||
db_type = Ok(quote! {
|
||||
Enum(Self::name(), Self::values())
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
db_type = syn::parse_str::<TokenStream>(&s)
|
||||
.map_err(Error::Syn);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if name == "enum_name" {
|
||||
if let Lit::Str(litstr) = &nv.lit {
|
||||
enum_name = litstr.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,6 +142,7 @@ impl ActiveEnum {
|
||||
|
||||
Ok(ActiveEnum {
|
||||
ident,
|
||||
enum_name,
|
||||
rs_type: rs_type?,
|
||||
db_type: db_type?,
|
||||
is_string,
|
||||
@ -141,6 +159,7 @@ impl ActiveEnum {
|
||||
fn impl_active_enum(&self) -> TokenStream {
|
||||
let Self {
|
||||
ident,
|
||||
enum_name,
|
||||
rs_type,
|
||||
db_type,
|
||||
is_string,
|
||||
@ -181,6 +200,10 @@ impl ActiveEnum {
|
||||
impl sea_orm::ActiveEnum for #ident {
|
||||
type Value = #rs_type;
|
||||
|
||||
fn name() -> String {
|
||||
#enum_name.to_owned()
|
||||
}
|
||||
|
||||
fn to_value(&self) -> Self::Value {
|
||||
match self {
|
||||
#( Self::#variant_idents => #variant_values, )*
|
||||
|
@ -509,6 +509,9 @@ pub fn derive_active_model_behavior(input: TokenStream) -> TokenStream {
|
||||
/// - `db_type`: Define `ColumnType` returned by `ActiveEnum::db_type()`
|
||||
/// - Possible values: all available enum variants of `ColumnType`, e.g. `String(None)`, `String(Some(1))`, `Integer`
|
||||
/// - Note that value has to be passed as string, i.e. `db_type = "Integer"`
|
||||
/// - `enum_name`: Define `String` returned by `ActiveEnum::name()`
|
||||
/// - This attribute is optional with default value being the name of enum in camel-case
|
||||
/// - Note that value has to be passed as string, i.e. `db_type = "Integer"`
|
||||
///
|
||||
/// - For enum variant
|
||||
/// - `string_value` or `num_value`:
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{ColumnDef, DbErr, TryGetable};
|
||||
use crate::{ColumnDef, DbErr, Iterable, TryGetable};
|
||||
use sea_query::{Nullable, Value, ValueType};
|
||||
|
||||
/// A Rust representation of enum defined in database.
|
||||
@ -17,8 +17,12 @@ use sea_query::{Nullable, Value, ValueType};
|
||||
/// use sea_orm::entity::prelude::*;
|
||||
///
|
||||
/// // Using the derive macro
|
||||
/// #[derive(Debug, PartialEq, DeriveActiveEnum)]
|
||||
/// #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
|
||||
/// #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
/// #[sea_orm(
|
||||
/// rs_type = "String",
|
||||
/// db_type = "String(Some(1))",
|
||||
/// enum_name = "category"
|
||||
/// )]
|
||||
/// pub enum DeriveCategory {
|
||||
/// #[sea_orm(string_value = "B")]
|
||||
/// Big,
|
||||
@ -27,7 +31,7 @@ use sea_query::{Nullable, Value, ValueType};
|
||||
/// }
|
||||
///
|
||||
/// // Implementing it manually
|
||||
/// #[derive(Debug, PartialEq)]
|
||||
/// #[derive(Debug, PartialEq, EnumIter)]
|
||||
/// pub enum Category {
|
||||
/// Big,
|
||||
/// Small,
|
||||
@ -38,6 +42,11 @@ use sea_query::{Nullable, Value, ValueType};
|
||||
/// type Value = String;
|
||||
///
|
||||
/// // Will be atomically generated by `DeriveActiveEnum`
|
||||
/// fn name() -> String {
|
||||
/// "category".to_owned()
|
||||
/// }
|
||||
///
|
||||
/// // Will be atomically generated by `DeriveActiveEnum`
|
||||
/// fn to_value(&self) -> Self::Value {
|
||||
/// match self {
|
||||
/// Self::Big => "B",
|
||||
@ -71,7 +80,7 @@ use sea_query::{Nullable, Value, ValueType};
|
||||
/// use sea_orm::entity::prelude::*;
|
||||
///
|
||||
/// // Define the `Category` active enum
|
||||
/// #[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
|
||||
/// #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
/// #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
|
||||
/// pub enum Category {
|
||||
/// #[sea_orm(string_value = "B")]
|
||||
@ -95,10 +104,13 @@ use sea_query::{Nullable, Value, ValueType};
|
||||
///
|
||||
/// impl ActiveModelBehavior for ActiveModel {}
|
||||
/// ```
|
||||
pub trait ActiveEnum: Sized {
|
||||
pub trait ActiveEnum: Sized + Iterable {
|
||||
/// Define the Rust type that each enum variant represents.
|
||||
type Value: Into<Value> + ValueType + Nullable + TryGetable;
|
||||
|
||||
/// Get the name of enum
|
||||
fn name() -> String;
|
||||
|
||||
/// Convert enum variant into the corresponding value.
|
||||
fn to_value(&self) -> Self::Value;
|
||||
|
||||
@ -107,6 +119,11 @@ pub trait ActiveEnum: Sized {
|
||||
|
||||
/// Get the database column definition of this active enum.
|
||||
fn db_type() -> ColumnDef;
|
||||
|
||||
/// Get the name of all enum variants
|
||||
fn values() -> Vec<Self::Value> {
|
||||
Self::iter().map(|s| s.to_value()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -117,7 +134,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn active_enum_string() {
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, EnumIter)]
|
||||
pub enum Category {
|
||||
Big,
|
||||
Small,
|
||||
@ -126,6 +143,10 @@ mod tests {
|
||||
impl ActiveEnum for Category {
|
||||
type Value = String;
|
||||
|
||||
fn name() -> String {
|
||||
"category".to_owned()
|
||||
}
|
||||
|
||||
fn to_value(&self) -> Self::Value {
|
||||
match self {
|
||||
Self::Big => "B",
|
||||
@ -150,8 +171,12 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
|
||||
#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(
|
||||
rs_type = "String",
|
||||
db_type = "String(Some(1))",
|
||||
enum_name = "category"
|
||||
)]
|
||||
pub enum DeriveCategory {
|
||||
#[sea_orm(string_value = "B")]
|
||||
Big,
|
||||
@ -195,13 +220,16 @@ mod tests {
|
||||
|
||||
assert_eq!(Category::db_type(), ColumnType::String(Some(1)).def());
|
||||
assert_eq!(DeriveCategory::db_type(), ColumnType::String(Some(1)).def());
|
||||
|
||||
assert_eq!(Category::name(), DeriveCategory::name());
|
||||
assert_eq!(Category::values(), DeriveCategory::values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn active_enum_derive_signed_integers() {
|
||||
macro_rules! test_int {
|
||||
($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
#[derive(Debug, PartialEq, DeriveActiveEnum)]
|
||||
#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = $rs_type, db_type = $db_type)]
|
||||
pub enum $ident {
|
||||
#[sea_orm(num_value = 1)]
|
||||
@ -241,7 +269,7 @@ mod tests {
|
||||
fn active_enum_derive_unsigned_integers() {
|
||||
macro_rules! test_uint {
|
||||
($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
#[derive(Debug, PartialEq, DeriveActiveEnum)]
|
||||
#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = $rs_type, db_type = $db_type)]
|
||||
pub enum $ident {
|
||||
#[sea_orm(num_value = 1)]
|
||||
|
@ -15,7 +15,7 @@ pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
|
||||
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
|
||||
pub enum Category {
|
||||
#[sea_orm(string_value = "B")]
|
||||
@ -24,7 +24,7 @@ pub enum Category {
|
||||
Small,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
|
||||
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = "i32", db_type = r#"Integer"#)]
|
||||
pub enum Color {
|
||||
#[sea_orm(num_value = 0)]
|
||||
@ -33,11 +33,8 @@ pub enum Color {
|
||||
White,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
|
||||
#[sea_orm(
|
||||
rs_type = "String",
|
||||
db_type = r#"Enum("tea".to_owned(), vec!["EverydayTea".to_owned(), "BreakfastTea".to_owned()])"#
|
||||
)]
|
||||
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")]
|
||||
pub enum Tea {
|
||||
#[sea_orm(string_value = "EverydayTea")]
|
||||
EverydayTea,
|
||||
|
Loading…
x
Reference in New Issue
Block a user