mirror of
https://github.com/ManyakRus/starter.git
synced 2025-11-26 23:10:42 +02:00
сделал postgres_gorm2
This commit is contained in:
@@ -17,6 +17,13 @@ DB_PORT=
|
||||
DB_USER=
|
||||
DB_PASSWORD=
|
||||
|
||||
DB_HOST2=
|
||||
DB_NAME2=
|
||||
DB_SCHEME2=
|
||||
DB_PORT2=
|
||||
DB_USER2=
|
||||
DB_PASSWORD2=
|
||||
|
||||
NATS_HOST=
|
||||
NATS_PORT=
|
||||
NATS_LOGIN=
|
||||
|
||||
643
postgres_gorm2/postgres_gorm2.go
Normal file
643
postgres_gorm2/postgres_gorm2.go
Normal file
@@ -0,0 +1,643 @@
|
||||
// модуль для работы с базой данных
|
||||
// полная копия postgres_gorm
|
||||
// нужен для второго подключения к БД
|
||||
|
||||
package postgres_gorm2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ManyakRus/starter/constants"
|
||||
"github.com/ManyakRus/starter/logger"
|
||||
"github.com/ManyakRus/starter/port_checker"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ManyakRus/starter/contextmain"
|
||||
"github.com/ManyakRus/starter/micro"
|
||||
"github.com/ManyakRus/starter/stopapp"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
gormlogger "gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
// Conn - соединение к базе данных
|
||||
var Conn *gorm.DB
|
||||
|
||||
// log - глобальный логгер
|
||||
var log = logger.GetLog()
|
||||
|
||||
// mutexReconnect - защита от многопоточности Reconnect()
|
||||
var mutexReconnect = &sync.Mutex{}
|
||||
|
||||
// NeedReconnect - флаг необходимости переподключения
|
||||
var NeedReconnect bool
|
||||
|
||||
// Settings хранит все нужные переменные окружения
|
||||
var Settings SettingsINI
|
||||
|
||||
// SettingsINI - структура для хранения всех нужных переменных окружения
|
||||
type SettingsINI struct {
|
||||
DB_HOST string
|
||||
DB_PORT string
|
||||
DB_NAME string
|
||||
DB_SCHEMA string
|
||||
DB_USER string
|
||||
DB_PASSWORD string
|
||||
}
|
||||
|
||||
// NamingStrategy - структура для хранения настроек наименования таблиц
|
||||
var NamingStrategy = schema.NamingStrategy{}
|
||||
|
||||
// Connect - подключается к базе данных
|
||||
func Connect() {
|
||||
|
||||
if Settings.DB_HOST == "" {
|
||||
FillSettings()
|
||||
}
|
||||
|
||||
port_checker.CheckPort(Settings.DB_HOST, Settings.DB_PORT)
|
||||
|
||||
err := Connect_err()
|
||||
LogInfo_Connected(err)
|
||||
|
||||
}
|
||||
|
||||
// Connect_err - подключается к базе данных
|
||||
func Connect_err() error {
|
||||
var err error
|
||||
err = Connect_WithApplicationName_err("")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect_WithApplicationName_SingularTableName - подключается к базе данных, с указанием имени приложения, без переименования имени таблиц
|
||||
func Connect_WithApplicationName_SingularTableName(ApplicationName string) {
|
||||
err := Connect_WithApplicationName_SingularTableName_err(ApplicationName)
|
||||
if err != nil {
|
||||
log.Panicln("POSTGRES gorm2 Connect_WithApplicationName_SingularTableName_err() to database host: ", Settings.DB_HOST, ", Error: ", err)
|
||||
} else {
|
||||
log.Info("POSTGRES gorm2 Connected. host: ", Settings.DB_HOST, ", base name: ", Settings.DB_NAME, ", schema: ", Settings.DB_SCHEMA)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect_WithApplicationName_SingularTableName_err - подключается к базе данных, с указанием имени приложения, без переименования имени таблиц
|
||||
func Connect_WithApplicationName_SingularTableName_err(ApplicationName string) error {
|
||||
SetSingularTableNames(true)
|
||||
err := Connect_WithApplicationName_err(ApplicationName)
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect_WithApplicationName - подключается к базе данных, с указанием имени приложения
|
||||
func Connect_WithApplicationName(ApplicationName string) {
|
||||
err := Connect_WithApplicationName_err(ApplicationName)
|
||||
if err != nil {
|
||||
log.Panicln("POSTGRES gorm2 Connect_WithApplicationName_err() to database host: ", Settings.DB_HOST, ", Error: ", err)
|
||||
} else {
|
||||
log.Info("POSTGRES gorm2 Connected. host: ", Settings.DB_HOST, ", base name: ", Settings.DB_NAME, ", schema: ", Settings.DB_SCHEMA)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect_WithApplicationName_err - подключается к базе данных, с указанием имени приложения
|
||||
func Connect_WithApplicationName_err(ApplicationName string) error {
|
||||
var err error
|
||||
|
||||
if Settings.DB_HOST == "" {
|
||||
FillSettings()
|
||||
}
|
||||
|
||||
//
|
||||
if contextmain.GetContext().Err() != nil {
|
||||
return contextmain.GetContext().Err()
|
||||
}
|
||||
|
||||
//get the database connection URL.
|
||||
dsn := GetDSN(ApplicationName)
|
||||
|
||||
//
|
||||
conf := &gorm.Config{
|
||||
Logger: gormlogger.Default.LogMode(gormlogger.Silent),
|
||||
}
|
||||
conf.NamingStrategy = NamingStrategy
|
||||
|
||||
//
|
||||
config := postgres.Config{
|
||||
DSN: dsn,
|
||||
PreferSimpleProtocol: true, //для запуска мультизапросов
|
||||
}
|
||||
|
||||
//
|
||||
dialect := postgres.New(config)
|
||||
Conn, err = gorm.Open(dialect, conf)
|
||||
|
||||
if err == nil {
|
||||
DB, err := Conn.DB()
|
||||
if err != nil {
|
||||
log.Error("Conn.DB() error: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = DB.Ping()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// IsClosed проверка что база данных закрыта
|
||||
func IsClosed() bool {
|
||||
var otvet bool
|
||||
if Conn == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
DB, err := Conn.DB()
|
||||
if err != nil {
|
||||
log.Error("Conn.DB() error: ", err)
|
||||
return true
|
||||
}
|
||||
|
||||
err = DB.Ping()
|
||||
if err != nil {
|
||||
log.Error("DB.CheckPort() error: ", err)
|
||||
return true
|
||||
}
|
||||
return otvet
|
||||
}
|
||||
|
||||
// Reconnect повторное подключение к базе данных, если оно отключено
|
||||
// или полная остановка программы
|
||||
func Reconnect(err error) {
|
||||
mutexReconnect.Lock()
|
||||
defer mutexReconnect.Unlock()
|
||||
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
|
||||
if Conn == nil {
|
||||
log.Warn("Reconnect()")
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
log.Error("error: ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if IsClosed() {
|
||||
micro.Pause(1000)
|
||||
log.Warn("Reconnect()")
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
log.Error("error: ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
sError := err.Error()
|
||||
if sError == "Conn closed" {
|
||||
micro.Pause(1000)
|
||||
log.Warn("Reconnect()")
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
log.Error("error: ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//PgError, ok := err.(*pgconn.PgError)
|
||||
//if ok {
|
||||
// if PgError.Code == "P0001" { // Class P0 — PL/pgSQL Error, RaiseException
|
||||
// return //нужен
|
||||
// }
|
||||
//}
|
||||
|
||||
//остановим программу т.к. она не должна работать при неработающеё БД
|
||||
log.Error("STOP app. Error: ", err)
|
||||
stopapp.StopApp()
|
||||
|
||||
}
|
||||
|
||||
// CloseConnection - закрытие соединения с базой данных
|
||||
func CloseConnection() {
|
||||
if Conn == nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := CloseConnection_err()
|
||||
if err != nil {
|
||||
log.Error("Postgres gorm CloseConnection() error: ", err)
|
||||
} else {
|
||||
log.Info("Postgres gorm connection closed")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CloseConnection - закрытие соединения с базой данных
|
||||
func CloseConnection_err() error {
|
||||
if Conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
DB, err := Conn.DB()
|
||||
if err != nil {
|
||||
log.Error("Conn.DB() error: ", err)
|
||||
return err
|
||||
}
|
||||
err = DB.Close()
|
||||
if err != nil {
|
||||
log.Error("DB.Close() error: ", err)
|
||||
}
|
||||
Conn = nil
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitStop - ожидает отмену глобального контекста
|
||||
func WaitStop() {
|
||||
|
||||
select {
|
||||
case <-contextmain.GetContext().Done():
|
||||
log.Warn("Context app is canceled. Postgres gorm.")
|
||||
}
|
||||
|
||||
//
|
||||
stopapp.WaitTotalMessagesSendingNow("Postgres gorm")
|
||||
|
||||
//
|
||||
CloseConnection()
|
||||
|
||||
stopapp.GetWaitGroup_Main().Done()
|
||||
}
|
||||
|
||||
// StartDB - делает соединение с БД, отключение и др.
|
||||
func StartDB() {
|
||||
var err error
|
||||
|
||||
ctx := contextmain.GetContext()
|
||||
WaitGroup := stopapp.GetWaitGroup_Main()
|
||||
err = Start_ctx(&ctx, WaitGroup)
|
||||
LogInfo_Connected(err)
|
||||
|
||||
}
|
||||
|
||||
// Start_ctx - необходимые процедуры для подключения к серверу БД
|
||||
// Свой контекст и WaitGroup нужны для остановки работы сервиса Graceful shutdown
|
||||
// Для тех кто пользуется этим репозиторием для старта и останова сервиса можно просто StartDB()
|
||||
func Start_ctx(ctx *context.Context, WaitGroup *sync.WaitGroup) error {
|
||||
var err error
|
||||
|
||||
//запомним к себе контекст
|
||||
contextmain.Ctx = ctx
|
||||
if ctx == nil {
|
||||
contextmain.GetContext()
|
||||
}
|
||||
|
||||
//запомним к себе WaitGroup
|
||||
stopapp.SetWaitGroup_Main(WaitGroup)
|
||||
if WaitGroup == nil {
|
||||
stopapp.StartWaitStop()
|
||||
}
|
||||
|
||||
//
|
||||
err = Connect_err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stopapp.GetWaitGroup_Main().Add(1)
|
||||
go WaitStop()
|
||||
|
||||
stopapp.GetWaitGroup_Main().Add(1)
|
||||
go ping_go()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Start - делает соединение с БД, отключение и др.
|
||||
func Start(ApplicationName string) {
|
||||
err := Connect_WithApplicationName_err(ApplicationName)
|
||||
LogInfo_Connected(err)
|
||||
//if err != nil {
|
||||
// log.Panic("Postgres gorm Start() error: ", err)
|
||||
//}
|
||||
|
||||
stopapp.GetWaitGroup_Main().Add(1)
|
||||
go WaitStop()
|
||||
|
||||
stopapp.GetWaitGroup_Main().Add(1)
|
||||
go ping_go()
|
||||
|
||||
}
|
||||
|
||||
// Start_SingularTableName - делает соединение с БД, отключение и др. Без переименования имени таблиц на множественное число
|
||||
func Start_SingularTableName(ApplicationName string) {
|
||||
SetSingularTableNames(true)
|
||||
Start(ApplicationName)
|
||||
|
||||
}
|
||||
|
||||
// FillSettings загружает переменные окружения в структуру из файла или из переменных окружения
|
||||
func FillSettings() {
|
||||
Settings = SettingsINI{}
|
||||
// заполним из переменных оуружения
|
||||
Settings.DB_HOST = os.Getenv("DB_HOST2")
|
||||
Settings.DB_PORT = os.Getenv("DB_PORT2")
|
||||
Settings.DB_NAME = os.Getenv("DB_NAME2")
|
||||
Settings.DB_SCHEMA = os.Getenv("DB_SCHEME2")
|
||||
Settings.DB_USER = os.Getenv("DB_USER2")
|
||||
Settings.DB_PASSWORD = os.Getenv("DB_PASSWORD2")
|
||||
|
||||
//// заполним из переменных оуружения как у Нечаева
|
||||
//if Settings.DB_HOST == "" {
|
||||
// Settings.DB_HOST = os.Getenv("STORE_HOST")
|
||||
// Settings.DB_PORT = os.Getenv("STORE_PORT")
|
||||
// Settings.DB_NAME = os.Getenv("STORE_NAME")
|
||||
// Settings.DB_SCHEMA = os.Getenv("STORE_SCHEME")
|
||||
// Settings.DB_USER = os.Getenv("STORE_LOGIN")
|
||||
// Settings.DB_PASSWORD = os.Getenv("STORE_PASSWORD")
|
||||
//}
|
||||
|
||||
if Settings.DB_HOST == "" {
|
||||
log.Panicln("Need fill DB_HOST2 ! in os.ENV ")
|
||||
}
|
||||
|
||||
if Settings.DB_PORT == "" {
|
||||
log.Panicln("Need fill DB_PORT2 ! in os.ENV ")
|
||||
}
|
||||
|
||||
if Settings.DB_NAME == "" {
|
||||
log.Panicln("Need fill DB_NAME2 ! in os.ENV ")
|
||||
}
|
||||
|
||||
if Settings.DB_SCHEMA == "" {
|
||||
log.Panicln("Need fill DB_SCHEMA2 ! in os.ENV ")
|
||||
}
|
||||
|
||||
if Settings.DB_USER == "" {
|
||||
log.Panicln("Need fill DB_USER2 ! in os.ENV ")
|
||||
}
|
||||
|
||||
if Settings.DB_PASSWORD == "" {
|
||||
log.Panicln("Need fill DB_PASSWORD2 ! in os.ENV ")
|
||||
}
|
||||
|
||||
//
|
||||
NamingStrategy.SchemaName(Settings.DB_SCHEMA)
|
||||
NamingStrategy.TablePrefix = Settings.DB_SCHEMA + "."
|
||||
}
|
||||
|
||||
// GetDSN - возвращает строку соединения к базе данных
|
||||
func GetDSN(ApplicationName string) string {
|
||||
ApplicationName = strings.ReplaceAll(ApplicationName, " ", "_")
|
||||
|
||||
dsn := "host=" + Settings.DB_HOST + " "
|
||||
dsn += "user=" + Settings.DB_USER + " "
|
||||
dsn += "password=" + Settings.DB_PASSWORD + " "
|
||||
dsn += "dbname=" + Settings.DB_NAME + " "
|
||||
dsn += "port=" + Settings.DB_PORT + " "
|
||||
dsn += "sslmode=disable TimeZone=" + constants.TIME_ZONE + " "
|
||||
dsn += "application_name=" + ApplicationName
|
||||
|
||||
return dsn
|
||||
}
|
||||
|
||||
// GetConnection - возвращает соединение к нужной базе данных
|
||||
func GetConnection() *gorm.DB {
|
||||
if Conn == nil {
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
log.Error("POSTGRES gorm2 Connect() to database host: ", Settings.DB_HOST, ", error: ", err)
|
||||
} else {
|
||||
log.Info("POSTGRES gorm2 Connected. host: ", Settings.DB_HOST, ", base name: ", Settings.DB_NAME, ", schema: ", Settings.DB_SCHEMA)
|
||||
}
|
||||
}
|
||||
|
||||
return Conn
|
||||
}
|
||||
|
||||
// GetConnection_WithApplicationName - возвращает соединение к нужной базе данных, с указанием имени приложения
|
||||
func GetConnection_WithApplicationName(ApplicationName string) *gorm.DB {
|
||||
if Conn == nil {
|
||||
err := Connect_WithApplicationName_err(ApplicationName)
|
||||
if err != nil {
|
||||
log.Panic("GetConnection_WithApplicationName() error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
return Conn
|
||||
}
|
||||
|
||||
// ping_go - делает пинг каждые 60 секунд, и реконнект
|
||||
func ping_go() {
|
||||
|
||||
ticker := time.NewTicker(60 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
addr := Settings.DB_HOST + ":" + Settings.DB_PORT
|
||||
|
||||
//бесконечный цикл
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-contextmain.GetContext().Done():
|
||||
log.Warn("Context app is canceled. postgres_gorm.ping")
|
||||
break loop
|
||||
case <-ticker.C:
|
||||
err := port_checker.CheckPort_err(Settings.DB_HOST, Settings.DB_PORT)
|
||||
//log.Debug("ticker, ping err: ", err) //удалить
|
||||
if err != nil {
|
||||
NeedReconnect = true
|
||||
log.Warn("postgres_gorm CheckPort(", addr, ") error: ", err)
|
||||
} else if NeedReconnect == true {
|
||||
log.Warn("postgres_gorm CheckPort(", addr, ") OK. Start Reconnect()")
|
||||
NeedReconnect = false
|
||||
err = Connect_err()
|
||||
if err != nil {
|
||||
NeedReconnect = true
|
||||
log.Error("Connect_err() error: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stopapp.GetWaitGroup_Main().Done()
|
||||
}
|
||||
|
||||
//// RawMultipleSQL - выполняет текст запроса, отдельно для каждого запроса
|
||||
//func RawMultipleSQL(db *gorm.DB, TextSQL string) *gorm.DB {
|
||||
// var tx *gorm.DB
|
||||
// var err error
|
||||
// tx = db
|
||||
//
|
||||
// // запустим все запросы отдельно
|
||||
// sqlSlice := strings.Split(TextSQL, ";")
|
||||
// len1 := len(sqlSlice)
|
||||
// for i, v := range sqlSlice {
|
||||
// if i == len1-1 {
|
||||
// tx = tx.Raw(v)
|
||||
// err = tx.Error
|
||||
// } else {
|
||||
// tx = tx.Exec(v)
|
||||
// err = tx.Error
|
||||
// }
|
||||
// if err != nil {
|
||||
// TextError := fmt.Sprint("db.Raw() error: ", err, ", TextSQL: \n", v)
|
||||
// err = errors.New(TextError)
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if tx == nil {
|
||||
// log.Panic("db.Raw() error: rows =nil")
|
||||
// }
|
||||
//
|
||||
// return tx
|
||||
//}
|
||||
|
||||
// RawMultipleSQL - выполняет текст запроса, отдельно для каждого запроса
|
||||
func RawMultipleSQL(db *gorm.DB, TextSQL string) *gorm.DB {
|
||||
var tx *gorm.DB
|
||||
var err error
|
||||
tx = db
|
||||
|
||||
if tx == nil {
|
||||
log.Error("RawMultipleSQL() error: db =nil")
|
||||
return tx
|
||||
}
|
||||
|
||||
//запустим транзакцию
|
||||
//tx0 := tx.Begin()
|
||||
//defer tx0.Commit()
|
||||
|
||||
//
|
||||
TextSQL1 := ""
|
||||
TextSQL2 := TextSQL
|
||||
|
||||
//запустим все запросы, кроме последнего
|
||||
pos1 := strings.LastIndex(TextSQL, ";")
|
||||
if pos1 > 0 {
|
||||
TextSQL1 = TextSQL[0:pos1]
|
||||
TextSQL2 = TextSQL[pos1:]
|
||||
tx = tx.Exec(TextSQL1)
|
||||
err = tx.Error
|
||||
if err != nil {
|
||||
TextError := fmt.Sprint("db.Exec() error: ", err, ", TextSQL: \n", TextSQL1)
|
||||
err = errors.New(TextError)
|
||||
return tx
|
||||
}
|
||||
}
|
||||
|
||||
//запустим последний запрос, с возвратом результата
|
||||
tx = tx.Raw(TextSQL2)
|
||||
err = tx.Error
|
||||
if err != nil {
|
||||
TextError := fmt.Sprint("db.Raw() error: ", err, ", TextSQL: \n", TextSQL2)
|
||||
err = errors.New(TextError)
|
||||
return tx
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
// ReplaceSchema - заменяет "public." на Settings.DB_SCHEMA
|
||||
func ReplaceSchema(TextSQL string) string {
|
||||
Otvet := TextSQL
|
||||
|
||||
if Settings.DB_SCHEMA == "" {
|
||||
return Otvet
|
||||
}
|
||||
|
||||
Otvet = strings.ReplaceAll(Otvet, "\tpublic.", "\t"+Settings.DB_SCHEMA+".")
|
||||
Otvet = strings.ReplaceAll(Otvet, "\npublic.", "\n"+Settings.DB_SCHEMA+".")
|
||||
Otvet = strings.ReplaceAll(Otvet, " public.", " "+Settings.DB_SCHEMA+".")
|
||||
|
||||
return Otvet
|
||||
}
|
||||
|
||||
// ReplaceTemporaryTableNamesToUnique - заменяет "public.TableName" на "public.TableName_UUID"
|
||||
func ReplaceTemporaryTableNamesToUnique(TextSQL string) string {
|
||||
Otvet := TextSQL
|
||||
|
||||
sUUID := micro.StringIdentifierFromUUID()
|
||||
map1 := make(map[string]int)
|
||||
|
||||
//найдём список всех временных таблиц, и заполним в map1
|
||||
s0 := Otvet
|
||||
for {
|
||||
sFind := "CREATE TEMPORARY TABLE "
|
||||
sFind2 := "create temporary table "
|
||||
pos1 := micro.IndexSubstringMin2(s0, sFind, sFind2)
|
||||
if pos1 < 0 {
|
||||
break
|
||||
}
|
||||
s2 := s0[pos1+len(sFind):]
|
||||
pos2 := micro.IndexSubstringMin2(s2, " ", "\n")
|
||||
if pos2 <= 0 {
|
||||
break
|
||||
}
|
||||
name1 := s0[pos1+len(sFind) : pos1+len(sFind)+pos2]
|
||||
if name1 == "" {
|
||||
break
|
||||
}
|
||||
|
||||
s0 = s0[pos1+len(sFind)+pos2:]
|
||||
map1[name1] = len(name1)
|
||||
}
|
||||
|
||||
//заменим все временные таблицы на уникальные
|
||||
MassNames := micro.SortMapStringInt_Desc(map1)
|
||||
for _, v := range MassNames {
|
||||
sFirst := " "
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+" ", " "+v+"_"+sUUID+" ")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"\n", " "+v+"_"+sUUID+"\n")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"\t", " "+v+"_"+sUUID+"\t")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+";", " "+v+"_"+sUUID+";")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"(", " "+v+"_"+sUUID+"(")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+")", " "+v+"_"+sUUID+")")
|
||||
|
||||
sFirst = "\t"
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+" ", " "+v+"_"+sUUID+" ")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"\n", " "+v+"_"+sUUID+"\n")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"\t", " "+v+"_"+sUUID+"\t")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+";", " "+v+"_"+sUUID+";")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"(", " "+v+"_"+sUUID+"(")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+")", " "+v+"_"+sUUID+")")
|
||||
|
||||
sFirst = "\n"
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+" ", " "+v+"_"+sUUID+" ")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"\n", " "+v+"_"+sUUID+"\n")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"\t", " "+v+"_"+sUUID+"\t")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+";", " "+v+"_"+sUUID+";")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+"(", " "+v+"_"+sUUID+"(")
|
||||
Otvet = strings.ReplaceAll(Otvet, sFirst+v+")", " "+v+"_"+sUUID+")")
|
||||
|
||||
}
|
||||
|
||||
return Otvet
|
||||
}
|
||||
|
||||
// SetSingularTableNames - меняет настройку "SingularTable" - надо ли НЕ переименовывать имя таблиц во вножественное число
|
||||
// true = не переименовывать
|
||||
func SetSingularTableNames(IsSingular bool) {
|
||||
NamingStrategy.SingularTable = IsSingular
|
||||
}
|
||||
|
||||
// LogInfo_Connected - выводит сообщение в Лог, или паника при ошибке
|
||||
func LogInfo_Connected(err error) {
|
||||
if err != nil {
|
||||
log.Panicln("POSTGRES gorm2 Connect() to database host: ", Settings.DB_HOST, ", Error: ", err)
|
||||
} else {
|
||||
log.Info("POSTGRES gorm2 Connected. host: ", Settings.DB_HOST, ", base name: ", Settings.DB_NAME, ", schema: ", Settings.DB_SCHEMA)
|
||||
}
|
||||
|
||||
}
|
||||
338
postgres_gorm2/postgres_gorm2_test.go
Normal file
338
postgres_gorm2/postgres_gorm2_test.go
Normal file
@@ -0,0 +1,338 @@
|
||||
package postgres_gorm2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
//log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/ManyakRus/starter/config_main"
|
||||
"github.com/ManyakRus/starter/contextmain"
|
||||
"github.com/ManyakRus/starter/micro"
|
||||
|
||||
// logger "github.com/ManyakRus/starter/common/v0/logger"
|
||||
"github.com/ManyakRus/starter/stopapp"
|
||||
)
|
||||
|
||||
func TestConnect_err(t *testing.T) {
|
||||
config_main.LoadEnv()
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
t.Error("TestConnect error: ", err)
|
||||
}
|
||||
|
||||
err = CloseConnection_err()
|
||||
if err != nil {
|
||||
t.Error("TestConnect() error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsClosed(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
t.Error("TestIsClosed Connect() error: ", err)
|
||||
}
|
||||
|
||||
isClosed := IsClosed()
|
||||
if isClosed == true {
|
||||
t.Error("TestIsClosed() isClosed = true ")
|
||||
}
|
||||
|
||||
err = CloseConnection_err()
|
||||
if err != nil {
|
||||
t.Error("TestIsClosed() CloseConnection() error: ", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestReconnect(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
t.Error("TestIsClosed Connect() error: ", err)
|
||||
}
|
||||
|
||||
//ctx := context.Background()
|
||||
Reconnect(errors.New(""))
|
||||
|
||||
err = CloseConnection_err()
|
||||
if err != nil {
|
||||
t.Error("TestReconnect() CloseConnection() error: ", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWaitStop(t *testing.T) {
|
||||
stopapp.StartWaitStop()
|
||||
|
||||
stopapp.GetWaitGroup_Main().Add(1)
|
||||
go WaitStop()
|
||||
|
||||
micro.Pause(10)
|
||||
|
||||
//stopapp.SignalInterrupt <- syscall.SIGINT
|
||||
contextmain.CancelContext()
|
||||
}
|
||||
|
||||
func TestStartDB(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
StartDB()
|
||||
err := CloseConnection_err()
|
||||
if err != nil {
|
||||
t.Error("db_test.TestStartDB() CloseConnection() error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnect(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
Connect()
|
||||
|
||||
CloseConnection()
|
||||
}
|
||||
|
||||
func TestGetConnection(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
GetConnection()
|
||||
|
||||
CloseConnection()
|
||||
}
|
||||
|
||||
func TestConnect_WithApplicationName_err(t *testing.T) {
|
||||
|
||||
config_main.LoadEnv()
|
||||
err := Connect_WithApplicationName_err("starter test")
|
||||
if err != nil {
|
||||
t.Error("TestConnect_WithApplicationName_err error: ", err)
|
||||
}
|
||||
|
||||
//micro.Pause(60 * 1000)
|
||||
|
||||
err = CloseConnection_err()
|
||||
if err != nil {
|
||||
t.Error("TestConnect_WithApplicationName_err() error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawMultipleSQL(t *testing.T) {
|
||||
config_main.LoadEnv()
|
||||
GetConnection()
|
||||
defer CloseConnection()
|
||||
|
||||
TimeStart := time.Now()
|
||||
|
||||
TextSQL := `
|
||||
drop table if exists temp_TestRawMultipleSQL2;
|
||||
CREATE TEMPORARY TABLE temp_TestRawMultipleSQL2 (id int);
|
||||
|
||||
insert into temp_TestRawMultipleSQL2
|
||||
select 1;
|
||||
|
||||
SELECT * FROM temp_TestRawMultipleSQL2
|
||||
`
|
||||
//TextSQL := "SELECT 1; SELECT 2"
|
||||
tx := RawMultipleSQL(Conn, TextSQL)
|
||||
err := tx.Error
|
||||
if err != nil {
|
||||
t.Error("TestRawMultipleSQL() error: ", err)
|
||||
}
|
||||
|
||||
t.Log("Прошло время: ", time.Since(TimeStart))
|
||||
}
|
||||
|
||||
func TestRawMultipleSQL2(t *testing.T) {
|
||||
config_main.LoadEnv()
|
||||
GetConnection()
|
||||
defer CloseConnection()
|
||||
|
||||
TimeStart := time.Now()
|
||||
|
||||
TextSQL := `
|
||||
drop table if exists temp_TestRawMultipleSQL2;
|
||||
CREATE TEMPORARY TABLE temp_TestRawMultipleSQL2 (id int);
|
||||
|
||||
insert into temp_TestRawMultipleSQL2
|
||||
select 1;
|
||||
|
||||
SELECT * FROM temp_TestRawMultipleSQL2
|
||||
`
|
||||
tx := RawMultipleSQL(Conn, TextSQL)
|
||||
err := tx.Error
|
||||
if err != nil {
|
||||
t.Error("TestRawMultipleSQL() error: ", err)
|
||||
}
|
||||
|
||||
if tx.RowsAffected != 1 {
|
||||
t.Error("TestRawMultipleSQL() RowsAffected = ", tx.RowsAffected)
|
||||
}
|
||||
|
||||
t.Log("Прошло время: ", time.Since(TimeStart))
|
||||
}
|
||||
|
||||
func TestRawMultipleSQL3(t *testing.T) {
|
||||
config_main.LoadEnv()
|
||||
wg := sync.WaitGroup{}
|
||||
GetConnection()
|
||||
defer CloseConnection()
|
||||
|
||||
TimeStart := time.Now()
|
||||
|
||||
TextSQL := `
|
||||
drop table if exists temp_TestRawMultipleSQL2;
|
||||
CREATE TEMPORARY TABLE temp_TestRawMultipleSQL2 (id int);
|
||||
|
||||
insert into temp_TestRawMultipleSQL2
|
||||
select 1;
|
||||
|
||||
SELECT * FROM temp_TestRawMultipleSQL2
|
||||
`
|
||||
f := func(t *testing.T) {
|
||||
tx := RawMultipleSQL(Conn, TextSQL)
|
||||
err := tx.Error
|
||||
if err != nil {
|
||||
t.Error("TestRawMultipleSQL3() error: ", err)
|
||||
}
|
||||
|
||||
if tx.RowsAffected != 1 {
|
||||
t.Error("TestRawMultipleSQL3() RowsAffected = ", tx.RowsAffected)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
//запустим 100 потоков
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go f(t)
|
||||
}
|
||||
|
||||
//micro.Pause(100)
|
||||
wg.Wait()
|
||||
|
||||
t.Log("Прошло время: ", time.Since(TimeStart))
|
||||
}
|
||||
|
||||
func TestReplaceSchema(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
schema string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "No schema",
|
||||
input: "SELECT * FROM public.users",
|
||||
schema: "",
|
||||
expected: "SELECT * FROM public.users",
|
||||
},
|
||||
{
|
||||
name: "Schema with tabs and newlines",
|
||||
input: "\tSELECT * FROM public.users\n",
|
||||
schema: "myschema",
|
||||
expected: "\tSELECT * FROM myschema.users\n",
|
||||
},
|
||||
{
|
||||
name: "Schema with spaces",
|
||||
input: "SELECT * FROM public.users ",
|
||||
schema: "myschema",
|
||||
expected: "SELECT * FROM myschema.users ",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
Settings.DB_SCHEMA = tt.schema
|
||||
got := ReplaceSchema(tt.input)
|
||||
if got != tt.expected {
|
||||
t.Errorf("ReplaceSchema() = %v, expected %v", got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceTemporaryTableNamesToUnique(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
}{
|
||||
{
|
||||
name: "One temporary table",
|
||||
input: "CREATE TEMPORARY TABLE temp_TableName (id int); SELECT * FROM temp_TableName",
|
||||
},
|
||||
{
|
||||
name: "Multiple temporary tables",
|
||||
input: "CREATE TEMPORARY TABLE temp_TableName1 (id int); CREATE TEMPORARY TABLE temp_TableName2 (name varchar); SELECT * FROM temp_TableName1; SELECT * FROM temp_TableName2",
|
||||
},
|
||||
{
|
||||
name: "Temporary table with different cases",
|
||||
input: "CREATE TEMPORARY TABLE temp_tableName (id int); SELECT * FROM temp_tableName",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ReplaceTemporaryTableNamesToUnique(tt.input)
|
||||
if got == tt.input {
|
||||
t.Errorf("ReplaceTemporaryTableNamesToUnique() error: no changes")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceTemporaryTableNamesToUnique_EmptyInput(t *testing.T) {
|
||||
input := ""
|
||||
expected := ""
|
||||
result := ReplaceTemporaryTableNamesToUnique(input)
|
||||
if result != expected {
|
||||
t.Errorf("Expected: %s, but got: %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceTemporaryTableNamesToUnique_NoTempTable(t *testing.T) {
|
||||
input := "SELECT * FROM TableName"
|
||||
expected := "SELECT * FROM TableName"
|
||||
result := ReplaceTemporaryTableNamesToUnique(input)
|
||||
if result != expected {
|
||||
t.Errorf("Expected: %s, but got: %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceTemporaryTableNamesToUnique_OneTempTable(t *testing.T) {
|
||||
input := "CREATE TEMPORARY TABLE temp_Test (id int); SELECT * FROM temp_Test "
|
||||
result := ReplaceTemporaryTableNamesToUnique(input)
|
||||
if result == input {
|
||||
t.Errorf("TestReplaceTemporaryTableNamesToUnique_OneTempTable() error: no changes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceTemporaryTableNamesToUnique_MultipleTempTables(t *testing.T) {
|
||||
input := "CREATE TEMPORARY TABLE temp1 (id int); CREATE TEMPORARY TABLE temp2 (name varchar); SELECT * FROM temp1;"
|
||||
result := ReplaceTemporaryTableNamesToUnique(input)
|
||||
if result == input {
|
||||
t.Errorf("TestReplaceTemporaryTableNamesToUnique_OneTempTable() error: no changes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetSingularTableNames(t *testing.T) {
|
||||
// Test case 1: IsSingular is true
|
||||
IsSingular := true
|
||||
SetSingularTableNames(IsSingular)
|
||||
if NamingStrategy.SingularTable != IsSingular {
|
||||
t.Errorf("Expected SingularTable to be %v, but got %v", IsSingular, NamingStrategy.SingularTable)
|
||||
}
|
||||
|
||||
// Test case 2: IsSingular is false
|
||||
IsSingular = false
|
||||
SetSingularTableNames(IsSingular)
|
||||
if NamingStrategy.SingularTable != IsSingular {
|
||||
t.Errorf("Expected SingularTable to be %v, but got %v", IsSingular, NamingStrategy.SingularTable)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user