我正在尝试根据 joi 模式添加 null 值

I am trying to add null value based on joi schema

提问人:jos j 提问时间:9/12/2023 最后编辑:jos j 更新时间:9/20/2023 访问量:34

问:

基本上我有一个 JOI 模式,它可能会有所不同,我正在尝试创建一个通用解决方案, 例:

const templateSchema = Joi.object({
        studentData: Joi.object({
           addr: Joi.object({
               studentName: Joi.string().required(),
               studentAge: Joi.number().required()
           }).required(),
           education: Joi.object({
                schoolName: Joi.string().required(),
                studentGrade: Joi.number().required()
           }).required()
        }).required()
    }).required();

数据示例

const apiData = {
    studentData: {
        addr: null,
        education: {
            schoolName: "TKM",
            studentGrade: 10
        }
    }
};`

`const apiData = {
    studentData: {
        education: {
            schoolName: "TKM",
            studentGrade: 10
        }
    }
};

我正在研究一个通用解决方案,它适用于任何复杂的架构和数据,并将 null 添加到末叶的节点

我尝试过的解决方案,但不适用于所有情况

function populateMissingFields(data, error, schemaDescription) {
    if (error && error.details) {
        error.details.forEach(detail => {
            const currentPathValue = _.get(data, detail.path);

            if (detail.type === 'object.base' && (currentPathValue === null || currentPathValue === undefined)) {
                expandObjectBasedOnSchema(data, detail.path, schemaDescription);
            } else if (detail.type === 'array.base' && !Array.isArray(currentPathValue)) {
                _.set(data, detail.path, []);
            } else {
                _.set(data, detail.path, null);
            }
        });
    }
    return data;
}
function expandObjectBasedOnSchema(data, path, rootSchemaDescription) {
    let currentSchemaDesc = rootSchemaDescription;
    for (const key of path) {
        if (currentSchemaDesc.keys && currentSchemaDesc.keys[key]) {
            currentSchemaDesc = currentSchemaDesc.keys[key];
        } else {
            console.error('Unable to find schema for path:', path);
            return;
        }
    }

    if (currentSchemaDesc.type === 'object') {
        const objectToSet = {};
        for (const [key, keySchema] of Object.entries(currentSchemaDesc.keys || {})) {
            if (keySchema.type === 'object') {
                objectToSet[key] = {};
            } else if (keySchema.type === 'array') {
                objectToSet[key] = []; 
            } else {
                objectToSet[key] = null; 
            }
        }
        _.set(data, path, objectToSet);
    }
}
const validatedResult = templateSchema.validate(apiData, { abortEarly: false });
const modifiedData = populateMissingFields(apiData, validatedResult.error, templateSchema.describe());
console.log(modifiedData)

所以它并不适用于所有情况,如果缺少 sn 对象,它就不起作用,我们需要转到最后一页

预期输出

const apiData = {
    studentData: {
       addr:{
           studentName: null,
           studentAge:null
        }
        education: {
            schoolName: "TKM",
            studentGrade: 10
        }
    }
};
JavaScript JSON Lodash JOI

评论


答:

0赞 wesleyfung 9/19/2023 #1

因此,根据我对您的问题的理解,您的对象在结构上可能会有所不同,但您希望有一个通用解决方案来“填充”缺失的属性,然后再验证架构。

// provide a Schema, this is a good way to set defaults too.
// I would suggest putting the 'schema' variable in a separate file also.
const schema = {
    studentData: {
        addr: {
            studentName: null,
            studentAge: null
        },
        education: {
            schoolName: null,
            studentGrade: null
        }
    }
};

// recursive function to 'fill' your incoming data
function transformApiData(apiData, schemaData) {
    for (const key of Object.keys(schemaData)) {
        if (schemaData[key] instanceof Object) {
            apiData[key] = apiData[key] || {};
            // this recursion goes to the last leaf of the schema
            // by passing schemaData[key] into itself
            transformApiData(apiData[key], schemaData[key]);
        } else if (!(key in apiData)) {
            // if not found, assign null (or some other default)
            apiData[key] = schemaData[key];
        }
    }
    return apiData;
}

// data
const apiData1 = {
    studentData: {
        addr: null,
        education: {
            schoolName: "TKM",
            studentGrade: 10
        }
    }
};

const apiData2 = {
    studentData: {
        education: {
            schoolName: "TKM",
            studentGrade: 10
        }
    }
};

console.log(transformApiData(apiData1, schema));
console.log(transformApiData(apiData2, schema));

这将给你:

apiData1: {
  "studentData": {
    "addr": {
      "studentName": null,
      "studentAge": null
    },
    "education": {
      "schoolName": "TKM",
      "studentGrade": 10
    }
  }
}

apiData2: {
  "studentData": {
    "education": {
      "schoolName": "TKM",
      "studentGrade": 10
    },
    "addr": {
      "studentName": null, 
      "studentAge": null
    }
  }
}

如果我以其他方式理解您的问题,请告诉我!