Добавлены новые скрипты в package.json для автоматизации работы с базой данных, включая инициализацию и сброс данных. Обновлена схема Prisma для поддержки автоматического seeding. Реализован новый резолвер для получения всех категорий товаров в GraphQL. Исправлен форматирование в queries.ts.

This commit is contained in:
Bivekich
2025-07-28 09:34:43 +03:00
parent 32b436c35d
commit e56d4e309d
6 changed files with 310 additions and 2 deletions

View File

@ -2,11 +2,15 @@
"name": "sferav", "name": "sferav",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"type": "module",
"scripts": { "scripts": {
"dev": "next dev --turbopack", "dev": "next dev --turbopack",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "next lint",
"db:seed": "node prisma/seed.js",
"db:reset": "npx prisma db push --force-reset && npm run db:seed",
"postinstall": "npx prisma generate"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.13.8", "@apollo/client": "^3.13.8",

View File

@ -2,6 +2,12 @@ generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
} }
// Конфигурация для автоматического seeding
generator seed {
provider = "prisma-client-js"
output = "./generated/client"
}
datasource db { datasource db {
provider = "postgresql" provider = "postgresql"
url = env("DATABASE_URL") url = env("DATABASE_URL")

141
prisma/seed.js Normal file
View File

@ -0,0 +1,141 @@
import { PrismaClient } from '@prisma/client'
import bcrypt from 'bcryptjs'
const prisma = new PrismaClient()
// Список базовых категорий товаров
const DEFAULT_CATEGORIES = [
'Одежда и обувь',
'Косметика и парфюмерия',
'Дом и сад',
'Детские товары',
'Спорт и отдых',
'Электроника',
'Книги',
'Здоровье',
'Автотовары',
'Строительство и ремонт',
'Продукты питания',
'Зоотовары',
'Дача, сад и огород',
'Канцелярские товары',
'Хобби и творчество',
'Украшения и аксессуары',
'Сумки и чемоданы',
'Техника для дома',
'Музыкальные инструменты',
'Игры и игрушки'
]
async function seedAdmin() {
try {
console.log('🔐 Создание администратора...')
// Проверяем есть ли уже админ
const existingAdmin = await prisma.admin.findUnique({
where: { username: 'admin' }
})
if (existingAdmin) {
console.log(' Администратор уже существует, пропускаем создание')
return existingAdmin
}
// Генерируем хеш пароля
const password = 'admin123' // Временный пароль
const hashedPassword = await bcrypt.hash(password, 12)
// Создаем администратора
const admin = await prisma.admin.create({
data: {
username: 'admin',
password: hashedPassword,
email: 'admin@sferav.com',
isActive: true
}
})
console.log('✅ Администратор создан:')
console.log(` Логин: ${admin.username}`)
console.log(` Пароль: ${password}`)
console.log(` Email: ${admin.email}`)
console.log(' ⚠️ Обязательно смените пароль после первого входа!')
return admin
} catch (error) {
console.error('❌ Ошибка создания администратора:', error)
throw error
}
}
async function seedCategories() {
try {
console.log('\n📂 Создание категорий...')
let createdCount = 0
let skippedCount = 0
for (const categoryName of DEFAULT_CATEGORIES) {
try {
// Проверяем существует ли категория
const existingCategory = await prisma.category.findUnique({
where: { name: categoryName }
})
if (existingCategory) {
skippedCount++
continue
}
// Создаем категорию
await prisma.category.create({
data: {
name: categoryName
}
})
createdCount++
console.log(` ✅ Создана категория: ${categoryName}`)
} catch (error) {
console.log(` ⚠️ Ошибка создания категории "${categoryName}":`, error.message)
}
}
console.log(`\n📊 Результат создания категорий:`)
console.log(` Создано: ${createdCount}`)
console.log(` Пропущено (уже существует): ${skippedCount}`)
console.log(` Всего категорий: ${DEFAULT_CATEGORIES.length}`)
return { createdCount, skippedCount, total: DEFAULT_CATEGORIES.length }
} catch (error) {
console.error('❌ Ошибка создания категорий:', error)
throw error
}
}
async function main() {
try {
console.log('🚀 Запуск инициализации базы данных...\n')
// Создаем админа
await seedAdmin()
// Создаем категории
await seedCategories()
console.log('\n🎉 Инициализация базы данных завершена успешно!')
} catch (error) {
console.error('\n💥 Ошибка инициализации базы данных:', error)
process.exit(1)
} finally {
await prisma.$disconnect()
}
}
// Запускаем если скрипт вызван напрямую
if (import.meta.url === `file://${process.argv[1]}`) {
main()
}
export { seedAdmin, seedCategories }

View File

@ -835,4 +835,4 @@ export const GET_SUPPLY_ORDERS = gql`
} }
} }
} }
` `;

View File

@ -8,6 +8,7 @@ import { DaDataService } from "@/services/dadata-service";
import { MarketplaceService } from "@/services/marketplace-service"; import { MarketplaceService } from "@/services/marketplace-service";
import { WildberriesService } from "@/services/wildberries-service"; import { WildberriesService } from "@/services/wildberries-service";
import { Prisma } from "@prisma/client"; import { Prisma } from "@prisma/client";
import "@/lib/seed-init"; // Автоматическая инициализация БД
// Сервисы // Сервисы
const smsService = new SmsService(); const smsService = new SmsService();
@ -1241,6 +1242,21 @@ export const resolvers = {
return scheduleRecords; return scheduleRecords;
}, },
// Получение всех категорий товаров
categories: async () => {
try {
const categories = await prisma.category.findMany({
orderBy: {
name: 'asc'
}
});
return categories;
} catch (error) {
console.error('Ошибка получения категорий:', error);
throw new GraphQLError('Не удалось получить категории');
}
},
}, },
Mutation: { Mutation: {

141
src/lib/seed-init.ts Normal file
View File

@ -0,0 +1,141 @@
import { PrismaClient } from '@prisma/client'
import bcrypt from 'bcryptjs'
const prisma = new PrismaClient()
// Список базовых категорий товаров
const DEFAULT_CATEGORIES = [
'Одежда и обувь',
'Косметика и парфюмерия',
'Дом и сад',
'Детские товары',
'Спорт и отдых',
'Электроника',
'Книги',
'Здоровье',
'Автотовары',
'Строительство и ремонт',
'Продукты питания',
'Зоотовары',
'Дача, сад и огород',
'Канцелярские товары',
'Хобби и творчество',
'Украшения и аксессуары',
'Сумки и чемоданы',
'Техника для дома',
'Музыкальные инструменты',
'Игры и игрушки'
]
let isInitialized = false
export async function ensureAdmin() {
try {
// Проверяем есть ли уже админ
const existingAdmin = await prisma.admin.findUnique({
where: { username: 'admin' }
})
if (existingAdmin) {
return existingAdmin
}
console.log('🔐 Создание администратора...')
// Генерируем хеш пароля
const password = 'admin123' // Временный пароль
const hashedPassword = await bcrypt.hash(password, 12)
// Создаем администратора
const admin = await prisma.admin.create({
data: {
username: 'admin',
password: hashedPassword,
email: 'admin@sferav.com',
isActive: true
}
})
console.log('✅ Администратор создан:', admin.username)
return admin
} catch (error) {
console.error('❌ Ошибка создания администратора:', error)
return null
}
}
export async function ensureCategories() {
try {
// Проверяем сколько категорий уже есть
const existingCount = await prisma.category.count()
if (existingCount >= DEFAULT_CATEGORIES.length) {
return { created: 0, existing: existingCount }
}
let createdCount = 0
for (const categoryName of DEFAULT_CATEGORIES) {
try {
// Проверяем существует ли категория
const existingCategory = await prisma.category.findUnique({
where: { name: categoryName }
})
if (!existingCategory) {
// Создаем категорию
await prisma.category.create({
data: { name: categoryName }
})
createdCount++
}
} catch (error) {
// Игнорируем ошибки дублирования
if (error.code !== 'P2002') {
console.error(`Ошибка создания категории "${categoryName}":`, error.message)
}
}
}
if (createdCount > 0) {
console.log(`📂 Создано категорий: ${createdCount}`)
}
return { created: createdCount, existing: existingCount }
} catch (error) {
console.error('❌ Ошибка создания категорий:', error)
return { created: 0, existing: 0 }
}
}
export async function initializeDatabase() {
if (isInitialized) {
return
}
try {
console.log('🚀 Проверка инициализации базы данных...')
// Инициализируем админа и категории параллельно
const [admin, categories] = await Promise.all([
ensureAdmin(),
ensureCategories()
])
isInitialized = true
if (admin || categories.created > 0) {
console.log('✨ Инициализация базы данных завершена')
}
return { admin, categories }
} catch (error) {
console.error('💥 Ошибка инициализации базы данных:', error)
return null
}
}
// Автоматическая инициализация при импорте модуля
if (typeof window === 'undefined') { // Только на сервере
initializeDatabase().catch(console.error)
}