从异步函数返回查询对象时,如何防止 Knex.js 来自 运行 查询对象?
How to prevent Knex.js from running a query object when returning it from an async function?
我有一个 node.js 后端,它使用 Knex.js 从各种输入动态构建数据库查询。一些输入需要异步处理。我的问题是,我不能 return 来自异步函数(或者当然是 Promise 解析函数)的 knex 查询对象,因为这会触发查询的执行。目前,我需要先处理所有异步输入,然后再将它们交给查询构建函数,但这确实限制了它们的可组合性。有没有办法阻止 Knex 在异步上下文中执行查询对象?
您需要将构建器包装到函数或对象中:
async function returnsQueryBuilder() {
return { builder : knex('mytable').where('foo', 'bar') };
}
const query = (await returnsQueryBuilder()).builder;
因为异步函数实际上包装并解析了 returned values/promises/thenables 并且 knex
查询构建器是一个 thenable
(https://promisesaplus.com/ 第 1.2 章)它得到了解析自动。
出于同样的原因,您也可以直接等待查询构建器从构建的查询中获取结果。如果没有 knex 查询生成器 thenable
,这也不起作用:
// returns all the rows of the table
const result = await knex('table');
所以正如我所说,唯一的选择是不直接 return 查询生成器实例,而是将其包装到不是 thenable
.
的东西中
感谢 Mikael Lepistö 的回答,我知道了如何解决这个问题。正如他指出的那样,Knex 查询由于具有 then
功能而 thenables
。 JavaScript await 关键字实际上调用了您提供给它的任何 object 的 then
函数,无论是否承诺。因此,为了防止在等待(或 .then())时执行查询,您可以 remove/rename 查询 then
函数。例如
const getQuery = async () => {
const qb = knex("users")
.select("id")
.limit(100);
qb.promise = qb.then;
qb.then = undefined;
return qb;
};
const query = await getQuery();
console.log(query.toString());
console.log(await query.promise());
更新,警告:不要在家里尝试这个孩子s :)
我觉得有必要在评论中指出 Mikael 的有效批评。这是编写自己的包装器 class 的 hacky 和潜在危险的捷径,可能会使您的代码更难理解。但我也坚持我的评估,即在我的特定用例中使用正确的 TypeScript 键入它是一个有效且高效的解决方案。
UPDATE2:现在不要弄乱原型 :)。在实例上将 .then 设置为 undefined 就可以了。
对于我的需要,最重要的是提取 where 子句,因为这通常是复杂的部分并且在多个查询之间共享。令人高兴的是,使用 Knex 可以轻松做到这一点。
例如,如果您有此查询,并且 where 函数是与其他查询共享的内容。
const data = await knex("mytable")
.where(builder => {
builder.whereNull("mytable.deleted_at")
if (something) {
builder.where("something", 42)
}
})
.select("*")
您可以重构为:
const makeWhereClause = ({ something }) => builder => {
builder.whereNull("mytable.deleted_at")
if (something) {
builder.where("something", 42)
}
}
const data = await knex("mytable")
.where(makeWhereClause({something})
.select("*")
我有一个 node.js 后端,它使用 Knex.js 从各种输入动态构建数据库查询。一些输入需要异步处理。我的问题是,我不能 return 来自异步函数(或者当然是 Promise 解析函数)的 knex 查询对象,因为这会触发查询的执行。目前,我需要先处理所有异步输入,然后再将它们交给查询构建函数,但这确实限制了它们的可组合性。有没有办法阻止 Knex 在异步上下文中执行查询对象?
您需要将构建器包装到函数或对象中:
async function returnsQueryBuilder() {
return { builder : knex('mytable').where('foo', 'bar') };
}
const query = (await returnsQueryBuilder()).builder;
因为异步函数实际上包装并解析了 returned values/promises/thenables 并且 knex
查询构建器是一个 thenable
(https://promisesaplus.com/ 第 1.2 章)它得到了解析自动。
出于同样的原因,您也可以直接等待查询构建器从构建的查询中获取结果。如果没有 knex 查询生成器 thenable
,这也不起作用:
// returns all the rows of the table
const result = await knex('table');
所以正如我所说,唯一的选择是不直接 return 查询生成器实例,而是将其包装到不是 thenable
.
感谢 Mikael Lepistö 的回答,我知道了如何解决这个问题。正如他指出的那样,Knex 查询由于具有 then
功能而 thenables
。 JavaScript await 关键字实际上调用了您提供给它的任何 object 的 then
函数,无论是否承诺。因此,为了防止在等待(或 .then())时执行查询,您可以 remove/rename 查询 then
函数。例如
const getQuery = async () => {
const qb = knex("users")
.select("id")
.limit(100);
qb.promise = qb.then;
qb.then = undefined;
return qb;
};
const query = await getQuery();
console.log(query.toString());
console.log(await query.promise());
更新,警告:不要在家里尝试这个孩子s :)
我觉得有必要在评论中指出 Mikael 的有效批评。这是编写自己的包装器 class 的 hacky 和潜在危险的捷径,可能会使您的代码更难理解。但我也坚持我的评估,即在我的特定用例中使用正确的 TypeScript 键入它是一个有效且高效的解决方案。
UPDATE2:现在不要弄乱原型 :)。在实例上将 .then 设置为 undefined 就可以了。
对于我的需要,最重要的是提取 where 子句,因为这通常是复杂的部分并且在多个查询之间共享。令人高兴的是,使用 Knex 可以轻松做到这一点。
例如,如果您有此查询,并且 where 函数是与其他查询共享的内容。
const data = await knex("mytable")
.where(builder => {
builder.whereNull("mytable.deleted_at")
if (something) {
builder.where("something", 42)
}
})
.select("*")
您可以重构为:
const makeWhereClause = ({ something }) => builder => {
builder.whereNull("mytable.deleted_at")
if (something) {
builder.where("something", 42)
}
}
const data = await knex("mytable")
.where(makeWhereClause({something})
.select("*")