1use crate::composite_type::{CompositeTypeMacro, handle_composite_type_macro};
19use crate::lifetimes::anonymize_lifetimes;
20
21use quote::ToTokens;
22use syn::parse::{Parse, ParseStream};
23use syn::spanned::Spanned;
24use syn::{GenericArgument, Token};
25
26use super::metadata::FunctionMetadataTypeEntity;
27
28#[derive(Debug, Clone)]
30pub struct UsedType {
31 pub original_ty: syn::Type,
32 pub resolved_ty: syn::Type,
33 pub resolved_ty_inner: Option<syn::Type>,
34 pub composite_type: Option<CompositeTypeMacro>,
36 pub variadic: bool,
38 pub default: Option<String>,
39 pub optional: Option<syn::Type>,
41 pub result: bool,
43}
44
45impl UsedType {
46 pub fn new(ty: syn::Type) -> syn::Result<Self> {
47 let original_ty = ty.clone();
48 let (resolved_ty, default) = match ty.clone() {
58 syn::Type::Macro(macro_pat) => {
60 let mac = ¯o_pat.mac;
61 let archetype = mac.path.segments.last().expect("No last segment");
62 match archetype.ident.to_string().as_str() {
63 "default" => {
64 let (maybe_resolved_ty, default) = handle_default_macro(mac)?;
65 (maybe_resolved_ty, default)
66 }
67 _ => (syn::Type::Macro(macro_pat), None),
68 }
69 }
70 original => (original, None),
71 };
72
73 let (resolved_ty, composite_type) = match resolved_ty {
75 syn::Type::Macro(macro_pat) => {
77 let mac = ¯o_pat.mac;
78 match &*mac.path.segments.last().expect("No last segment").ident.to_string() {
79 "default" => {
80 return Err(syn::Error::new(
83 mac.span(),
84 "default!(default!()) not supported, use it only once",
85 ))?;
86 }
87 "composite_type" => {
88 let composite_macro = handle_composite_type_macro(mac)?;
89 let ty = composite_macro.expand_with_lifetime();
90 (ty, Some(composite_macro))
91 }
92 _ => (syn::Type::Macro(macro_pat), None),
93 }
94 }
95 syn::Type::Path(path) => {
96 let segments = &path.path;
97 let last = segments
98 .segments
99 .last()
100 .ok_or(syn::Error::new(path.span(), "Could not read last segment of path"))?;
101
102 match last.ident.to_string().as_str() {
103 "Option" => resolve_option_inner(path)?,
109 "Result" => resolve_result_inner(path)?,
115 "Vec" => resolve_vec_inner(path)?,
118 "VariadicArray" => resolve_variadic_array_inner(path)?,
121 "Array" => resolve_array_inner(path)?,
124 _ => (syn::Type::Path(path), None),
125 }
126 }
127 original => (original, None),
128 };
129
130 let (resolved_ty, variadic, optional, result) = match resolved_ty {
132 syn::Type::Path(type_path) => {
133 let path = &type_path.path;
134 let last_segment = path.segments.last().ok_or(syn::Error::new(
135 path.span(),
136 "No last segment found while scanning path",
137 ))?;
138 let ident_string = last_segment.ident.to_string();
139 match ident_string.as_str() {
140 "Result" => {
141 if let syn::PathArguments::AngleBracketed(angles) = &last_segment.arguments
142 && let syn::GenericArgument::Type(inner_ty) =
143 angles.args.first().ok_or(syn::Error::new(
144 angles.span(),
145 "No inner arg for Result<T, E> found",
146 ))?
147 {
148 match inner_ty {
149 syn::Type::Path(inner_type_path) => {
151 let path = &inner_type_path.path;
152 let last_segment = inner_type_path.path.segments.last().ok_or(
153 syn::Error::new(
154 path.span(),
155 "No last segment found while scanning path",
156 ),
157 )?;
158 let ident_string = last_segment.ident.to_string();
159 match ident_string.as_str() {
160 "VariadicArray" => (
161 syn::Type::Path(type_path.clone()),
162 true,
163 Some(inner_ty.clone()),
164 false,
165 ),
166 "Option" => (
167 syn::Type::Path(type_path.clone()),
168 false,
169 Some(inner_ty.clone()),
170 true,
171 ),
172 _ => {
173 (syn::Type::Path(type_path.clone()), false, None, true)
174 }
175 }
176 }
177 _ => (syn::Type::Path(type_path.clone()), false, None, true),
179 }
180 } else {
181 return Err(syn::Error::new(
182 type_path.span(),
183 "Unexpected Item found inside `Result` (expected `<T>`)",
184 ));
185 }
186 }
187 "Option" => {
188 if let syn::PathArguments::AngleBracketed(angles) = &last_segment.arguments
190 && let syn::GenericArgument::Type(inner_ty) =
191 angles.args.first().ok_or(syn::Error::new(
192 angles.span(),
193 "No inner arg for Option<T> found",
194 ))?
195 {
196 match inner_ty {
197 syn::Type::Path(inner_type_path) => {
199 let path = &inner_type_path.path;
200 let last_segment =
201 path.segments.last().ok_or(syn::Error::new(
202 path.span(),
203 "No last segment found while scanning path",
204 ))?;
205 let ident_string = last_segment.ident.to_string();
206 match ident_string.as_str() {
207 "VariadicArray" => (
209 syn::Type::Path(type_path.clone()),
210 true,
211 Some(inner_ty.clone()),
212 false,
213 ),
214 _ => (
215 syn::Type::Path(type_path.clone()),
216 false,
217 Some(inner_ty.clone()),
218 false,
219 ),
220 }
221 }
222 _ => (
224 syn::Type::Path(type_path.clone()),
225 false,
226 Some(inner_ty.clone()),
227 false,
228 ),
229 }
230 } else {
231 return Err(syn::Error::new(
233 type_path.span(),
234 "Unexpected Item found inside `Option` (expected `<T>`)",
235 ));
236 }
237 }
238 "VariadicArray" => (syn::Type::Path(type_path), true, None, false),
240 _ => (syn::Type::Path(type_path), false, None, false),
242 }
243 }
244 original => (original, false, None, false),
245 };
246
247 let mut resolved_ty_inner: Option<syn::Type> = None;
249 if result
250 && let syn::Type::Path(tp) = &resolved_ty
251 && let Some(first_segment) = tp.path.segments.first()
252 && let syn::PathArguments::AngleBracketed(ab) = &first_segment.arguments
253 && let Some(syn::GenericArgument::Type(ty)) = ab.args.first()
254 {
255 resolved_ty_inner = Some(ty.clone());
256 }
257
258 Ok(Self {
259 original_ty,
260 resolved_ty,
261 resolved_ty_inner,
262 optional,
263 result,
264 variadic,
265 default,
266 composite_type,
267 })
268 }
269
270 pub fn entity_tokens(&self) -> syn::Expr {
271 let mut resolved_ty = self.resolved_ty.clone();
272 let mut resolved_ty_inner = self.resolved_ty_inner.clone().unwrap_or(resolved_ty.clone());
273 anonymize_lifetimes(&mut resolved_ty);
279 anonymize_lifetimes(&mut resolved_ty_inner);
280 let resolved_ty_string = resolved_ty.to_token_stream().to_string();
281 let composite_type = self.composite_type.clone().map(|v| v.expr);
282 let composite_type_iter = composite_type.iter();
283 let variadic = &self.variadic;
284 let optional = &self.optional.is_some();
285 let default = self.default.iter();
286
287 syn::parse_quote! {
288 ::pgrx::pgrx_sql_entity_graph::UsedTypeEntity {
289 ty_source: #resolved_ty_string,
290 ty_id: core::any::TypeId::of::<#resolved_ty_inner>(),
291 full_path: core::any::type_name::<#resolved_ty>(),
292 module_path: {
293 let ty_name = core::any::type_name::<#resolved_ty>();
294 let mut path_items: Vec<_> = ty_name.split("::").collect();
295 let _ = path_items.pop(); path_items.join("::")
297 },
298 composite_type: None #( .unwrap_or(Some(#composite_type_iter)) )*,
299 variadic: #variadic,
300 default: None #( .unwrap_or(Some(#default)) )*,
301 optional: #optional,
303 metadata: {
304 use ::pgrx::pgrx_sql_entity_graph::metadata::SqlTranslatable;
305 <#resolved_ty>::entity()
306 },
307 }
308 }
309 }
310}
311
312#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
313pub struct UsedTypeEntity {
314 pub ty_source: &'static str,
315 pub ty_id: core::any::TypeId,
316 pub full_path: &'static str,
317 pub module_path: String,
318 pub composite_type: Option<&'static str>,
319 pub variadic: bool,
320 pub default: Option<&'static str>,
321 pub optional: bool,
323 pub metadata: FunctionMetadataTypeEntity,
324}
325
326impl crate::TypeIdentifiable for UsedTypeEntity {
327 fn ty_id(&self) -> &core::any::TypeId {
328 &self.ty_id
329 }
330 fn ty_name(&self) -> &str {
331 self.full_path
332 }
333}
334
335fn resolve_vec_inner(
336 original: syn::TypePath,
337) -> syn::Result<(syn::Type, Option<CompositeTypeMacro>)> {
338 let segments = &original.path;
339 let last = segments
340 .segments
341 .last()
342 .ok_or(syn::Error::new(original.span(), "Could not read last segment of path"))?;
343
344 if let syn::PathArguments::AngleBracketed(path_arg) = &last.arguments
345 && let Some(syn::GenericArgument::Type(ty)) = path_arg.args.last()
346 {
347 match ty.clone() {
348 syn::Type::Macro(macro_pat) => {
349 let mac = ¯o_pat.mac;
350 let archetype = mac.path.segments.last().expect("No last segment");
351 match archetype.ident.to_string().as_str() {
352 "default" => Err(syn::Error::new(
353 mac.span(),
354 "`Vec<default!(T, default)>` not supported, choose `default!(Vec<T>, ident)` instead",
355 )),
356 "composite_type" => {
357 let composite_mac = handle_composite_type_macro(mac)?;
358 let comp_ty = composite_mac.expand_with_lifetime();
359 let sql = Some(composite_mac);
360 let ty = syn::parse_quote! {
361 Vec<#comp_ty>
362 };
363 Ok((ty, sql))
364 }
365 _ => Ok((syn::Type::Path(original), None)),
366 }
367 }
368 syn::Type::Path(arg_type_path) => {
369 let last = arg_type_path
370 .path
371 .segments
372 .last()
373 .ok_or(syn::Error::new(arg_type_path.span(), "No last segment in type path"))?;
374 if last.ident == "Option" {
375 let (inner_ty, expr) = resolve_option_inner(arg_type_path)?;
376 let wrapped_ty = syn::parse_quote! {
377 Vec<#inner_ty>
378 };
379 Ok((wrapped_ty, expr))
380 } else {
381 Ok((syn::Type::Path(original), None))
382 }
383 }
384 _ => Ok((syn::Type::Path(original), None)),
385 }
386 } else {
387 Ok((syn::Type::Path(original), None))
388 }
389}
390
391fn resolve_variadic_array_inner(
392 mut original: syn::TypePath,
393) -> syn::Result<(syn::Type, Option<CompositeTypeMacro>)> {
394 let original_span = original.span();
395 let last = original
396 .path
397 .segments
398 .last_mut()
399 .ok_or(syn::Error::new(original_span, "Could not read last segment of path"))?;
400
401 if let syn::PathArguments::AngleBracketed(ref mut path_arg) = last.arguments
402 && let Some(syn::GenericArgument::Type(ty)) = path_arg.args.last()
404 {
405 match ty.clone() {
406 syn::Type::Macro(macro_pat) => {
407 let mac = ¯o_pat.mac;
408 let archetype = mac.path.segments.last().expect("No last segment");
409 match archetype.ident.to_string().as_str() {
410 "default" => Err(syn::Error::new(
411 mac.span(),
412 "`VariadicArray<default!(T, default)>` not supported, choose `default!(VariadicArray<T>, ident)` instead",
413 )),
414 "composite_type" => {
415 let composite_mac = handle_composite_type_macro(mac)?;
416 let comp_ty = composite_mac.expand_with_lifetime();
417 let sql = Some(composite_mac);
418 let ty = syn::parse_quote! {
419 ::pgrx::datum::VariadicArray<'_, #comp_ty>
420 };
421 Ok((ty, sql))
422 }
423 _ => Ok((syn::Type::Path(original), None)),
424 }
425 }
426 syn::Type::Path(arg_type_path) => {
427 let last = arg_type_path
428 .path
429 .segments
430 .last()
431 .ok_or(syn::Error::new(arg_type_path.span(), "No last segment in type path"))?;
432 if last.ident == "Option" {
433 let (inner_ty, expr) = resolve_option_inner(arg_type_path)?;
434 let wrapped_ty = syn::parse_quote! {
435 ::pgrx::datum::VariadicArray<'_, #inner_ty>
436 };
437 Ok((wrapped_ty, expr))
438 } else {
439 Ok((syn::Type::Path(original), None))
440 }
441 }
442 _ => Ok((syn::Type::Path(original), None)),
443 }
444 } else {
445 Ok((syn::Type::Path(original), None))
446 }
447}
448
449fn resolve_array_inner(
450 mut original: syn::TypePath,
451) -> syn::Result<(syn::Type, Option<CompositeTypeMacro>)> {
452 let original_span = original.span();
453 let last = original
454 .path
455 .segments
456 .last_mut()
457 .ok_or(syn::Error::new(original_span, "Could not read last segment of path"))?;
458
459 if let syn::PathArguments::AngleBracketed(ref mut path_arg) = last.arguments
460 && let Some(syn::GenericArgument::Type(ty)) = path_arg.args.last()
461 {
462 match ty.clone() {
463 syn::Type::Macro(macro_pat) => {
464 let mac = ¯o_pat.mac;
465 let archetype = mac.path.segments.last().expect("No last segment");
466 match archetype.ident.to_string().as_str() {
467 "default" => Err(syn::Error::new(
468 mac.span(),
469 "`VariadicArray<default!(T, default)>` not supported, choose `default!(VariadicArray<T>, ident)` instead",
470 )),
471 "composite_type" => {
472 let composite_mac = handle_composite_type_macro(mac)?;
473 let comp_ty = composite_mac.expand_with_lifetime();
474 let sql = Some(composite_mac);
475 let ty = syn::parse_quote! {
476 ::pgrx::datum::Array<'_, #comp_ty>
477 };
478 Ok((ty, sql))
479 }
480 _ => Ok((syn::Type::Path(original), None)),
481 }
482 }
483 syn::Type::Path(arg_type_path) => {
484 let last = arg_type_path
485 .path
486 .segments
487 .last()
488 .ok_or(syn::Error::new(arg_type_path.span(), "No last segment in type path"))?;
489 match last.ident.to_string().as_str() {
490 "Option" => {
491 let (inner_ty, expr) = resolve_option_inner(arg_type_path)?;
492 let wrapped_ty = syn::parse_quote! {
493 ::pgrx::datum::Array<'_, #inner_ty>
494 };
495 Ok((wrapped_ty, expr))
496 }
497 _ => Ok((syn::Type::Path(original), None)),
498 }
499 }
500 _ => Ok((syn::Type::Path(original), None)),
501 }
502 } else {
503 Ok((syn::Type::Path(original), None))
504 }
505}
506
507fn resolve_option_inner(
508 original: syn::TypePath,
509) -> syn::Result<(syn::Type, Option<CompositeTypeMacro>)> {
510 let segments = &original.path;
511 let last = segments
512 .segments
513 .last()
514 .ok_or(syn::Error::new(original.span(), "Could not read last segment of path"))?;
515
516 if let syn::PathArguments::AngleBracketed(path_arg) = &last.arguments
517 && let Some(syn::GenericArgument::Type(ty)) = path_arg.args.first()
518 {
519 match ty.clone() {
520 syn::Type::Macro(macro_pat) => {
521 let mac = ¯o_pat.mac;
522 let archetype = mac.path.segments.last().expect("No last segment");
523 match archetype.ident.to_string().as_str() {
524 "composite_type" => {
526 let composite_mac = handle_composite_type_macro(mac)?;
527 let comp_ty = composite_mac.expand_with_lifetime();
528 let sql = Some(composite_mac);
529 let ty = syn::parse_quote! {
530 Option<#comp_ty>
531 };
532 Ok((ty, sql))
533 }
534 "default" => Err(syn::Error::new(
536 mac.span(),
537 "`Option<default!(T, \"my_default\")>` not supported, choose `Option<T>` for a default of `NULL`, or `default!(T, default)` for a non-NULL default",
538 )),
539 _ => Ok((syn::Type::Path(original), None)),
540 }
541 }
542 syn::Type::Path(arg_type_path) => {
543 let last = arg_type_path
544 .path
545 .segments
546 .last()
547 .ok_or(syn::Error::new(arg_type_path.span(), "No last segment in type path"))?;
548 match last.ident.to_string().as_str() {
549 "Vec" => {
552 let (inner_ty, expr) = resolve_vec_inner(arg_type_path)?;
553 let wrapped_ty = syn::parse_quote! {
554 ::std::option::Option<#inner_ty>
555 };
556 Ok((wrapped_ty, expr))
557 }
558 "VariadicArray" => {
561 let (inner_ty, expr) = resolve_variadic_array_inner(arg_type_path)?;
562 let wrapped_ty = syn::parse_quote! {
563 ::std::option::Option<#inner_ty>
564 };
565 Ok((wrapped_ty, expr))
566 }
567 "Array" => {
570 let (inner_ty, expr) = resolve_array_inner(arg_type_path)?;
571 let wrapped_ty = syn::parse_quote! {
572 ::std::option::Option<#inner_ty>
573 };
574 Ok((wrapped_ty, expr))
575 }
576 _ => Ok((syn::Type::Path(original), None)),
578 }
579 }
580 _ => Ok((syn::Type::Path(original), None)),
581 }
582 } else {
583 Ok((syn::Type::Path(original), None))
584 }
585}
586
587fn resolve_result_inner(
588 original: syn::TypePath,
589) -> syn::Result<(syn::Type, Option<CompositeTypeMacro>)> {
590 let segments = &original.path;
591 let last = segments
592 .segments
593 .last()
594 .ok_or(syn::Error::new(original.span(), "Could not read last segment of path"))?;
595
596 let mut without_type_args = original.path.clone();
598 without_type_args.segments.last_mut().unwrap().arguments = syn::PathArguments::None;
599
600 let (ok_ty, err_ty) = {
601 if let syn::PathArguments::AngleBracketed(path_arg) = last.arguments.clone() {
602 let mut iter = path_arg.args.into_iter();
603 match (iter.next(), iter.next()) {
604 (None, _) => {
605 return Err(syn::Error::new(
607 last.arguments.span(),
608 "Cannot return a Result without type generic arguments.",
609 ));
610 }
611 (Some(first_ty), None) => (first_ty, None),
615 (Some(first_ty), Some(second_ty)) => (first_ty, Some(second_ty)),
617 }
618 } else {
619 return Err(syn::Error::new(
621 last.arguments.span(),
622 "Cannot return a Result without type generic arguments.",
623 ));
624 }
625 };
626
627 fn type_for_args(
630 no_args_path: syn::Path,
631 first_ty: syn::Type,
632 err_ty: Option<GenericArgument>,
633 ) -> syn::Type {
634 match err_ty {
635 Some(e) => {
636 syn::parse_quote! {
637 #no_args_path<#first_ty, #e>
638 }
639 }
640 None => {
641 syn::parse_quote! {
645 #no_args_path<#first_ty>
646 }
647 }
648 }
649 }
650
651 if let syn::GenericArgument::Type(ty) = ok_ty {
652 match ty.clone() {
653 syn::Type::Macro(macro_pat) => {
654 let mac = ¯o_pat.mac;
655 let archetype = mac.path.segments.last().expect("No last segment");
656 match archetype.ident.to_string().as_str() {
657 "composite_type" => {
659 let composite_mac = handle_composite_type_macro(mac)?;
660 let comp_ty = composite_mac.expand_with_lifetime();
661 let sql = Some(composite_mac);
662
663 let ty = type_for_args(without_type_args, comp_ty, err_ty);
664 Ok((ty, sql))
665 }
666 "default" => Err(syn::Error::new(
668 mac.span(),
669 "`Result<default!(T, default), E>` not supported, choose `default!(Result<T, E>, ident)` instead",
670 )),
671 _ => Ok((syn::Type::Path(original), None)),
672 }
673 }
674 syn::Type::Path(arg_type_path) => {
675 let last = arg_type_path
676 .path
677 .segments
678 .last()
679 .ok_or(syn::Error::new(arg_type_path.span(), "No last segment in type path"))?;
680 match last.ident.to_string().as_str() {
681 "Option" => {
684 let (inner_ty, expr) = resolve_option_inner(arg_type_path)?;
685 let wrapped_ty = type_for_args(without_type_args, inner_ty, err_ty);
686 Ok((wrapped_ty, expr))
687 }
688 "Vec" => {
691 let (inner_ty, expr) = resolve_vec_inner(arg_type_path)?;
692 let wrapped_ty = type_for_args(without_type_args, inner_ty, err_ty);
693 Ok((wrapped_ty, expr))
694 }
695 "VariadicArray" => {
698 let (inner_ty, expr) = resolve_variadic_array_inner(arg_type_path)?;
699 let wrapped_ty = type_for_args(without_type_args, inner_ty, err_ty);
700 Ok((wrapped_ty, expr))
701 }
702 "Array" => {
705 let (inner_ty, expr) = resolve_array_inner(arg_type_path)?;
706 let wrapped_ty = type_for_args(without_type_args, inner_ty, err_ty);
707 Ok((wrapped_ty, expr))
708 }
709 _ => Ok((syn::Type::Path(original), None)),
711 }
712 }
713 _ => Ok((syn::Type::Path(original), None)),
714 }
715 } else {
716 Ok((syn::Type::Path(original), None))
717 }
718}
719
720fn handle_default_macro(mac: &syn::Macro) -> syn::Result<(syn::Type, Option<String>)> {
721 let out: DefaultMacro = mac.parse_body()?;
722 let true_ty = out.ty;
723 match out.expr {
724 syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(def), .. }) => {
725 let value = def.value();
726 Ok((true_ty, Some(value)))
727 }
728 syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Float(def), .. }) => {
729 let value = def.base10_digits();
730 Ok((true_ty, Some(value.to_string())))
731 }
732 syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(def), .. }) => {
733 let value = def.base10_digits();
734 Ok((true_ty, Some(value.to_string())))
735 }
736 syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Bool(def), .. }) => {
737 let value = def.value();
738 Ok((true_ty, Some(value.to_string())))
739 }
740 syn::Expr::Unary(syn::ExprUnary { op: syn::UnOp::Neg(_), ref expr, .. }) => match &**expr {
741 syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(def), .. }) => {
742 let value = def.base10_digits();
743 Ok((true_ty, Some("-".to_owned() + value)))
744 }
745 _ => Err(syn::Error::new(
747 mac.span(),
748 format!("Unrecognized UnaryExpr in `default!()` macro, got: {:?}", out.expr),
749 )),
750 },
751 syn::Expr::Path(syn::ExprPath { path: syn::Path { ref segments, .. }, .. }) => {
752 let last = segments.last().expect("No last segment");
753 let last_string = last.ident.to_string();
754 if last_string == "NULL" {
755 Ok((true_ty, Some(last_string)))
756 } else {
757 Err(syn::Error::new(
759 mac.span(),
760 format!(
761 "Unable to parse default value of `default!()` macro, got: {:?}",
762 out.expr
763 ),
764 ))
765 }
766 }
767 _ => Err(syn::Error::new(
769 mac.span(),
770 format!("Unable to parse default value of `default!()` macro, got: {:?}", out.expr),
771 )),
772 }
773}
774
775#[derive(Debug, Clone)]
776pub(crate) struct DefaultMacro {
777 ty: syn::Type,
778 pub(crate) expr: syn::Expr,
779}
780
781impl Parse for DefaultMacro {
782 fn parse(input: ParseStream) -> Result<Self, syn::Error> {
783 let ty = input.parse()?;
784 let _comma: Token![,] = input.parse()?;
785 let expr = input.parse()?;
786 Ok(Self { ty, expr })
787 }
788}