Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FromValue and FromRow derive macros #80

Merged
merged 6 commits into from
Mar 4, 2023
Merged
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
4 changes: 3 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
run: cargo fmt -- --check
- name: Features subsets
run: |
ruby -e "fs=['bigdecimal', 'bigdecimal03', 'chrono', 'rust_decimal', 'time', 'time03', 'frunk']; \
ruby -e "fs=['bigdecimal', 'bigdecimal03', 'chrono', 'rust_decimal', 'time', 'time03', 'frunk', 'derive']; \
(1..fs.length).each do |n| puts fs.combination(n).to_a.map {|x| x.join(\" \")}.join(\"\n\"); end" \
| while read -r line; do \
echo "$line" && cargo check --quiet --tests --no-default-features --features "flate2/zlib test $line"; \
Expand All @@ -30,3 +30,5 @@ jobs:
run: cargo build
- name: Run tests
run: cargo test --features test
- name: Run derive tests
run: (cd derive && cargo test)
52 changes: 38 additions & 14 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[workspace]
members = ["derive"]

[package]
authors = ["blackbeam <[email protected]>"]
name = "mysql_common"
Expand All @@ -12,9 +15,14 @@ categories = ["database"]
# * Invoke `cargo readme > README.md` if relevant!
version = "0.29.2"


edition = "2018"
exclude = ["/lib", "/proptest-regressions", "/test-data", "/wrapper.cc", "/wrapper.hh"]
exclude = [
"/lib",
"/proptest-regressions",
"/test-data",
"/wrapper.cc",
"/wrapper.hh",
]

[badges]
travis-ci = { repository = "blackbeam/rust_mysql_common" }
Expand Down Expand Up @@ -42,18 +50,26 @@ sha1 = "0.10.0"
sha2 = "0.10.0"
smallvec = { version = "1.6.1", features = ["union", "write"] }
thiserror = "1.0.24"
time = { version = "0.2", default-features = false, features = ["std"], optional = true }
time03 = { package = "time", version = "0.3", default-features = false, features = ["parsing"], optional = true }
uuid = "1"
time = { version = "0.2", default-features = false, features = [
"std",
], optional = true }
time03 = { package = "time", version = "0.3", default-features = false, features = [
"parsing",
], optional = true }
uuid = { version = "1" }
saturating = "0.1"
serde = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"

mysql-common-derive = { path = "derive", optional = true }

[dev-dependencies]
proptest = "1.0"

[build-dependencies]
bindgen = { version = "0.59.2", default-features = false, features = ["runtime"] }
bindgen = { version = "0.59.2", default-features = false, features = [
"runtime",
] }
cc = "1.0.54"
cmake = "0.1.44"
subprocess = "0.2.4"
Expand All @@ -62,12 +78,20 @@ subprocess = "0.2.4"
debug = true

[features]
default = [
"flate2/zlib",
"bigdecimal03",
"rust_decimal",
default = ["flate2/zlib", "bigdecimal03", "rust_decimal", "time03", "frunk"]
test = ["derive"]
derive = ["mysql-common-derive"]
nightly = ["test"]

[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
no-default-features = true
features = [
"time",
"time03",
"frunk",
"rust_decimal",
"chrono",
"bigdecimal03",
"bigdecimal",
"derive",
]
test = []
nightly = ["test"]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ Also crate provides from-row convertion for the following list of types (see `Fr
| `time03` | Enables `time` v0.3.x types support | 🟢 |
| `uuid` | Enables `Uuid` type support | 🟢 |
| `frunk` | Enables `FromRow` for `frunk::Hlist!` types | 🟢 |
| `derive` | Enables [`FromValue` derive macro][2] | 🔴 |

[1]: https://dev.mysql.com/doc/internals/en/binary-protocol-value.html
[2]: https://docs.rs/mysql-common-derive

## License

Expand Down
25 changes: 25 additions & 0 deletions derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "mysql-common-derive"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true
bench = false

[dependencies]
darling = "0.14.1"
heck = "0.4.0"
num-bigint = "0.4.3"
proc-macro-crate = "1.2.1"
proc-macro-error = "1"
proc-macro2 = "1.0.42"
quote = "1.0.9"
syn = { version = "1.0.74", features = ["full"] }
termcolor = "1.1.3"
thiserror = "1"

[dev-dependencies]
mysql_common = { path = "..", features = ["derive"] }
serde = { version = "1.0.93", features = ["derive"] }
serde_json = "1.0.93"
Empty file added derive/README.md
Empty file.
72 changes: 72 additions & 0 deletions derive/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use proc_macro2::Span;
use proc_macro_error::{Diagnostic, Level};

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("expected a struct with a single unnamed field")]
NotANewTypeStruct(Span),
#[error("structs with named fields are not supported")]
NamedFieldsNotSupported(Span),
#[error("unit structs are not supported")]
UnitStructsNotSupported(Span),
#[error("structs with unnamed fields are not supported")]
StructsWithUnnamedFieldsNotSupported(Span),
#[error("unions are not supported")]
UnionsNotSupported(Span),
#[error("enums are not supported")]
EnumsNotSupported(Span),
#[error("non-unit variants are not supported")]
NonUnitVariant(Span),
#[error("unsupported discriminant")]
UnsupportedDiscriminant(Span),
#[error("add #[mysql(explicit_invalid)] attribute to allow")]
ExplicitInvalid(Span),
#[error("no suitable crate found, use #[mysql(crate = \"..\")] to specify the crate name")]
NoCrateNameFound,
#[error("multiple crates found, use #[mysql(crate = \"..\")] to specify the particular name")]
MultipleCratesFound,
#[error(transparent)]
Syn(#[from] syn::Error),
#[error(transparent)]
Darling(#[from] darling::error::Error),
#[error("conflicting attributes")]
ConflictingsAttributes(Span, Span),
#[error("representation won't fit into MySql integer")]
UnsupportedRepresentation(Span),
#[error("this attribute requires `{}` attribute", 0)]
AttributeRequired(Span, &'static str),
}

impl From<Error> for Diagnostic {
fn from(x: Error) -> Diagnostic {
match x {
Error::UnionsNotSupported(span)
| Error::EnumsNotSupported(span)
| Error::NonUnitVariant(span)
| Error::UnsupportedDiscriminant(span)
| Error::ExplicitInvalid(span)
| Error::NotANewTypeStruct(span)
| Error::NamedFieldsNotSupported(span)
| Error::UnitStructsNotSupported(span)
| Error::UnsupportedRepresentation(span)
| Error::StructsWithUnnamedFieldsNotSupported(span) => {
Diagnostic::spanned(span, Level::Error, format!("FromValue: {x}"))
}
Error::Syn(ref e) => {
Diagnostic::spanned(e.span(), Level::Error, format!("FromValue: {x}"))
}
Error::Darling(ref e) => {
Diagnostic::spanned(e.span(), Level::Error, format!("FromValue: {x}"))
}
Error::NoCrateNameFound => Diagnostic::new(Level::Error, format!("FromValue: {x}")),
Error::MultipleCratesFound => Diagnostic::new(Level::Error, format!("FromValue: {x}")),
Error::ConflictingsAttributes(s1, s2) => {
Diagnostic::spanned(s1, Level::Error, format!("FromValue: {x}"))
.span_error(s2, "conflicting attribute".into())
}
Error::AttributeRequired(s, _) => {
Diagnostic::spanned(s, Level::Error, format!("FromValue: {x}"))
}
}
}
}
16 changes: 16 additions & 0 deletions derive/src/from_row/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use proc_macro2::TokenStream;

mod structs;

pub fn impl_from_row(input: &syn::DeriveInput) -> crate::Result<TokenStream> {
match input.data {
syn::Data::Struct(ref data_struct) => structs::impl_from_row_for_struct(
&input.attrs,
&input.ident,
&input.generics,
data_struct,
),
syn::Data::Enum(_) => Err(crate::Error::EnumsNotSupported(input.ident.span())),
syn::Data::Union(_) => Err(crate::Error::UnionsNotSupported(input.ident.span())),
}
}
18 changes: 18 additions & 0 deletions derive/src/from_row/structs/attrs/container.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use darling::{util::SpannedValue, FromMeta};

use crate::from_value::{
enums::attrs::container::{Crate, RenameAll},
structs::attrs::container::Bound,
};

#[derive(Default, FromMeta)]
pub struct Mysql {
#[darling(default)]
pub crate_name: Crate,
#[darling(default)]
pub rename_all: Option<RenameAll>,
#[darling(default)]
pub table_name: Option<SpannedValue<String>>,
#[darling(default)]
pub bound: Option<Bound>,
}
9 changes: 9 additions & 0 deletions derive/src/from_row/structs/attrs/field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use darling::FromMeta;

#[derive(Debug, Default, FromMeta)]
pub struct Mysql {
#[darling(default)]
pub json: bool,
#[darling(default)]
pub rename: Option<String>,
}
2 changes: 2 additions & 0 deletions derive/src/from_row/structs/attrs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod container;
pub mod field;
Loading