Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,40 @@ func NewContext(parent context.Context, exec Executor) Context {
}
}

// NewDatabaseContext creates a new dbx Context from a Database instance.
// This is a convenience function that allows creating a context from any Database,
// regardless of whether it implements ContextCreator or not.
//
// Parameters:
// - parent: The parent Go context to wrap
// - db: The Database instance to use as the executor
//
// Returns:
// - Context: A new dbx Context with the database as executor
//
// Example:
//
// db := dbx.New(sqlDB)
// dbCtx := dbx.NewDatabaseContext(context.Background(), db)
// result, err := dbCtx.Executor().Exec("INSERT INTO users (name) VALUES (?)", "John")
func NewDatabaseContext(parent context.Context, db Database) Context {
return &defaultContext{
parent: parent,
executor: db,
}
}

// NewContextFrom attempts to find an existing dbx Context in the provided context,
// or creates a new one using the provided ContextCreator if none is found.
// or creates a new one using the provided creator if none is found.
// This function is useful for ensuring that a dbx Context is available while
// avoiding unnecessary Context creation when one already exists.
//
// The creator parameter can be either a ContextCreator, a Database, or any type that has
// a Context(context.Context) Context method.
//
// Parameters:
// - ctx: The context to search for an existing dbx Context
// - creator: ContextCreator to use if no existing Context is found
// - creator: Either a ContextCreator, Database, or any type with Context method to use if no existing Context is found
//
// Returns:
// - Context: Either the existing dbx Context or a newly created one
Expand All @@ -107,14 +133,30 @@ func NewContext(parent context.Context, exec Executor) Context {
// // This will reuse existing dbx Context or create new one
// dbCtx := dbx.NewContextFrom(ctx, database)
// executor := dbCtx.Executor()
func NewContextFrom(ctx context.Context, creator ContextCreator) Context {
func NewContextFrom(ctx context.Context, creator interface{}) Context {
found := FromContext(ctx)

if found != nil {
return found
}

return creator.Context(ctx)
// Try ContextCreator interface first
if cc, ok := creator.(ContextCreator); ok {
return cc.Context(ctx)
}

// Try Database interface
if db, ok := creator.(Database); ok {
return NewDatabaseContext(ctx, db)
}

// Try any type with Context method (for backward compatibility)
if contextProvider, ok := creator.(interface{ Context(context.Context) Context }); ok {
return contextProvider.Context(ctx)
}

// If none work, panic with helpful message
panic("creator must implement ContextCreator, Database, or have Context(context.Context) Context method")
}

// FromContext extracts a dbx Context from the provided Go context.
Expand Down
7 changes: 5 additions & 2 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ type defaultDatabase struct {
// automatic transaction management while preserving all the functionality
// of the underlying sql.DB.
//
// The returned database also implements ContextCreator, allowing direct
// context creation via the Context method.
//
// Parameters:
// - db: A properly initialized sql.DB instance. The caller retains ownership
// and responsibility for the sql.DB's configuration and driver setup.
//
// Returns:
// - Database: A dbx Database that can be used to create contexts and manage transactions.
// - DatabaseWithContext: A dbx Database that can create contexts and manage transactions.
//
// Example:
//
Expand All @@ -37,7 +40,7 @@ type defaultDatabase struct {
//
// ctx := dbxDB.Context(context.Background())
// rows, err := ctx.Executor().Query("SELECT * FROM users")
func New(db *sql.DB) Database {
func New(db *sql.DB) DatabaseWithContext {
return &defaultDatabase{db}
}

Expand Down
15 changes: 10 additions & 5 deletions lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ type (
Context(ctx context.Context) Context
}

// DatabaseWithContext is an optional interface that databases can implement
// to provide context creation capabilities. This is separate from the main
// Database interface to maintain compatibility with external packages.
DatabaseWithContext interface {
Database
ContextCreator
}

// Operation represents a user-defined database operation that needs to be
// performed within a transaction. Operations receive a dbx Context and
// should return an error if the operation fails.
Expand All @@ -147,8 +155,8 @@ type (
OperationWithResult[T any] func(ctx Context) (T, error)

// Database interface represents the main entry point for dbx operations.
// It combines database connection management, context creation, transaction
// initiation, and direct query execution capabilities.
// It combines database connection management, transaction initiation, and
// direct query execution capabilities.
//
// Database implementations should wrap sql.DB and provide context-aware
// database operations while maintaining compatibility with the standard
Expand All @@ -157,9 +165,6 @@ type (
// Embed io.Closer to allow proper database connection cleanup
io.Closer

// Embed ContextCreator to bootstrap dbx contexts
ContextCreator

// Embed Beginner to support transaction creation
Beginner

Expand Down
Loading