Files
rmser/internal/infrastructure/db/postgres.go
SERTY 5f35d7a75f добавлен биллинг и тарифы
добавлена интеграция с юкасса
2025-12-24 09:06:19 +03:00

126 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package db
import (
"database/sql"
"fmt"
"log"
"os"
"regexp"
"rmser/internal/domain/account"
"rmser/internal/domain/billing"
"rmser/internal/domain/catalog"
"rmser/internal/domain/drafts"
"rmser/internal/domain/invoices"
"rmser/internal/domain/ocr"
"rmser/internal/domain/operations"
"rmser/internal/domain/recipes"
"rmser/internal/domain/recommendations"
"rmser/internal/domain/suppliers"
"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(
&account.User{},
&account.RMSServer{},
&account.ServerUser{},
&billing.Order{},
&catalog.Product{},
&catalog.MeasureUnit{},
&catalog.ProductContainer{},
&catalog.Store{},
&suppliers.Supplier{},
&recipes.Recipe{},
&recipes.RecipeItem{},
&invoices.Invoice{},
&invoices.InvoiceItem{},
&drafts.DraftInvoice{},
&drafts.DraftInvoiceItem{},
&operations.StoreOperation{},
&recommendations.Recommendation{},
&ocr.ProductMatch{},
&ocr.UnmatchedItem{},
)
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)
}
}