Home > Software design >  JOI validate if array has only single matching item. Not more than one
JOI validate if array has only single matching item. Not more than one

Time:12-29

example arrays:

const first = {
    class: 'XYZ',
    people: [{
        id: 1,
        name: "John",
        isCreator: false
    }, {
        id: 2,
        name: "Alex",
        isCreator: true
    }]
};
const second = {
    class: 'XYZ',
    people: [{
        id: 1,
        name: "John",
        isCreator: false
    }, {
        id: 2,
        name: "Alex",
        isCreator: false
    }]
};
const third = {
    class: 'XYZ',
    people: [{
        id: 1,
        name: "John",
        isCreator: true
    }, {
        id: 2,
        name: "Alex",
        isCreator: true
    }]
};

I want to validate that there must be a creator (isCreator: true) in people array, but only one, not more

My schema looks like this:

const schema = Joi.object().keys({
    class: Joi.string().required(),
    people: Joi.array().items(
        Joi.object().keys({
            id: Joi.number().integer().positive().required(),
            name: Joi.string().alphanum().required(),
            isCreator: Joi.boolean().required()
        })
    ).min(2)
    .has(Joi.object().keys({
        id: Joi.number(),
        name: Joi.string(),
        isCreator: Joi.valid(true)  // <-- this
    })).required()
});
schema.validate(first);
schema.validate(second);
schema.validate(third);
  • "first" array is returning success which is ok as there's only one creator
  • "second" array is returning failure which is ok as there's not a single creator

But

  • "third" array is returning success which is wrong as there're 2 matching items i.e. 2 creators. And this is my issue actually

CodePudding user response:

You can use unique and compare your isCreator field:

Joi.object().keys({
    class: Joi.string().required(),
    people: Joi.array().items(
        Joi.object().keys({
            id: Joi.number().integer().positive().required(),
            name: Joi.string().alphanum().required(),
            isCreator: Joi.boolean()
        })
    ).unique((a, b) => a.isCreator !== false)
})

This way, you can only have one object with isCreator=true.

If you send this object:

{
    class: 'XYZ',
    people: [{
        id: 1,
        name: "John",
        isCreator: false
    }, {
        id: 2,
        name: "Alex",
        isCreator: true
    },{
        id: 3,
        name: "Math",
        isCreator: true
    }]
}

You will get the following error:

Validation Error: "people[2]" contains a duplicate value

CodePudding user response:

I have found my answer with the help of soltex's one. Have to make some amendments:

const schema = Joi.object().keys({
    class: Joi.string().required(),
    people: Joi.array().items(
        Joi.object().keys({
            id: Joi.number().integer().positive().required(),
            name: Joi.string().alphanum().required(),
            isCreator: Joi.boolean().required()
        })
    )
    // re-added this part
    .has(Joi.object().keys({
        id: Joi.number(),
        name: Joi.string(),
        isCreator: Joi.valid(true)
    }))
    .unique((a, b) =>
        a.isCreator !== false /* also added this --> */ && b.isCreator == a.isCreator
    )
});

Now all possible test cases are working absolutely as required. Thanks for the help @soltex

people: [{..., isCreator: false}, {..., isCreator: false}, {..., isCreator: false}]
// is returning error "people" does not contain at least one required match            
  • Related