Prisma ORM — Примеры

Пример 1 — Проследите связь от сгенерированного типа

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

model Order {
  id         Int      @id
  status     String
  customer   Customer @relation(fields: [customerId], references: [id])
  customerId Int
}

model Customer {
  id     Int     @id
  email  String
  orders Order[]
}

Решение

const orders = await db.order.findMany({
  where: { status: "open" },
  include: { customer: true },   // разрешается в исходном запросе
});

for (const order of orders) {
  notify(order.customer.email);  // ни одной инструкции на заказ
}

// журнал сгенерированных инструкций (одна инструкция на весь список):
// SELECT "order".*, "customer".*
// FROM "Order" JOIN "Customer" ON "order"."customerId" = "customer"."id"
// WHERE "order"."status" = 'open'

Файл схемы — источник истины и для типов, и для базы данных, поэтому форма включённой связи входит в тип результата: обращение к свойству компилируется, а журнал инструкций подтверждает, что связь разрешена один раз, а не по разу на строку. Проверить это надёжно можно только по журналу: код выглядел бы почти одинаково и при соединении, и при запросе на каждую строку; обычно же ошибаются иначе — включают в исходный запрос одну связь, а внутри цикла обходят другую, и шаблон возвращается на уровень ниже.

Пример 2 — Переименование, которое сгенерированная миграция удаляет

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

изменение схемы: Customer.fullName -> Customer.name

сгенерированная миграция:
  ALTER TABLE "Customer" DROP COLUMN "fullName";
  ALTER TABLE "Customer" ADD COLUMN "name" TEXT;

Решение

-- прочитано и исправлено вручную до применения миграции
ALTER TABLE "Customer" RENAME COLUMN "fullName" TO "name";

Инструмент видит лишь то, что одно поле исчезло, а другое появилось, поэтому и выражает переименование как удаление и добавление; отревьюенная версия сохраняет столбец, его значения и любой индекс, который на него ссылался, — и при этом модель с базой всё равно приходят в соответствие. Этап генерации должен выполняться и при сборке. Пропущенная генерация компилируется против устаревшего клиента или падает вовсе. Обычно же к сгенерированной миграции относятся как к артефакту для применения, а не как к коду для чтения.