Joi - 多个“when”子句
Joi - multiple `when` clauses
我要对同一个负载执行两个验证:
当 hasSalary
为真时,必须存在 monthlySalary
或 annualSalary
。
当 hasCosts
为真时,必须存在 monthlyCosts
或 annualCosts
。
我将其编码为:
Joi.object({
hasSalary: Joi.boolean(),
monthlySalary: Joi.number(),
annualSalary: Joi.number(),
hasCosts: Joi.boolean(),
monthlyCosts: Joi.number(),
annualCosts: Joi.number(),
})
.when(
Joi.object({ hasSalary: Joi.boolean().valid(true).required() }),
{
then: Joi.object().xor('monthlySalary', 'annualSalary')
}
)
.when(
Joi.object({ hasCosts: Joi.boolean().valid(true).required() }),
{
then: Joi.object().xor('monthlyCosts', 'annualCosts')
}
);
这正确地给出了验证错误:{ hasSalary: true }
:
message: '"value" must contain at least one of [monthlySalary, annualSalary]'
... 对于 { hasCosts: true }
:
message: '"value" must contain at least one of [monthlyCosts, annualCosts]'
...但是当两个布尔值都是 true
并且不满足第二个 when
的约束时,它不会像我预期的那样工作:
{
hasSalary: true,
monthlySalary: 300,
hasCosts: true,
}
我希望在这里 "value" must contain at least one of [monthlyCosts, annualCosts]
,但我得到了一个干净的验证,没有错误。
我想我明白发生了什么 - 链接 when
s 正在创建一系列守卫,第一个匹配的人获胜。
那么我可以在 Joi(最好是版本 15)中使用什么构造来实现我想要的?
使用最新版本 Joi
17.2.1 你没有这个问题(当条件正确解决时有多个)
但是对于 Joi
15.1.1,您可以使用以下解决方法:
const Joi = require('@hapi/joi');
const one = Joi.object({
hasSalary: Joi.boolean().valid(true),
monthlySalary: Joi.number(),
annualSalary: Joi.number(),
}).xor('monthlySalary', 'annualSalary');
const two = Joi.object({
hasSalary: Joi.boolean().valid(false),
monthlySalary: Joi.number(),
annualSalary: Joi.number(),
});
const three = Joi.object({
hasCosts: Joi.boolean().valid(true),
monthlyCosts: Joi.number(),
annualCosts: Joi.number(),
}).xor('monthlyCosts', 'annualCosts');
const four = Joi.object({
hasCosts: Joi.boolean().valid(false),
monthlyCosts: Joi.number(),
annualCosts: Joi.number(),
});
const one_three = one.concat(three);
const one_four = one.concat(four);
const two_three = two.concat(three);
const two_four = two.concat(four);
const schema = Joi.alternatives().try(
one,
two,
three,
four,
one_three,
one_four,
two_three,
two_four,
);
运行 一些测试:
// works
const data1 = {
hasSalary: true,
monthlySalary: 2000,
};
console.log(schema.validate(data1).error);
// works
const data2 = {
hasSalary: false,
};
console.log(schema.validate(data2).error);
// works
const data3 = {
hasCosts: true,
monthlyCosts: 300,
};
console.log(schema.validate(data3).error);
// works
const data4 = {
hasCosts: false,
};
console.log(schema.validate(data4).error);
// works
const data5 = {
hasSalary: true,
monthlySalary: 2000,
hasCosts: true,
monthlyCosts: 300,
};
console.log(schema.validate(data5).error);
// works
const data6 = {
hasSalary: false,
hasCosts: true,
monthlyCosts: 300,
};
console.log(schema.validate(data6).error);
// works
const data7 = {
hasSalary: true,
monthlySalary: 2000,
hasCosts: false,
};
console.log(schema.validate(data7).error);
// works
const data8 = {
hasSalary: false,
hasCosts: false,
};
console.log(schema.validate(data8).error);
// error
const data9 = {
hasSalary: true
};
console.log(schema.validate(data9).error.message)
// error
const data10 = {
hasSalary: true,
annualSalary: 1000,
hasCosts: true,
};
console.log(schema.validate(data10).error.message)
我要对同一个负载执行两个验证:
当 hasSalary
为真时,必须存在 monthlySalary
或 annualSalary
。
当 hasCosts
为真时,必须存在 monthlyCosts
或 annualCosts
。
我将其编码为:
Joi.object({
hasSalary: Joi.boolean(),
monthlySalary: Joi.number(),
annualSalary: Joi.number(),
hasCosts: Joi.boolean(),
monthlyCosts: Joi.number(),
annualCosts: Joi.number(),
})
.when(
Joi.object({ hasSalary: Joi.boolean().valid(true).required() }),
{
then: Joi.object().xor('monthlySalary', 'annualSalary')
}
)
.when(
Joi.object({ hasCosts: Joi.boolean().valid(true).required() }),
{
then: Joi.object().xor('monthlyCosts', 'annualCosts')
}
);
这正确地给出了验证错误:{ hasSalary: true }
:
message: '"value" must contain at least one of [monthlySalary, annualSalary]'
... 对于 { hasCosts: true }
:
message: '"value" must contain at least one of [monthlyCosts, annualCosts]'
...但是当两个布尔值都是 true
并且不满足第二个 when
的约束时,它不会像我预期的那样工作:
{
hasSalary: true,
monthlySalary: 300,
hasCosts: true,
}
我希望在这里 "value" must contain at least one of [monthlyCosts, annualCosts]
,但我得到了一个干净的验证,没有错误。
我想我明白发生了什么 - 链接 when
s 正在创建一系列守卫,第一个匹配的人获胜。
那么我可以在 Joi(最好是版本 15)中使用什么构造来实现我想要的?
使用最新版本 Joi
17.2.1 你没有这个问题(当条件正确解决时有多个)
但是对于 Joi
15.1.1,您可以使用以下解决方法:
const Joi = require('@hapi/joi');
const one = Joi.object({
hasSalary: Joi.boolean().valid(true),
monthlySalary: Joi.number(),
annualSalary: Joi.number(),
}).xor('monthlySalary', 'annualSalary');
const two = Joi.object({
hasSalary: Joi.boolean().valid(false),
monthlySalary: Joi.number(),
annualSalary: Joi.number(),
});
const three = Joi.object({
hasCosts: Joi.boolean().valid(true),
monthlyCosts: Joi.number(),
annualCosts: Joi.number(),
}).xor('monthlyCosts', 'annualCosts');
const four = Joi.object({
hasCosts: Joi.boolean().valid(false),
monthlyCosts: Joi.number(),
annualCosts: Joi.number(),
});
const one_three = one.concat(three);
const one_four = one.concat(four);
const two_three = two.concat(three);
const two_four = two.concat(four);
const schema = Joi.alternatives().try(
one,
two,
three,
four,
one_three,
one_four,
two_three,
two_four,
);
运行 一些测试:
// works
const data1 = {
hasSalary: true,
monthlySalary: 2000,
};
console.log(schema.validate(data1).error);
// works
const data2 = {
hasSalary: false,
};
console.log(schema.validate(data2).error);
// works
const data3 = {
hasCosts: true,
monthlyCosts: 300,
};
console.log(schema.validate(data3).error);
// works
const data4 = {
hasCosts: false,
};
console.log(schema.validate(data4).error);
// works
const data5 = {
hasSalary: true,
monthlySalary: 2000,
hasCosts: true,
monthlyCosts: 300,
};
console.log(schema.validate(data5).error);
// works
const data6 = {
hasSalary: false,
hasCosts: true,
monthlyCosts: 300,
};
console.log(schema.validate(data6).error);
// works
const data7 = {
hasSalary: true,
monthlySalary: 2000,
hasCosts: false,
};
console.log(schema.validate(data7).error);
// works
const data8 = {
hasSalary: false,
hasCosts: false,
};
console.log(schema.validate(data8).error);
// error
const data9 = {
hasSalary: true
};
console.log(schema.validate(data9).error.message)
// error
const data10 = {
hasSalary: true,
annualSalary: 1000,
hasCosts: true,
};
console.log(schema.validate(data10).error.message)