Skip to content

Commit

Permalink
Rewrite #[derive(Queryable)] in derives2
Browse files Browse the repository at this point in the history
This was fairly recently rewritten, so it should in theory be the most
straightforward derive to port. Unfortunately, due to
rust-lang/rust#47311, it's obnoxiously hard to
actually construct a struct in a derive right now. We have to do hacky
workarounds until that is fixed.
  • Loading branch information
sgrif committed Feb 3, 2018
1 parent 14887fc commit fbe7ca4
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 58 deletions.
6 changes: 0 additions & 6 deletions diesel_derives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,13 @@ mod from_sql_row;
mod insertable;
mod model;
mod query_id;
mod queryable;
mod queryable_by_name;
mod sql_type;
mod util;

use proc_macro::TokenStream;
use syn::parse_derive_input;

#[proc_macro_derive(Queryable, attributes(column_name))]
pub fn derive_queryable(input: TokenStream) -> TokenStream {
expand_derive(input, queryable::derive_queryable)
}

#[proc_macro_derive(QueryableByName, attributes(table_name, column_name, sql_type, diesel))]
pub fn derive_queryable_by_name(input: TokenStream) -> TokenStream {
expand_derive(input, queryable_by_name::derive)
Expand Down
49 changes: 0 additions & 49 deletions diesel_derives/src/queryable.rs

This file was deleted.

1 change: 0 additions & 1 deletion diesel_derives/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ extern crate diesel;
#[macro_use]
extern crate diesel_derives;

mod queryable;
mod queryable_by_name;
mod associations;
mod test_helpers;
13 changes: 13 additions & 0 deletions diesel_derives2/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ pub enum FieldName {
Unnamed(syn::Index),
}

impl FieldName {
pub fn for_assignment(&self) -> quote::Tokens {
match *self {
FieldName::Named(mut x) => {
// https://github.com/rust-lang/rust/issues/47311
x.span = Span::call_site();
quote!(#x)
}
FieldName::Unnamed(ref x) => quote!(#x),
}
}
}

impl quote::ToTokens for FieldName {
fn to_tokens(&self, tokens: &mut quote::Tokens) {
use proc_macro2::{Spacing, TokenNode, TokenTree};
Expand Down
6 changes: 6 additions & 0 deletions diesel_derives2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod util;

mod as_changeset;
mod identifiable;
mod queryable;

use diagnostic_shim::*;

Expand All @@ -42,6 +43,11 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream {
expand_derive(input, identifiable::derive)
}

#[proc_macro_derive(Queryable, attributes(column_name))]
pub fn derive_queryable(input: TokenStream) -> TokenStream {
expand_derive(input, queryable::derive)
}

fn expand_derive(
input: TokenStream,
f: fn(syn::DeriveInput) -> Result<quote::Tokens, Diagnostic>,
Expand Down
57 changes: 57 additions & 0 deletions diesel_derives2/src/queryable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use proc_macro2::Span;
use quote;
use syn;

use model::*;
use util::*;

pub fn derive(item: syn::DeriveInput) -> Result<quote::Tokens, Diagnostic> {
let model = Model::from_item(&item)?;

let struct_name = item.ident;
let field_ty = model.fields().iter().map(|f| &f.ty).collect::<Vec<_>>();
let field_ty = &field_ty;
let build_expr = model.fields().iter().enumerate().map(|(i, f)| {
let field_name = &f.name.for_assignment();
let i: syn::Index = i.into();
// Make sure `row` has a `def_site` span
let row = quote!(row);
// https://github.com/rust-lang/rust/issues/47311
let span = Span::call_site();
quote_spanned!(span=> #field_name: (#row.#i))
});

let (_, ty_generics, _) = item.generics.split_for_impl();
let mut generics = item.generics.clone();
generics
.params
.push(parse_quote!(__DB: diesel::backend::Backend));
generics.params.push(parse_quote!(__ST));
{
let where_clause = generics.where_clause.get_or_insert(parse_quote!(where));
where_clause
.predicates
.push(parse_quote!((#(#field_ty,)*): Queryable<__ST, __DB>));
}
let (impl_generics, _, where_clause) = generics.split_for_impl();

Ok(wrap_in_dummy_mod(
model.dummy_mod_name("queryable"),
quote! {
use self::diesel::Queryable;

impl #impl_generics Queryable<__ST, __DB> for #struct_name #ty_generics
#where_clause
{
type Row = <(#(#field_ty,)*) as Queryable<__ST, __DB>>::Row;

fn build(row: Self::Row) -> Self {
let row: (#(#field_ty,)*) = Queryable::build(row);
Self {
#(#build_expr,)*
}
}
}
},
))
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use diesel::dsl::sql;
use diesel::*;
use diesel::sql_types::Integer;

use test_helpers::connection;
use helpers::connection;

#[test]
fn named_struct_definition() {
Expand All @@ -20,7 +20,7 @@ fn named_struct_definition() {
#[test]
fn tuple_struct() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable)]
struct MyStruct(#[column_name(foo)] i32, #[column_name(bar)] i32);
struct MyStruct(#[column_name = "foo"] i32, #[column_name = "bar"] i32);

let conn = connection();
let data = select(sql::<(Integer, Integer)>("1, 2")).get_result(&conn);
Expand Down
1 change: 1 addition & 0 deletions diesel_derives2/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ mod schema;

mod as_changeset;
mod identifiable;
mod queryable;

0 comments on commit fbe7ca4

Please sign in to comment.