Как назло, объектно-реляционное сопоставление (ORM) получило очень удачное название. Это техника, позволяющая запрашивать и манипулировать реляционными данными из базы данных («R») и сопоставлять («M») результат с реальными объектами («O»), используемыми в объектно-ориентированном программировании.

Оказывается, говоря об ORM, большинство людей имеют в виду библиотеки, которые реализуют этот метод отображения, отсюда и фраза «ORM».

Слои абстракции.

По мере того как я с нетерпением прочитываю многочисленные статьи об ORM, концепция абстракции продолжает появляться. В компьютерных науках это относится к удалению элементов или деталей, которые отвлекали бы программиста от более важных элементов, тем самым повышая производительность.

Как и в большинстве вещей в жизни, кажется, что некоторое количество абстракции — это хорошо, но слишком много может быть проблематично. Например, без какой-либо абстракции мы могли бы программировать только с помощью двоичных единиц и нулей или путем ввода ассемблерного кода в консоли. С другой стороны, слишком много снизит производительность нашего кода настолько, что повышенная производительность просто быстрее даст нам больше плохого кода.

Вопрос о том, какова на самом деле правильная степень абстракции, вызывает горячие споры в сообществе разработчиков, причем многие из этих споров происходят в разделах комментариев к статьям, которые я читаю.

Драйверы базы данных.

Мне сказали начать с самого низкого уровня абстракции в опросе базы данных, драйверов базы данных. Это отличная новость, так как я уже научился использовать один из них (модуль pg) во время Bootcamp. Драйвер базы данных обрабатывает соединение с базой данных и позволяет нам отправлять запросы, записанные в виде строк SQL, а затем возвращает ответ.

Мне очень понравилось изучать SQL, но я понимаю, что для людей, которым важно время, усилия, потраченные на его изучение, считаются затратами. Тем не менее, когда я представляю мир ORM, в котором SQL больше не нужен и спрятан под плотным одеялом абстракции, мне становится немного грустно.

Как и во всех хороших технических статьях, которые я читал, я собираюсь добавить здесь пример кода, чтобы показать, как на практике может выглядеть использование драйвера базы данных:

const { Client } = require('pg');
const connection = require('./connection.json');
const client = new Client(connection);

client.connect();
const searchPlayers = function(position) {
  const queryString = `
    SELECT players.* FROM players
    JOIN positions ON players.id = positions.player_id
    WHERE positions.position = '${position}'
    AND players.selected_position IS NULL
    ORDER BY players.value DESC;`

  return db
    .query(queryString)
    .then((result) => {
      if (result.rows) {
        return result.rows;
      } else {
        return null;
      }
    })
    .catch((err) => {
      console.log(err.message);
    });
};

Конструкторы запросов.

Следующая ступенька лестницы абстракции приводит нас к конструкторам запросов. Когда я просматриваю страницы своего поиска в Google, я задаюсь вопросом, как я никогда не слышал о knex? Этот модуль, похоже, зашил рынок построителей запросов. Он имеет библиотеки для многочисленных баз данных (PostgreSQL, Amazon Redshift, MySQL, MariaDB, SQLite, MSSQL и Oracle) и поможет вам избежать уязвимостей безопасности, таких как атаки путем внедрения, которые могут повлиять на SQL при использовании динамических запросов. Как вы можете видеть ниже, код, который вы пишете, по-прежнему будет напоминать базовые SQL-запросы, но будет работать с любой из поддерживаемых баз данных, позволяя вам забыть о тонких различиях между ними:

const posts = await knex('posts')
 .join('users', { 'users.id': 'posts.user_id', 'users.email': '[email protected]' })
 .select('*')

ORM.

Со вздохом облегчения я понимаю, что после двух дней борьбы я, наконец, добрался до той части задания, которую действительно собирался написать. Когда я перечитывал различные разделы статей, которые я нашел полезными в своих первоначальных исследованиях, мне напомнили, что это почти конец пути для SQL, поскольку ORM будет переводить все мои запросы к базе данных в JavaScript для меня. Предварительно необходимо выполнить некоторую работу по настройке ORM для базы данных, но просто посмотрите на разницу, которую это может дать, из этого примера псевдокода в Переполнение стека. Представьте, что вы хотите получить все книги, автором которых является Линус. Вручную вы бы сделали что-то вроде этого:

book_list = new List();
sql = "SELECT book FROM library WHERE author = 'Linus'";
data = query(sql); // I over simplify ...
while (row = data.next())
{
     book = new Book();
     book.setAuthor(row.get('author');
     book_list.add(book);
}

С библиотекой ORM это будет выглядеть так:

book_list = BookTable.query(author="Linus");

Я уже впечатлен, но меньшее количество строк кода даже не обсуждается как одно из преимуществ использования ORM. Список положительных моментов длинный и, кажется, растет с каждой прочитанной статьей:

  • ORM будут писать более качественные SQL-запросы, чем я
  • Мой код будет легче писать и поддерживать, так как он будет написан на одном языке.
  • Я буду вынужден структурировать свой код СУХИМ образом (не повторяйтесь), отделяя модель данных, которая, как мы все знаем, очень похожа на GCP (Good Coding Practice).
  • Если я когда-нибудь решу, что с меня достаточно моей надежной базы данных PostgreSQL, я легко могу переключиться на другую благодаря абстракции.
  • Я смогу больше сосредоточиться на бизнес-логике, фактически заставляя свое приложение делать то, что мне нужно, и меньше на написании кода для запросов к моей базе данных.

Здесь, вероятно, стоит отметить, что одним из самых популярных результатов поиска в Google по запросу Javascript ORM является статья под названием ORM Node.js: почему вам не следует их использовать. Оказывается, есть некоторые вещи, которые мне нужно иметь в виду, решая, действительно ли ORM для меня:

  • Другое дело, когда я уже успешно завершил модуль SQL Bootcamp.
  • Его необходимо установить и настроить, прежде чем его можно будет использовать.
  • Сложные запросы могут оказаться неэффективными или невозможными для выполнения в ORM, и в этом случае мне нужно будет вернуться к своим заметкам по SQL и написать запрос самостоятельно.

Популярные ORM Javascript.

Мои исследования продолжаются, и я задаю вопрос: Кто является кнексом пространства ORM?. Оказывается, нет ни одной, и есть несколько популярных библиотек на выбор. Кажется, что хорошей мерой популярности каждого из них будет количество еженедельных загрузок npm, хотя показатель используется на GitHub тоже кажется важным.

Sequelize упоминается во всех статьях, которые я читал, поэтому я сначала проверяю их. 1 661 190 загрузок в неделю с npm и использовано 621 103 разными людьми на GitHub. Это звучит как много, и оказывается, что, хотя он существует уже более 10 лет, его популярность на самом деле растет. Старость в этом случае оказывается плюсом, так как большинство проблем уже устранено; есть отличная документация и множество пользователей, предлагающих обильную поддержку нам, новичкам.

Также часто упоминается TypeORM. Он похож на другие, но ориентирован на разработчиков, использующих TypeScript (версия Javascript от Microsoft, которая предлагает дополнительную статическую типизацию). Он также довольно популярен: 1 281 147 еженедельных загрузок npm и 222 945 человек на Github.

Я мог бы продолжить, но мне не очень интересно составлять пост типа 10 лучших ORM, которые позволят вам программировать как старший разработчик…. Чего я действительно хочу добиться, так это Prisma (с его 1 410 577 еженедельными загрузками и 147 836 пользователями GitHub… извините, я не мог удержаться). В этот момент, возможно, следует сделать небольшое признание. Прежде чем приступить к этому заданию, я уже просмотрел учебные пособия на веб-сайте Vercel в рамках моего исследования Next.js, и так получилось, что во всех их примерах используется ORM Prisma. Так что да, я все время планировал попробовать Prisma; двух зайцев одним выстрелом и все такое...

Призма.

Prisma, самопровозглашенная ORM нового поколения, немного отличается от других. Вместо использования объектных моделей для сопоставления таблиц и столбцов из базы данных используется файл схемы. Я понятия не имею, что это значит, поэтому я решаю, что пришло время прыгнуть в учебник, чтобы узнать.

Когда я начинаю процесс установки, я понимаю, что в руководстве будет использоваться TypeScript, чего я никогда раньше не видел. Задаваясь вопросом, не исказит ли Microsoft JavaScript во что-то, чего я не пойму, я делаю глубокий вдох и смело продолжаю.

Установка идет хорошо, но еще многое предстоит сделать:

hello-prisma > npx prisma init

✔ Your Prisma schema was created at prisma/schema.prisma
  You can now open it in your favorite editor.

Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. 
If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the provider of the datasource block in schema.prisma to match your 
database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can then start 
querying your database.

Я создаю новую базу данных PostgreSQL на SupaBase (это бесплатно!) и вставляю URL-адрес в файл .env моего проекта. Следующим шагом является добавление данных модели в мой файл схемы следующего поколения. Признаюсь, я немного разочарован тем, что следующее поколение очень похоже на текущее. Вот модель, которая станет таблицей users:

model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  posts   Post[]
  profile Profile?
}

Используя команду migrate, Prisma создает таблицы в моей базе данных. Довольно круто, но теперь я создаю клиент Prisma и просто чтобы помочь мне, есть диаграмма, объясняющая, что происходит:

Клиент Prisma.

С помощью моего блестящего нового клиента Prisma Client я добавляю файл, чтобы сделать свой первый запрос к базе данных, prisma.user.findMany(), по-видимому, следующее поколение будет писать SELECT * FROM users;

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  const allUsers = await prisma.user.findMany()
  console.log(allUsers)
}

Я запускаю файл, и все, что я получаю, это пустой массив []. Виноват; Я еще не добавлял пользователей в базу данных. Как старый друг, туториал понимающе улыбается и ведет меня через процесс добавления пользователя, поста и профиля в базу данных. Это очень просто и все написано на JavaScript (ну, TypeScript). Чтобы закончить, мы немного наглеем и обновляем запись. Я просматриваю базу данных, чтобы убедиться, что она работает, прежде чем быстро просмотреть последнюю страницу руководства, которая пытается соблазнить меня фильтровать и удалять записи. Я должен признать, что этот материал следующего поколения в конце концов довольно впечатляет, и, несмотря на мое первоначальное беспокойство, я собираюсь порекомендовать моей проектной группе попробовать его.

Ссылки: