Skip to content

Commit

Permalink
Merge pull request #821 from SeaQL/sea-query-derive
Browse files Browse the repository at this point in the history
Continue #769
  • Loading branch information
tyt2y3 authored Sep 28, 2024
2 parents 6937748 + 0a6be65 commit 60a18c9
Show file tree
Hide file tree
Showing 30 changed files with 482 additions and 178 deletions.
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ path = "src/lib.rs"

[dependencies]
inherent = "1.0"
sea-query-attr = { version = "0.1.1", path = "sea-query-attr", default-features = false, optional = true }
sea-query-derive = { version = "0.4.0", path = "sea-query-derive", default-features = false, optional = true }
serde_json = { version = "1", default-features = false, optional = true, features = ["std"] }
educe = { version = "=0.5.11", default-features = false, optional = true, features = ["Hash", "PartialEq", "Eq"] }
Expand All @@ -56,7 +55,7 @@ backend-postgres = []
backend-sqlite = []
default = ["derive", "backend-mysql", "backend-postgres", "backend-sqlite"]
derive = ["sea-query-derive"]
attr = ["sea-query-attr"]
attr = []
hashable-value = ["educe", "ordered-float"]
postgres-array = []
postgres-vector = ["pgvector"]
Expand Down
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ SeaQuery is very lightweight, all dependencies are optional (except `inherent`).

### Feature flags

Macro: `derive` `attr`
Macro: `derive`

Async support: `thread-safe` (use `Arc` inplace of `Rc`)

Expand Down Expand Up @@ -175,10 +175,9 @@ impl Iden for Character {
```

If you're okay with running another procedural macro, you can activate
the `derive` or `attr` feature on the crate to save you some boilerplate.
the `derive` feature on the crate to save you some boilerplate.
For more usage information, look at
[the derive examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-derive/tests/pass)
or [the attribute examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-attr/tests/pass).
[the derive examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-derive/tests/pass).

```rust
#[cfg(feature = "derive")]
Expand All @@ -198,7 +197,7 @@ assert_eq!(Glyph.to_string(), "glyph");
```

```rust
#[cfg(feature = "attr")]
#[cfg(feature = "derive")]
use sea_query::{enum_def, Iden};

#[enum_def]
Expand Down Expand Up @@ -248,7 +247,7 @@ assert_eq!(
r#"SELECT "character" FROM "character""#,
r#"WHERE ("size_w" + 1) * 2 = ("size_h" / 2) - 1"#,
r#"AND "size_w" IN (SELECT ln(2.4 ^ 1.2))"#,
r#"AND (("character" LIKE 'D') AND ("character" LIKE 'E'))"#,
r#"AND ("character" LIKE 'D' AND "character" LIKE 'E')"#,
]
.join(" ")
);
Expand Down Expand Up @@ -558,7 +557,7 @@ assert_eq!(
r#"CREATE TABLE IF NOT EXISTS "character" ("#,
r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
r#""font_size" integer NOT NULL,"#,
r#""character" text NOT NULL,"#,
r#""character" varchar NOT NULL,"#,
r#""size_w" integer NOT NULL,"#,
r#""size_h" integer NOT NULL,"#,
r#""font_id" integer DEFAULT NULL,"#,
Expand Down
10 changes: 7 additions & 3 deletions sea-query-attr/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[workspace]
# A separate workspace

[package]
name = "sea-query-attr"
version = "0.1.2"
Expand All @@ -15,10 +18,11 @@ rust-version = "1.60"
proc-macro = true

[dependencies]
syn = { version = "1", default-features = false }
proc-macro2 = { version = "1", default-features = false }
syn = { version = "2", default-features = false }
quote = { version = "1", default-features = false }
heck = { version = "0.4", default-features = false }
darling = { version = "0.14", default-features = false }
heck = { version = "0.5", default-features = false }
darling = { version = "0.20", default-features = false }

[dev-dependencies]
trybuild = "1.0"
Expand Down
54 changes: 35 additions & 19 deletions sea-query-attr/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#![allow(clippy::manual_unwrap_or_default)]

use darling::FromMeta;
use darling::{ast::NestedMeta, FromMeta};
use heck::{ToPascalCase, ToSnakeCase};
use proc_macro::TokenStream;
use syn::{
parse_macro_input, spanned::Spanned, AttributeArgs, Data, DataStruct, DeriveInput, Fields,
Ident,
parse_macro_input, punctuated::Punctuated, spanned::Spanned, Data, DataStruct, DeriveInput,
Fields, Ident,
};

type AttributeArgs = Punctuated<NestedMeta, syn::Token![,]>;

struct NamingHolder {
pub default: Ident,
pub pascal: Ident,
Expand Down Expand Up @@ -40,35 +40,51 @@ impl Default for GenEnumArgs {
}
}

#[deprecated(
since = "0.1.2",
note = "use #[enum_def] attr defined in `sea-query-derive` crate"
)]
#[proc_macro_attribute]
pub fn enum_def(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as AttributeArgs);
let args = parse_macro_input!(args with AttributeArgs::parse_terminated);
let input = parse_macro_input!(input as DeriveInput);
let args = GenEnumArgs::from_list(&args).unwrap_or_default();

expand(args, input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}

fn expand(attr_args: AttributeArgs, input: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
let attr_args = attr_args.into_iter().collect::<Vec<_>>();
let args = GenEnumArgs::from_list(&attr_args)?;
let fields = match &input.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("#[enum_def] can only be used on structs"),
_ => {
return Err(syn::Error::new(
input.span(),
"#[enum_def] can only be used on structs",
))
}
};

let field_names: Vec<NamingHolder> = fields
let field_names = fields
.iter()
.map(|field| {
let ident = &field.ident;
let string = ident
.as_ref()
.expect("#[enum_def] can only be used on structs with named fields")
.to_string();
let ident = field.ident.as_ref().ok_or(syn::Error::new(
field.span(),
"#[enum_def] can only be used on structs with named fields",
))?;
let string = ident.to_string();
let as_pascal = string.to_pascal_case();
NamingHolder {
default: ident.as_ref().unwrap().clone(),
syn::Result::Ok(NamingHolder {
default: ident.clone(),
pascal: Ident::new(as_pascal.as_str(), ident.span()),
}
})
})
.collect();
.collect::<syn::Result<Vec<NamingHolder>>>()?;

let table_name = Ident::new(
args.table_name
Expand All @@ -93,7 +109,7 @@ pub fn enum_def(args: TokenStream, input: TokenStream) -> TokenStream {
input.span(),
);

TokenStream::from(quote::quote! {
Ok(quote::quote! {
#input

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down
8 changes: 8 additions & 0 deletions sea-query-attr/tests/compile-fail/enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use sea_query_attr::enum_def;

#[enum_def]
enum Hello {
Name,
}

fn main() {}
13 changes: 13 additions & 0 deletions sea-query-attr/tests/compile-fail/enum.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: #[enum_def] can only be used on structs
--> tests/compile-fail/enum.rs:4:1
|
4 | enum Hello {
| ^^^^

warning: use of deprecated macro `enum_def`: use #[enum_def] attr defined in `sea-query-derive` crate
--> tests/compile-fail/enum.rs:3:3
|
3 | #[enum_def]
| ^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
6 changes: 6 additions & 0 deletions sea-query-attr/tests/compile-fail/tuple_struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use sea_query_attr::enum_def;

#[enum_def]
struct Hello(String);

fn main() {}
13 changes: 13 additions & 0 deletions sea-query-attr/tests/compile-fail/tuple_struct.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: #[enum_def] can only be used on structs
--> tests/compile-fail/tuple_struct.rs:4:1
|
4 | struct Hello(String);
| ^^^^^^

warning: use of deprecated macro `enum_def`: use #[enum_def] attr defined in `sea-query-derive` crate
--> tests/compile-fail/tuple_struct.rs:3:3
|
3 | #[enum_def]
| ^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
8 changes: 8 additions & 0 deletions sea-query-attr/tests/compile-fail/unknown_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use sea_query_attr::enum_def;

#[enum_def(unknown_field)]
pub struct Hello {
pub name: String,
}

fn main() {}
13 changes: 13 additions & 0 deletions sea-query-attr/tests/compile-fail/unknown_field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: Unknown field: `unknown_field`
--> tests/compile-fail/unknown_field.rs:3:12
|
3 | #[enum_def(unknown_field)]
| ^^^^^^^^^^^^^

warning: use of deprecated macro `enum_def`: use #[enum_def] attr defined in `sea-query-derive` crate
--> tests/compile-fail/unknown_field.rs:3:3
|
3 | #[enum_def(unknown_field)]
| ^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
2 changes: 1 addition & 1 deletion sea-query-attr/tests/test_build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[test]
fn build_tests() {
let t = trybuild::TestCases::new();
//t.compile_fail("./tests/compile-fail/*.rs");
t.compile_fail("./tests/compile-fail/*.rs");

// all of these are exactly the same as the examples in `examples/derive.rs`
t.pass("./tests/pass/*.rs");
Expand Down
1 change: 1 addition & 0 deletions sea-query-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ proc-macro = true
syn = { version = "2", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
quote = { version = "1", default-features = false }
heck = { version = "0.4", default-features = false }
darling = { version = "0.20", default-features = false }
proc-macro2 = { version = "1", default-features = false }
thiserror = { version = "1.0", default-features = false }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::convert::{TryFrom, TryInto};
use syn::spanned::Spanned;
use syn::{Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta};

use crate::{error::ErrorMsg, iden_path::IdenPath};
use super::{error::ErrorMsg, path::IdenPath};

#[derive(PartialEq, Eq)]
pub(crate) enum IdenAttr {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use syn::Ident;

use crate::iden_path::IdenPath;
use super::path::IdenPath;

#[derive(Debug, thiserror::Error)]
pub enum ErrorMsg {
Expand Down
34 changes: 34 additions & 0 deletions sea-query-derive/src/iden/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
pub(crate) mod attr;
pub(crate) mod error;
pub(crate) mod path;
pub(crate) mod write_arm;

use proc_macro2::TokenStream;
use quote::quote;
use syn::Ident;

use self::write_arm::WriteArm;

pub(crate) struct DeriveIden;

impl WriteArm for DeriveIden {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => write!(s, "{}", #name).unwrap() }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.unquoted(s) }
}
}

pub(crate) struct DeriveIdenStatic;

impl WriteArm for DeriveIdenStatic {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => #name }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.as_str() }
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,13 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{Error, Fields, FieldsNamed, Ident, Variant};

use crate::{error::ErrorMsg, find_attr, iden_attr::IdenAttr, must_be_valid_iden};
use super::{attr::IdenAttr, error::ErrorMsg};
use crate::{find_attr, must_be_valid_iden};

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

pub(crate) struct DeriveIden;

impl WriteArm for DeriveIden {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => write!(s, "{}", #name).unwrap() }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.unquoted(s) }
}
}

pub(crate) struct DeriveIdenStatic;

impl WriteArm for DeriveIdenStatic {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => #name }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.as_str() }
}
}

pub(crate) struct IdenVariant<'a, T> {
ident: &'a Ident,
fields: &'a Fields,
Expand Down Expand Up @@ -183,7 +159,7 @@ where
T::variant(variant, name)
}

pub(super) fn must_be_valid_iden(&self) -> bool {
pub(crate) fn must_be_valid_iden(&self) -> bool {
let name: String = match &self.attr {
Some(a) => match a {
IdenAttr::Rename(name) => name.to_owned(),
Expand Down
Loading

0 comments on commit 60a18c9

Please sign in to comment.