如果我更喜欢使用 raw 而不是其内置函数,那么使用 Knex 是否毫无意义?

Is it pointless to use Knex if I prefer using raw over its built-in functions?

我知道 Knex 有很多好处,这就是我考虑将它用于我的 Node 应用程序的原因。我以前用过它,我真的很喜欢用它来编写原始查询。 (注意:我仍处于 Knex 的学习阶段。)就个人而言,我认为它们使代码看起来比使用基本 SQL 稍微好一些。我的问题就是从这一点开始的,因为也许我的偏好在这里很愚蠢。

我也很想对 Knex 的内置功能发表意见。对于那些喜欢生的人来说,你喜欢他们什么?无论我选择哪种途径,我的目标都是在我的应用程序中保持一致性。

感谢您的意见!

这不是毫无意义的。这在一定程度上取决于您是否在团队环境中工作,还有谁可能必须维护它,以及他们对编写 SQL 查询的舒适程度。请注意,许多可以使用 Knex 完成的事情也可以使用直接数据库驱动程序完成,因此对于许多技术选择,它归结为 personal/team 偏好和易于维护。

即使假设您从不使用查询生成器,Knex 也提供:

  • 根据目前的配置比较简单NODE_ENV
  • connection/pool 管理
  • 简单的参数化
  • 轻松交易
  • 轻松迁移和播种

为什么不用.raw?好吧,这是品尝者的选择,查询构建器并不适合所有人。但是,查询构建器的粉丝会告诉您:

  • 当你不处理一堆原始数据时,在数据库后端之间迁移会更容易 SQL
  • 许多人发现 Knex 语法更容易阅读,因为能够合理理解 JavaScript 承诺链的人数可能超过理解 SQL
  • 的人数
  • 它往往更紧凑
  • 它比 .raw 提供了 name/syntax 级别的安全性(如果您使用的是 TypeScript,还提供编译时类型安全和编辑器支持)。

查询构建器也非常适合组合,因此:

const userPhoneNumbers = knex('users').select({ id, email });

// later...
const gmailUsers = userPhoneNumbers.where('email', 'ilike', '%gmail.com');

// still later...
return gmailUsers.where('email_confirmed', true);

一个人为的例子,但在处理不那么琐碎的需求时它可以非常有表现力。

我知道这个 post 有点旧,但我同意混合方法。在某些情况下,查询构建器语法会为正在编写的“错误”查询提供良好的反馈,这很好。

另一方面,我有一些我认为使用构建器编写会变得过于冗长的查询,所以我使用 .raw。这是我认为保持 .raw 格式的查询示例。

    select
    s.client_id,
    s.package_id,
    p.products as pp,
    s.products as sp
    from (
      # grouped subscribed products
      select
      client_id,
      package_id,
      group_concat(product_id order by product_id) as products
      from subscriptions where package_id is not null
      group by client_id, package_id) as s
    inner join (
      # grouped package products
      select
      package_id,
      group_concat(product_id order by product_id) as products
      from package_products
      group by package_id) as p
    on p.package_id = s.package_id where p.products <> s.products
    order by s.client_id

我当然可以使用生成器,但我发现原始 SQL 使用嵌套选择更容易掌握。我还创建了一个抽象 class 以简化为微型 ORM。

class Table {
  constructor() {
    // nothing
  }

  static tableName = null;

  /**
   * Find by id
   * @param {Integer} userId
   * @return {Promise}
   *
   * Example:
   * Table.findById(id).then(result => {
   *   console.log(result)
   * }).catch(err => {
   *   console.error(err);
   * })
   */
  static findById(itemId) {
    return this.findOneBy({id: itemId});
  }

  /**
   * Generic findBy
   * @param {String|Object} column or objcet with keys
   * @param {Any} value
   */
  static findOneBy(column, value = null) {
    return this.findBy(column, value).then(results => {
      return results[0];
    });
  }

  /**
   * Generic findBy
   * @param {String|Object} column or objcet with keys
   * @param {Any} value
   */
  static findBy(column, value = null) {
    return database.getConnection().then(conn => {
      const schema = this.schemaName;
      const query = conn.select().from(this.tableName);
      if (schema){
        query.withSchema(schema);
      }
      if (typeof column === 'object '&& !Array.isArray(column) && value === null) {
        for (const col in column) {
          query.where(col, column[col]);
        }
      } else {
        query.where(column, value);
      }
      return query;
    });
  }
}

这允许我使用以下方法创建模型:

class Client extends Table {
  static tableName = 'clients';
  constructor() {
    super();
  }
}

Client.findById(1).then(result => {
  console.log(result);
}).catch(console.error);