我有以下型号:
const Invoice = sequelize.define("invoice", {
number: {
type: DataTypes.STRING,
allowNull: false,
unique: { msg: "Invoice number already exists" },
validate: { ...notEmptyMsg("Invoice number") },
},
dateIssued: {
type: DataTypes.DATE,
allowNull: false,
validate: isDateMsg("dateIssued"),
},
dueDate: {
type: DataTypes.DATE,
allowNull: false,
validate: {
...isDateMsg("dueDate"),
isAfterDateIssued(value) {
if (this.dateIssued && value < this.dateIssued) {
throw new Error("Due date cannot be before the date issued");
}
},
},
},
sender: {
type: DataTypes.TEXT,
allowNull: false,
validate: notEmptyMsg("Sender"),
},
recipient: {
type: DataTypes.TEXT,
allowNull: false,
validate: notEmptyMsg("Recipient"),
},
items: {
type: DataTypes.JSON,
allowNull: false,
validate: { isArrayOfItems: validateItemsArray },
},
status: {
type: DataTypes.ENUM("Draft", "Issued", "Paid", "Part Paid", "Cancelled", "Disputed", "On Hold"),
allowNull: false,
validate: {
isIn: {
args: [["Draft", "Issued", "Paid", "Part Paid", "Cancelled", "Disputed", "On Hold"]],
msg: "Invalid status",
},
},
},
footnotes: {
type: DataTypes.TEXT,
allowNull: true,
validate: {
isString(value) {
if (typeof value !== "string") {
throw new Error("Footnotes must be a string");
}
},
},
},
organizationId: {
type: DataTypes.INTEGER,
allowNull: false,
references: { model: "organizations", key: "id" },
},
// Virtual field calculating total
total: {
type: DataTypes.VIRTUAL,
get() {
return parseFloat(
this.items
.reduce((acc, item) => acc + item.quantity * item.unitPrice * (1 + item.taxRate), 0)
.toFixed(2)
);
},
},
// Virtual field calculating subtotal
subtotal: {
type: DataTypes.VIRTUAL,
get() {
return this.items.reduce((acc, item) => acc + item.quantity * item.unitPrice, 0);
},
},
});
在更新字段时,我遇到了一个关于虚拟字段的奇怪问题.
以下测试通过:
test("Update an invoice", async () => {
const invoiceData = createInvoiceData();
const invoice = await Invoice.create(invoiceData);
await invoice.update({ recipient: "Lorem" });
expect(invoice.recipient).toBe("Lorem");
});
但这一次抛出了一个错误:
test("Update an invoice", async () => {
const invoiceData = createInvoiceData();
const invoice = await Invoice.create(invoiceData);
await Invoice.update({ recipient: "Lorem" }, { where: { id: invoice.id } });
const updatedInvoice = await Invoice.findByPk(invoice.id);
expect(updatedInvoice.recipient).toBe("Lorem");
});
这是错误:
● Invoice Model › Update an invoice
TypeError: Cannot read properties of undefined (reading 'reduce')
129 | return parseFloat(
130 | this.items
> 131 | .reduce((acc, item) => acc + item.quantity * item.unitPrice * (1 + item.taxRate), 0)
| ^
132 | .toFixed(2)
133 | );
134 | },
at model.reduce (src/models/invoice.js:131:8)
at model.get (node_modules/sequelize/src/model.js:3651:41)
at model.get (node_modules/sequelize/src/model.js:3685:33)
at Function.update (node_modules/sequelize/src/model.js:3247:44)
at Object.update (tests/invoice.model.test.js:72:17)
显然,在这种情况下,当试图计算虚拟字段"总数"时,项是"未定义的".
我不明白为什么第二种写作方法失败了.我在更新数据库,不是吗?
More strangely even是这样一个事实,在测试中失败的同一个方法在生产代码中似乎工作得很好.这就是我在express 路由上做的事情:
exports.updateInvoice = async (req, res, next) => {
try {
const [updateCount] = await Invoice.update(
{ ...req.body },
{
where: { id: req.params.id },
}
);
而且它工作起来没有任何问题.
UPDATE个
有趣的细节我注意到了.如果我在测试用例中更新的是items
字段,则测试通过...
test("Update an invoice (Method #1)", async () => {
const invoiceData = createInvoiceData();
const invoice = await Invoice.create(invoiceData);
await Invoice.update({ items: [] }, { where: { id: invoice.id } });
const updatedInvoice = await Invoice.findByPk(invoice.id);
expect(updatedInvoice.items.length).toBe(0);
});