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

Check if parent is undefined, then check children #106

Open
benneq opened this issue Jan 15, 2019 · 10 comments
Open

Check if parent is undefined, then check children #106

benneq opened this issue Jan 15, 2019 · 10 comments

Comments

@benneq
Copy link

benneq commented Jan 15, 2019

const data = {
    foo: undefined   // because it is optional, but it could contain an object:
// foo: {
//      bar: 42
// }
}

Now I'd like to validate foo.bar (if present), which works fine as long as foo is not undefined. If it's undefined, there'll be an exception in var keys = Object.keys(inputFn()).

Here's a real world example I'd like to use:

  • If foo === undefined, it is VALID.
  • If foo === null, it is INVALID: "must not be null"
  • If typeof foo !== 'object', it is INVALID: "must be an object"
  • Now that we're sure that it's an object, we can proceed to validate: If foo.bar <= 9000, then bar is INVALID: "must be over 9000!"

Is there some way to get this working?


The result objects then might looks like this:

{
  foo: true // if foo === undefined
}

{
  foo: ["must not be null"] // if foo === null
}

{
  foo: ["must be an object"] // if typeof foo !== 'object'
}

{
  foo: {
    bar: "must be over 9000!" // if foo.bar <= 9000
  }
}

{
  foo: {
    bar: true // if foo.bar > 9000
  }
}
@busypeoples
Copy link
Owner

@benneq I will try to provide a detailed answer to your problem tomorrow!

@busypeoples
Copy link
Owner

busypeoples commented Jan 17, 2019

That is a very good example. What it would need is a way to define validation functions that validate the parent data and depending on the result either stop or continue validating.
That would also need a different way of structuring the validation data.

Maybe we can add a special function to spected, that enables to define a chain of functions, that stop validating as soon as one validation functions fails, and continues to validate deeper nested data as long as the higher level data is valid.

Not sure how this might look like, but maybe something like this:

const rules = {
   foo: runValidations([
      [a => a !== null, "no null"], 
      [a => a !== undefined, "no undefined"], 
      {
        bar: barRules
      }
  ])
}

@benneq
Copy link
Author

benneq commented Jan 17, 2019

Is this somehow possible using a validation function?

I still don't really know how this ramda stuff works, though I write some pseudo code)

const validationRules = {
  foo: (value) => {
    if(value === undefined) {
      return true;  // results in "foo: true"
    } else if(value === null) {
      return "errmsg";  // results in "foo: ["errmsg"]"
    } else {
      return {
        bar: [[(value) => value > 9000, "errmsg"]] // results in "foo: { bar: ["errmsg"] }"
      }
    }
  }
}

The question is: Is it already possible to stop after the first error using some fancy ramda stuff?

I think the whole process should stay functional. That's what this lib is all about.

Some more pseudo code:

const rules = {
  foo: stopAtFirstError([
    [...],
    [...],
    [...]
  ])
}

@busypeoples
Copy link
Owner

busypeoples commented Jan 17, 2019

No, that isn't possible right now. spected runs all functions and collects all messages at the moment.
Let me see how we can solve this.

@benneq
Copy link
Author

benneq commented Jan 17, 2019

But I'm sure, you could write a function, that does this internally :)

A simple function that returns an array of validation rules. But this function does the validation itself ... kinda...

Like the stopAtFirstError I posted above. It won't give spected all 3 elements, but instead it will run each element itself (maybe using spected? 😃 ), and then returns only a single validation rule.


Would be really nice if you would help with the TypeScript stuff. Then I could play around with that stuff myself!

I just need the function signature(s?) for this:

const rules = {
  foo: (values) => ?? => ??? => ????
}

@busypeoples
Copy link
Owner

I will take a look at the types!

Sure, we can implement it internally, it should be straight forward to use, I think this is the important part.

@benneq
Copy link
Author

benneq commented Jan 17, 2019

Okay, I now found a way, to make this possible... It's not very nice, and it's even not working for now, because spected has some issues with null / undefined values 😢

Here's the code that (in my opinion) should work:

const data = {
    foo: undefined
}

/* this works:
const data = {
    foo: {
        bar: 42
    }
}
*/

const rules = {
    foo: (value) => {
        if(value === undefined) {
            return [[() => true, '']] // some rule that always returns true
        } else if (value === null) {
            return [[() => false, 'cannot be null']] // some rule that always returns false
        } else {
            return { // the validation for the nested object
                bar: [[(val) => val > 9000, 'must be over 9000']]
            }
        }
    }
}

const res = spected(rules, data);

If you could make some changes to spected, to get this working, it should be quite easy to make a custom function for this, so you can then simply write:

const rules = {
    foo: validIfUndefinedAndNotValidIfNullElseValidateTheFollowing(
      {
        bar: [[(val) => val > 9000, 'must be over 9000']]
      }
    )
}

Then it should also be possible to write some kind of stopOnFirstError function I guess.

@busypeoples
Copy link
Owner

The problem is that spected currently always expects an array or object as input, so the problem is recursion. I will see how we can improve this.

@benneq
Copy link
Author

benneq commented Jan 17, 2019

Yeah, I saw that.

Maybe there should be some "catch" at the beginning of the validate function, that checks if input is a "simple type". Then you may also be able to solve this: #104

@busypeoples
Copy link
Owner

Yes #104 and #106 are the same issue. Will have a look at it later on.

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

No branches or pull requests

2 participants