diff --git a/ormx-macros/src/backend/common/mod.rs b/ormx-macros/src/backend/common/mod.rs index 2663562..da8d2e8 100644 --- a/ormx-macros/src/backend/common/mod.rs +++ b/ormx-macros/src/backend/common/mod.rs @@ -23,7 +23,7 @@ pub(crate) fn getters(table: &Table) -> TokenStream { let sql = format!( "SELECT {} FROM {} WHERE {} = {}", column_list, - table.table, + table.name(), field.column(), B::Bindings::default().next().unwrap() ); @@ -103,7 +103,7 @@ pub fn setters(table: &Table) -> TokenStream { let mut bindings = B::Bindings::default(); let sql = format!( "UPDATE {} SET {} = {} WHERE {} = {}", - table.table, + table.name(), field.column(), bindings.next().unwrap(), table.id.column(), @@ -141,7 +141,7 @@ pub fn setters(table: &Table) -> TokenStream { } } -pub(crate) fn impl_patch(patch: &Patch) -> TokenStream { +pub(crate) fn impl_patch(patch: &Patch) -> TokenStream { let patch_ident = &patch.ident; let table_path = &patch.table; let field_idents = &patch @@ -165,7 +165,7 @@ pub(crate) fn impl_patch(patch: &Patch) -> TokenStream { let sql = format!( "UPDATE {} SET {} WHERE {} = {}", - &patch.table_name, + &patch.table_name(), assignments, patch.id, bindings.next().unwrap() diff --git a/ormx-macros/src/backend/common/table.rs b/ormx-macros/src/backend/common/table.rs index 60afdf4..8c7a997 100644 --- a/ormx-macros/src/backend/common/table.rs +++ b/ormx-macros/src/backend/common/table.rs @@ -51,7 +51,7 @@ fn get(table: &Table, column_list: &str) -> TokenStream { let get_sql = format!( "SELECT {} FROM {} WHERE {} = {}", column_list, - table.table, + table.name(), table.id.column(), B::Bindings::default().next().unwrap() ); @@ -82,7 +82,7 @@ fn update(table: &Table) -> TokenStream { let update_sql = format!( "UPDATE {} SET {} WHERE {} = {}", - table.table, + table.name(), assignments, table.id.column(), bindings.next().unwrap() @@ -107,7 +107,7 @@ fn update(table: &Table) -> TokenStream { fn stream_all(table: &Table, column_list: &str) -> TokenStream { let box_stream = crate::utils::box_stream(); - let all_sql = format!("SELECT {} FROM {}", column_list, table.table); + let all_sql = format!("SELECT {} FROM {}", column_list, table.name()); quote! { fn stream_all<'a, 'c: 'a>( @@ -125,7 +125,7 @@ fn stream_all_paginated(table: &Table, column_list: &str) -> Toke let all_sql = format!( "SELECT {} FROM {} LIMIT {} OFFSET {}", column_list, - table.table, + table.name(), bindings.next().unwrap(), bindings.next().unwrap() ); @@ -147,7 +147,7 @@ fn delete(table: &Table) -> TokenStream { let id_ty = &table.id.ty; let delete_sql = format!( "DELETE FROM {} WHERE {} = {}", - table.table, + table.name(), table.id.column(), B::Bindings::default().next().unwrap() ); diff --git a/ormx-macros/src/backend/mod.rs b/ormx-macros/src/backend/mod.rs index 37b4592..561c56c 100644 --- a/ormx-macros/src/backend/mod.rs +++ b/ormx-macros/src/backend/mod.rs @@ -53,7 +53,7 @@ pub trait Backend: Sized + Clone { } /// Implement [Patch] - fn impl_patch(patch: &Patch) -> TokenStream { + fn impl_patch(patch: &Patch) -> TokenStream { common::impl_patch::(patch) } } diff --git a/ormx-macros/src/backend/mysql/insert.rs b/ormx-macros/src/backend/mysql/insert.rs index ca660f1..e7cf20a 100644 --- a/ormx-macros/src/backend/mysql/insert.rs +++ b/ormx-macros/src/backend/mysql/insert.rs @@ -79,7 +79,7 @@ fn query_default(table: &Table) -> TokenStream { let query_default_sql = format!( "SELECT {} FROM {} WHERE {} = ?", default_fields.map(TableField::fmt_for_select).join(", "), - table.table, + table.name(), table.id.column() ); @@ -97,7 +97,7 @@ fn insert(table: &Table) -> TokenStream { let insert_sql = format!( "INSERT INTO {} ({}) VALUES ({})", - table.table, + table.name(), insert_fields.iter().map(|field| field.column()).join(", "), MySqlBindings.take(insert_fields.len()).join(", ") ); diff --git a/ormx-macros/src/backend/postgres/insert.rs b/ormx-macros/src/backend/postgres/insert.rs index 551cac9..c4fc9f4 100644 --- a/ormx-macros/src/backend/postgres/insert.rs +++ b/ormx-macros/src/backend/postgres/insert.rs @@ -19,12 +19,12 @@ fn insert_sql(table: &Table, insert_fields: &[&TableField] if returning_fields.is_empty() { format!( "INSERT INTO {} ({}) VALUES ({})", - table.table, columns, fields + table.name(), columns, fields ) } else { format!( "INSERT INTO {} ({}) VALUES ({}) RETURNING {}", - table.table, columns, fields, returning_fields + table.name(), columns, fields, returning_fields ) } } diff --git a/ormx-macros/src/patch/mod.rs b/ormx-macros/src/patch/mod.rs index 3d2c482..6c8f39a 100644 --- a/ormx-macros/src/patch/mod.rs +++ b/ormx-macros/src/patch/mod.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::{convert::TryFrom, borrow::Cow, marker::PhantomData}; use proc_macro2::TokenStream; use quote::quote; @@ -8,12 +8,14 @@ use crate::backend::{Backend, Implementation}; mod parse; -pub struct Patch { +pub struct Patch { pub ident: Ident, pub table_name: String, + pub reserved_table_name: bool, pub table: Path, pub id: String, pub fields: Vec, + pub _phantom: PhantomData<*const B>, } pub struct PatchField { @@ -24,6 +26,16 @@ pub struct PatchField { pub by_ref: bool, } +impl Patch { + pub fn table_name(&self) -> Cow { + if self.reserved_table_name { + format!("{}{}{}", B::QUOTE, self.table_name, B::QUOTE).into() + } else { + Cow::Borrowed(&self.table_name) + } + } +} + impl PatchField { pub fn fmt_as_argument(&self) -> TokenStream { let ident = &self.ident; diff --git a/ormx-macros/src/patch/parse.rs b/ormx-macros/src/patch/parse.rs index 6a9c85e..c8c5150 100644 --- a/ormx-macros/src/patch/parse.rs +++ b/ormx-macros/src/patch/parse.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::{convert::TryFrom, marker::PhantomData}; use syn::{Data, DeriveInput, Error, Field, Result}; @@ -6,10 +6,10 @@ use super::Patch; use crate::{ attrs::{parse_attrs, PatchAttr, PatchFieldAttr}, patch::PatchField, - utils::{missing_attr, set_once}, + utils::{missing_attr, set_once}, backend::Backend, }; -impl TryFrom<&syn::DeriveInput> for Patch { +impl TryFrom<&syn::DeriveInput> for Patch { type Error = Error; fn try_from(value: &DeriveInput) -> Result { @@ -35,12 +35,17 @@ impl TryFrom<&syn::DeriveInput> for Patch { } } + let table_name = table_name.ok_or_else(|| missing_attr("table_name"))?; + let reserved_table_name = B::RESERVED_IDENTS.contains(&&*table_name.to_string().to_uppercase()); + Ok(Patch { ident: value.ident.clone(), - table_name: table_name.ok_or_else(|| missing_attr("table_name"))?, + table_name, + reserved_table_name, table: table.ok_or_else(|| missing_attr("table"))?, id: id.ok_or_else(|| missing_attr("id"))?, fields, + _phantom: PhantomData, }) } } diff --git a/ormx-macros/src/table/mod.rs b/ormx-macros/src/table/mod.rs index cc64475..16827bc 100644 --- a/ormx-macros/src/table/mod.rs +++ b/ormx-macros/src/table/mod.rs @@ -16,6 +16,7 @@ pub struct Table { pub ident: Ident, pub vis: Visibility, pub table: String, + pub reserved_table_name: bool, pub id: TableField, pub fields: Vec>, pub insertable: Option, @@ -59,6 +60,14 @@ impl Table { .map(|field| field.fmt_for_select()) .join(", ") } + + pub fn name(&self) -> Cow { + if self.reserved_table_name { + format!("{}{}{}", B::QUOTE, self.table, B::QUOTE).into() + } else { + Cow::Borrowed(&self.table) + } + } } impl TableField { diff --git a/ormx-macros/src/table/parse.rs b/ormx-macros/src/table/parse.rs index 4842b28..c5aa49a 100644 --- a/ormx-macros/src/table/parse.rs +++ b/ormx-macros/src/table/parse.rs @@ -124,10 +124,20 @@ impl TryFrom<&syn::DeriveInput> for Table { )); } + let table = table.ok_or_else(|| missing_attr("table"))?; + let reserved_table_name = B::RESERVED_IDENTS.contains(&&*table.to_string().to_uppercase()); + if reserved_table_name { + proc_macro_error::emit_warning!( + Span::call_site(), + "This table name is a reserved keyword, you might want to consider choosing a different name." + ); + } + Ok(Table { ident: value.ident.clone(), vis: value.vis.clone(), - table: table.ok_or_else(|| missing_attr("table"))?, + table, + reserved_table_name, id, insertable, fields,