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

field validation based on another field condition #13

Open
thgpdr opened this issue Jun 21, 2020 · 9 comments
Open

field validation based on another field condition #13

thgpdr opened this issue Jun 21, 2020 · 9 comments
Labels
enhancement New feature or request hacktoberfest help wanted Extra attention is needed severity-minor Item is not urgent

Comments

@thgpdr
Copy link

thgpdr commented Jun 21, 2020

It should be possible to validate sinbling fields based on a condition.

Something like this:

const User = 
    entity('Person', {
        name: field(String),
        hasChildren: field(Boolean),
        childrenNames: field([String]).when('hasChildren', {
            is: true, // possibility to use a function instead
            then: ({ validation: { presence: true } }),
            // otherwise: some other validation
        }),
    })

inspired on yup .when()

what do you guys think?

@endersoncosta
Copy link
Contributor

This feature would bring a better way to validate some business rules in a simpler way. In short I liked it.

@dalssoft
Copy link
Member

dalssoft commented Jul 7, 2020

I think we should focus on the issue #2 first and come back to this one later since it could be a evolution of it

@jhomarolo
Copy link
Contributor

Since we finished the #2, @thgpdr i belive we can rediscuss this topic

@thgpdr
Copy link
Author

thgpdr commented May 21, 2021

Its a more declarative way to write, and opens more possibilities when designing entities validations. Would be nice the possibility to, combined with #2 set different custom validations to the same field based on entity type.

Something like:

const User = entity("Person", {
    name: field(String),
    hasChildren: field(Boolean),
    hasParents: field(Boolean),
    childrenNames: field([String])
        .when("hasChildren", {
            is: true, // possibility to use a function instead: (val) => val == true
            then: { validations: [function hasSameLastName() {}, function checkDNA() {}] }
        })
        .when("hasParents", {
            is: true,
            then: { validations: [function hasAllowance() {}, function hasHeritage() {}] }
        })
});

or

const User = entity("Person", {
    name: field(String),
    occupation: field(String, {
        validation: {
            presence: false,
            length: { minimum: 1 },
            contains: ["Medic", "Lawyer"],
        },
    }),
    exertsGraduation: field(Boolean)
        .when("occupation", {
            is: (occupation) => occupation === 'Medic',
            then: { validations: [function hasCRM() {}] }
        })
        .when("occupation", {
            is: (occupation) => occupation === 'Lawyer',
            then: { validations: [function hasBarAssociation() {}] }
        })
});

The question is if this validations should be on subtypes entities (different files/entities) by default.
What your thoughts about it?

@dalssoft
Copy link
Member

@thgpdr , just to make sure, is the code below a equivalent of the code proposed? (btw, the code below does not work, it is just a concept)

The idea here is to (1) make it clear the intention of the proposed solution and (2) be open for different ideas to get to the same result.

const User = entity("Person", {
    name: field(String),
    occupation: field(String, {
        validation: {
            presence: false,
            length: { minimum: 1 },
            contains: ["Medic", "Lawyer"],
        },
    }),
    exertsGraduation: field(Boolean, {
        validation: { 
            custom: { 
                validOccupation: (value, person) => {
                    const occupation = person.occupation
                    if (occupation === 'Medic') return hasCRM()
                    if (occupation === 'Lawyer') return hasBarAssociation()
                }
            } 
        } 
    })
});

Or even:

const User = entity("Person", {
    name: field(String),
    occupation: field(String, {
        validation: {
            presence: false,
            length: { minimum: 1 },
            contains: ["Medic", "Lawyer"],
        },
    }),
    exertsGraduation: field(Boolean, {
        validation: { 
            custom: { 
                validOccupation: (value, person) => person.hasGraduation()
            } 
        } 
    }),

    hasGraduation() {
        if (this.occupation === 'Medic') return hasCRM()
        if (this.occupation === 'Lawyer') return hasBarAssociation()
    }
});

If the idea was to populate exertsGraduation, then the code below show be something like this:

const User = entity("Person", {
    name: field(String),
    occupation: field(String, {
        validation: {
            presence: false,
            length: { minimum: 1 },
            contains: ["Medic", "Lawyer"],
        },
        onChange: (person) => person.hasGraduation()   // triggered by the changed value
    }),
    exertsGraduation: field(Boolean),

    hasGraduation() {
        if (this.occupation === 'Medic') this.exertsGraduation = hasCRM()
        if (this.occupation === 'Lawyer') this.exertsGraduation = hasBarAssociation()
    }
});

@thgpdr please, bring your thoughts to this. thanks!

@thgpdr
Copy link
Author

thgpdr commented May 25, 2021

const User = entity("Person", {
   name: field(String),
   occupation: field(String, {
       validation: {
           presence: false,
           length: { minimum: 1 },
           contains: ["Medic", "Lawyer"],
       },
   }),
   exertsGraduation: field(Boolean, {
       validation: { 
           custom: { 
               validOccupation: (value, person) => {
                   const occupation = person.occupation
                   if (occupation === 'Medic') return hasCRM()
                   if (occupation === 'Lawyer') return hasBarAssociation()
               }
           } 
       } 
   })
});

@dalssoft this one suits for me
The possibility to have an implementation of 'Person' inside a custom validation func eliminates the need for .when()

@dalssoft
Copy link
Member

If validOccupation validates person.occupation (or is based on its value), why it is a exertsGraduation validation?

@thgpdr
Copy link
Author

thgpdr commented May 30, 2021

Just an example of

set different custom validations to the same field based on entity type.

a better one would be:

const User = entity("Person", {
   name: field(String),
   occupation: field(String, {
       validation: {
           presence: false,
           length: { minimum: 1 },
           contains: ["Coder", "Lawyer", "Doctor"],
       },
   }),
   degree: field(String, {
       validation: {
           presence: false,
           length: { minimum: 1 },
           contains: ["Tecnology", "Medicine", "LawSchool"],
       },
   }),
   exertsGraduation: field(Boolean, {
       validation: { 
           custom: { 
               validOccupation: (value, person) => { //true if the occupation matchs the degree
                   const degree = person.degree
                   const occupation = person.occupation
                   if (degree === 'Medicine' && occupation === 'Doctor') return hasCRM()
                   if (degree === 'LawSchool' && occupation === 'Lawyer') return hasBarAssociation()
                   if (degree === 'Tecnology' && occupation === 'Coder') return hasHerbsPr()
               }
           } 
       } 
   })
});

In this example you can observe 2 points: (1) different validations based on person type. (2) the possibility to store some info (exertsGraduation: Boolean) without the need to invalidate occupation input.

So this way, I can have a Person who's a coder but has a degree in climatology and store/validate the match (occupation x degree) information in one field. Does that make sense for a real world scenario?

@dalssoft
Copy link
Member

Given you example, what would happen when person.validate()? What would be the value for person.errors and person.exertsGraduation?

@jhomarolo jhomarolo added enhancement New feature or request help wanted Extra attention is needed severity-minor Item is not urgent labels Dec 24, 2021
@jhomarolo jhomarolo moved this to Ready to code in Herbs enterprise roadmap 2023 Jan 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request hacktoberfest help wanted Extra attention is needed severity-minor Item is not urgent
Projects
Status: Ready to code
Development

No branches or pull requests

5 participants