我有一个node.js后端,该后端使用Knex.js从各种输入动态构造数据库查询。一些输入需要异步处理。我的问题是,我无法从异步函数(或者当然在Promise resolve函数中)返回knex查询对象,因为这会触发查询的执行。当前,我需要先处理所有异步输入,然后再将其交给查询构建函数,但这确实限制了它们的可组合性。有没有一种方法可以防止Knex在异步上下文中执行查询对象?
答案 0 :(得分:0)
您需要将构建器包装为函数或对象:
async function returnsQueryBuilder() {
return { builder : knex('mytable').where('foo', 'bar') };
}
const query = (await returnsQueryBuilder()).builder;
因为异步函数实际上包装并解析了返回的值/承诺/可转换对象,并且knex
查询生成器是thenable
(https://promisesaplus.com/第1.2章),因此它会自动重新解析。
出于相同的原因,您还可以直接等待查询构建器从构建的查询中获取结果。如果没有knex查询生成器,thenable
也不起作用:
// returns all the rows of the table
const result = await knex('table');
因此,正如我所说,唯一的选择是不直接返回查询构建器实例,而是将其包装到非thenable
的东西中。
答案 1 :(得分:0)
感谢MikaelLepistö的回答,我对如何解决这个问题有了一个想法。正如他指出的那样,借助具有thenables
函数,Knex查询是then
。实际上,JavaScript await关键字会调用您提供给它的任何对象的then
函数,无论是否承诺。因此,为了防止在await(或.then())上执行查询,您可以删除/重命名查询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:)
我有义务在评论中指出米凯尔的有效批评。这是编写自己的包装器类的棘手且潜在的危险捷径,并且可能使您的代码更难以理解。但我也坚持认为,在我的特定用例中键入正确的TypeScript是一种有效且有效的解决方案。
UPDATE2 :现在,无需弄乱原型:)。在实例上将.then设置为undefined即可。
答案 2 :(得分:0)
对我而言,最重要的是提取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("*")