diesel_derives/
sql_type.rs

1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3use syn::Result;
4use syn::{DeriveInput, Ident};
5
6use crate::model::Model;
7use crate::parsers::PostgresType;
8use crate::util::wrap_in_dummy_mod;
9
10pub fn derive(item: DeriveInput) -> Result<TokenStream> {
11    let model = Model::from_item(&item, true, false)?;
12
13    let struct_name = &item.ident;
14    let generic_count = item.generics.params.len();
15    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
16
17    let sqlite_tokens = sqlite_tokens(&item, &model);
18    let mysql_tokens = mysql_tokens(&item, &model);
19    let pg_tokens = pg_tokens(&item, &model);
20
21    let is_array = struct_name == "Array" && generic_count == 1;
22
23    Ok(wrap_in_dummy_mod({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "SqlType");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "IsNull");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "sql_types");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "is_nullable");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "NotNull");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "const");
            ::quote::__private::push_ident(&mut _s, "IS_ARRAY");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "bool");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&is_array, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "SingleValue");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        ::quote::__private::TokenStream::new());
    ::quote::ToTokens::to_tokens(&sqlite_tokens, &mut _s);
    ::quote::ToTokens::to_tokens(&mysql_tokens, &mut _s);
    ::quote::ToTokens::to_tokens(&pg_tokens, &mut _s);
    _s
}quote! {
24        impl #impl_generics diesel::sql_types::SqlType
25            for #struct_name #ty_generics
26        #where_clause
27        {
28            type IsNull = diesel::sql_types::is_nullable::NotNull;
29
30            const IS_ARRAY: bool = #is_array;
31        }
32
33        impl #impl_generics diesel::sql_types::SingleValue
34            for #struct_name #ty_generics
35        #where_clause
36        {
37        }
38
39        #sqlite_tokens
40        #mysql_tokens
41        #pg_tokens
42    }))
43}
44
45fn sqlite_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
46    model
47        .sqlite_type
48        .as_ref()
49        .map(|sqlite_type| Ident::new(&sqlite_type.name.value(), Span::mixed_site()))
50        .and_then(|ty| {
51            if falsecfg!(not(feature = "sqlite")) {
52                return None;
53            }
54
55            let struct_name = &item.ident;
56            let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
57
58            Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "HasSqlType");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sqlite");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Sqlite");
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "metadata");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_underscore(&mut _s);
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "mut");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "sqlite");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "SqliteType");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "sqlite");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "SqliteType");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::ToTokens::to_tokens(&ty, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote! {
59                impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
60                    for diesel::sqlite::Sqlite
61                #where_clause
62                {
63                    fn metadata(_: &mut ()) -> diesel::sqlite::SqliteType {
64                        diesel::sqlite::SqliteType::#ty
65                    }
66                }
67            })
68        })
69}
70
71fn mysql_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
72    model
73        .mysql_type
74        .as_ref()
75        .map(|mysql_type| Ident::new(&mysql_type.name.value(), Span::mixed_site()))
76        .and_then(|ty| {
77            if falsecfg!(not(feature = "mysql")) {
78                return None;
79            }
80
81            let struct_name = &item.ident;
82            let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
83
84            Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "HasSqlType");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "mysql");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Mysql");
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "metadata");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_underscore(&mut _s);
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "mut");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "mysql");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "MysqlType");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "mysql");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "MysqlType");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::ToTokens::to_tokens(&ty, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote! {
85                impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
86                    for diesel::mysql::Mysql
87                #where_clause
88                {
89                    fn metadata(_: &mut ()) -> diesel::mysql::MysqlType {
90                        diesel::mysql::MysqlType::#ty
91                    }
92                }
93            })
94        })
95}
96
97fn pg_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
98    model.postgres_type.as_ref().and_then(|ty| {
99        if falsecfg!(not(feature = "postgres")) {
100            return None;
101        }
102
103        let struct_name = &item.ident;
104        let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
105
106        let metadata_fn = match ty {
107            PostgresType::Fixed(oid, array_oid) => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::__private::push_ident(&mut _s, "metadata");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_underscore(&mut _s);
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_ident(&mut _s, "mut");
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "MetadataLookup");
            _s
        });
    ::quote::__private::push_rarrow(&mut _s);
    ::quote::__private::push_ident(&mut _s, "PgTypeMetadata");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "PgTypeMetadata");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "new");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&oid, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::ToTokens::to_tokens(&array_oid, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote!(
108                fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
109                    PgTypeMetadata::new(#oid, #array_oid)
110                }
111            ),
112            PostgresType::Lookup(type_name, Some(type_schema)) => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::__private::push_ident(&mut _s, "metadata");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "lookup");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_ident(&mut _s, "mut");
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "MetadataLookup");
            _s
        });
    ::quote::__private::push_rarrow(&mut _s);
    ::quote::__private::push_ident(&mut _s, "PgTypeMetadata");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "lookup");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "lookup_type");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&type_name, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Some");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::ToTokens::to_tokens(&type_schema, &mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote!(
113                fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata {
114                    lookup.lookup_type(#type_name, Some(#type_schema))
115                }
116            ),
117            PostgresType::Lookup(type_name, None) => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::__private::push_ident(&mut _s, "metadata");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "lookup");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_ident(&mut _s, "mut");
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "MetadataLookup");
            _s
        });
    ::quote::__private::push_rarrow(&mut _s);
    ::quote::__private::push_ident(&mut _s, "PgTypeMetadata");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "lookup");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "lookup_type");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&type_name, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "None");
                    _s
                });
            _s
        });
    _s
}quote!(
118                fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata {
119                    lookup.lookup_type(#type_name, None)
120                }
121            ),
122        };
123
124        Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "use");
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "pg");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "PgMetadataLookup");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "PgTypeMetadata");
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "HasSqlType");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "pg");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Pg");
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&metadata_fn, &mut _s);
            _s
        });
    _s
}quote! {
125            use diesel::pg::{PgMetadataLookup, PgTypeMetadata};
126
127            impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
128                for diesel::pg::Pg
129            #where_clause
130            {
131                #metadata_fn
132            }
133        })
134    })
135}