feat(epic1): implement core infrastructure (stories 1.1-1.5)
Implemented Epic 1 core kernel and infrastructure stories: Story 1.1: Enhanced DI Container - Added providers for database, health, metrics, and error bus - Extended CoreModule to include all core services Story 1.2: Database Layer with Ent ORM - Created Ent schema for User, Role, Permission, AuditLog entities - Implemented many-to-many relationships (User-Role, Role-Permission) - Created database client wrapper with connection pooling - Added database provider to DI container with migration support Story 1.3: Health Monitoring and Metrics System - Implemented health check registry and interface - Added database health checker - Created Prometheus metrics system with HTTP instrumentation - Added health and metrics providers to DI container Story 1.4: Error Handling and Error Bus - Implemented channel-based error bus - Created ErrorPublisher interface - Added error bus provider with lifecycle management Story 1.5: HTTP Server Foundation - Created HTTP server with Gin framework - Implemented comprehensive middleware stack: - Request ID generation - Structured logging - Panic recovery with error bus integration - Prometheus metrics collection - CORS support - Registered core routes: /healthz, /ready, /metrics - Integrated with FX lifecycle for graceful shutdown All components are integrated via DI container and ready for use.
This commit is contained in:
87
internal/infra/database/client.go
Normal file
87
internal/infra/database/client.go
Normal file
@@ -0,0 +1,87 @@
|
||||
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.Client.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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user