// Package database provides database client and connection management. package database import ( "context" "database/sql" "fmt" "time" "entgo.io/ent/dialect" entsql "entgo.io/ent/dialect/sql" "git.dcentral.systems/toolz/goplt/internal/ent" _ "github.com/lib/pq" // PostgreSQL driver ) // Client wraps the Ent client with additional functionality. type Client struct { *ent.Client db *sql.DB } // Config holds database configuration. type Config struct { DSN string MaxConnections int MaxIdleConns int ConnMaxLifetime time.Duration ConnMaxIdleTime time.Duration } // NewClient creates a new Ent client with connection pooling. func NewClient(cfg Config) (*Client, error) { // Open database connection db, err := sql.Open("postgres", cfg.DSN) if err != nil { return nil, fmt.Errorf("failed to open database connection: %w", err) } // Configure connection pool db.SetMaxOpenConns(cfg.MaxConnections) db.SetMaxIdleConns(cfg.MaxIdleConns) db.SetConnMaxLifetime(cfg.ConnMaxLifetime) db.SetConnMaxIdleTime(cfg.ConnMaxIdleTime) // Test connection ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := db.PingContext(ctx); err != nil { _ = db.Close() return nil, fmt.Errorf("failed to ping database: %w", err) } // Create Ent driver drv := entsql.OpenDB(dialect.Postgres, db) // Create Ent client entClient := ent.NewClient(ent.Driver(drv)) return &Client{ Client: entClient, db: db, }, nil } // Close closes the database connection. func (c *Client) Close() error { if err := c.Client.Close(); err != nil { return err } return c.db.Close() } // Migrate runs database migrations. func (c *Client) Migrate(ctx context.Context) error { return c.Schema.Create(ctx) } // Ping checks database connectivity. func (c *Client) Ping(ctx context.Context) error { return c.db.PingContext(ctx) } // DB returns the underlying *sql.DB for advanced operations. func (c *Client) DB() *sql.DB { return c.db }