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