Haven't found any working solution for my case, so I'm creating a new one. I've got this architecture:
function getParts1() {
return {
common: joi.object({
common_key: joi.number().integer().required(),
common_conditional: joi.string().valid("AB", "CD", "EF").required(),
common_value1: joi.string().max(144).required(),
}),
variation1: joi.object({
field1: joi.number().allow(0).required(),
field2: joi.string().max(255).allow("").required(),
}),
variation2: joi.object({
another_field1: joi.number().allow(0).required(),
another_field2: joi.string().max(255).allow("").required(),
}),
variation3: joi.object({
super_another_field1: joi.number().allow(0).required(),
super_another_field2: joi.string().max(255).allow("").required(),
}),
};
}
function getParts2() {}; //And much more functions like getParts1 with the same keys but different objects as values
I need to create a function that can work with the output of this kind of functions in the next way:
common
part from resulting array.common_conditional
. In this example I need to merge to array.common
keys from array.variation1
if array.common.common_conditional == "AB"
, variation2
if "CD"
, etc. It can be much more.Because of difference in joi.object(...)
of each variation
for each Parts
, I can't find any solution for this problem.
For example, for the code above if such schema will be created:
const schema = getSchemaFromParts(getParts1());
const data1 = {
common_key: 12,
common_conditional: "AB",
common_value1: "somevalue",
field1: 14,
field2: "Value for field2"
}
const data2 = {
common_key: 16,
common_conditional: "CD",
common_value1: "somevalue2",
another_field1: 18,
another_field2: "Hello world"
}
const data3 = {
common_key: 16,
common_conditional: "EF",
common_value1: "somevalue3",
another_field1: 20,
another_field2: "Broken data"
}
const res1 = schema.validate(data1);
const res2 = schema.validate(data2);
const res3 = schema.validate(data3);
console.log(res1.error)
console.log(res2.error)
console.log(res3.error)
It should pass the res1 and res2, but res3 should throw an error of ValidationError: "another_field1" is not allowed { …(2) }
.
Is there any solutions for this case, or maybe it's better to create a different architecture for the Parts
function?
The problem sounds quite straightforward, let me know if this solution fits your needs. The script below implements directly what you have stated in requirements. And is generic and reusable so you only will have to add new variations and new keys into CONDITIONS
map without making any changes to getSchemaBasedOnConditional
method.
const Joi = require("joi");
// Define reusable condition mappings
const CONDITIONS = {
AB: "variation1",
CD: "variation2",
EF: "variation3",
};
function getParts() {
return {
common: Joi.object({
common_key: Joi.number().integer().required(),
common_conditional: Joi.string()
.valid(...Object.keys(CONDITIONS)) // convert object keys (conditions) into an array of strings
.required(),
common_value1: Joi.string().max(144).required(),
}),
variation1: Joi.object({
field1: Joi.number().allow(0).required(),
field2: Joi.string().max(255).allow("").required(),
}),
variation2: Joi.object({
another_field1: Joi.number().allow(0).required(),
another_field2: Joi.string().max(255).allow("").required(),
}),
variation3: Joi.object({
super_another_field1: Joi.number().allow(0).required(),
super_another_field2: Joi.string().max(255).allow("").required(),
}),
};
}
// Dynamically create schema based on common_conditional
function getSchemaBasedOnConditional(data) {
const parts = getParts();
// Start with the common schema
let schema = parts.common;
// Retrieve the appropriate variation schema based on CONDITIONS mapping
// 1. Check common conditional ["AB", "CD", "EF"]
// 2. Get the variation key to lookup a variation object
// 3. concat parts[variationKey]
const variationKey = CONDITIONS[data.common_conditional];
if (variationKey && parts[variationKey]) {
schema = schema.concat(parts[variationKey]);
}
return schema;
}
// Validate data based on dynamically generated schema
function validateData(data) {
const schema = getSchemaBasedOnConditional(data);
return schema.validate(data);
}
// Test cases
const data1 = {
common_key: 12,
common_conditional: "AB",
common_value1: "somevalue",
field1: 14,
field2: "Value for field2",
};
const data2 = {
common_key: 16,
common_conditional: "CD",
common_value1: "somevalue2",
another_field1: 18,
another_field2: "Hello world",
};
const data3 = {
common_key: 16,
common_conditional: "EF",
common_value1: "somevalue3",
another_field1: 20, // This field does not exist in `variation3`
another_field2: "Broken data",
};
console.log(
"res1:",
validateData(data1).error
? validateData(data1).error.details[0].message
: "Valid"
); // valid
console.log(
"res2:",
validateData(data2).error
? validateData(data2).error.details[0].message
: "Valid"
); // valid
console.log(
"res3:",
validateData(data3).error
? validateData(data3).error.details[0].message
: "Valid"
); // error