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