Работа с базами данных в TypeScript: PostgreSQL и MongoDB
TypeScript — это мощный язык программирования, который добавляет статическую типизацию в JavaScript. При разработке современных веб-приложений работа с базами данных является неотъемлемой частью. В этой статье мы рассмотрим, как эффективно работать с двумя популярными базами данных — реляционной PostgreSQL и документо-ориентированной MongoDB — используя TypeScript.
1. Подготовка окружения и выбор ORM
Прежде чем начать, необходимо настроить проект. Создайте новый проект Node.js с поддержкой TypeScript:
mkdir ts-database-demo
cd ts-database-demo
npm init -y
npm install typescript @types/node ts-node --save-dev
npx tsc --init
Для работы с базами данных мы будем использовать популярные библиотеки:
- Prisma — современный ORM для PostgreSQL (и других SQL-баз)
- Mongoose — ODM для MongoDB с отличной поддержкой TypeScript
Установите необходимые пакеты:
npm install prisma @prisma/client mongoose
npm install @types/mongoose --save-dev
2. Работа с PostgreSQL через Prisma
Prisma — это ORM, который автоматически генерирует типы TypeScript на основе вашей схемы базы данных. Это обеспечивает полную типовую безопасность.
2.1. Настройка Prisma
Инициализируйте Prisma в проекте:
npx prisma init
В файле prisma/schema.prisma определите модель данных:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Создайте файл .env с строкой подключения:
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
Выполните миграцию:
npx prisma migrate dev --name init
2.2. CRUD-операции с TypeScript
Теперь напишем типизированный код для работы с базой данных. Создайте файл src/postgres.ts:
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
interface CreateUserInput {
email: string;
name?: string;
}
interface CreatePostInput {
title: string;
content?: string;
authorId: number;
}
// Создание пользователя
async function createUser(data: CreateUserInput) {
return await prisma.user.create({
data: {
email: data.email,
name: data.name,
},
});
}
// Получение всех пользователей с постами
async function getUsersWithPosts() {
return await prisma.user.findMany({
include: {
posts: true,
},
});
}
// Создание поста
async function createPost(data: CreatePostInput) {
return await prisma.post.create({
data: {
title: data.title,
content: data.content,
authorId: data.authorId,
},
});
}
// Обновление пользователя
async function updateUser(id: number, data: Partial<CreateUserInput>) {
return await prisma.user.update({
where: { id },
data,
});
}
// Удаление пользователя
async function deleteUser(id: number) {
return await prisma.user.delete({
where: { id },
});
}
// Пример использования
(async () => {
try {
const user = await createUser({
email: 'ivan@example.com',
name: 'Иван Иванов',
});
console.log('Создан пользователь:', user);
const post = await createPost({
title: 'Первая запись',
content: 'Содержимое поста',
authorId: user.id,
});
console.log('Создан пост:', post);
const users = await getUsersWithPosts();
console.log('Пользователи с постами:', JSON.stringify(users, null, 2));
} catch (error) {
console.error('Ошибка:', error);
} finally {
await prisma.$disconnect();
}
})();
Благодаря Prisma, все операции полностью типизированы — вы получите ошибку на этапе компиляции, если попытаетесь передать неверное поле или тип.
3. Работа с MongoDB через Mongoose
MongoDB — это NoSQL база данных, которая хранит данные в формате, похожем на JSON. Mongoose предоставляет удобную типизацию для TypeScript.
3.1. Определение схем и типов
Создайте файл src/models/User.ts:
import mongoose, { Schema, Document, Model } from 'mongoose';
// Определение TypeScript интерфейса
export interface IUser extends Document {
email: string;
name?: string;
age?: number;
createdAt: Date;
updatedAt: Date;
}
// Определение схемы
const UserSchema: Schema = new Schema(
{
email: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
},
name: {
type: String,
trim: true,
},
age: {
type: Number,
min: 0,
},
},
{
timestamps: true, // автоматически добавляет createdAt и updatedAt
}
);
// Экспорт модели с типизацией
export const User: Model<IUser> = mongoose.model<IUser>('User', UserSchema);
3.2. CRUD-операции с MongoDB
Создайте файл src/mongodb.ts:
import mongoose from 'mongoose';
import { User, IUser } from './models/User';
const MONGO_URI = 'mongodb://localhost:27017/ts_demo';
// Подключение к MongoDB
async function connectDB() {
try {
await mongoose.connect(MONGO_URI);
console.log('Подключено к MongoDB');
} catch (error) {
console.error('Ошибка подключения:', error);
process.exit(1);
}
}
interface CreateUserInput {
email: string;
name?: string;
age?: number;
}
// Создание пользователя
async function createUser(data: CreateUserInput): Promise<IUser> {
const user = new User(data);
return await user.save();
}
// Получение всех пользователей
async function getUsers(): Promise<IUser[]> {
return await User.find().sort({ createdAt: -1 });
}
// Поиск пользователя по email
async function getUserByEmail(email: string): Promise<IUser | null> {
return