为 objection.js 进行的所有查询打印完整的 SQL

Print complete SQL for all queries made by objection.js

我正在寻找一种方法来为 Objection.js 库执行的所有查询捕获原始 SQL,并将绑定插入 SQL字符串.

我知道有一个 Knex event handler 可以利用,但是 on('query', data) 的第二个参数是一个包含 SQL 模板的对象,绑定是分开的。

例如

{
  sql: "select \"accounts\".* from \"accounts\" where \"id\" = ?",
  bindings: [1]
}

我想知道执行此操作的最优雅方法是否是使用 QueryBuilder 上存在的类似 .toString() 方法的方法,但我认为 QueryBuilder 的特定实例不可用回调。理想情况下,我不会重新发明轮子并重新编写 Knex 的插值方法。

任何指点将不胜感激。

谢谢!

Knex / objection.js 不提供任何可以安全进行插值的方法。 .toString() 在某些情况下会产生无效结果,并且它们容易受到 sql 注入攻击。

如果仅用于调试目的,查看 .toQuery() 的实现方式会有所帮助。 https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/interface.js#L12

knex.client._formatQuery(sql, bindings, tz)

虽然它不是 public API,但不能保证它在 knex 的补丁版本之间是相同的。

您可以使用 .toKnexQuery() function to pull out the underlying knex query builder and gain access to .toSQL().toQuery()

我使用 Objection 的版本 2 测试并验证了以下示例。我在 version 1 docs 中找不到 .toKnexQuery(),因此无法验证它是否适用于早期版本的 Objection。

// Users.js
const { Model } = require('objection')

class Users extends Model {
  static get tableName() { return 'users' }
  // Insert jsonSchema, relationMappings, etc. here
}

module.exports = Users
const Users = require('./path/to/Users')

const builder = Users.query()
  .findById(1)
  .toKnexQuery()

console.log(builder.toQuery())
// "select `users`.* from `users` where `users`.`id` = 1"

console.log(builder.toSQL())
// {
//   method: 'select',
//   bindings: [ 1 ],
//   sql: 'select `users`.* from `users` where `users`.`id` = ?'
// }

可能应该重申,除了 .toString().toQuery() 也容易受到 SQL 注入攻击(参见 here)。

修改查询的更“负责任”的方式可能是这样的(MySQL):

const { sql, bindings } = Users.query()
  .insert({ id: 1 })
  .toKnexQuery()
  .toSQL()
  .toNative()

Users.knex().raw(`${sql} ON DUPLICATE KEY UPDATE foo = ?`, [...bindings, 'bar'])