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 (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
15
16    let sqlite_tokens = sqlite_tokens(&item, &model);
17    let mysql_tokens = mysql_tokens(&item, &model);
18    let pg_tokens = pg_tokens(&item, &model);
19
20    Ok(wrap_in_dummy_mod(quote! {
21        impl #impl_generics diesel::sql_types::SqlType
22            for #struct_name #ty_generics
23        #where_clause
24        {
25            type IsNull = diesel::sql_types::is_nullable::NotNull;
26        }
27
28        impl #impl_generics diesel::sql_types::SingleValue
29            for #struct_name #ty_generics
30        #where_clause
31        {
32        }
33
34        #sqlite_tokens
35        #mysql_tokens
36        #pg_tokens
37    }))
38}
39
40fn sqlite_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
41    model
42        .sqlite_type
43        .as_ref()
44        .map(|sqlite_type| Ident::new(&sqlite_type.name.value(), Span::call_site()))
45        .and_then(|ty| {
46            if cfg!(not(feature = "sqlite")) {
47                return None;
48            }
49
50            let struct_name = &item.ident;
51            let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
52
53            Some(quote! {
54                impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
55                    for diesel::sqlite::Sqlite
56                #where_clause
57                {
58                    fn metadata(_: &mut ()) -> diesel::sqlite::SqliteType {
59                        diesel::sqlite::SqliteType::#ty
60                    }
61                }
62            })
63        })
64}
65
66fn mysql_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
67    model
68        .mysql_type
69        .as_ref()
70        .map(|mysql_type| Ident::new(&mysql_type.name.value(), Span::call_site()))
71        .and_then(|ty| {
72            if cfg!(not(feature = "mysql")) {
73                return None;
74            }
75
76            let struct_name = &item.ident;
77            let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
78
79            Some(quote! {
80                impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
81                    for diesel::mysql::Mysql
82                #where_clause
83                {
84                    fn metadata(_: &mut ()) -> diesel::mysql::MysqlType {
85                        diesel::mysql::MysqlType::#ty
86                    }
87                }
88            })
89        })
90}
91
92fn pg_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
93    model.postgres_type.as_ref().and_then(|ty| {
94        if cfg!(not(feature = "postgres")) {
95            return None;
96        }
97
98        let struct_name = &item.ident;
99        let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
100
101        let metadata_fn = match ty {
102            PostgresType::Fixed(oid, array_oid) => quote!(
103                fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata {
104                    PgTypeMetadata::new(#oid, #array_oid)
105                }
106            ),
107            PostgresType::Lookup(type_name, Some(type_schema)) => quote!(
108                fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata {
109                    lookup.lookup_type(#type_name, Some(#type_schema))
110                }
111            ),
112            PostgresType::Lookup(type_name, None) => quote!(
113                fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata {
114                    lookup.lookup_type(#type_name, None)
115                }
116            ),
117        };
118
119        Some(quote! {
120            use diesel::pg::{PgMetadataLookup, PgTypeMetadata};
121
122            impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
123                for diesel::pg::Pg
124            #where_clause
125            {
126                #metadata_fn
127            }
128        })
129    })
130}