mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-18 11:02:54 +00:00
- Move all subscriber, payment method, transaction, and notification CRUD operations to crud.go - Remove models import from database.go as it's no longer needed - Keep database initialization, connection management, and IMSI allocation in database.go - Maintain ListSubscribersRequest struct definition in crud.go alongside related functions
118 lines
2.9 KiB
Go
118 lines
2.9 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os/exec"
|
|
"time"
|
|
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
"github.com/nutcas3/telecom-platform/apps/api-server/internal/config"
|
|
)
|
|
|
|
type Database struct {
|
|
DB *gorm.DB
|
|
}
|
|
|
|
type IMSIAllocation struct {
|
|
ID uint `gorm:"primaryKey"`
|
|
LastIMSI uint64 `gorm:"not null"`
|
|
MinIMSI uint64 `gorm:"not null"`
|
|
MaxIMSI uint64 `gorm:"not null"`
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
func NewDatabase(cfg *config.DatabaseConfig) (*Database, error) {
|
|
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=%s",
|
|
cfg.Host, cfg.Username, cfg.Password, cfg.Database, cfg.Port, cfg.SSLMode)
|
|
|
|
gormLogger := logger.Default.LogMode(logger.Info)
|
|
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: gormLogger})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to connect to database: %w", err)
|
|
}
|
|
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get underlying sql.DB: %w", err)
|
|
}
|
|
|
|
sqlDB.SetMaxIdleConns(25)
|
|
sqlDB.SetMaxOpenConns(100)
|
|
sqlDB.SetConnMaxLifetime(time.Hour)
|
|
sqlDB.SetConnMaxIdleTime(30 * time.Minute)
|
|
|
|
database := &Database{DB: db}
|
|
|
|
if err := runMigrations(dsn); err != nil {
|
|
return nil, fmt.Errorf("failed to run migrations: %w", err)
|
|
}
|
|
|
|
if err := database.InitializeIMSIAllocation(); err != nil {
|
|
return nil, fmt.Errorf("failed to initialize IMSI allocation: %w", err)
|
|
}
|
|
|
|
return database, nil
|
|
}
|
|
|
|
func runMigrations(dsn string) error {
|
|
cmd := exec.Command("goose", "postgres", dsn, "up", "migrations")
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("goose migration failed: %w, output: %s", err, string(output))
|
|
}
|
|
log.Printf("Database migrations completed successfully")
|
|
return nil
|
|
}
|
|
|
|
func (d *Database) InitializeIMSIAllocation() error {
|
|
var allocation IMSIAllocation
|
|
result := d.DB.First(&allocation)
|
|
|
|
if result.Error == gorm.ErrRecordNotFound {
|
|
allocation = IMSIAllocation{LastIMSI: 0, MinIMSI: 1, MaxIMSI: 999999999}
|
|
if err := d.DB.Create(&allocation).Error; err != nil {
|
|
return fmt.Errorf("failed to create IMSI allocation: %w", err)
|
|
}
|
|
log.Printf("Created IMSI allocation record")
|
|
} else if result.Error != nil {
|
|
return fmt.Errorf("failed to query IMSI allocation: %w", result.Error)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *Database) Close() error {
|
|
sqlDB, err := d.DB.DB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return sqlDB.Close()
|
|
}
|
|
|
|
func (d *Database) Ping(ctx context.Context) error {
|
|
sqlDB, err := d.DB.DB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return sqlDB.PingContext(ctx)
|
|
}
|
|
|
|
func (d *Database) GetIMSIAllocation(ctx context.Context) (*IMSIAllocation, error) {
|
|
var allocation IMSIAllocation
|
|
err := d.DB.WithContext(ctx).First(&allocation).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &allocation, nil
|
|
}
|
|
|
|
func (d *Database) UpdateIMSIAllocation(ctx context.Context, allocation *IMSIAllocation) error {
|
|
return d.DB.WithContext(ctx).Save(allocation).Error
|
|
}
|