pgx_utils/sql_entity_graph/postgres_enum/
mod.rs1pub mod entity;
18
19use crate::sql_entity_graph::ToSqlConfig;
20use proc_macro2::{Span, TokenStream as TokenStream2};
21use quote::{quote, ToTokens, TokenStreamExt};
22use syn::parse::{Parse, ParseStream};
23use syn::punctuated::Punctuated;
24use syn::{DeriveInput, Generics, Ident, ItemEnum, Token};
25
26#[derive(Debug, Clone)]
49pub struct PostgresEnum {
50 name: Ident,
51 generics: Generics,
52 variants: Punctuated<syn::Variant, Token![,]>,
53 to_sql_config: ToSqlConfig,
54}
55
56impl PostgresEnum {
57 pub fn new(
58 name: Ident,
59 generics: Generics,
60 variants: Punctuated<syn::Variant, Token![,]>,
61 to_sql_config: ToSqlConfig,
62 ) -> Result<Self, syn::Error> {
63 if !to_sql_config.overrides_default() {
64 crate::ident_is_acceptable_to_postgres(&name)?;
65 }
66
67 Ok(Self { name, generics, variants, to_sql_config })
68 }
69
70 pub fn from_derive_input(derive_input: DeriveInput) -> Result<Self, syn::Error> {
71 let to_sql_config =
72 ToSqlConfig::from_attributes(derive_input.attrs.as_slice())?.unwrap_or_default();
73 let data_enum = match derive_input.data {
74 syn::Data::Enum(data_enum) => data_enum,
75 syn::Data::Union(_) | syn::Data::Struct(_) => {
76 return Err(syn::Error::new(derive_input.ident.span(), "expected enum"))
77 }
78 };
79 Self::new(derive_input.ident, derive_input.generics, data_enum.variants, to_sql_config)
80 }
81}
82
83impl Parse for PostgresEnum {
84 fn parse(input: ParseStream) -> Result<Self, syn::Error> {
85 let parsed: ItemEnum = input.parse()?;
86 let to_sql_config =
87 ToSqlConfig::from_attributes(parsed.attrs.as_slice())?.unwrap_or_default();
88 Self::new(parsed.ident, parsed.generics, parsed.variants, to_sql_config)
89 }
90}
91
92impl ToTokens for PostgresEnum {
93 fn to_tokens(&self, tokens: &mut TokenStream2) {
94 let name = self.name.clone();
96 let mut static_generics = self.generics.clone();
97 static_generics.params = static_generics
98 .params
99 .clone()
100 .into_iter()
101 .flat_map(|param| match param {
102 item @ syn::GenericParam::Type(_) | item @ syn::GenericParam::Const(_) => {
103 Some(item)
104 }
105 syn::GenericParam::Lifetime(mut lifetime) => {
106 lifetime.lifetime.ident = Ident::new("static", Span::call_site());
107 Some(syn::GenericParam::Lifetime(lifetime))
108 }
109 })
110 .collect();
111 let mut staticless_generics = self.generics.clone();
112 staticless_generics.params = static_generics
113 .params
114 .clone()
115 .into_iter()
116 .flat_map(|param| match param {
117 item @ syn::GenericParam::Type(_) | item @ syn::GenericParam::Const(_) => {
118 Some(item)
119 }
120 syn::GenericParam::Lifetime(_) => None,
121 })
122 .collect();
123 let (staticless_impl_generics, _staticless_ty_generics, _staticless_where_clauses) =
124 staticless_generics.split_for_impl();
125 let (_static_impl_generics, static_ty_generics, static_where_clauses) =
126 static_generics.split_for_impl();
127
128 let variants = self.variants.iter();
129 let sql_graph_entity_fn_name =
130 syn::Ident::new(&format!("__pgx_internals_enum_{}", name), Span::call_site());
131
132 let to_sql_config = &self.to_sql_config;
133
134 let inv = quote! {
135 unsafe impl #staticless_impl_generics ::pgx::utils::sql_entity_graph::metadata::SqlTranslatable for #name #static_ty_generics #static_where_clauses {
136 fn argument_sql() -> core::result::Result<::pgx::utils::sql_entity_graph::metadata::SqlMapping, ::pgx::utils::sql_entity_graph::metadata::ArgumentError> {
137 Ok(::pgx::utils::sql_entity_graph::metadata::SqlMapping::As(String::from(stringify!(#name))))
138 }
139
140 fn return_sql() -> core::result::Result<::pgx::utils::sql_entity_graph::metadata::Returns, ::pgx::utils::sql_entity_graph::metadata::ReturnsError> {
141 Ok(::pgx::utils::sql_entity_graph::metadata::Returns::One(::pgx::utils::sql_entity_graph::metadata::SqlMapping::As(String::from(stringify!(#name)))))
142 }
143 }
144
145 #[no_mangle]
146 #[doc(hidden)]
147 pub extern "Rust" fn #sql_graph_entity_fn_name() -> ::pgx::utils::sql_entity_graph::SqlGraphEntity {
148 extern crate alloc;
149 use alloc::vec::Vec;
150 use alloc::vec;
151 use ::pgx::WithTypeIds;
152 let mut mappings = Default::default();
153 <#name #static_ty_generics as ::pgx::datum::WithTypeIds>::register_with_refs(&mut mappings, stringify!(#name).to_string());
154 ::pgx::datum::WithSizedTypeIds::<#name #static_ty_generics>::register_sized_with_refs(&mut mappings, stringify!(#name).to_string());
155 ::pgx::datum::WithArrayTypeIds::<#name #static_ty_generics>::register_array_with_refs(&mut mappings, stringify!(#name).to_string());
156 ::pgx::datum::WithVarlenaTypeIds::<#name #static_ty_generics>::register_varlena_with_refs(&mut mappings, stringify!(#name).to_string());
157
158 let submission = ::pgx::utils::sql_entity_graph::PostgresEnumEntity {
159 name: stringify!(#name),
160 file: file!(),
161 line: line!(),
162 module_path: module_path!(),
163 full_path: core::any::type_name::<#name #static_ty_generics>(),
164 mappings,
165 variants: vec![ #( stringify!(#variants) ),* ],
166 to_sql_config: #to_sql_config,
167 };
168 ::pgx::utils::sql_entity_graph::SqlGraphEntity::Enum(submission)
169 }
170 };
171 tokens.append_all(inv);
172 }
173}