start rmser

This commit is contained in:
2025-11-29 08:40:24 +03:00
commit 5aa2238eea
2117 changed files with 375169 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
package db
import (
"database/sql"
"fmt"
"log"
"os"
"regexp"
"rmser/internal/domain/catalog"
"rmser/internal/domain/invoices"
"rmser/internal/domain/ocr"
"rmser/internal/domain/operations"
"rmser/internal/domain/recipes"
"rmser/internal/domain/recommendations"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func NewPostgresDB(dsn string) *gorm.DB {
// 1. Проверка и создание БД перед основным подключением
ensureDBExists(dsn)
// 2. Настройка логгера GORM
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Warn,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
)
// 3. Основное подключение
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(fmt.Sprintf("не удалось подключиться к БД: %v", err))
}
// 4. Автомиграция
err = db.AutoMigrate(
&catalog.Product{},
&recipes.Recipe{},
&recipes.RecipeItem{},
&invoices.Invoice{},
&invoices.InvoiceItem{},
&operations.StoreOperation{},
&recommendations.Recommendation{},
&ocr.ProductMatch{},
)
if err != nil {
panic(fmt.Sprintf("ошибка миграции БД: %v", err))
}
return db
}
// ensureDBExists подключается к системной БД 'postgres' и создает целевую, если её нет
func ensureDBExists(fullDSN string) {
// Регулярка для извлечения имени базы из DSN (ищем dbname=... )
re := regexp.MustCompile(`dbname=([^\s]+)`)
matches := re.FindStringSubmatch(fullDSN)
if len(matches) < 2 {
// Если не нашли dbname, возможно формат URL (postgres://...),
// пропускаем авто-создание, полагаемся на ошибку драйвера
return
}
targetDB := matches[1]
// Заменяем целевую БД на системную 'postgres' для подключения
maintenanceDSN := re.ReplaceAllString(fullDSN, "dbname=postgres")
// Используем стандартный sql драйвер через pgx (который под капотом у gorm/postgres)
// Важно: нам не нужен GORM здесь, нужен чистый SQL для CREATE DATABASE
db, err := sql.Open("pgx", maintenanceDSN)
if err != nil {
// Если не вышло подключиться к postgres, просто выходим,
// основная ошибка вылетит при попытке gorm.Open
log.Printf("[WARN] Не удалось подключиться к системной БД для проверки: %v", err)
return
}
defer db.Close()
// Проверяем существование базы
var exists bool
checkSQL := fmt.Sprintf("SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = '%s')", targetDB)
err = db.QueryRow(checkSQL).Scan(&exists)
if err != nil {
log.Printf("[WARN] Ошибка проверки существования БД: %v", err)
return
}
if !exists {
log.Printf("[INFO] База данных '%s' не найдена. Создаю...", targetDB)
// CREATE DATABASE не может быть выполнен в транзакции, поэтому Exec
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE \"%s\"", targetDB))
if err != nil {
panic(fmt.Sprintf("не удалось создать базу данных %s: %v", targetDB, err))
}
log.Printf("[INFO] База данных '%s' успешно создана", targetDB)
}
}