Какие плюсы и минусы у Knex.js?

Ответ

Плюсы Knex.js как query builder для Node.js:

  • Безопасность: Автоматически экранирует параметры, что предотвращает SQL-инъекции.
  • Кроссплатформенность: Единый API для работы с PostgreSQL, MySQL, SQLite, Oracle и другими СУБД.
  • Гибкость: Позволяет комбинировать построитель запросов с raw SQL, когда это необходимо.
  • Миграции: Встроенная и простая в использовании система миграций и сидов.
  • Простота: Более низкий порог входа по сравнению с полноценными ORM.

Минусы:

  • Отсутствие ORM-функций: Нет встроенной работы с отношениями (associations), валидации на уровне модели или хуков жизненного цикла.
  • Сложные запросы: Для очень сложных JOIN или оконных функций синтаксис builder может стать громоздким, и проще написать raw SQL.
  • Дополнительный слой: Это всё же дополнительная абстракция, которая может скрывать некоторые специфичные для базы оптимизации.

Пример использования в Node.js-проекте:

const knex = require('knex')({
  client: 'pg',
  connection: process.env.DATABASE_URL,
});

// Построение запроса с помощью builder
const users = await knex('users')
  .select('id', 'email')
  .where('created_at', '>', knex.raw("NOW() - INTERVAL '7 days'"))
  .orderBy('email', 'asc');

// Использование raw SQL для специфичной функции
const stats = await knex.raw(`
  SELECT date_trunc('day', created_at) as day,
         COUNT(*) as signups
  FROM users
  GROUP BY day
  ORDER BY day DESC
`);

Ответ 18+ 🔞

А, Knex.js, говоришь? Ну, это такая штука, которая в мире Node.js как надежный мужик с инструментами — не ORM-монстр, а так, query builder, но со своими приколами. Слушай, давай разберем, что он может и где он нихуя не может.

Что в нём хорошего, или почему его иногда любят:

  • Безопасность, мать его. Это главный козырь. Он параметры сам экранирует, так что можно не бздеть по поводу SQL-инъекций. Не придется, как в старые времена, строки склеивать и молиться, чтобы какой-нибудь хитрожопый пользователь не вставил ' OR '1'='1. За это ему отдельный респект.
  • Кроссплатформенность, ёпта. Ну то есть пишешь код один раз, а он работает с PostgreSQL, MySQL, SQLite... Хуй с ним, даже с Oracle! Меняешь в конфиге одну строчку — client — и вроде как всё должно поехать. Не надо учить кучу разных диалектов SQL сходу. Удобно, чо.
  • Гибкость — овердохуища. Не нравится тебе его синтаксис для какой-то дикой оконной функции? Да похуй! Берёшь knex.raw() и пишешь голый SQL, как бог на душу положит. Лучше, чем в чистом ORM, где тебя могут заставить прыгать через обручи, чтобы выполнить простой запрос.
  • Миграции. Встроены, простые. Не надо городить огород со сторонними скриптами. Создал, накатил, откатил — красота. Для старта проектов — то, что надо.
  • Простота. По сравнению с тем же Sequelize или TypeORM, порог входа ниже плинтуса. Открыл документацию, через полчаса уже запросы пишешь. Не надо разбираться в хитросплетениях моделей, отношений и прочей магии.

А теперь, блядь, ложка дёгтя, или где он нихуя не канает:

  • ORM-то нет, сука! Вот это главная засада. Хочешь автоматически подтянуть связанные записи? Например, юзера с его заказами? Забудь. Придётся самому джойны писать и руками объекты собирать. Валидация данных? Тоже твои проблемы. Хуки на сохранение или удаление? Иди нахуй, сам придумывай. Это просто строитель запросов, а не волшебная палочка.
  • Сложные запросы. Ну, когда начинаешь городить многоэтажные JOIN'ы с кучей условий, его синтаксис превращается в такую кашу, что глаза кровоточат. Иногда проще, честно, взять raw и написать SQL-запрос в чистом виде — и читабельнее, и понятнее будет. А то получается пиздопроебина какая-то из цепочки методов.
  • Лишний слой. Это всё же абстракция. А любая абстракция иногда скрывает какие-то специфичные для конкретной базы фишки, которые могли бы ускорить запрос в три раза. Бывает, смотришь на сгенерированный им SQL и думаешь: «Ну ядрёна вошь, зачем ты так, можно же было проще!».

Ну и, как водится, примерчик, чтобы было понятно, о чём речь:

const knex = require('knex')({
  client: 'pg',
  connection: process.env.DATABASE_URL,
});

// Вот так это выглядит — красиво, цепочкой, как будто Лего собираешь.
const users = await knex('users')
  .select('id', 'email')
  .where('created_at', '>', knex.raw("NOW() - INTERVAL '7 days'"))
  .orderBy('email', 'asc');

// А вот тут уже, бля, его синтаксис не вывозит, и ты просто пишешь SQL как мужик.
const stats = await knex.raw(`
  SELECT date_trunc('day', created_at) as day,
         COUNT(*) as signups
  FROM users
  GROUP BY day
  ORDER BY day DESC
`);

Короче, инструмент как инструмент. Для быстрых проектов, микросервисов или когда тебе осточертели ORM и их навороты — самое то. А если тебе нужны сложные связи, валидация и магия — это, чувак, не твой выбор, иди смотри в сторону полноценных ORM. Выбор за тобой.