orm sequelize что это
ORM-система Sequelize для Node.js
В этом уроке мы узнаем, что такое ORM, зачем он нужен, какие ORM библиотеки есть для Node.js и как с ними работать.
ORM (англ. Object-Relational Mapping, рус. объектно-реляционное отображение) — это технология программирования, который связывает базу данных с моделью объектно-ориентированных языков программирования. Он создает для СУБД виртуальный объектный интерфейс.
ORM помогает программистам избавиться от больших кусков кода, ошибок и повышает скорость разработки. То есть, мы избавляемся от обычных SQL запросов, пишем небольшие куски кодов в объектно-ориентированным стилем, а библиотека транслирует этот код в sql запросы.
Сейчас есть довольно большое количество ORM библиотек для различных языков. Например, для PHP это Propel, Doctrine и Qcodo. Для Python это SQLAlchemy, Storm. Для Java это Hibernate. Для всех популярных объектно-ориентированных языков есть по крайней мере один свой ORM.
После того, как с помощью языка JavaScript (Node.js) стало возможно программировать на сервере, и для этого языка появились ORM системы. Самый популярный из них — это Sequelize. Как понимаете, в этом уроке мы будем изучать его.
Node.js и ORM-система Sequelize — Начинаем работать
Библиотека Sequelize — это Node.js ORM система для работы с такими базами данных, как PostgreSQL, MySQL, SQLite и MSSQL. Давайте начнем работать с Sequelize. Нам нужно установить данную библиотеку. Для установки открываем терминал (командная строка) и вводим команду ниже.
После этого нужно установить одну из библиотек. Например, если вы хотите работать с MySQL, то нужно установить mysql2.
Настройка соединения
После установки библиотек мы можем установить соединение с базой данных.
Давайте немного подробнее рассмотрим этот код. После подключение ORM-системы Sequelize, нам в первом строке кода вернется функция / конструктор. Конструктор принимает несколько аргументов. Во второй строке кода мы вызываем конструктор (создаем новый объект с помощью оператора new), и передаем нужные аргументы / параметры.
Первые три аргументы — это данные доступа к базе данных:
Последним аргументом конструктор принимает объект, где в виде key-value указаны необходимые параметры.
Пример кода, который указан выше, это общий пример, поэтому предлагаю рассмотреть конкретный пример. Например, давайте подключимся к базе данных MySQL.
В константе (переменная) sequelize содержится экземпляр соединения и мы можем с ним работать. Sequelize имеет функцию (метод) authenticate, с помощью которого можно проверить состояние соединение.
Опасная уязвимость в популярной библиотеке Sequelize
Привет, Хабр! Данная статья будет интересна тем, кто уже использует библиотеку Sequelize или же только собирается с ней работать. Под катом мы расскажем, чем встроенный функционал operatorAliases может быть вреден и как избежать утечки из собственной базы данных.
Что такое Sequelize, где он используется и для чего?
Sequelize — это ORM-библиотека на Node.js для Postgres, MySQL, MariaDB, SQLite и Microsoft SQL Server, которая осуществляет сопоставление таблиц в бд и отношений между ними с классами. При использовании Sequelize мы можем не писать SQL-запросы, а должны работать с данными как с обычными объектами. Она имеет надежную поддержку транзакций, отношения, активную и отложенную загрузку, репликацию чтения и многое другое.
Что за опция operatorAliases, и в чем заключается ее опасность?
По умолчанию Sequelize использует операторы символов. Использование Sequelize без символьных псевдонимов, конечно, повышает безопасность. И хотя отсутствие строковых псевдонимов делает инъекцию операторов крайне маловероятной, мы всегда должны корректно проверять и очищать данные, вводимые пользователем.
А сама опция operatorAliases позволяет установить, будут ли доступны операторы-псевдонимы. Вот как выглядит пример активации в коде:
Когда все работает правильно
Рассмотрим код демо-приложения. Файл модели user.model.js содержит:
Видно, что в таблице пользователей есть три поля, и они все имеют строковой тип данных.
Файл контроллера auth.controller.js содержит:
В коде используется метод findOne к модели User. И метод findOne возвращает первую строку из базы данных, согласно переданному условию запроса. В данном случае, приложение получает от пользователя данные username и password, применяет их в запрос к таблице users.
Сгенерированный в данном случае запрос будет выглядеть примерно так:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = :username AND `users`.`password` = :password LIMIT 1;
Поскольку используется ORM для формирования запросов, банальная SQL-инъекция не сработает. Если в базе не найдется совпадений по пользователю, приложение вернет ошибку User Not found. В случае совпадений вводных данных на уровне базы данных приложение сравнит введенный пароль с паролем, хранящимся в базе, и либо вернет ошибку «Invalid Password!» при несовпадении, либо токен авторизации в случае успеха. Алгоритм проверки вводных данных выбран специально для тестирования уязвимости.
Таблица будет содержать такие данные:
Авторизация работает исправно.
А что же с операторами и псевдонимами?
Псевдонимы обозначаются символом “$”, синтаксис псевдонимов схож с MongoDB. Нам доступны операторы поиска, сравнения и многие другие. Не смотря на строгую типизацию данных в модели, передача данных от пользователя в ORM в формате JSON влечет за собой нормализацию. И тут начинается самое интересное!
Когда беда стучится в DOM
Групповая атака (Batching attack)
Такого вида запрос к приложению инициирует запрос к базе:
Executing (default): SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` IN (‘admin’, ‘more’, ‘much more’) AND `users`.`password` = ‘wrong pass’ LIMIT 1;
При помощи этой атаки можно за один запрос к серверу проверить на валидность много логинов на конкретный пароль и наоборот. Атака работает в последней на декабрь 2020 версии библиотеки (6.3.5) и при выключенной опции operatorsAliases.
Атака преобразования типов данных
Если передать приложению данные вида…
… то, ничего в нашем случае не произойдет. Логическое условие в базу данных хоть и будет правильным, проверка пароля в исследуемом приложении на уровне приложения и сравнение разных типов данных не может вернуть true.
Атака при помощи операторов сравнения
База данных возвращает данные, так как есть совпадение username = admin и пароля, не равного “aaa”. Для того чтобы пройти процесс авторизации полностью, нам необходимо достать пароль.
Атака операторов регулярных выражений и поиска в строке
Когда символ не сойдется, возникнет ошибка, что пользователь не найден.
Если символ сойдется, будет ошибка о неверном пароле. В базу выполняется запрос вида:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = ‘admin’ AND `users`.`password` LIKE ‘E%’ LIMIT 1;
Таким образом, посимвольно можно восстановить данные из таблицы.
Атака сравнения столбцов в таблице
Запрос в базу будет:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = ‘admin’ AND `users`.`password` = `aaaaa` LIMIT 1;
Выполнит в базу следующий запрос:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = ‘admin’ AND `users`.`password` = `password` LIMIT 1;
Тем самым выполнив логическое условие на уровне базы данных.
Идеальный инструмент для работы с СУБД без SQL для Node.js или Все, что вы хотели знать о Sequelize. Часть 2
Это вторая из 3 частей руководства, в которой мы поговорим о простых и продвинутых ассоциациях (отношениях между моделями), «параноике», нетерпеливой и ленивой загрузке, а также о многом другом.
Я постараюсь быть максимально лаконичным (надеюсь, без ущерба для полноты изложения материала). Я также постараюсь излагать материал максимально простым языком. Большинство примеров, приводимых в руководстве, заимствованы из официальной документации.
Содержание
Ассоциации
Sequelize поддерживает стандартные ассоциации или отношения между моделями: один-к-одному (One-To-One), один-ко-многим (One-To-Many), многие-ко-многим (Many-To-Many).
Существует 4 типа ассоциаций:
Определение ассоциации
Все эти функции принимают объект с настройками (для первых трех он является опциональным, для последнего — обязательным). В настройках должно быть определено как минимум свойство through :
Порядок определения ассоциаций имеет принципиальное значение. В приведенных примерах A — это модель-источник (source), а B — это целевая модель (target). Запомните эти термины.
A.hasOne(B) означает, что между A и B существуют отношения один-к-одному, при этом, внешний ключ (foreign key) определяется в целевой модели ( B ).
A.belongsTo(B) — отношения один-к-одному, внешний ключ определяется в источнике ( A ).
A.hasMany(B) — отношения один-ко-многим, внешний ключ определяется в целевой модели ( B ).
В этих случаях Sequelize автоматически добавляет внешние ключи (при их отсутствии) в соответствующие модели (таблицы).
A.belongsToMany(B, < through: 'C' >) означает, что между A и B существуют отношения многие-ко-многим, таблица C выступает в роли связующего звена между ними через внешние ключи (например, aId и bId ). Sequelize автоматически создает модель C при ее отсутствии, определяя в ней соответствующие ключи.
Определение стандартных отношений
Как правило, ассоциации используются парами:
Один-к-одному
Обратите внимание: для того, чтобы решить, в какой из двух таблиц должен быть определен внешний ключ, следует ответить на вопрос о том, какая из таблиц может существовать без другой.
Дальнейший вызов Bar.sync() приведет к отправке в БД следующего запроса:
При создании ассоциации могут использоваться некоторые настройки.
Пример кастомизации поведения при удалении и обновлении внешнего ключа:
В случае кастомизации внешнего ключа с помощью объекта, можно определять его тип, значение по умолчанию, ограничения и т.д. Например, в качестве типа внешнего ключа можно использовать DataTypes.UUID вместо дефолтного INTEGER :
Один-ко-многим
Обратите внимание: в данном случае вопрос о том, в какой из двух таблиц должен быть определен внешний ключ не является актуальным, поскольку такой ключ может быть определен только в целевой модели.
В данном случае в БД будет отправлен такой запрос:
Как и в случае с отношениями один-к-одному, рассматриваемую ассоциацию можно настраивать различными способами.
Многие-ко-многим
Обратите внимание: в отличие от первых двух ассоциаций, внешний ключ не может быть определен ни в одной из связанных таблиц. Для этого используется так называемая «соединительная таблица» (junction, join, through table).
Как упоминалось ранее, Sequelize создает соединительную таблицу автоматически. Но мы вполне можем сделать это самостоятельно:
В этом случае в БД будет отправлен такой запрос:
Выполнение запросов, включающих ассоциации
Немедленная загрузка и отложенная загрузка
«Ленивая» (lazy) или отложенная загрузка позволяет получать ассоциации (т.е. связанные экземпляры) по мере необходимости, а «нетерпеливая» (eager) или немедленная загрузка предполагает получение всех ассоциаций сразу при выполнении запроса.
Пример ленивой загрузки
В данном случае мы выполняем два запроса — корабль запрашивается при необходимости. Это позволяет сэкономить время и память. Обратите внимание: метод getShip() был создан автоматически, автоматически создаются и другие методы (см. ниже).
Пример нетерпеливой загрузки
Создание, обновление и удаление ассоциаций
Для создания, обновления и удаления ассоциаций можно использовать как обычные запросы:
так и специальные методы/миксины (микшины, примеси, mixins) (см. ниже).
Синонимы ассоциаций и кастомные внешние ключи
Немного упростим пример с кораблями и капитанами:
Вызов Ship.belongsTo(Captain) приводит к автоматическому созданию внешнего ключа и «геттеров»:
Название внешнего ключа может быть указано при определении ассоциации:
Внешний ключ также может быть определен в виде синонима:
Ничто не мешает нам использовать оба способа определения внешних ключей одновременно:
Специальные методы/миксины
Foo.hasOne(Bar)
Foo.belongsTo(Bar)
Foo.hasMany
Геттеры принимают такие же настройки, что и обычные поисковые методы (такие как findAll() ):
Foo.belongsToMany(Bar, < through: Baz >)
Для формирования названий методов вместо названия модели может использоваться синоним, например:
Обратите внимание: как было отмечено ранее, ассоциации определяются в паре. Это объясняется тем, что обе модели должны знать о существовании ассоциации между ними.
Синонимы позволяют определять несколько ассоциаций между одними и теми же моделями:
Создание ассоциаций с помощью полей, которые не являются первичными ключами
В качестве внешних ключей могут использоваться не только основные ключи, но и другие поля. Единственным требованием к полю, используемому в качестве внешнего ключа, является то, что его значение должно быть уникальным, в противном случае, это не будет иметь смысла.
belongsTo()
Ассоциация A.belongsTo(B) приводит к созданию внешнего ключа в модели-источнике ( A ).
Снова вернемся к примеру с кораблями и ограничим уникальность имен капитанов:
После этого мы можем делать так:
hasOne() и hasMany()
В данном случае вместо targetKey определяется настройка sourceKey :
belongsToMany()
В данном случае необходимо определить два внешних ключа в соединительной таблице.
Далее выполняется один из следующих 4 шагов:
Еще раз в качестве напоминания:
«Параноик»
Sequelize поддерживает создание так называемых «параноидальных» (paranoid) таблиц. Из таких таблиц данные по-настоящему не удаляются. Вместо этого, в них добавляется колонка deletedAt в момент выполнения запроса на удаление. Это означает, что в таких таблицах выполняется мягкое удаление (soft-deletion).
При вызове метода destroy() производится мягкое удаление:
Для окончательного удаления параноика следует использовать настройку force: true :
Для восстановления «удаленного» значения используется метод restore() :
Для учета «удаленных» записей при выполнении запроса используется настройка paranoid: false :
Нетерпеливая загрузка
Нетерпеливая загрузка — это одновременная загрузка основной и связанных с ней моделей. На уровне SQL это означает одно или более соединение (join).
В дальнейших примерах будут использоваться следующие модели:
Получение одного связанного экземпляра
Получение всех связанных экземпляров
Получение ассоциации через синоним
Существуют и другие способы получения ассоциаций через синонимы:
Фильтрация с помощью нетерпеливой загрузки
Фильтрация на уровне связанной модели
Генерируемый SQL-запрос выглядит так:
В следующем примере настройка where применяется для фильтрации значений связанной модели с помощью функции Sequelize.col() :
Сложная фильтрация с помощью where на верхнем уровне
Генерируемый SQL-запрос выглядит так:
При этом, уровень вложенности фильтруемых колонок значения не имеет.
include может принимать массив связанных моделей:
Нетерпеливая загрузка в случае с отношениями многие-ко-многим
В данном случае Sequelize автоматически добавляет соединительную таблицу:
Настройка attributes позволяет определять включаемые в ответ поля соединительной таблицы:
В случае, когда нам не нужны такие поля, в attributes передается пустой массив:
Включаемые поля соединительной таблицы можно фильтровать с помощью настройки where :
Генерируемый SQL-запрос ( sqlite ):
Для включения всех связанных моделей используются настройки all и nested :
Сортировка связанных экземпляров при нетерпеливой загрузке
Для сортировки связанных экземпляров используется настройка order (на верхнем уровне):
В случае с отношениями многие-ко-многим, у нас имеется возможность выполнять сортировку по атрибутам соединительной таблицы. Предположим, что между моделями Division и Department существуют такие отношения, а соединительная таблица между ними называется DepartmentDivision :
Вложенная нетерпеливая загрузка
Вложенная нетерпеливая загрузка может использоваться для загрузки всех связанных экземпляров связанного экземпляра:
Данный запрос выполняет внешнее соединение ( OUTER JOIN ). Применение настройки where к связанной модели произведет внутреннее соединение ( INNER JOIN ) — будут возвращены только экземпляры, которые имеют совпадающие подмодели. Для получения всех родительских экземпляров используется настройка required: false :
Создание экземпляров с ассоциациями
Экземпляр может быть создан сразу с вложенной ассоциацией. Однако, выполнение обновлений и удалений вложенных объектов в настоящее время не поддерживается.
Последний пример может быть расширен для поддержки ассоциаций:
Имеется возможность связать продукт с несколькими тегами. Соответствующая настройка может выглядеть так:
Теперь создадим продукт с несколькими тегами:
И с поддержкой синонимов:
Продвинутые ассоциации M:N
Начнем с создания ассоциации многие-ко-многим между моделями User и Profile :
Определение соединительной таблицы самостоятельно имеет некоторые преимущества по сравнению с ее автоматической генерацией. Мы, например, можем определять дополнительные атрибуты в такой таблице:
После этого мы можем получать дооплнительную информацию из соединительной таблицы. Например, при вызове user.addProfile() мы можем передавать значения для дополнительной колонки с помощью настройки through :
Также вместо уникального, в соединительной таблице можно определить первичный ключ:
Ассоциация «супер многие-ко-многим»
Наши модели будут выглядеть так:
Определяем отношения многие-ко-многим между моделями User и Profile через модель Grant :
Что если вместо определения отношения многие-ко-многим мы сделаем так?
Это показывает, что отношения многие-ко-многим не сильно отличаются от двух ассоциаций один-ко-многим. Единственным отличием между ними является то, как будет работать нетерпеливая загрузка:
На самом деле, для успешного выполнения всех указанных выше операций достаточно скомбинировать оба подхода:
Это позволяет выполнять все виды вложенных включений:
Синонимы и кастомные названия для ключей
В случае с ассоциацией многие-ко-многим синонимы определяются следующим образом:
Вот как выглядит SQL-запрос на создание таблицы product_categories :
Обратите внимание: настройки foreignKey и otherKey должны определяться в обоих вызовах. Если определить их только в одном вызове, поведение Sequelize будет непредсказуемым.
Sequelize также поддерживает циклические отношения многие-ко-многим:
Определение возвращаемых атрибутов соединительной таблицы
По умолчанию при нетерпеливой загрузке в случае с ассоциацией многие-ко-многим возвращается такой объект ( User.findOne(< include: Profile >) ):
Для того, чтобы получить только некоторые поля из соединительной таблицы используется настройка attributes :
При использовании миксинов (например, user.getProfiles() ), вместо методов для поиска (например, User.findAll() ), для фильтрации полей соединительной таблицы используется настройка joinTableAttributes :
Ассоциация многие-ко-многим-ко-многим и т.д.
Предположим, что мы моделируем игру. У нас есть игроки и команды. Команды играют в игры. Игроки могут менять команды в середине чемпионата (но не в середине игры). В одной игре участвует две команды, в каждой команде имеется свой набор игроков (для текущей игры).
Начнем с определения соответствующих моделей:
Вопрос: как определить ассоциацию между этими моделями?
Первое, что можно заметить:
Это означает, что между моделями Game и Team должны существовать отношения многие-ко-многим. Реализуем супер-вариант названной ассоциации (как в предыдущем примере):
Для обеспечения максимальной гибкости снова прибегнем к супер-версии M:N:
Эта ассоциация делает именно то, что мы хотим.
Полный пример выглядит так:
На этом вторая часть руководства завершена. В следующей части мы поговорим об областях видимости ассоциаций, полиморфных ассоциациях, транзакциях, хуках, интерфейсе запросов, подзапросах, индексах, а также о многом другом.
Благодарю за внимание и хорошего дня!
Аренда облачного сервера с быстрыми NVMе-дисками и посуточной оплатой у хостинга Маклауд.
Идеальный инструмент для работы с СУБД без SQL для Node.js или Все, что вы хотели знать о Sequelize. Часть 3
Доброго времени суток, друзья!
Это третья и последняя часть руководства, в которой мы поговорим об областях видимости ассоциаций, полиморфных ассоциациях, транзакциях, хуках, интерфейсе запросов, подзапросах, индексах, а также о многом другом.
Я постараюсь быть максимально лаконичным (надеюсь, без ущерба для полноты изложения материала). Я также постараюсь излагать материал максимально простым языком. Большинство примеров, приводимых в руководстве, заимствованы из официальной документации.
Содержание
Область видимости ассоциаций
Область видимости ассоциаций (assosiation scopes) похожа на области видимости моделей в том, что обе автоматически применяют к запросам такие вещи, как предложение where ; разница между ними состоит в том, что область модели применяется к вызовам статических методов для поиска, а область ассоциации — к вызовам поисковых методов экземпляра (таким как миксины).
Пример применения области ассоциации для отношений один-ко-многим:
Последний вызов приводит к генерации такого запроса:
На самом деле, мы можем добиться такого же поведения с помощью стандартной области видимости:
После этого, вызов foo.getOpenBars() вернет аналогичный результат.
Полиморфные ассоциации
Полиморфная ассоциация (polymorphic assosiation) состоит из двух и более ассоциаций, взаимодействующих с одним внешним ключом.
Перед настройкой такой ассоциации, рассмотрим пример ее использования:
Создание полиассоциации один-ко-многим
Для настройки полиассоциации для приведенного выше примера (полиассоциации один-ко-многим) необходимо выполнить следующие шаги:
Обратите внимание на следующее:
Эти области автоматически применяются при использовании ассоциативных функций. Несколько примеров:
Полиморфная ленивая загрузка
Обратите внимание, что приведенная выше реализация getCommentable() :
Полиморфная нетерпеливая загрузка
Теперь мы хотим выполнить полиморфную нетерпеливую загрузку связанных commentable для одного (или более) комментария:
Решение состоит во включении Image и Video для того, чтобы хук afterFind() мог автоматически добавить поле commentable в экземпляр.
Настройка полиассоциации многие-ко-многим
Для настройки рассматриваемой полиассоциации необходимо выполнить следующие шаги:
Применение области ассоциации к целевой модели
Область ассоциации может применяться не только к соединительной таблице, но и к целевой модели.
После этого, вызов image.getPendingTags() приведет к генерации такого запроса:
Мы видим, что обе области были автоматически применены:
Транзакции
Sequelize поддерживает выполнение двух видов транзакций:
Неуправляемые транзакции
Управляемые тразакции
Для выполнения управляемой транзакции в sequelize.transaction() передается функция обратного вызова. Далее происходит следующее:
Таким образом, sequelize.transaction() либо разрешается с результатом, возвращаемым колбэком, либо отклоняется с ошибкой.
Автоматическая передача транзакции во все запросы
В приведенных примерах транзакция передавалась вручную — < transaction: t >. Для автоматической передачи транзакции во все запросы необходимо установить модуль cls-hooked (CLS — Continuation Local Storage, «длящееся» локальное хранилище) и инстанцировать пространство имен (namespace):
Затем следует использовать это пространство имен следующим образом:
Обратите внимание: мы вызываем метод useCLS() на конструкторе, а не на экземпляре. Это означает, что пространство имен будет доступно всем экземплярам, а также, что CLS — это «все или ничего», нельзя включить его только для некоторых экземпляров.
В большинстве случаев, в явном вызове namespace.get(‘transaction’) нет необходимости, поскольку все запросы автоматически получают транзакцию из пространства имен:
Параллельные/частичные транзакции
С помощью последовательности запросов можно выполнять параллельные транзакции. Также имеется возможность исключать запросы из транзакции. Для управления тем, каким транзакциям принадлежит запрос, используется настройка transaction (обратите внимание: SQLite не поддерживает одновременное выполнение более одной транзакции).
Уровни изоляции
Возможные уровни изоляции при запуске транзакции:
По умолчанию Sequelize использует уровень изоляции БД. Для изменения уровня изоляции используется настройка isolationLevel :
Или на уровне всего приложения:
Использование транзакции совместно с другими методами
Обычно, transaction передается в метод вместе с другими настройками в качестве первого аргумента.
Хук afterCommit()
Объект transaction позволяет регистрировать фиксацию изменений. Хук afterCommit() может быть добавлен как к управляемым, так и к неуправляемым объектам транзакции:
Обратите внимание на следующее:
Хук afterCommit() можно использовать в дополнение к хукам модели для определения момента сохранения экземпляра и его доступности за пределами транзакции:
Обратите внимание: хуки могут использоваться только на уровне моделей.
Доступные хуки
Sequelize предоставляет большое количество хуков. Их полный список можно найти здесь. Порядок вызова наиболее распространенных хуков следующий:
Определение хуков
Аргументы в хуки передаются по ссылкам. Это означает, что мы можем модифицировать значения и это отразится на соответствующих инструкциях. Хук может содержать асинхронные операции — в этом случае функция должна возвращать промис.
Существует три способа программного добавления хуков:
Обратите внимание, что удаляться могут только именованные хуки:
Глобальные/универсальные хуки
Глобальными называются хуки, которые выполняются для всех моделей. Особенно полезными такие хуки являются в плагинах. Они определяются двумя способами:
Хуки, связанные с подключением к БД
Существует 4 хука, выполняемые до и после подключения к БД и отключения от нее:
Эти хуки могут использоваться для асинхронного получения полномочий (credentials) для доступа к БД или получения прямого доступа к низкоуровневому соединению с БД после его установки.
Например, мы можем асинхронно получить пароль от БД из хранилища токенов и модифицировать объект с настройками:
Рассматриваемые хуки могут быть определены только как глобальные, поскольку соединение является общим для всех моделей.
Хуки экземпляров
Следующие хуки будут запускаться при редактировании единичного объекта:
Хуки моделей
Хуки и ассоциации
Один-к-одному и один-ко-многим
По умолчанию Sequelize пытается максимально оптимизировать запросы. Например, при вызове каскадного удаления Sequelize выполняет:
Однако, добавление hooks: true отключает оптимизации. В этом случае Sequelize сначала выполняет выборку связанных объектов с помощью SELECT и затем уничтожает каждый экземпляр по одному для обеспечения вызова соответствующих хуков с правильными параметрами.
Хуки и транзакции
Если в оригинальном вызове была определена транзакция, она будет передана в хук вместе с другими настройками:
Интерфейс запросов
Каждый экземпляр использует интерфейс запросов (query interface) для взаимодействия с БД. Методы этого интерфейса являются низкоуровневыми в сравнении с обычными методами. Но, разумеется, по сравнению с запросами SQL, они являются высокоуровневыми.
Рассмотрим несколько примеров использования методов названного интерфейса (полный список методов можно найти здесь).