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

Rewrite derive macro implementation #262

Merged
merged 80 commits into from
Sep 29, 2023
Merged

Rewrite derive macro implementation #262

merged 80 commits into from
Sep 29, 2023

Conversation

pintariching
Copy link
Contributor

A proposal on rewriting the derive macro implementation using the darling crate. It massively simplifies the macro. The only two validators I got up an working are the length and email just for show. Also there is no error handling for now.

Also I had to upgrade syn version to 2 as darling would work with version 1.

Copy link
Owner

@Keats Keats left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Veeery nice

min: Option<u64>,
max: Option<u64>,
equal: Option<u64>,
message: Option<String>,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing code as well. It is much nicer and waaaay less code, very nice.

Random thought: is it possible to parse all the attributes into a hashmap rather than a struct? I'm wondering if there would be a way for a user to register functions with validator and use them on the derive as if they were built-in. Maybe it's not worth it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a map attribute for the macro that let's you specify a function to run after parsing the attributes like

#[derive(FromMeta)]
#[darling(map = "to_hashmap")]
struct Custom {
    par_1: Option<Expr>,
    par_2: Option<Expr>,
    par_3: Option<Expr>,
    #[darling(skip)]
    hashmap: HashMap<String, Expr>
}

fn to_hashmap(custom: Custom) -> HashMap<String, Expr> {}

I have to try it out, I'm not sure if this will work

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's only worth it if we have some kind of register of fns, and I'm not sure how to configure where to look that up... Maybe let's not worry about it for now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very well. I'll implement the rest of the macro and get it up and running and possibly passing the tests and then worry about everything else.

@@ -12,7 +12,7 @@ use indexmap::{IndexMap, IndexSet};
/// If you apply it on String, don't forget that the length can be different
/// from the number of visual characters for Unicode
#[must_use]
pub fn validate_length<T: ValidateLength>(
pub fn validate_length<T: ValidateLength<u64>>(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is kind of useless now that there's the trait I think. Also casting the min, max and equal values to u64 might lead to issues when you for example cast a negative i32 to u64. So I thought to add a generic, so that the length and all the parameters have to be the same type to compare them without runtime errors or weird casting issues.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove it then I think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the functions will be used in the macro from the validator crate so they can be removed unless they're used anywhere else?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep they can be removed now that we have traits

@pintariching
Copy link
Contributor Author

I've rewritten the custom validation a bit. If you want arguments for your function you can specify them like:

#[derive(Validate)]
struct TestStruct {
    #[validate(custom(
        function = "valid_reference_with_lifetime",
        arg = "len: i64",
        arg = "something: bool",
        arg = "name: String"
    ))]
    value: String,
}

let test = TestStruct { name: "asdfg".to_string() };
let res = test.validate(TestStructArgs { len: 123, something: false, name: "Something".into() });

Also the TestStructArgs could be given a builder pattern if we wanna be fancy, so you get

TestStructArgs::build().len(123).something(false).name("Something").build()

How does this look? I'm now wrangling with lifetimes so for now you can only pass values and not references. Should I continue with this or go back to tuples like it's now?

@pintariching
Copy link
Contributor Author

The UI tests now pass. I had to put them behind a feature to avoid running them on anything other than stable due to the errors that keep changing and reordering. Also for some reason the error produced by compile-fail::range::wrong_type test was different in the CI and locally, even though both use stable, so I removed it.

Copy link
Owner

@Keats Keats left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit i went a little fast on the review but i left some comments

@@ -58,6 +58,22 @@ impl ValidationErrors {
}
}

pub fn merge_self(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is that? I am thinking we probably also want to maybe re-think the errors interface in another PR to be easier to use/more intuitive

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had some trouble adding errors on nested validations so I whipped up this function. And I agree, the errors API should be redone.

validator/src/validation/regex.rs Outdated Show resolved Hide resolved
validator/src/validation/urls.rs Outdated Show resolved Hide resolved
validator/src/validation/urls.rs Outdated Show resolved Hide resolved
validator_derive/src/tokens/ip.rs Show resolved Hide resolved
@@ -1,5 +1,5 @@
error: Invalid attribute #[validate] on field `s`: unknown argument `eq` for validator `length` (it only has `min`, `max`, `equal`)
--> $DIR/unknown_arg.rs:5:23
error: Unknown field: `eq`. Did you mean `equal`?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's an unknown attribute/argument, not an unknown field

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an error from darling. I think it defaults to field for everything?

panic!("Expected list validation errors");
}
}
// Skip this test for now
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can it be enabled again?

validator_derive_tests/tests/complex.rs Outdated Show resolved Hide resolved
@@ -1,5 +1,5 @@
error: Invalid schema level validation: `function` is required
--> $DIR/missing_function.rs:4:12
error: Missing field `function`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again attribute/argument

@@ -114,81 +117,103 @@ fn can_fail_schema_fn_validation() {
assert_eq!(errs["__all__"][0].code, "meh");
}

// #[test]
// fn can_fail_multiple_schema_fn_validation() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can that test be enabled?

@Keats
Copy link
Owner

Keats commented Sep 25, 2023

Just a couple more tests that are currently commented out, can I merge and uncomment them or is there a reason they are commented out?

@pintariching
Copy link
Contributor Author

Sorry for the wait, forgot about this. No the tests don't pass currently if you uncomment them I think. I was thinking gating the serde original name behind a feature.

@Keats
Copy link
Owner

Keats commented Sep 27, 2023

ah it's all related to that feature? You can just remove it for now then

@pintariching
Copy link
Contributor Author

Ok I removed the original field name from serde test and added back multiple schema validation. I think that makes everything? Also the documentation should be updated, this PR is a breaking change after all.

@Keats
Copy link
Owner

Keats commented Sep 29, 2023

Let's update the docs later, we might have more things.

Thanks a lot!

@Keats Keats merged commit 31593cb into Keats:next Sep 29, 2023
4 checks passed
Keats pushed a commit that referenced this pull request Mar 4, 2024
* Rewrite derive macro implementation

* Add better error handling

* Add new types to validator macro

* Add empty files in tokens module

* Removed i32 tests for length

* Fix email to pass tests

* fix length validation trait to work with u64 only

* Add credit card token generation to macro

* Add url token generation to macro

* Add ValidateIp trait

* Add ip token generation to macro

* Remove unneeded import

* Export ValidateIp trait from main crate

* Add tests for ValidateIp macro

* Add non control character token generation to macro

* Add test for range with enums

* Add range token generation to macro

* Add required token generation to macro

* Fix ValidationErrors merge function

* Move contains trait to contains.rs

* Add ValidateContains trait and fix tests

* Add ValidateContains and DoesNotContain traits to macro

* Add must match token generation to macro

* Add regex token generation

* Add custom validation token generation to macro

* Add custom validation with arguments to macro

* Add custom validation with args with contexts

* Add custom validation recommit

* Fix custom validation to work without lifetimes

* Change custom validation to use closures

* Fix tests for custom validation

* Change custom validation to implement FnOnce and add tests

* Remove code used for experementing

* Remove unneeded code

* Remove unused imports

* Add schema with arguments and fix tests

* Impl ValidateLength trait for Option types

* Fix impls for ValidateRange

* Fix duplicate use statements

* Fix tests and add Option impls for Contains

* Implement ValidateUrl traits for specific types

* Implement ValidateEmail traits for specific types

* Fix some tests and warnings

* Add regex trait for validation

* Fix to pass tests in validator lib

* Fix range validation trait to pass tests

* Update and remove unneeded dependencies

* Add ValidateNested trait

* Fix custom and nested validation

* Fix Regex validator to work with OnceCell and OnceLock

* Fix derive macro to support all the arguments

* Remove unneeded functions and fix tests

* Remove validator_types crate and fix tests

* Update CI workflow

* Fix custom to be used in nested validations

* Fix custom validation to use context

* Add custom nested validation with args test

* Fix validation to use Validation trait

* Remove conflicting trait

* Fixed tests and remove ValidateContext trait

* Fix nested validation

* Fix custom args test

* Add `nest_all_fields` attribute

* Add better error handling and start fixing UI tests

* Pass almost all tests

* Add skip_on_field_errors attribute to schema

* Remove rust beta channel from workflow

* Use proc_macro_error instead of darling diagnostics feature

* Conditionally run UI tests

* Fix ci.yml

* Fix ci.yml

* Remove UI test for wrong type on range

* Change trait impls to be consistent

* Run cargo clippy --fix

* Replace if else with match

* Remove cargo-expand leftovers

* Replace underscore with `#[allow(unused)]`

* Add support for multiple schema validations

* Remove serde original field name test
Keats pushed a commit that referenced this pull request Mar 4, 2024
* Rewrite derive macro implementation

* Add better error handling

* Add new types to validator macro

* Add empty files in tokens module

* Removed i32 tests for length

* Fix email to pass tests

* fix length validation trait to work with u64 only

* Add credit card token generation to macro

* Add url token generation to macro

* Add ValidateIp trait

* Add ip token generation to macro

* Remove unneeded import

* Export ValidateIp trait from main crate

* Add tests for ValidateIp macro

* Add non control character token generation to macro

* Add test for range with enums

* Add range token generation to macro

* Add required token generation to macro

* Fix ValidationErrors merge function

* Move contains trait to contains.rs

* Add ValidateContains trait and fix tests

* Add ValidateContains and DoesNotContain traits to macro

* Add must match token generation to macro

* Add regex token generation

* Add custom validation token generation to macro

* Add custom validation with arguments to macro

* Add custom validation with args with contexts

* Add custom validation recommit

* Fix custom validation to work without lifetimes

* Change custom validation to use closures

* Fix tests for custom validation

* Change custom validation to implement FnOnce and add tests

* Remove code used for experementing

* Remove unneeded code

* Remove unused imports

* Add schema with arguments and fix tests

* Impl ValidateLength trait for Option types

* Fix impls for ValidateRange

* Fix duplicate use statements

* Fix tests and add Option impls for Contains

* Implement ValidateUrl traits for specific types

* Implement ValidateEmail traits for specific types

* Fix some tests and warnings

* Add regex trait for validation

* Fix to pass tests in validator lib

* Fix range validation trait to pass tests

* Update and remove unneeded dependencies

* Add ValidateNested trait

* Fix custom and nested validation

* Fix Regex validator to work with OnceCell and OnceLock

* Fix derive macro to support all the arguments

* Remove unneeded functions and fix tests

* Remove validator_types crate and fix tests

* Update CI workflow

* Fix custom to be used in nested validations

* Fix custom validation to use context

* Add custom nested validation with args test

* Fix validation to use Validation trait

* Remove conflicting trait

* Fixed tests and remove ValidateContext trait

* Fix nested validation

* Fix custom args test

* Add `nest_all_fields` attribute

* Add better error handling and start fixing UI tests

* Pass almost all tests

* Add skip_on_field_errors attribute to schema

* Remove rust beta channel from workflow

* Use proc_macro_error instead of darling diagnostics feature

* Conditionally run UI tests

* Fix ci.yml

* Fix ci.yml

* Remove UI test for wrong type on range

* Change trait impls to be consistent

* Run cargo clippy --fix

* Replace if else with match

* Remove cargo-expand leftovers

* Replace underscore with `#[allow(unused)]`

* Add support for multiple schema validations

* Remove serde original field name test
@nopeNoshishi nopeNoshishi mentioned this pull request Apr 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants