如何为自定义 mongoose SchemaType 的所有实例提供默认验证?

How can I provide default validation for all instances of a custom mongoose SchemaType?

我已按照 mongoose 文档创建 Custom Schema Types。我的实施是有效的,但没有产生我想要的结果。

我的目标是拥有一个自定义 schemaType,它在转换失败时(或转换成功但验证失败时)提供自定义错误消息,而无需在我的 [=] 中每次使用数据类型时都声明验证方法31=]的架构。

举个例子(我会尽量在评论中解释):

const mongoose = require('mongoose')

// Create Custom Schema Type
class UUIDv4 extends mongoose.SchemaType {
    constructor(key, options) {
        super(key, options, 'UUIDv4');
    }

    cast(val) {
        if (/*Do UUIDv4 validation check here*/) {

            /* Because of the way mongoose works, this error message is difficult
               to present to a user because the built-in casting error message is 
               always used at the top level.
             */
            throw new Error(`${val} is not a valid version 4 UUID`);
        }
        return val;
    }
}

// Add `UUIDv4` to the type registry
mongoose.Schema.Types.UUIDv4 = UUIDv4;

const entitySchema = new mongoose.Schema({
    entityKey: {
        type: UUIDv4,
        required: true
    }
})

const Entity = mongoose.model('Entity', entitySchema)

const testEntity = new Entity({
    entityKey: "123456789"
})

testEntity.save().then(() => {
    console.log('done')
}).catch((e) => {
    console.log(e.errors.entityKey.reason.message) // This is where the custom message can be found
})

显然,我可以跳过创建自定义 SchemaType,但我希望避免每次在我的模式中使用 entityKey 时都必须指定自定义验证器(它们被大量使用)。

const UUIDv4Validator = {
    validator: function(v) {
        // If is valid. . . return true
        // else return false
    },
    message: 'Invalid UUIDv4'
}

const entitySchema = new mongoose.Schema({
    entityKey: {
        type: String,
        required: true,
        validate: UUIDv4Validator // I don't want to have to do this every time
    }
})

我知道我可以保留自定义模式类型并使用可选的链接运算符检查我的 try/catch 语句中是否存在此错误,但我宁愿避免这种需要,因为它会重复:

try {
    // do stuff . . .
    await testEntity.save()
} catch (e) {
    const message = e?.errors?.entityKey?.reason?.message ?? e.message. // No thank you!
    // do stuff . . .
}

我尝试阅读文档以了解如何为自定义架构类型创建自定义验证方法,但我没有成功尝试任何工作,到目前为止我没有在网上找到任何示例。

如何让自定义验证器永久链接到我的 UUIDv4 自定义架构类型,它将评估试图保存的数据,并在适当时 return 我的自定义错误消息?

我按照 mongoose SchemaTypes documentation 中的 link 并挖掘了一些 mongoose 插件的源代码找到了答案。

本质上,要制作一个普遍应用于 mongoose SchemaType 的所有实例的自定义验证器,应该将验证器直接传递给 SchemaType 的 validate() 方法。

在自定义 SchemaType class 定义中,可以通过在 class 构造函数中调用 super 的验证器方法来完成。这是一个例子:

class UUIDv4 extends mongoose.SchemaType {
    constructor(key, options) {
        super(key, options, 'UUIDv4');
        
        // Call the validate method of super and pass in a validator
        // function and a message to return when validation fails
        this.validate(function(val){
            return isUUIDv4(val) // Example UUIDv4 validation check
        }, '{PATH}: "{VALUE}" is not a valid version 4 UUID')
    }
    
    // Other class methods such as cast(), etc. . .
}

如文档(以及我最初的问题)所示,mongoose validators 接受一个包含 validatormessage 的对象 {}。尽管它们经常被添加到模式中以为特定的 field/path 提供自定义验证,但可以通过调用 SchemaType.validate() 将它们添加到模式类型的整体验证中(其中 SchemaType 被实际的 SchemaType 名称替换,即 String ) 并将验证器函数和消息作为两个单独的参数传递。

对于那些使用自定义 SchemaTypes 的人,例如在我的用例中,可以通过使 cast() 方法始终 return 为真,并且仅从验证器获取所需的错误消息在 save().

上处理验证