diesel_codegen 0.16.1

Custom derive and procedural macros for Diesel
Documentation
use quote::Tokens;
use syn;

use attr::Attr;
use model::Model;
use util::wrap_item_in_const;

pub fn derive_queryable(item: syn::DeriveInput) -> Tokens {
    let model = t!(Model::from_item(&item, "Queryable"));

    let generics = syn::aster::from_generics(model.generics.clone())
        .ty_param_id("__DB")
        .ty_param_id("__ST")
        .build();
    let struct_ty = &model.ty;

    let row_ty = model.attrs.as_slice().iter().map(|a| &a.ty);
    let row_ty = quote!((#(#row_ty,)*));

    let build_expr = build_expr_for_model(&model);
    let field_names = model.attrs.as_slice().iter().map(Attr::name_for_pattern);
    let row_pat = quote!((#(#field_names,)*));

    let model_name_uppercase = model.name.as_ref().to_uppercase();
    let dummy_const = format!("_IMPL_QUERYABLE_FOR_{}", model_name_uppercase).into();

    wrap_item_in_const(dummy_const, quote!(
        impl#generics diesel::Queryable<__ST, __DB> for #struct_ty where
            __DB: diesel::backend::Backend + diesel::types::HasSqlType<__ST>,
            #row_ty: diesel::types::FromSqlRow<__ST, __DB>,
        {
           type Row = #row_ty;

           fn build(#row_pat: Self::Row) -> Self {
               #build_expr
           }
        }
    ))
}

fn build_expr_for_model(model: &Model) -> Tokens {
    let struct_name = &model.name;
    let field_names = model.attrs.as_slice().iter().map(Attr::name_for_pattern);

    let field_assignments = field_names.map(|field_name| {
        if model.is_tuple_struct() {
            quote!(#field_name)
        } else {
            quote!(#field_name: #field_name)
        }
    });

    if model.is_tuple_struct() {
        quote!(#struct_name(#(#field_assignments),*))
    } else {
        quote!(#struct_name {
            #(#field_assignments,)*
        })
    }
}