Skip to content

Commit

Permalink
Merge pull request #2764 from hi-rustin/rustin-patch-queryable
Browse files Browse the repository at this point in the history
QueryableByName supoort non ident column name
  • Loading branch information
weiznich authored May 10, 2021
2 parents f669046 + ea02c36 commit adec833
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 20 deletions.
2 changes: 1 addition & 1 deletion diesel_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ path = "../diesel_migrations/"
difference = "2.0"
tempfile = "3.1.0"
regex = "1.3.9"
url = { version = "2.1.0" }
url = { version = "2.2.2" }

[features]
default = ["postgres", "sqlite", "mysql"]
Expand Down
2 changes: 1 addition & 1 deletion diesel_cli/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ fn change_database_of_url(database_url: &str, default_database: &str) -> (String
let database = base.path_segments().unwrap().last().unwrap().to_owned();
let mut new_url = base.join(default_database).unwrap();
new_url.set_query(base.query());
(database, new_url.into_string())
(database, new_url.into())
}

#[allow(clippy::needless_pass_by_value)]
Expand Down
6 changes: 3 additions & 3 deletions diesel_derives/src/as_changeset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn derive(item: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Diagno
let fields_for_update = model
.fields()
.iter()
.filter(|f| !model.primary_key_names.contains(&f.column_name()))
.filter(|f| !model.primary_key_names.contains(&f.column_name_ident()))
.collect::<Vec<_>>();
let ref_changeset_ty = fields_for_update.iter().map(|field| {
field_changeset_ty(
Expand Down Expand Up @@ -92,7 +92,7 @@ fn field_changeset_ty(
treat_none_as_null: bool,
lifetime: Option<proc_macro2::TokenStream>,
) -> syn::Type {
let column_name = field.column_name();
let column_name = field.column_name_ident();
if !treat_none_as_null && is_option_ty(&field.ty) {
let field_ty = inner_of_option_ty(&field.ty);
parse_quote!(std::option::Option<diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>>)
Expand All @@ -109,7 +109,7 @@ fn field_changeset_expr(
lifetime: Option<proc_macro2::TokenStream>,
) -> syn::Expr {
let field_access = field.name.access();
let column_name = field.column_name();
let column_name = field.column_name_ident();
if !treat_none_as_null && is_option_ty(&field.ty) {
if lifetime.is_some() {
parse_quote!(self#field_access.as_ref().map(|x| #table_name::#column_name.eq(x)))
Expand Down
32 changes: 27 additions & 5 deletions diesel_derives/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ pub struct Field {
pub span: Span,
pub sql_type: Option<syn::Type>,
pub flags: MetaItem,
column_name_from_attribute: Option<syn::Ident>,
column_name_from_attribute: Option<MetaItem>,
}

impl Field {
pub fn from_struct_field(field: &syn::Field, index: usize) -> Self {
let column_name_from_attribute =
MetaItem::with_name(&field.attrs, "column_name").map(|m| m.expect_ident_value());
let column_name_from_attribute = MetaItem::with_name(&field.attrs, "column_name");
let name = match field.ident.clone() {
Some(mut x) => {
// https://github.com/rust-lang/rust/issues/47983#issuecomment-362817105
Expand Down Expand Up @@ -49,9 +48,10 @@ impl Field {
}
}

pub fn column_name(&self) -> syn::Ident {
pub fn column_name_ident(&self) -> syn::Ident {
self.column_name_from_attribute
.clone()
.as_ref()
.map(|m| m.expect_ident_value())
.unwrap_or_else(|| match self.name {
FieldName::Named(ref x) => x.clone(),
_ => {
Expand All @@ -65,6 +65,28 @@ impl Field {
})
}

pub fn column_name_str(&self) -> String {
self.column_name_from_attribute
.as_ref()
.map(|m| {
m.str_value().unwrap_or_else(|e| {
e.emit();
m.name().segments.first().unwrap().ident.to_string()
})
})
.unwrap_or_else(|| match self.name {
FieldName::Named(ref x) => x.to_string(),
_ => {
self.span
.error(
"All fields of tuple structs must be annotated with `#[column_name]`",
)
.emit();
"unknown_column".to_string()
}
})
}

pub fn has_flag(&self, flag: &str) -> bool {
self.flags.has_flag(flag)
}
Expand Down
8 changes: 4 additions & 4 deletions diesel_derives/src/insertable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ fn field_expr_embed(field: &Field, lifetime: Option<proc_macro2::TokenStream>) -

fn field_ty_serialize_as(field: &Field, table_name: &syn::Path, ty: &syn::Type) -> syn::Type {
let inner_ty = inner_of_option_ty(&ty);
let column_name = field.column_name();
let column_name = field.column_name_ident();

parse_quote!(
std::option::Option<diesel::dsl::Eq<
Expand All @@ -138,7 +138,7 @@ fn field_ty_serialize_as(field: &Field, table_name: &syn::Path, ty: &syn::Type)

fn field_expr_serialize_as(field: &Field, table_name: &syn::Path, ty: &syn::Type) -> syn::Expr {
let field_access = field.name.access();
let column_name = field.column_name();
let column_name = field.column_name_ident();
let column: syn::Expr = parse_quote!(#table_name::#column_name);

if is_option_ty(&ty) {
Expand All @@ -154,7 +154,7 @@ fn field_ty(
lifetime: Option<proc_macro2::TokenStream>,
) -> syn::Type {
let inner_ty = inner_of_option_ty(&field.ty);
let column_name = field.column_name();
let column_name = field.column_name_ident();

parse_quote!(
std::option::Option<diesel::dsl::Eq<
Expand All @@ -170,7 +170,7 @@ fn field_expr(
lifetime: Option<proc_macro2::TokenStream>,
) -> syn::Expr {
let field_access = field.name.access();
let column_name = field.column_name();
let column_name = field.column_name_ident();
let column: syn::Expr = parse_quote!(#table_name::#column_name);
if is_option_ty(&field.ty) {
if lifetime.is_some() {
Expand Down
2 changes: 1 addition & 1 deletion diesel_derives/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Model {
pub fn find_column(&self, column_name: &syn::Ident) -> Result<&Field, Diagnostic> {
self.fields()
.iter()
.find(|f| &f.column_name() == column_name)
.find(|f| &f.column_name_ident() == column_name)
.ok_or_else(|| {
column_name
.span()
Expand Down
6 changes: 3 additions & 3 deletions diesel_derives/src/queryable_by_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ pub fn derive(item: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Diagno
row,
)?))
} else {
let name = f.column_name();
let field_ty = &f.ty;
let deserialize_ty = f.ty_for_deserialize()?;
let name = f.column_name_str();
Ok(quote!(
{
let field = diesel::row::NamedRow::get(row, stringify!(#name))?;
let field = diesel::row::NamedRow::get(row, #name)?;
<#deserialize_ty as Into<#field_ty>>::into(field)
}
))
Expand Down Expand Up @@ -93,12 +93,12 @@ fn get_ident(field: &Field) -> Ident {

fn sql_type(field: &Field, model: &Model) -> syn::Type {
let table_name = model.table_name();
let column_name = field.column_name();

match field.sql_type {
Some(ref st) => st.clone(),
None => {
if model.has_table_name_attribute() {
let column_name = field.column_name_ident();
parse_quote!(diesel::dsl::SqlTypeOf<#table_name::#column_name>)
} else {
let field_name = match field.name {
Expand Down
4 changes: 2 additions & 2 deletions diesel_derives/src/selectable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn field_column_ty(field: &Field, model: &Model) -> Result<syn::Type, Diagnostic
Ok(parse_quote!(<#embed_ty as Selectable<__DB>>::SelectExpression))
} else {
let table_name = model.table_name();
let column_name = field.column_name();
let column_name = field.column_name_ident();
Ok(parse_quote!(#table_name::#column_name))
}
}
Expand All @@ -61,7 +61,7 @@ fn field_column_inst(field: &Field, model: &Model) -> Result<syn::Expr, Diagnost
Ok(parse_quote!(<#embed_ty as Selectable<__DB>>::construct_selection()))
} else {
let table_name = model.table_name();
let column_name = field.column_name();
let column_name = field.column_name_ident();
Ok(parse_quote!(#table_name::#column_name))
}
}
19 changes: 19 additions & 0 deletions diesel_derives/tests/queryable_by_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,25 @@ fn struct_with_no_table() {
assert_eq!(Ok(MyStructNamedSoYouCantInferIt { foo: 1, bar: 2 }), data);
}

#[test]
fn struct_with_non_ident_column_name() {
#[derive(Debug, Clone, PartialEq, Eq, QueryableByName)]
struct QueryPlan {
#[sql_type = "diesel::sql_types::Text"]
#[column_name = "QUERY PLAN"]
qp: String,
}

let conn = connection();
let data = sql_query("SELECT 'some plan' AS \"QUERY PLAN\"").get_result(&conn);
assert_eq!(
Ok(QueryPlan {
qp: "some plan".to_string()
}),
data
);
}

#[test]
fn embedded_struct() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)]
Expand Down

0 comments on commit adec833

Please sign in to comment.