首页 > 解决方案 > 续集验证:对于单个属性,只允许一项为真

问题描述

export default function (sequelize, DataTypes) {
  const OrderAddress = sequelize.define('OrderAddress', {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
      allowNull: false,
    },
    is_default: {
      type: DataTypes.BOOLEAN,
      allowNull: true,
      defaultValue: false,
    },
    receiver_name: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    phone_number: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    address: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    address_detail: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    postcode: {
      type: DataTypes.STRING,
      allowNull: true,
    },
  }
});

我的orderAddress模型如上所示,我想进行验证以仅允许将一项is_default设置为true.

所以,

const address = {
  is_default: true, // default one
}
const address2 = {
  is_default: true // no you can't!
}

我应该为此模型制作is_default字段unique: true还是添加一些自定义项?validation

标签: sequelize.js

解决方案


您可以在order_id(或任何您的关系字段)和is_defualt(第一个示例)上添加唯一索引,或者您可以对其进行一些重构以将其设置为default_addressonOrder而不是将其设置在OrderAddress(第二个示例)

第一个选项,添加唯一索引

indexes: [
  {
    fields: ['is_default', 'order_id'], // or whatever your relational field is
    unique: true,
  },
],

第二个选项,在订单级别检查

假设它OrderAddress属于Order模型之类的东西,您还可以在此处添加验证以提高效率。由于您想知道哪个地址是默认地址,并且只允许一个,因此添加一个名为的字段Order.default_address并将值设置为“地址”或“地址2”的枚举,指示应该使用哪个地址 - 自然只能设置一个而不是两者兼而有之。

Order然后,您可以在模型上添加一个beforeValidate钩子,检查设置为“默认”的字段是否包含OrderAddress.

export default function (sequelize, DataTypes) {
  const Order = sequelize.define('Order', {
    // your fields
    default_address: {
      type: DataTypes.ENUM(),
      values: ['address', 'address2'],
      allowNull: false,
      // defaultValue: 'address',
  },
  {
    hooks: {
      beforeValidate: function(instance) {
        switch (instance.default_address) {
          case 'address':
          case 'address2': {
            // check to see if address_id or address2_id is set, as needed
            if (!instance[instance.default_address + '_id') { // or + 'Id' if you use camel case
              return Sequelize.Promise.reject(
                new Error(`Default "${instance.default_address}" not set`)
              );
            }
          }
          default: {
            return Sequelize.Promise.reject(
              new Error('You must set a default address')
            );
          }
        }  
      },
    }
  }
});

推荐阅读