jeanpaul62
jeanpaul62

Reputation: 10571

Joi: Require exactly two of three fields to be non-empty

Here is a simple version of my schema.

var schema = Joi.object().keys({
    a: Joi.string(),
    b: Joi.string(),
    c: Joi.string()
});

I want a, b, c to be exactly 2 out of 3 non-empty. I.e.:

Tried using .or() but obviously doesn't do the trick. Looked into .alternatives() but didn't get it working.

Upvotes: 1

Views: 581

Answers (1)

Ankh
Ankh

Reputation: 5718

It's tricky to find an elegant way to handle this without stumbling into circular dependency issues. I've managed to get something working using .alternatives() and .try().

The solution in its raw form would be this:

Joi.alternatives().try(
    Joi.object().keys({
        a: Joi.string().required(),
        b: Joi.string().required(),
        c: Joi.string().required().valid('')
    }),
    Joi.object().keys({
        a: Joi.string().required().valid(''),
        b: Joi.string().required(),
        c: Joi.string().required()
    }),
    Joi.object().keys({
        a: Joi.string().required(),
        b: Joi.string().required().valid(''),
        c: Joi.string().required()
    })
);

It's certainly not pretty and could get pretty bloated if any more dependencies are introduced.

In an attempt to reduce the amount of repetition, the following would also work:

var base = {
    a: Joi.string().required(),
    b: Joi.string().required(),
    c: Joi.string().required()
};

Joi.alternatives().try(
    Joi.object().keys(Object.assign({}, base,
    {
        a: base.a.valid('')
    })),
    Joi.object().keys(Object.assign({}, base,
    {
        b: base.b.valid('')
    })),
    Joi.object().keys(Object.assign({}, base,
    {
        c: base.c.valid('')
    }))
);

Upvotes: 1

Related Questions