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

Partial or Custom Entity Validation #70

Open
dalssoft opened this issue Jan 3, 2023 · 0 comments
Open

Partial or Custom Entity Validation #70

dalssoft opened this issue Jan 3, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@dalssoft
Copy link
Member

dalssoft commented Jan 3, 2023

Problem

When defining a entity, the validation rules are defined for all the fields, but sometimes we want to have different validation rules for different scenarios.

Partial or Custom Validation

for this use case we can think in several approaches:

(1) "Manual" Check for error return

Without extra implementation, it would be possible to check the returned error code:

if(!user.isValid()){ 
	if (user.error...) {
		// check if the only error came from `createdAt`, regarding `presence`.
		// we could create a helper function to do that
	}
}

This can be a bit verbose, but feasible.

(2) Validation Ignore or Override - Specific

This would make the caller to be able to ignore or override the validation rules for a specific field.

This is important because the validation are defined in the context of the caller and might be very specific to be generalized.

if(!user.isValid({ ignore: { createdAt: "presence"} })){ 

or

if(!user.isValid({ override: { createdAt: { presence: false } } })){ 

(3) Validation Contexts - Generalization

Let´s say there is a context validation that can be reused in several scenarios. For instance, the dev started with a specific validation for a specific scenario, but then realized that the same validation can be used in other scenarios.

There could have be a extra metadata on the entity for validation scenarios, like:

const User = entity('User', {
	id: id(Number, { presence: true }),
	name: field(String, { presence: true }),
	email: field(String, { presence: true }),
	createdAt: field(Date, { presence: true }),

    // this 
	create: validation({
            override: { createdAt: { presence: false } },
            ignore: { email: "presence" } 
	}),

    // or
    validations: {
        create: {
            override: { createdAt: { presence: false } },
            ignore: { email: "presence" } 
        }
    }    
})

to use it:

if(!user.isValid({ context: 'create' })){ 

Of course, the suggested code and names are just that, suggestions. Ideas on how to improve this are welcome.

(4) Conditional Validation

This is a more complex approach, but it would allow to define a validation rule that would be executed only if a condition is met.

const User = entity('User', {
    id: id(Number, { presence: true }),
    name: field(String, { presence: true }),
    email: field(String, { presence: true }),
    createdAt: field(Date, { presence: true })

    validations: {
        create: {
            condition: (user) => user.createdAt === null, // or a function that returns a boolean
            override: { createdAt: { presence: false } },
        }
    }    
})

To use it:

if(!user.isValid()) { // no need to pass the context here - if the condition is met, the validation will be executed 

I feel this could be polished a bit more. Ideas are welcome.

Error return

The error returned should be the same, regardless of the approach (1), (2), (3) or (4)

user.errors // {"password":[{"cantBeNull":true}]}

Conclusion

I would suggest start with (2), since it can help in many scenarios, and then move to (3) and (4) if needed.

Benchmarks

    class User < ApplicationRecord
        with_options if: :is_admin? do |admin|
            admin.validates :password, length: { minimum: 10 }
            admin.validates :email, presence: true
        end
    end

Reference

This issue is a spin off from #49

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant