Open benneq opened 5 years ago
@benneq I will try to provide a detailed answer to your problem tomorrow!
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
}
])
}
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([
[...],
[...],
[...]
])
}
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.
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) => ?? => ??? => ????
}
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.
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.
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.
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: https://github.com/25th-floor/spected/issues/104
Yes #104 and #106 are the same issue. Will have a look at it later on.
Now I'd like to validate
foo.bar
(if present), which works fine as long asfoo
is notundefined
. If it's undefined, there'll be an exception invar keys = Object.keys(inputFn())
.Here's a real world example I'd like to use:
foo === undefined
, it is VALID.foo === null
, it is INVALID: "must not be null"typeof foo !== 'object'
, it is INVALID: "must be an object"foo.bar <= 9000
, thenbar
is INVALID: "must be over 9000!"Is there some way to get this working?
The result objects then might looks like this: