从异步函数返回查询对象时,如何防止Knex.js运行查询对象?

时间:2019-07-04 20:53:35

标签: javascript node.js knex.js

我有一个node.js后端,该后端使用Knex.js从各种输入动态构造数据库查询。一些输入需要异步处理。我的问题是,我无法从异步函数(或者当然在Promise resolve函数中)返回knex查询对象,因为这会触发查询的执行。当前,我需要先处理所有异步输入,然后再将其交给查询构建函数,但这确实限制了它们的可组合性。有没有一种方法可以防止Knex在异步上下文中执行查询对象?

3 个答案:

答案 0 :(得分:0)

您需要将构建器包装为函数或对象:

async function returnsQueryBuilder() {
  return { builder : knex('mytable').where('foo', 'bar') };
}

const query = (await returnsQueryBuilder()).builder;

因为异步函数实际上包装并解析了返回的值/承诺/可转换对象,并且knex查询生成器是thenablehttps://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("*")