Escape rust keywords with r# raw identifier

This commit is contained in:
Billy Chan 2021-10-04 23:30:20 +08:00
parent 632290469b
commit 19a572b721
No known key found for this signature in database
GPG Key ID: A2D690CAC7DF3CC7
6 changed files with 134 additions and 14 deletions

View File

@ -1,4 +1,4 @@
use crate::util::field_not_ignored; use crate::util::{escape_rust_keyword, field_not_ignored, trim_starting_raw_identifier};
use heck::CamelCase; use heck::CamelCase;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned};
@ -29,10 +29,10 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<Token
.clone() .clone()
.into_iter() .into_iter()
.map(|field| { .map(|field| {
let mut ident = format_ident!( let ident = field.ident.as_ref().unwrap().to_string();
"{}", let ident = trim_starting_raw_identifier(ident).to_camel_case();
field.ident.as_ref().unwrap().to_string().to_camel_case() let ident = escape_rust_keyword(ident);
); let mut ident = format_ident!("{}", &ident);
for attr in field.attrs.iter() { for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" { if ident != "sea_orm" {

View File

@ -1,3 +1,5 @@
use crate::util::{escape_rust_keyword, trim_starting_raw_identifier};
use convert_case::{Case, Casing};
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::quote; use quote::quote;
use syn::{ use syn::{
@ -5,8 +7,6 @@ use syn::{
Lit, Meta, Lit, Meta,
}; };
use convert_case::{Case, Casing};
pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Result<TokenStream> { pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Result<TokenStream> {
// if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct // if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct
let mut table_name = None; let mut table_name = None;
@ -60,8 +60,10 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
if let Fields::Named(fields) = item_struct.fields { if let Fields::Named(fields) = item_struct.fields {
for field in fields.named { for field in fields.named {
if let Some(ident) = &field.ident { if let Some(ident) = &field.ident {
let mut field_name = let mut field_name = Ident::new(
Ident::new(&ident.to_string().to_case(Case::Pascal), Span::call_site()); &trim_starting_raw_identifier(&ident).to_case(Case::Pascal),
Span::call_site(),
);
let mut nullable = false; let mut nullable = false;
let mut default_value = None; let mut default_value = None;
@ -168,6 +170,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
field_name = enum_name; field_name = enum_name;
} }
field_name = Ident::new(&escape_rust_keyword(field_name), Span::call_site());
if ignore { if ignore {
continue; continue;
} else { } else {

View File

@ -1,4 +1,7 @@
use crate::{attributes::derive_attr, util::field_not_ignored}; use crate::{
attributes::derive_attr,
util::{escape_rust_keyword, field_not_ignored, trim_starting_raw_identifier},
};
use heck::CamelCase; use heck::CamelCase;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned};
@ -43,10 +46,10 @@ impl DeriveModel {
let column_idents = fields let column_idents = fields
.iter() .iter()
.map(|field| { .map(|field| {
let mut ident = format_ident!( let ident = field.ident.as_ref().unwrap().to_string();
"{}", let ident = trim_starting_raw_identifier(ident).to_camel_case();
field.ident.as_ref().unwrap().to_string().to_camel_case() let ident = escape_rust_keyword(ident);
); let mut ident = format_ident!("{}", &ident);
for attr in field.attrs.iter() { for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" { if ident != "sea_orm" {

View File

@ -24,3 +24,43 @@ pub(crate) fn field_not_ignored(field: &Field) -> bool {
} }
true true
} }
pub(crate) fn trim_starting_raw_identifier<T>(string: T) -> String
where
T: ToString,
{
string
.to_string()
.trim_start_matches(RAW_IDENTIFIER)
.to_string()
}
pub(crate) fn escape_rust_keyword<T>(string: T) -> String
where
T: ToString,
{
let string = string.to_string();
if is_rust_keyword(&string) {
format!("r#{}", string)
} else {
string
}
}
pub(crate) fn is_rust_keyword<T>(string: T) -> bool
where
T: ToString,
{
let string = string.to_string();
RUST_KEYWORDS.iter().any(|s| s.eq(&string))
}
pub(crate) const RAW_IDENTIFIER: &str = "r#";
pub(crate) const RUST_KEYWORDS: [&str; 52] = [
"as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
"false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub",
"ref", "return", "Self", "self", "static", "struct", "super", "trait", "true", "type", "union",
"unsafe", "use", "where", "while", "abstract", "become", "box", "do", "final", "macro",
"override", "priv", "try", "typeof", "unsized", "virtual", "yield",
];

View File

@ -7,6 +7,7 @@ pub mod cake_filling_price;
pub mod entity_linked; pub mod entity_linked;
pub mod filling; pub mod filling;
pub mod fruit; pub mod fruit;
pub mod rust_keyword;
pub mod vendor; pub mod vendor;
pub use cake::Entity as Cake; pub use cake::Entity as Cake;
@ -15,4 +16,5 @@ pub use cake_filling::Entity as CakeFilling;
pub use cake_filling_price::Entity as CakeFillingPrice; pub use cake_filling_price::Entity as CakeFillingPrice;
pub use filling::Entity as Filling; pub use filling::Entity as Filling;
pub use fruit::Entity as Fruit; pub use fruit::Entity as Fruit;
pub use rust_keyword::Entity as RustKeyword;
pub use vendor::Entity as Vendor; pub use vendor::Entity as Vendor;

View File

@ -0,0 +1,71 @@
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "rust_keyword")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub testing: i32,
pub rust: i32,
pub keywords: i32,
pub r#as: i32,
pub r#async: i32,
pub r#await: i32,
pub r#break: i32,
pub r#const: i32,
pub r#continue: i32,
pub r#dyn: i32,
pub r#else: i32,
pub r#enum: i32,
pub r#extern: i32,
pub r#false: i32,
pub r#fn: i32,
pub r#for: i32,
pub r#if: i32,
pub r#impl: i32,
pub r#in: i32,
pub r#let: i32,
pub r#loop: i32,
pub r#match: i32,
pub r#mod: i32,
pub r#move: i32,
pub r#mut: i32,
pub r#pub: i32,
pub r#ref: i32,
pub r#return: i32,
pub r#static: i32,
pub r#struct: i32,
pub r#trait: i32,
pub r#true: i32,
pub r#type: i32,
pub r#union: i32,
pub r#unsafe: i32,
pub r#use: i32,
pub r#where: i32,
pub r#while: i32,
pub r#abstract: i32,
pub r#become: i32,
pub r#box: i32,
pub r#do: i32,
pub r#final: i32,
pub r#macro: i32,
pub r#override: i32,
pub r#priv: i32,
pub r#try: i32,
pub r#typeof: i32,
pub r#unsized: i32,
pub r#virtual: i32,
pub r#yield: i32,
}
#[derive(Debug, EnumIter)]
pub enum Relation {}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
unreachable!()
}
}
impl ActiveModelBehavior for ActiveModel {}