Подключение базы данных
До сих пор статьи жили в массиве и пропадали после перезапуска сервера. Сохраним их в базе данных SQLite — это один файл на диске, отдельный сервер не нужен. Работать с базой будем через Drizzle ORM: библиотеку, в которой таблицы описывают на TypeScript, а запросы пишут методами вместо строк SQL.
Установка
npm install drizzle-orm better-sqlite3
npm install -D drizzle-kit @types/better-sqlite3better-sqlite3 — драйвер SQLite для Node.js, drizzle-kit — консольная утилита, которая создаёт таблицы по схеме.
Схема
Создайте файл db/schema.ts в корне проекта:
// db/schema.ts
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
export const posts = sqliteTable('posts', {
slug: text('slug').primaryKey(),
title: text('title').notNull(),
body: text('body').notNull(),
});
export const comments = sqliteTable('comments', {
id: integer('id').primaryKey({ autoIncrement: true }),
postSlug: text('post_slug').notNull().references(() => posts.slug),
author: text('author').notNull(),
text: text('text').notNull(),
});Каждый вызов sqliteTable описывает таблицу: её имя в базе и колонки с типами.
Создание таблиц
Утилите нужен файл настроек drizzle.config.ts в корне:
// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
dialect: 'sqlite',
schema: './db/schema.ts',
dbCredentials: { url: 'blog.db' },
});npx drizzle-kit pushКоманда создаст файл blog.db с таблицами posts и comments. Посмотреть и заполнить таблицы можно в браузере командой npx drizzle-kit studio.
Подключение
// db/index.ts
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
export const db = drizzle({ client: new Database('blog.db') });Объект db импортируют везде, где нужны запросы.
Запросы вместо массива
Перепишите lib/posts.ts. Страницы и действия вызывают те же функции, поэтому их менять не нужно:
// lib/posts.ts
import { eq } from 'drizzle-orm';
import { db } from '@/db';
import { posts } from '@/db/schema';
export type Post = typeof posts.$inferSelect;
export async function getPosts(): Promise<Post[]> {
return db.select().from(posts);
}
export async function getPost(slug: string): Promise<Post | undefined> {
const [post] = await db.select().from(posts).where(eq(posts.slug, slug));
return post;
}
export async function addPost(post: Post): Promise<void> {
await db.insert(posts).values(post);
}Тип Post теперь выводится из схемы. Добавьте статью через форму /posts/new и перезапустите npm run dev — статья останется на месте. Так же перепишите lib/comments.ts для таблицы comments.
Основные запросы
| Задача | Код |
|---|---|
| Все строки | db.select().from(posts) |
| С условием | .where(eq(posts.slug, slug)) |
| Вставка | db.insert(posts).values(post) |
| Изменение | db.update(posts).set(data).where(...) |
| Удаление | db.delete(posts).where(...) |
Для PostgreSQL меняются только драйвер, dialect и функция pgTable вместо sqliteTable.
Частая ошибка
Изменить схему и забыть применить её к базе. Запрос к новой колонке завершится ошибкой «no such column». После каждой правки db/schema.ts запускайте npx drizzle-kit push, а файл blog.db добавьте в .gitignore.