2021-08-26 16:16:50 +03:00
|
|
|
package db
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2026-07-16 10:08:54 +03:00
|
|
|
"errors"
|
2021-08-26 16:16:50 +03:00
|
|
|
"log"
|
2021-11-17 11:44:12 +03:00
|
|
|
"path/filepath"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
2021-08-26 16:16:50 +03:00
|
|
|
|
|
|
|
|
Config "micrach/config"
|
2021-11-17 11:44:12 +03:00
|
|
|
Files "micrach/files"
|
2021-08-26 16:16:50 +03:00
|
|
|
|
2026-07-16 10:08:54 +03:00
|
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
2021-08-26 16:16:50 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var Pool *pgxpool.Pool
|
|
|
|
|
|
2021-11-17 11:44:12 +03:00
|
|
|
type MigrationsMap map[int]string
|
|
|
|
|
type Migration struct {
|
|
|
|
|
ID int
|
|
|
|
|
Name string
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-16 10:08:54 +03:00
|
|
|
func Init(ctx context.Context) {
|
2021-08-26 16:16:50 +03:00
|
|
|
var err error
|
2026-07-16 10:08:54 +03:00
|
|
|
Pool, err = pgxpool.New(ctx, Config.Db.Url)
|
2021-08-26 16:16:50 +03:00
|
|
|
if err != nil {
|
|
|
|
|
log.Println("database - offline")
|
|
|
|
|
log.Panicln(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Println("database - online")
|
|
|
|
|
}
|
2021-11-17 11:44:12 +03:00
|
|
|
|
2026-07-16 10:08:54 +03:00
|
|
|
func Migrate(ctx context.Context) {
|
|
|
|
|
dbMigrations := getDbMigrations(ctx)
|
2021-11-17 11:44:12 +03:00
|
|
|
sqlMigrations := Files.GetFullFilePathsInFolder("migrations")
|
|
|
|
|
for _, m := range sqlMigrations {
|
|
|
|
|
filename := filepath.Base(m)
|
|
|
|
|
splitted := strings.Split(filename, "-")
|
|
|
|
|
id, err := strconv.Atoi(splitted[0])
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Panicln(err)
|
|
|
|
|
}
|
|
|
|
|
// Get name without extension
|
|
|
|
|
name := strings.Split(splitted[1], ".")[0]
|
|
|
|
|
|
|
|
|
|
_, isMigrationInDb := dbMigrations[id]
|
|
|
|
|
if !isMigrationInDb {
|
2022-01-21 02:24:30 +03:00
|
|
|
sql := Files.ReadFileText(m)
|
2026-07-16 10:08:54 +03:00
|
|
|
runMigration(ctx, id, name, sql)
|
2022-05-18 10:23:35 +03:00
|
|
|
log.Println("migration - " + name + " - online")
|
2021-11-17 11:44:12 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 10:23:35 +03:00
|
|
|
log.Println("migrations - online")
|
2021-11-17 11:44:12 +03:00
|
|
|
}
|
|
|
|
|
|
2026-07-16 10:08:54 +03:00
|
|
|
func runMigration(ctx context.Context, mid int, mname, msql string) {
|
|
|
|
|
_, err := Pool.Exec(ctx, msql)
|
2022-01-21 02:24:30 +03:00
|
|
|
if err != nil {
|
|
|
|
|
log.Panicln(err)
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-16 10:08:54 +03:00
|
|
|
_, err = Pool.Exec(ctx, `INSERT INTO migrations (id, name) VALUES ($1, $2)`, mid, mname)
|
2022-01-21 02:24:30 +03:00
|
|
|
if err != nil {
|
|
|
|
|
log.Panicln(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-16 10:08:54 +03:00
|
|
|
func getDbMigrations(ctx context.Context) MigrationsMap {
|
|
|
|
|
rows, err := Pool.Query(ctx, `SELECT id, name FROM migrations`)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if isUndefinedTable(err) {
|
|
|
|
|
return make(MigrationsMap)
|
|
|
|
|
}
|
2021-11-17 11:44:12 +03:00
|
|
|
log.Panicln(err)
|
|
|
|
|
}
|
2026-07-16 10:08:54 +03:00
|
|
|
defer rows.Close()
|
2021-11-17 11:44:12 +03:00
|
|
|
|
|
|
|
|
migrationsMap := make(MigrationsMap)
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
var m Migration
|
|
|
|
|
err = rows.Scan(&m.ID, &m.Name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Panicln(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
migrationsMap[m.ID] = m.Name
|
|
|
|
|
}
|
2026-07-16 10:08:54 +03:00
|
|
|
if err := rows.Err(); err != nil {
|
|
|
|
|
log.Panicln(err)
|
|
|
|
|
}
|
2021-11-17 11:44:12 +03:00
|
|
|
|
|
|
|
|
return migrationsMap
|
|
|
|
|
}
|
2022-05-18 10:23:35 +03:00
|
|
|
|
2026-07-16 10:08:54 +03:00
|
|
|
func isUndefinedTable(err error) bool {
|
|
|
|
|
var pgErr *pgconn.PgError
|
|
|
|
|
return errors.As(err, &pgErr) && pgErr.Code == "42P01"
|
2022-05-18 10:23:35 +03:00
|
|
|
}
|