Repository: sfackler/rust-postgres (rust)

Issue:
`"__r#type"` is not a valid identifier
I currently have to work with the raw identifier `r#type`, as one database table is using this. I can't change this name, as i'm merely reading out the data from a pre-existing format.

However, when i try to put in a struct format, like so;

```rs
#[derive(Debug, ToSql, FromSql)]
struct DeviceInboxMessageFormat {
    pub messages: Json<HashMap<UserId, HashMap<DeviceId, Value>>>,
    pub sender: UserId,
    pub r#type: String,
}
```

The proc-macro panics on;

```
error: proc-macro derive panicked
  --> adapters/synapse/src/extract.rs:83:24
   |
83 | #[derive(Debug, ToSql, FromSql)]
   |                        ^^^^^^^
   |
   = help: message: `"__r#type"` is not a valid identifier
```

I think this problem will be the same across all raw identifiers.

Pull request:
Fix handling of raw ident fields in derive
Closes #839

Patch:
diff --git a/postgres-derive/src/composites.rs b/postgres-derive/src/composites.rs
index f5599d37..c1e49515 100644
--- a/postgres-derive/src/composites.rs
+++ b/postgres-derive/src/composites.rs
@@ -14,7 +14,13 @@ impl Field {
 
         let ident = raw.ident.as_ref().unwrap().clone();
         Ok(Field {
-            name: overrides.name.unwrap_or_else(|| ident.to_string()),
+            name: overrides.name.unwrap_or_else(|| {
+                let name = ident.to_string();
+                match name.strip_prefix("r#") {
+                    Some(name) => name.to_string(),
+                    None => name,
+                }
+            }),
             ident,
             type_: raw.ty.clone(),
         })
diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs
index e1ab6ffa..3a59d622 100644
--- a/postgres-derive/src/fromsql.rs
+++ b/postgres-derive/src/fromsql.rs
@@ -1,5 +1,5 @@
-use proc_macro2::{Span, TokenStream};
-use quote::quote;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
 use std::iter;
 use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident};
 
@@ -119,7 +119,7 @@ fn domain_body(ident: &Ident, field: &syn::Field) -> TokenStream {
 fn composite_body(ident: &Ident, fields: &[Field]) -> TokenStream {
     let temp_vars = &fields
         .iter()
-        .map(|f| Ident::new(&format!("__{}", f.ident), Span::call_site()))
+        .map(|f| format_ident!("__{}", f.ident))
         .collect::<Vec<_>>();
     let field_names = &fields.iter().map(|f| &f.name).collect::<Vec<_>>();
     let field_idents = &fields.iter().map(|f| &f.ident).collect::<Vec<_>>();


Test patch:
diff --git a/postgres-derive-test/src/composites.rs b/postgres-derive-test/src/composites.rs
index 5efd3944..ed60bf48 100644
--- a/postgres-derive-test/src/composites.rs
+++ b/postgres-derive-test/src/composites.rs
@@ -215,3 +215,26 @@ fn wrong_type() {
         .unwrap_err();
     assert!(err.source().unwrap().is::<WrongType>());
 }
+
+#[test]
+fn raw_ident_field() {
+    #[derive(FromSql, ToSql, Debug, PartialEq)]
+    #[postgres(name = "inventory_item")]
+    struct InventoryItem {
+        r#type: String,
+    }
+
+    let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap();
+    conn.batch_execute(
+        "CREATE TYPE pg_temp.inventory_item AS (
+            type TEXT
+        )",
+    )
+    .unwrap();
+
+    let item = InventoryItem {
+        r#type: "foo".to_owned(),
+    };
+
+    test_type(&mut conn, "inventory_item", &[(item, "ROW('foo')")]);
+}