Базы данных
Учётные данные для базы данных напрямую подключают сценарий к базе Postgres или MySQL — читать и писать строки можно
через типизированные действия, а для всего, что они не покрывают, есть запасной вариант — сырой SQL. После
синхронизации схемы редактор «знает» таблицы подключённой базы: узел «Select» на таблице orders
предлагает orders в списке таблиц, результат типизирован по строкам, а Monaco подсказывает названия
колонок при вводе фильтра.
Подключение базы данных
Заголовок раздела «Подключение базы данных»Учётные данные для Postgres или MySQL добавляются так же, как для любой другой интеграции, — одной строкой
подключения: postgres://user:pass@host:5432/db или mysql://user:pass@host:3306/db, а не
отдельными полями хоста/порта/пользователя/пароля, потому что dev- и production-база обычно — два совершенно разных
сервера, а не один и тот же с другим паролем; строка подключения — это ещё и то, что уже даёт любой драйвер, ORM или
консоль облачного провайдера. Рядом с ней — настройка ssl (prefer/require/disable). Как и любые учётные
данные в движке, строка подключения хранится отдельно для dev- и prod-окружений и шифруется перед сохранением —
редактор и «Синхронизировать структуру» всегда используют dev-строку, опубликованный (production) запуск — prod.
Синхронизация структуры
Заголовок раздела «Синхронизация структуры»Нажмите «Синхронизировать структуру» на учётных данных, чтобы редактор прочитал реальные таблицы и колонки базы. Это одно подключение (по dev-строке), чтение схемы и её сохранение — после этого живого обращения к базе при редактировании узла больше не происходит. Перезапускайте синхронизацию всякий раз, когда схема меняется (добавлена колонка, переименована таблица), чтобы вернуть картину редактора в актуальное состояние; если забыть — ничего не ломается сразу, узел, ссылающийся на уже не совпадающую таблицу, просто упадёт с обычной ошибкой базы данных при следующем запуске.
После синхронизации у каждой таблицы появляются четыре типа, которыми редактор пользуется автоматически: Row
(все колонки, как они приходят из запроса), Insert (все колонки, но те, у которых есть значение по умолчанию
или допустим NULL, становятся необязательными), Patch (все колонки необязательны — для частичного
обновления) и Where (см. ниже). Типы колонок сопоставляются ожидаемо — целые и дробные числа в числа,
текст/даты/UUID в строки, булевы в булевы, JSON-колонки и всё нераспознанное — в разрешающий тип «any».
Действия
Заголовок раздела «Действия»У каждого диалекта (Postgres, MySQL, SQLite) одинаковый набор из шести действий:
Select — возвращает все подходящие строки массивом Row. Принимает необязательный фильтр
where,orderBy(например,created_at desc) иlimit.Select one — как Select, но возвращает одну строку Row и падает с ошибкой, если ничего не найдено; если «ни одной строки» — нормальный, ожидаемый результат, а не ошибка, используйте Select с лимитом 1.
Insert — вставляет одну строку (типизированную как Insert) и возвращает её обратно как Row, включая любые колонки, заполненные самой базой (автоинкрементный id, метка времени по умолчанию).
Update — применяет Patch ко всем строкам, подходящим под
where, и возвращает число изменённых строк.whereобязателен и не может быть пустым — случайно обновить всю таблицу, оставив фильтр пустым, невозможно.Delete — то же обязательное непустое
where, что и у Update, возвращает число удалённых строк.Query — запасной вариант для join’ов, агрегатов и всего остального, что не выражается пятью действиями выше: сырой SQL-запрос плюс отдельный список параметров, подставляемых через плейсхолдеры
$1/$2(Postgres) или?(MySQL/SQLite). Сам текст SQL никогда не подставляется со значениями напрямую — параметры всегда передаются отдельно, та же защита от SQL-инъекций, что даёт любой API с параметризованными запросами.
Фильтрация через where
Заголовок раздела «Фильтрация через where»where — небольшой язык фильтров, а не просто равенство. Голое значение у колонки означает «равно» (а
null — IS NULL); для чего-то другого дайте этой колонке объект с одним или несколькими
операторами — eq, ne, gt, gte, lt, lte,
in, notIn, isNull, а для текстовых колонок ещё like/
ilike/startsWith/contains. Несколько колонок по умолчанию объединяются через
AND; чтобы задать альтернативы, оберните их в явный массив or (или and) — их можно
вкладывать друг в друга:
// status равен "new" или "paid", и total больше 100{ status: { in: ['new', 'paid'] }, total: { gt: 100 } }
// id равен 1 или 2{ or: [{ id: 1 }, { id: 2 }] }
// note содержит "urgent" без учёта регистра (Postgres){ note: { ilike: '%urgent%' } }Повторы и идемпотентность
Заголовок раздела «Повторы и идемпотентность»Каждое действие с базой данных выполняется как отдельный шаг устойчивого выполнения сценария и, как любой другой шаг, автоматически повторяется при ошибке — сбой сети, оборванное соединение, кратковременно недоступная база. Обычно это именно то, что нужно: неудачная запись считается «строка не создана», и повтор доводит дело до конца. Единственный граничный случай, о котором стоит знать, — запись, которую база данных на самом деле зафиксировала, но подтверждение которой не успело вернуться до обрыва соединения: повтор в этом редком случае может вставить или обновить одну и ту же строку дважды. Если в таблицу пишет сценарий, который может повториться, добавьте ей уникальное ограничение (или отдельную колонку с ключом идемпотентности), чтобы повторная попытка отклонялась самой базой данных, а не молча выполнялась второй раз.
SQLite — только локально/для разработки
Заголовок раздела «SQLite — только локально/для разработки»SQLite доступен как третий диалект, работающий с обычным файлом (или базой в памяти) вместо отдельного сервера — не нужно запускать ещё один сервис, что удобно для локальной разработки, самостоятельного развёртывания на одном сервере с примонтированным томом и для тестов. Это не production-выбор для развёртывания, которое масштабирует runner-поды вверх и вниз: собственная файловая система runner-пода не сохраняется между перезапусками, поэтому файл SQLite внутри пода не переживёт масштабирование до нуля. Для всего, что должно пережить под, написавший данные, используйте Postgres или MySQL.
