Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Вставка элемента в БД: полный подход
Это фундаментальная операция, которая кажется простой, но имеет множество нюансов в production окружении.
1. Базовый SQL подход
const { Pool } = require("pg");
const pool = new Pool();
async function insertUser(name, email) {
const query = "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id";
const result = await pool.query(query, [name, email]);
return result.rows[0];
}
Важно: используем параметризованные запросы ($1, $2) — защита от SQL injection.
2. С использованием ORM (TypeORM/Prisma)
// Prisma
const user = await prisma.user.create({
data: {
name: "John",
email: "john@example.com"
}
});
// TypeORM
const userRepository = dataSource.getRepository(User);
const user = userRepository.create({
name: "John",
email: "john@example.com"
});
await userRepository.save(user);
3. С валидацией и обработкой ошибок
async function createUser(userData) {
// Валидация
if (!userData.email || !userData.name) {
throw new ValidationError("Email и name обязательны");
}
try {
// Проверка уникальности
const existing = await pool.query(
"SELECT id FROM users WHERE email = $1",
[userData.email]
);
if (existing.rows.length > 0) {
throw new ConflictError("Email уже существует");
}
// Вставка
const result = await pool.query(
"INSERT INTO users (name, email, created_at) VALUES ($1, $2, $3) RETURNING id, created_at",
[userData.name, userData.email, new Date()]
);
return result.rows[0];
} catch (error) {
if (error.code === "23505") { // Unique constraint violation
throw new ConflictError("Email уже существует");
}
throw error;
}
}
4. С транзакциями (важно для data integrity)
async function createUserWithProfile(userData, profileData) {
const client = await pool.connect();
try {
await client.query("BEGIN");
// Вставляем пользователя
const userResult = await client.query(
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id",
[userData.name, userData.email]
);
const userId = userResult.rows[0].id;
// Вставляем профиль
await client.query(
"INSERT INTO profiles (user_id, bio, avatar) VALUES ($1, $2, $3)",
[userId, profileData.bio, profileData.avatar]
);
await client.query("COMMIT");
return userId;
} catch (error) {
await client.query("ROLLBACK");
throw error;
} finally {
client.release();
}
}
5. Batch вставка (для производительности)
async function insertManyUsers(users) {
// Построение запроса
const values = users
.map((_, i) => `($${i * 2 + 1}, $${i * 2 + 2})`)
.join(",");
const params = users.flatMap(u => [u.name, u.email]);
const query = `INSERT INTO users (name, email) VALUES ${values} RETURNING id`;
return await pool.query(query, params);
}
6. Best Practices в production:
- Всегда валидируй данные перед вставкой
- Используй параметризованные запросы (защита от SQL injection)
- Проверяй уникальные ограничения перед вставкой или обрабатывай constraint errors
- Используй транзакции для связанных операций
- Логируй ошибки для отладки
- Используй indexes на часто запрашиваемых полях
- Кешируй результаты если нужно читать их часто
7. Обработка ошибок
const ErrorCodes = {
UNIQUE_VIOLATION: "23505",
NOT_NULL_VIOLATION: "23502",
FOREIGN_KEY_VIOLATION: "23503"
};
try {
await insertUser(name, email);
} catch (error) {
switch (error.code) {
case ErrorCodes.UNIQUE_VIOLATION:
return res.status(409).json({ error: "Email уже существует" });
case ErrorCodes.NOT_NULL_VIOLATION:
return res.status(400).json({ error: "Обязательное поле не заполнено" });
default:
return res.status(500).json({ error: "Внутренняя ошибка" });
}
}
Ключь к успеху — думать не только о happy path, но и о всех edge cases: дублирование данных, нарушение ограничений, network timeouts, connection pool exhaustion.