Skip to main content

pgrx_sql_entity_graph/
used_type.rs

1//LICENSE Portions Copyright 2019-2021 ZomboDB, LLC.
2//LICENSE
3//LICENSE Portions Copyright 2021-2023 Technology Concepts & Design, Inc.
4//LICENSE
5//LICENSE Portions Copyright 2023-2023 PgCentral Foundation, Inc. <contact@pgcentral.org>
6//LICENSE
7//LICENSE All rights reserved.
8//LICENSE
9//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
10/*!
11
12Type level metadata for Rust to SQL generation.
13
14> Like all of the [`sql_entity_graph`][crate] APIs, this is considered **internal**
15> to the `pgrx` framework and very subject to change between versions. While you may use this, please do it with caution.
16
17*/
18use 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/// A type, optionally with an overriding composite type name
29#[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    /// Set via `composite_type!()`
35    pub composite_type: Option<CompositeTypeMacro>,
36    /// Set via `VariadicArray` or `variadic!()`
37    pub variadic: bool,
38    pub default: Option<String>,
39    /// Set via the type being an `Option` or a `Result<Option<T>>`.
40    pub optional: Option<syn::Type>,
41    /// Set via the type being a `Result<T>`
42    pub result: bool,
43}
44
45impl UsedType {
46    pub fn new(ty: syn::Type) -> syn::Result<Self> {
47        let original_ty = ty.clone();
48        // There are several steps:
49        // * Resolve the `default!()` macro
50        // * Resolve the `variadic!()` macro
51        // * Resolve `composite_type!()`
52        // * Anonymize any lifetimes
53        // * Resolving any flags for that resolved type so we can not have to do this later.
54
55        // Resolve any `default` macro
56        // We do this first as it's **always** in the first position. It's not valid deeper in the type.
57        let (resolved_ty, default) = match ty.clone() {
58            // default!(..)
59            syn::Type::Macro(macro_pat) => {
60                let mac = &macro_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        // Now, resolve any `composite_type` macro
74        let (resolved_ty, composite_type) = match resolved_ty {
75            // composite_type!(..)
76            syn::Type::Macro(macro_pat) => {
77                let mac = &macro_pat.mac;
78                match &*mac.path.segments.last().expect("No last segment").ident.to_string() {
79                    "default" => {
80                        // If we land here, after already expanding the `default!()` above, the user has written it twice.
81                        // This is definitely an issue and we should tell them.
82                        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<composite_type!(..)>
104                    // Option<Vec<composite_type!(..)>>
105                    // Option<Vec<Option<composite_type!(..)>>>
106                    // Option<VariadicArray<composite_type!(..)>>
107                    // Option<VariadicArray<Option<composite_type!(..)>>>
108                    "Option" => resolve_option_inner(path)?,
109                    // Result<composite_type!(..), ..>
110                    // Result<Vec<composite_type!(..)>, ..>
111                    // Result<Vec<Option<composite_type!(..)>>, ..>
112                    // Result<VariadicArray<composite_type!(..)>, ..>
113                    // Result<VariadicArray<Option<composite_type!(..)>>, ..>
114                    "Result" => resolve_result_inner(path)?,
115                    // Vec<composite_type!(..)>
116                    // Vec<Option<composite_type!(..)>>
117                    "Vec" => resolve_vec_inner(path)?,
118                    // VariadicArray<composite_type!(..)>
119                    // VariadicArray<Option<composite_type!(..)>>
120                    "VariadicArray" => resolve_variadic_array_inner(path)?,
121                    // Array<composite_type!(..)>
122                    // Array<Option<composite_type!(..)>>
123                    "Array" => resolve_array_inner(path)?,
124                    _ => (syn::Type::Path(path), None),
125                }
126            }
127            original => (original, None),
128        };
129
130        // In this  step, we go look at the resolved type and determine if it is a variadic, optional, result, etc.
131        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                                // Result<$Type<T>>
150                                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                                // Result<T>
178                                _ => (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                        // Option<VariadicArray<T>>
189                        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                                // Option<VariadicArray<T>>
198                                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                                        // Option<VariadicArray<T>>
208                                        "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                                // Option<T>
223                                _ => (
224                                    syn::Type::Path(type_path.clone()),
225                                    false,
226                                    Some(inner_ty.clone()),
227                                    false,
228                                ),
229                            }
230                        } else {
231                            // Option<T>
232                            return Err(syn::Error::new(
233                                type_path.span(),
234                                "Unexpected Item found inside `Option` (expected `<T>`)",
235                            ));
236                        }
237                    }
238                    // VariadicArray<T>
239                    "VariadicArray" => (syn::Type::Path(type_path), true, None, false),
240                    // T
241                    _ => (syn::Type::Path(type_path), false, None, false),
242                }
243            }
244            original => (original, false, None, false),
245        };
246
247        // if the Type is like `Result<T, E>`, this finds the `T`
248        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        // The lifetimes of these are not relevant. Previously, we solved this by staticizing them
274        // but we want to avoid staticizing in this codebase going forward. Anonymization makes it
275        // easier to name the lifetime-bounded objects without the context for those lifetimes,
276        // without erasing all possible distinctions, since anon lifetimes may still be disunited.
277        // Non-static lifetimes, however, require the use of the NonStaticTypeId hack.
278        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(); // Drop the one we don't want.
296                    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                /// Set via the type being an `Option`.
302                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    /// Set via the type being an `Option`.
322    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 = &macro_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        // TODO: Lifetime????
403        && let Some(syn::GenericArgument::Type(ty)) = path_arg.args.last()
404    {
405        match ty.clone() {
406            syn::Type::Macro(macro_pat) => {
407                let mac = &macro_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 = &macro_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 = &macro_pat.mac;
522                let archetype = mac.path.segments.last().expect("No last segment");
523                match archetype.ident.to_string().as_str() {
524                    // Option<composite_type!(..)>
525                    "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                    // Option<default!(composite_type!(..))> isn't valid. If the user wanted the default to be `NULL` they just don't need a default.
535                    "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                    // Option<Vec<composite_type!(..)>>
550                    // Option<Vec<Option<composite_type!(..)>>>
551                    "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                    // Option<VariadicArray<composite_type!(..)>>
559                    // Option<VariadicArray<Option<composite_type!(..)>>>
560                    "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                    // Option<Array<composite_type!(..)>>
568                    // Option<Array<Option<composite_type!(..)>>>
569                    "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                    // Option<..>
577                    _ => 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    // Get the path of our Result type, to handle crate::module::Result pattern
597    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 early, Result<> with no type args.
606                    return Err(syn::Error::new(
607                        last.arguments.span(),
608                        "Cannot return a Result without type generic arguments.",
609                    ));
610                }
611                // Since `pub type Result<T> = std::error::Result<T, OurError>
612                // is a common pattern,
613                // we should support single-argument Result<T> style.
614                (Some(first_ty), None) => (first_ty, None),
615                // This is the more common Result<T, E>.
616                (Some(first_ty), Some(second_ty)) => (first_ty, Some(second_ty)),
617            }
618        } else {
619            // Return early, invalid signature for Result<T,E>
620            return Err(syn::Error::new(
621                last.arguments.span(),
622                "Cannot return a Result without type generic arguments.",
623            ));
624        }
625    };
626
627    // Inner / nested function for getting a type signature for a Result from
628    // the tuple of (ok_type, Option<error_type>)
629    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                // Since `pub type Result<T> = std::error::Result<T, OurError>
642                // is a common pattern,
643                // we should support single-argument Result<T> style.
644                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 = &macro_pat.mac;
655                let archetype = mac.path.segments.last().expect("No last segment");
656                match archetype.ident.to_string().as_str() {
657                    // Result<composite_type!(..), E>
658                    "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                    // Result<default!(composite_type!(..)), E>
667                    "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                    // Result<Option<composite_type!(..)>>
682                    // Result<Option<Vec<composite_type!(..)>>>>
683                    "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                    // Result<Vec<composite_type!(..)>>
689                    // Result<Vec<Option<composite_type!(..)>>>
690                    "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                    // Result<VariadicArray<composite_type!(..)>>
696                    // Result<VariadicArray<Option<composite_type!(..)>>>
697                    "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                    // Result<Array<composite_type!(..)>>
703                    // Result<Array<Option<composite_type!(..)>>>
704                    "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                    // Result<T> where T is plain-old-data and not a (supported) container type.
710                    _ => 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            // FIXME: add a UI test for this
746            _ => 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                // FIXME: add a UI test for this
758                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        // FIXME: add a UI test for this
768        _ => 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}