db
The db package defines a database connection abstraction used across the application. It provides a common Connection interface with concrete adapters for SQL databases (PostgreSQL via database/sql), MongoDB, and an in-memory no-op connection for testing.
Import path: ecom-engine/pkg/db
This package only defines the connection contract and lightweight wrappers. The actual database driver setup (connection strings, pooling, migrations) lives in
internal/infra/db.
Connection interface
type Connection interface {
Ping(ctx context.Context) error
Close() error
}
All adapters satisfy this interface. Use it as the parameter/field type anywhere you want to be agnostic about the underlying database.
| Method | Description |
|---|---|
Ping(ctx) | Verifies the connection is alive. Used by health check endpoints. |
Close() | Cleanly terminates the connection pool. Call on application shutdown. |
Adapters
SQLConnection
Wraps a standard *database/sql.DB connection pool. Suitable for any SQL driver (PostgreSQL via pgx, MySQL, SQLite, etc.).
type SQLConnection struct {
DB *sql.DB
}
DB is exported so callers can access the full *sql.DB API (query execution, transactions, etc.) when needed.
conn := &db.SQLConnection{DB: sqlDB}
if err := conn.Ping(ctx); err != nil {
log.Fatal("database unreachable:", err)
}
defer conn.Close()
MongoConnection
Wraps a *mongo.Client from the official MongoDB Go driver v2.
type MongoConnection struct {
Client *mongo.Client
}
Client is exported for direct access to MongoDB databases and collections.
conn := &db.MongoConnection{Client: mongoClient}
if err := conn.Ping(ctx); err != nil {
log.Fatal("mongo unreachable:", err)
}
defer conn.Close()
Close() calls Client.Disconnect with a fresh context.Background() to avoid using a cancelled context during shutdown.
MemoryConnection
A no-op adapter for tests and local simulation. Ping always returns nil, Close is a no-op.
conn := &db.MemoryConnection{}
// Safe to pass anywhere a Connection is expected in tests
Usage pattern
The connection is typically constructed in the application engine/startup layer and passed down via dependency injection:
// in engine startup
sqlDB, err := sql.Open("pgx", dsn)
if err != nil { ... }
conn := &db.SQLConnection{DB: sqlDB}
// health check route
router.GET("/healthz", func(c *gin.Context) {
if err := conn.Ping(c.Request.Context()); err != nil {
response.GinError(c, http.StatusServiceUnavailable, "database unavailable")
return
}
response.GinOK(c, gin.H{"status": "ok"})
})