diesel_derives 2.4.0

You should not use this crate directly, it is internal to Diesel.
Documentation
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::Result;
use syn::{DeriveInput, Ident};

use crate::model::Model;
use crate::util::wrap_in_dummy_mod;
use diesel_attribute_parser::parsers::PostgresType;

pub fn derive(item: DeriveInput) -> Result<TokenStream> {
    let model = Model::from_item(&item, true, false)?;

    let struct_name = &item.ident;
    let generic_count = item.generics.params.len();
    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();

    let sqlite_tokens = sqlite_tokens(&item, &model);
    let mysql_tokens = mysql_tokens(&item, &model);
    let mariadb_tokens = mariadb_tokens(&item, &model);
    let pg_tokens = pg_tokens(&item, &model);

    let is_array = struct_name == "Array" && generic_count == 1;

    let enum_sql_type = if model.enum_type {
        let mut generics = item.generics.clone();
        generics.params.push(syn::parse_quote!(__DB));
        generics
            .params
            .push(syn::parse_quote!(const __ANYWAY: bool));
        generics
            .make_where_clause()
            .predicates
            .push(syn::parse_quote!(__DB: diesel::backend::Backend));
        generics
            .make_where_clause()
            .predicates
            .push(syn::parse_quote!(diesel::internal::derives::sql_type::EnumTypeMapping: diesel::internal::derives::sql_type::EnumMapping<__DB>));
        let (impl_generics, _, where_clause) = generics.split_for_impl();
        Some(quote::quote! {

            impl #impl_generics diesel::sql_types::EnumSqlType<__ANYWAY, __DB> for #struct_name #ty_generics
                #where_clause
            {
                type Strategy = diesel::internal::derives::sql_type::EnumTypeMapping;
            }
        })
    } else {
        None
    };

    Ok(wrap_in_dummy_mod(quote! {
        impl #impl_generics diesel::sql_types::SqlType
            for #struct_name #ty_generics
        #where_clause
        {
            type IsNull = diesel::sql_types::is_nullable::NotNull;

            const IS_ARRAY: bool = #is_array;
        }

        impl #impl_generics diesel::sql_types::SingleValue
            for #struct_name #ty_generics
        #where_clause
        {
        }

        #enum_sql_type
        #sqlite_tokens
        #mysql_tokens
        #mariadb_tokens
        #pg_tokens
    }))
}

fn sqlite_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
    model
        .sqlite_type
        .as_ref()
        .map(|sqlite_type| Ident::new(&sqlite_type.name.value(), Span::mixed_site()))
        .map(|ty| {
            let struct_name = &item.ident;
            let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();

            quote! {
                diesel::internal::derives::sql_type::expand_sqlite! {
                    impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
                        for diesel::sqlite::Sqlite
                        #where_clause
                    {
                        fn metadata(_: &mut ()) -> diesel::sqlite::SqliteType {
                            diesel::sqlite::SqliteType::#ty
                        }
                    }}
            }
        })
}

fn mysql_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
    model
        .mysql_type
        .as_ref()
        .map(|mysql_type| Ident::new(&mysql_type.name.value(), Span::mixed_site()))
        .map(|ty| {
            let struct_name = &item.ident;
            let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();

            quote! {
                diesel::internal::derives::sql_type::expand_mysql! {
                    impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
                        for diesel::mysql::Mysql
                        #where_clause
                    {
                        fn metadata(_: &mut ()) -> diesel::mysql::MysqlType {
                            diesel::mysql::MysqlType::#ty
                        }
                    }
                }
            }
        })
}

fn mariadb_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
    model
        .mariadb_type
        .as_ref()
        .map(|mariadb_type| Ident::new(&mariadb_type.name.value(), Span::mixed_site()))
        .map(|ty| {
            let struct_name = &item.ident;
            let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();

            quote! {
                diesel::internal::derives::sql_type::expand_mariadb! {
                    impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
                        for diesel::mariadb::Mariadb
                        #where_clause
                    {
                        fn metadata(_: &mut ()) -> diesel::mariadb::MariadbType {
                            diesel::mariadb::MariadbType::#ty
                        }
                    }
                }
            }
        })
}

fn pg_tokens(item: &DeriveInput, model: &Model) -> Option<TokenStream> {
    model.postgres_type.as_ref().map(|ty| {
        let struct_name = &item.ident;
        let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();

        let metadata_fn = match ty {
            PostgresType::Fixed(oid, array_oid) => quote!(
                fn metadata(_: &mut Self::MetadataLookup) -> diesel::pg::PgTypeMetadata {
                    diesel::pg::PgTypeMetadata::new(#oid, #array_oid)
                }
            ),
            PostgresType::Lookup(type_name, Some(type_schema)) => quote!(
                fn metadata(lookup: &mut Self::MetadataLookup) -> diesel::pg::PgTypeMetadata {
                    use diesel::pg::PgMetadataLookup;
                    lookup.lookup_type(#type_name, Some(#type_schema))
                }
            ),
            PostgresType::Lookup(type_name, None) => quote!(
                fn metadata(lookup: &mut Self::MetadataLookup) -> diesel::pg::PgTypeMetadata {
                    use diesel::pg::PgMetadataLookup;
                    lookup.lookup_type(#type_name, None)
                }
            ),
        };

        quote! {
            diesel::internal::derives::sql_type::expand_pg! {
                impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics>
                    for diesel::pg::Pg
                    #where_clause
                {
                    #metadata_fn
                }
            }
        }
    })
}