Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions sea-query-derive/src/enum_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,6 @@ pub fn expand(args: TokenStream, input: TokenStream) -> TokenStream {
}
}

impl #import_name::Iden for #enum_name {
fn unquoted(&self) -> &str {
<Self as #import_name::IdenStatic>::as_str(&self)
}
}

impl ::std::convert::AsRef<str> for #enum_name {
fn as_ref(&self) -> &str {
<Self as #import_name::IdenStatic>::as_str(&self)
Expand Down
8 changes: 0 additions & 8 deletions sea-query-derive/src/iden/iden_static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ pub fn expand(input: DeriveInput) -> TokenStream {
fields: Fields::Unit,
..
}) => {
let impl_iden = impl_iden_for_unit_struct(&ident, &table_name);

return quote! {
#impl_iden

impl #sea_query_path::IdenStatic for #ident {
fn as_str(&self) -> &'static str {
#table_name
Expand All @@ -49,8 +45,6 @@ pub fn expand(input: DeriveInput) -> TokenStream {
return TokenStream::new();
}

let impl_iden = impl_iden_for_enum(&ident, &table_name, variants.iter());

let match_arms = match variants
.iter()
.map(|v| (table_name.as_str(), v))
Expand All @@ -62,8 +56,6 @@ pub fn expand(input: DeriveInput) -> TokenStream {
};

let output = quote! {
#impl_iden

impl #sea_query_path::IdenStatic for #ident {
fn as_str(&self) -> &'static str {
match self {
Expand Down
104 changes: 49 additions & 55 deletions sea-query-derive/src/iden/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,19 @@ pub fn expand(input: DeriveInput) -> TokenStream {
return TokenStream::new();
}

let output = impl_iden_for_enum(&ident, &table_name, variants.iter());
let can_be_static = variants.iter().all(|v| {
let variant = IdenVariant::<DeriveIden>::try_from((table_name.as_str(), v));
match variant {
Ok(v) => v.can_be_static(),
Err(_) => false,
}
});

let output = if can_be_static {
impl_iden_static_for_enum(&ident, &table_name, variants.iter())
} else {
impl_iden_for_enum(&ident, &table_name, variants.iter())
};

output.into()
}
Expand All @@ -57,25 +69,10 @@ fn impl_iden_for_unit_struct(
table_name: &str,
) -> proc_macro2::TokenStream {
let sea_query_path = sea_query_path();

if is_static_iden(table_name) {
quote! {
impl #sea_query_path::Iden for #ident {
fn quoted(&self) -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed(#table_name)
}

fn unquoted(&self) -> &str {
#table_name
}
}
}
} else {
quote! {
impl #sea_query_path::Iden for #ident {
fn unquoted(&self) -> &str {
#table_name
}
quote! {
impl #sea_query_path::IdenStatic for #ident {
fn as_str(&self) -> &'static str {
#table_name
}
}
}
Expand All @@ -91,43 +88,48 @@ where
{
let sea_query_path = sea_query_path();

let mut is_all_static_iden = true;

let match_arms = match variants
.map(|v| {
let v = IdenVariant::<DeriveIden>::try_from((table_name, v))?;
is_all_static_iden &= v.is_static_iden();
Ok(v)
})
.map(|v| IdenVariant::<DeriveIden>::try_from((table_name, v)))
.collect::<syn::Result<Vec<_>>>()
{
Ok(v) => v,
Err(e) => return e.to_compile_error(),
};

if is_all_static_iden {
quote! {
impl #sea_query_path::Iden for #ident {
fn quoted(&self) -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed(match self {
#(#match_arms),*
})
}

fn unquoted(&self) -> &str {
match self {
#(#match_arms),*
}
quote! {
impl #sea_query_path::Iden for #ident {
fn unquoted(&self) -> std::borrow::Cow<'static, str> {
match self {
#(#match_arms),*
}
}
}
} else {
quote! {
impl #sea_query_path::Iden for #ident {
fn unquoted(&self) -> &str {
match self {
#(#match_arms),*
}
}
}

fn impl_iden_static_for_enum<'a, T>(
ident: &proc_macro2::Ident,
table_name: &str,
variants: T,
) -> proc_macro2::TokenStream
where
T: Iterator<Item = &'a Variant>,
{
let sea_query_path = sea_query_path();

let match_arms = match variants
.map(|v| IdenVariant::<DeriveIdenStatic>::try_from((table_name, v)))
.collect::<syn::Result<Vec<_>>>()
{
Ok(v) => v,
Err(e) => return e.to_compile_error(),
};

quote! {
impl #sea_query_path::IdenStatic for #ident {
fn as_str(&self) -> &'static str {
match self {
#(#match_arms),*
}
}
}
Expand Down Expand Up @@ -190,11 +192,3 @@ fn find_attr(attrs: &[Attribute]) -> Option<&Attribute> {
attr.path().is_ident(&IdenPath::Iden) || attr.path().is_ident(&IdenPath::Method)
})
}

pub fn is_static_iden(name: &str) -> bool {
// can only begin with [a-z_]
name.chars()
.take(1)
.all(|c| c == '_' || c.is_ascii_alphabetic())
&& name.chars().all(|c| c == '_' || c.is_ascii_alphanumeric())
}
70 changes: 42 additions & 28 deletions sea-query-derive/src/iden/write_arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,26 @@ use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, TokenStreamExt, quote};
use syn::{Error, Fields, FieldsNamed, Ident, Variant};

use super::{
DeriveIden, DeriveIdenStatic, attr::IdenAttr, error::ErrorMsg, find_attr, is_static_iden,
};
use super::{DeriveIden, DeriveIdenStatic, attr::IdenAttr, error::ErrorMsg, find_attr};

pub(crate) trait WriteArm {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream;
fn renamed_variant(variant: TokenStream, name: &str) -> TokenStream;
fn method_variant(variant: TokenStream, method: &syn::Ident) -> TokenStream;
fn flattened(variant: TokenStream, name: &Ident) -> TokenStream;
}

impl WriteArm for DeriveIden {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => #name }
quote! { Self::#variant => std::borrow::Cow::Borrowed(#name) }
}

fn renamed_variant(variant: TokenStream, name: &str) -> TokenStream {
quote! { Self::#variant => std::borrow::Cow::Owned(#name.to_owned()) }
}

fn method_variant(variant: TokenStream, method: &syn::Ident) -> TokenStream {
quote! { Self::#variant => std::borrow::Cow::Owned(self.#method().to_owned()) }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
Expand All @@ -30,6 +38,14 @@ impl WriteArm for DeriveIdenStatic {
quote! { Self::#variant => #name }
}

fn renamed_variant(variant: TokenStream, name: &str) -> TokenStream {
quote! { Self::#variant => #name }
}

fn method_variant(variant: TokenStream, method: &syn::Ident) -> TokenStream {
quote! { Self::#variant => self.#method() }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.as_str() }
}
Expand Down Expand Up @@ -165,33 +181,31 @@ where
}

fn write_variant_name(&self, variant: TokenStream) -> TokenStream {
let name = self
.attr
.as_ref()
.map(|a| match a {
IdenAttr::Rename(name) => quote! { #name },
IdenAttr::Method(method) => quote! { self.#method() },
IdenAttr::Flatten => unreachable!(),
})
.unwrap_or_else(|| {
match &self.attr {
Some(IdenAttr::Rename(name)) => T::renamed_variant(variant, name),
Some(IdenAttr::Method(method)) => T::method_variant(variant, method),
Some(IdenAttr::Flatten) => unreachable!(),
None => {
let name = self.table_or_snake_case();
quote! { #name }
});

T::variant(variant, name)
T::variant(variant, quote! { #name })
}
}
}

pub(crate) fn is_static_iden(&self) -> bool {
let name: String = match &self.attr {
Some(a) => match a {
IdenAttr::Rename(name) => name.to_owned(),
IdenAttr::Method(_) => return false,
IdenAttr::Flatten => return false,
},
None => self.table_or_snake_case(),
};

is_static_iden(&name)
pub(crate) fn can_be_static(&self) -> bool {
match (&self.fields, &self.attr) {
// Unit variants are always static
(Fields::Unit, None) => true,
(Fields::Unit, Some(IdenAttr::Rename(_))) => true,
// Method variants cannot be static (return &str, not &'static str)
(_, Some(IdenAttr::Method(_))) => false,
// Flattened variants could be static if the inner type is IdenStatic,
// but we can't easily determine that at compile time, so assume they cannot be
(_, Some(IdenAttr::Flatten)) => false,
// Non-unit variants cannot be static
(Fields::Named(_), _) => false,
(Fields::Unnamed(_), _) => false,
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions sea-query-derive/tests/pass/flattened_named.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use sea_query::Iden;
use strum::{EnumIter, IntoEnumIterator};
use std::borrow::Cow;
use strum::{EnumIter, IntoEnumIterator};

#[derive(Copy, Clone, Iden, EnumIter)]
enum Asset {
Expand Down Expand Up @@ -36,6 +36,6 @@ fn main() {
.zip(expected)
.for_each(|(var, exp)| {
assert_eq!(var.to_string(), exp);
assert_eq!(var.quoted(), Cow::Borrowed(exp));
assert_eq!(var.unquoted(), Cow::Borrowed(exp));
})
}
6 changes: 3 additions & 3 deletions sea-query-derive/tests/pass/meta_list_renaming_everything.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use sea_query::{Iden, IntoIden, MysqlQueryBuilder, PostgresQueryBuilder, QuotedBuilder};
use strum::{EnumIter, IntoEnumIterator};
use std::borrow::Cow;
use strum::{EnumIter, IntoEnumIterator};

#[derive(Iden, EnumIter)]
// Outer iden attributes overrides what's used for "Table"...
Expand Down Expand Up @@ -38,7 +38,7 @@ fn main() {
.map(|var| var.to_string())
.zip(expected)
.for_each(|(iden, exp)| assert_eq!(iden, exp));

let mut string = String::new();
PostgresQueryBuilder.prepare_iden(&Custom::Email("".to_owned()).into_iden(), &mut string);
assert_eq!(string, "\"EM`ail\"");
Expand All @@ -47,5 +47,5 @@ fn main() {
MysqlQueryBuilder.prepare_iden(&Custom::Email("".to_owned()).into_iden(), &mut string);
assert_eq!(string, "`EM``ail`");

assert!(matches!(Custom::FirstName.quoted(), Cow::Owned(_)));
assert!(matches!(Custom::FirstName.unquoted(), Cow::Owned(_)));
}
16 changes: 5 additions & 11 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Translating the SQL AST into engine-specific SQL statements.

use crate::*;
use std::borrow::Cow;

#[cfg(feature = "backend-mysql")]
#[cfg_attr(docsrs, doc(cfg(feature = "backend-mysql")))]
Expand Down Expand Up @@ -46,17 +45,12 @@ pub trait QuotedBuilder {
let qq = q.1 as char;

sql.write_char(q.left()).unwrap();
match &iden.0 {
Cow::Borrowed(s) => sql.write_str(s).unwrap(),
Cow::Owned(s) => {
for char in s.chars() {
if char == qq {
sql.write_char(char).unwrap()
}
sql.write_char(char).unwrap()
}
for char in iden.0.chars() {
if char == qq {
sql.write_char(char).unwrap()
}
};
sql.write_char(char).unwrap()
}
sql.write_char(q.right()).unwrap();
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/extension/mysql/column.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::Iden;
use crate::IdenStatic;

#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
Expand All @@ -8,8 +8,8 @@ pub enum MySqlType {
LongBlob,
}

impl Iden for MySqlType {
fn unquoted(&self) -> &str {
impl IdenStatic for MySqlType {
fn as_str(&self) -> &'static str {
match self {
Self::TinyBlob => "tinyblob",
Self::MediumBlob => "mediumblob",
Expand Down
6 changes: 3 additions & 3 deletions src/extension/postgres/ltree.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::Iden;
use crate::{Iden, IdenStatic};

/// PostgreSQL `ltree` extension type.
///
Expand Down Expand Up @@ -50,8 +50,8 @@ use crate::Iden;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PgLTree;

impl Iden for PgLTree {
fn unquoted(&self) -> &str {
impl IdenStatic for PgLTree {
fn as_str(&self) -> &'static str {
"ltree"
}
}
Expand Down
Loading
Loading