Joi: Validating based on Previous Item in the array

Created on 13 Jun 2019  路  9Comments  路  Source: sideway/joi

Describe the problem you are trying to fix (provide as much context as possible)

Is there a way to access the index of the current item being validated in an array so i can do something like:

array().items(Joi.objects({
  // get the previous item's end date
  start: Joi.date().min(Joi.ref('..<index - 1>.end')),
  end: Joi.date().min(Joi.ref('start'))
})

Which API (or modification of the current API) do you suggest to solve that problem ?

I'm not sure, I'm a bit new to Joi

Are you ready to work on a pull request if your suggestion is accepted ?

Sure thing, but given the time I have in the next months I'd rather do a workaround for my current project for now

feature

All 9 comments

Please don't post the same message in multiple places.

In v16 you can reference the first item like this: https://github.com/hapijs/joi/blob/master/test/ref.js#L487. There is no current way to know your current index or to reference the "previous" one or last one.

Hi @hueniverse , my bad, I just thought my previous comment was in a rather wrong thread. Thanks for the reply. For this case, I might just build the validation dynamically based on the array I received since the maximum length of the array is quite small (max of 10)

As @Marsup pointed out to me, it looks like you are trying to ensure sort order, which we can solve much more cleanly with a new array().sort() method.

@hueniverse Ohh, let me check this array().sort() method. Technically yes, it's like making sure the array is sorted by some criteria (start of current and end of previous). Let me see if array().sort() can handle this case of mine. Thanks!

Hi @hueniverse , I have a question, not sure if this is a bug but

my schema is something like:

project: {
  someArray: Joi.array().items(Joi.object({
    prop1: some validations
  })
}

but whenever the array has an error and I call

let { error, value } = Joi.validate(...)

error is null - does validate not propagate to the returned object?
but value.someArray[0] is an object with the following property:

{ isJoi: true,
    type: 'string.regex.base',
    path: [ 'someArray', 0, 'prop1' ],
    options:
     { abortEarly: true,
       allowUnknown: false,
       convert: true,
       escapeHtml: false,
       language: {},
       nonEnumerables: false,
       noDefaults: false,
       presence: 'optional',
       skipFunctions: false,
       stripUnknown: false },
    message:
     '"someArray[0].prop1" must be less or equal to 8 decimal place(s) with a maximum of 20 significant digit(s).',
    template: null,
    context:
     { name: undefined,
       pattern: /^(0(\.(?!0+$)\d{1,8})|([1-9]\d{0,11}(\.\d{1,8})?))$/,
       value: 'asd',
       label: 'someArray[0].prop1',
       key: 'prop1' } } ]

I don't know what you are doing. I get this with current master:

> const Joi = require('.');
undefined
> const schema = Joi.object({ a: Joi.array().items(Joi.object({ x: Joi.number() }))});
undefined
> schema.validate({a: [{x: 'c'}]})
{ value: { a: [ [Object] ] },
  error:
   { ValidationError: "a[0].x" must be a number
       at Object.exports.process (/home/eran/code/hapijs/joi/lib/errors.js:97:12)
       at Object.exports.process (/home/eran/code/hapijs/joi/lib/validator.js:22:27)
       at internals.Object.validate (/home/eran/code/hapijs/joi/lib/types/any.js:544:26)
       at repl:1:8
       at Script.runInThisContext (vm.js:119:20)
       at REPLServer.defaultEval (repl.js:332:29)
       at bound (domain.js:395:14)
       at REPLServer.runBound [as eval] (domain.js:408:12)
       at REPLServer.onLine (repl.js:639:10)
       at REPLServer.emit (events.js:194:15) _original: { a: [Array] }, details: [ [Object] ] } }

Darn, I found the reason now. Apparently when we were using v15.0.3 we had a validator (a general one) that does:

.error((errors) => {
  // Modify the value of errors[0].message to something else if error.type === string.regex.base ...
  return errors
});

When I removed this handling, it worked
But now, how do we change the message for a specific error?

I modified the error function to:

(errors) => { return new Error(errors) }

but it doesn't work, i get result.error = null

You can look around but otherwise will have to wait until v16 release notes are ready.

Ohh, okay. Thanks for the help @hueniverse

Also good luck on the v16 release!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chrisegner picture chrisegner  路  4Comments

n-sviridenko picture n-sviridenko  路  3Comments

alekbarszczewski picture alekbarszczewski  路  3Comments

kevbook picture kevbook  路  4Comments

JbIPS picture JbIPS  路  4Comments