validate.js icon indicating copy to clipboard operation
validate.js copied to clipboard

[WIP] Add array support with any constraints

Open nishidayuya opened this issue 8 years ago • 16 comments

I implemented forEach validator and forEachSingle validator. We can specify any constraints for each array element.

Why [WIP]?

This pull-request is WIP (work in progress), because I want you to check following:

  • Adds validator specification about return value. (Any other ideas to implement array support are welcome)
  • Adds multiple words validator name, but current master has only single word validator name. (Maybe you want to change validator name to foreach)
  • And other your requests. implementation, validator name, and so on.

After you accept them, I will create tests, git push it and remove [WIP] mark.

forEach validator

This validator checks object properties in array element.

Sample:

validate({
  users: [
    {id: -1, name: 'foo'},
    {id: 1, name: '西田雄也'}
  ]
}, {
  users: {
    forEach: {
      id: {numericality: {greaterThan: 0}},
      name: {format: /^[a-zA-Z0-9]+$/}
    }
  }
})
//=> {"users[0].id":["Users[0] id must be greater than 0"],"users[1].name":["Users[1] name is invalid"]}

This is following requests implementation:

  • https://github.com/ansman/validate.js/issues/1#issuecomment-153413241
  • https://github.com/ansman/validate.js/issues/104

I think this validator name is forEach and it is better than each. I thought following:

  • Currently validate.js has forEachKeyInKeypath.
  • ECMAScript 2016 uses forEach (Array.prototype.forEach), and it doesn't use each. http://www.ecma-international.org/ecma-262/7.0/#sec-array.prototype.foreach

forEachSingle validator

This validator checks object in array element like validateSingle function.

Sample:

validate({ary: ['foo', '', 'tooLongString']}, {
  ary: {
    forEachSingle: {
      presence: true,
      length: {
        maximum: 3
      }
    }
  }
})
//=> {"ary[1]":["Ary[1] can't be blank"],"ary[2]":["Ary[2] is too long (maximum is 3 characters)"]}

nishidayuya avatar Dec 08 '16 10:12 nishidayuya

Coverage Status

Coverage decreased (-6.4%) to 93.603% when pulling 098d4440779b241df2b19c30e014a883283ffe5d on nishidayuya:add_array_support into ab5ad5a3a7a82546c7a1aecedb338b6413e20119 on ansman:master.

coveralls avatar Dec 08 '16 10:12 coveralls

Hey guys, when can we expect this to be released? 😃

simon2k avatar Jan 31 '17 12:01 simon2k

Is there any update on this?

luisfcolon avatar Feb 25 '17 04:02 luisfcolon

+1

BrunoQuaresma avatar Apr 06 '17 12:04 BrunoQuaresma

I think that instead return a object like:

{
   'ary[1].name': 'Cant be blank',
   'ary[1].somethikng': 'Cant be blank'
}

should be:

{
    ary: [
       { name: 'Cant be blank', something: 'Cant be blank' }
    ]
}

or:

{
    ary: {
       1: {
            name: 'Cant be blank',
            something: 'Cant be blank'
         }
    }
}

What you think?

BrunoQuaresma avatar Apr 10 '17 16:04 BrunoQuaresma

+1

stewartmegaw avatar May 06 '17 11:05 stewartmegaw

At first glance, without writing a custom formatter, it looks like the minimum we can do is the following.

length: {
  minimum: 1
}

which only checks length and a string would give us a false positive, when we're looking for an array. Is there a widely accepted array formatter pattern that people are using in the meantime?

Something that could validate this kind of pattern:

{
  "id": "123",
  "notes": [
    {
      "date": 2015-10-05T12:00:00,
      "comments": "monty python"
    },
    {
      "date": 2015-10-06T12:00:00,
      "comments": "something else entirely"
    }
  ]
}

definitely looking forward to this PR! thanks :)

edit: example custom validator to validate all values in an array for example above

custom validator:

validate.validators.arrayValidator = function(value, options) {
  if (!Array.isArray(value))
    return 'must be an array';

  value.forEach(function(obj) {
    validate(obj, options);
  });
};

schema:

  notes: {
    length: {
      minimum: 1
    },
    arrayValidator: {
      date: {
        datetime: true
      },
      comments: {
        length: {
          minimum: 10
        }
      }
    },
    presence: true

tom-spalding avatar Jun 04 '17 00:06 tom-spalding

I'm so sorry. This PR slipped through the cracks it seems, it looks like a good first implementation. If you add some tests I'll try to get it merged ASAP.

ansman avatar Jan 23 '18 00:01 ansman

@ansman Any update on when this will be released? Thank you.

adrianzielonka avatar Apr 30 '18 05:04 adrianzielonka

+1

jmagsumbol avatar May 23 '18 14:05 jmagsumbol

This would be pretty cool

paulevmo avatar Jul 17 '18 19:07 paulevmo

Its some way how works with var constraints = {} like with array

I have trouble, when is in {} some element which not exists, code does not work

Original: var constraints = { "addresses.shipping": { presence: true }, "addresses.shipping.street": { format: { // Must be numbers followed by a name pattern: "^[0-9]+ .+$", message: "^The street for the shipping address must be a valid street name" } } };

Will be like: ` var constraints = {};

// dont care about "exists()" if(exists("addresses.shipping")){ constraints.push( "addresses.shipping": { presence: true } );
}

// dont care about "exists()" if(exists("addresses.shipping.street")){ constraints.push( "addresses.shipping.street": { format: { // Must be numbers followed by a name pattern: "^[0-9]+ .+$", message: "^The street for the shipping address must be a valid street name" } } );
} `

slezak-petr avatar Sep 11 '18 11:09 slezak-petr

@nishidayuya resolve merge conflicts when you have time :D

tom-spalding avatar Sep 11 '18 17:09 tom-spalding

any update on when this will be released?

jo-flynn avatar Jan 29 '19 21:01 jo-flynn

+1 when can we expect this?

cheenu2 avatar Mar 19 '19 20:03 cheenu2

I worked around this for now, but it would be great to have this baked in.

JulianKingman avatar Oct 29 '19 17:10 JulianKingman