minusql
v1.9.4
Published
A minimalistic ORM for MySQL and Postgres
Readme
minusql
minusql это минималистичный конструктор SQL запросов для Node.js, поддерживающий MySQL и PostgreSQL. Пишем запросы красиво, а не как обычно.
Особенности
- 0 зависимостей
- автоматическая конвертация регистра (snake_case ↔ camelCase)
- параметризованные запросы
- мощный формат описания выражений любой сложности
- поддержка транзакций
- гибкие преобразования формата вывода
- поддержка JOIN
- обработка конфликтов при вставке (поддержка upsert)
- поддержка EXPLAIN
- возможность делать запросы вручную с помощью tagged template literals
Главный принцип — простые вещи должны решаться легко, а для сложных есть мощный и выразительный синтаксис, который не нужно долго осваивать.
Установка
npm install minusqlНачало работы
Библиотека работает как обёртка над драйверами БД. Создаём экземпляр класса MySQL или Postgres, передавая клиент из библиотек mysql или pg соответственно:
MySQL
const mysql = require('mysql');
const { MySQL } = require('minusql');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb'
});
const db = new MySQL(pool);
// Query example
const user = await db.users.selectOne({ id: 1 });PostgreSQL
const { Pool } = require('pg');
const { Postgres } = require('minusql');
const pool = new Pool({
host: 'localhost',
user: 'postgres',
password: 'password',
database: 'mydb'
});
const db = new Postgres(pool);
// Query example
const user = await db.users.selectOne({ id: 1 });По умолчанию minusql конвертирует все идентификаторы в snake_case при составлении запросов, и обратно в camelCase при получении результатов. Это поведение можно отключить, если передать в конструктор { convertCase: false } вторым аргументом.
API
Для выполнения запросов к какой-то таблице, обращайтесь к ней как к полю созданного экземпляра db: например, db.users соответствует таблице users. Чтобы выполнить join между несколькими таблицами, используйте db.join() (см. ниже).
Также для выбора таблицы можно использовать db.from('users').
Чтобы выполнять сырые запросы, используйте db.exec(query, params) или tagged templates (dbSELECT * FROM users WHERE id = ${1}).
Конструирование запросов
Чтобы выполнять CRUD-операции, используйте один из следующих методов (подробнее они описаны ниже):
db.table.select(where?, options?)db.table.insert(rows, options?)db.table.update(update, where?, options?)db.table.delete(where?)
Все они возвращают экземпляры класса Query, который представляет собой подготовленное к выполнению SQL-выражение (а также список подставляемых в него параметров).
Данный запрос будет выполнен как только вы сделаете await на нём (или вызовете его метод exec()). Вместо выполнения вы можете изучить его содержимое (поле text) для отладки или вызвать explain(), чтобы создать новый запрос — c EXPLAIN в начале.
Также доступно два вспомогательных метода для распространённых случаев:
selectAll(options?)эквивалентенselect(null, options)selectOne(where?, options?)эквивалентенselect(where, options).one()
Структурированные выражения
Для составления условий выборки, а также во всех остальных местах minusql использует собственный формат описания выражений. Он создавался так, чтобы быть лаконичным, но универсальным.
Выражение описывается объектом произвольной степени вложенности. Можно рассматривать его как AST-дерево. Узлом дерева может быть:
- Любое примитивное значение, экземпляры классов Date или RegExp (например,
'Hi'или3.1415)
Такое значение будет экранировано и непосредственно подставлено в текст запроса. - Экземляр класса Symbol (например
Symbol('birthday'))
Символы позволяют ссылаться на идентификаторы полей (колонки таблиц). Обратите внимание, что если вы используете просто строку, она будет экранирована именно как строка, а не как идентификатор. - Массив (например
['>', 5, 3])
В этом случае первый элемент — это название SQL-функции или оператора, а все последующие — аргументы (которые являются вложенными узлами дерева). Вы можете использовать практически любые функции и операторы, доступные в MySQL или Postgres. - Объект, содержащий поле $ (например
{$: 'Hello world', type: 'string'})
Так обозначаются значения, которые будут вынесены в список подставляемых переменных. Все данные, не являющиеся константами, рекомендуется оборачивать в такую конструкцию: это улучшает производительность, а также усиливает защиту от SQL-инъекций. Дополнительное полеtypeявляется опциональным. - Любой другой объект (например
{ id: 5, name: 'John' })
Это удобный способ записывать набор условий, объединённых операторомAND.- если вложенное значение является массивом, оно обрабатывается так, как если бы его ключ стоял после первого элемента:
{ x: ['>', y] }это то же самое, что['>', Symbol('x'), y] - если вложенное значение — регулярное выражение (экземпляр класса RegExp), оно конвертируется либо в оператор сравнения по шаблону (
LIKE/ILIKE), либо в сравнение с регулярным выражением (~/~*/REGEXP) - если вложенное значение это
null, оно становится выражением видаx IS NULL - в остальных случаях происходит преобразование в оператор равенства (колонки, соответствующей ключу, и вложенного выражения)
- если вложенное значение является массивом, оно обрабатывается так, как если бы его ключ стоял после первого элемента:
