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}