This proposal is motivated by the common need for a standard interface defining a standard way to unwrap SQL drivers that may have been wrapped by SQL instrumentation packages.
Problem
Such SQL driver wrapper types hide every other interface the wrapped type may implement. For example, database/sql/driver defines many optional interfaces that would be hidden by the following wrapper type definition:
type myDriverWrapper struct {
driver.Driver
}
func Wrap(drv driver.Driver) driver.Driver {
return myDriverWrapper{drv}
}
With this straightforward type definition, myDriverWrapper only implements interface driver.Driver, no matter what the actual driver may implement besides the driver.Driver interface.
SQL dialect detection functions based on the package path name gotten with reflect (with reflect.TypeOf(db.Driver()).PkgPath()) will also break when using the wrapped driver.
Proposed solution
Similarly to the Unwrap function of package errors (https://golang.org/pkg/errors/#Unwrap), package database/sql/driver could provide the Unwrapper interface allowing a driver wrapper to return its underlying SQL driver, but also let third-party packages know about it:
type Unwrapper interface {
Unwrap() Driver
}
// Unwrap returns the result of calling the Unwrap method on drv, if drv's
// type implemented the Unwrapper interface.
// Otherwise, Unwrap returns nil.
func Unwrap(drv Driver) Driver {
// copied from package errors
// Go generics could allow sharing `Unwrapper` and `Unwrap()` definitions
if u, ok := err.(Unwrapper); ok {
return u.Unwrap()
}
return nil
}
When a driver wrapper implements the Unwrapper interface, a third-party package is able to:
- detect a driver has been wrapped
- unwrap the driver until it implements a given interface
- get the package paths of every wrapper type, down the deepest driver which should be the actual one
And probably other use-cases I haven't considered :-)
This proposal is motivated by the common need for a standard interface defining a standard way to unwrap SQL drivers that may have been wrapped by SQL instrumentation packages.
Problem
Such SQL driver wrapper types hide every other interface the wrapped type may implement. For example,
database/sql/driverdefines many optional interfaces that would be hidden by the following wrapper type definition:With this straightforward type definition,
myDriverWrapperonly implements interfacedriver.Driver, no matter what the actual driver may implement besides thedriver.Driverinterface.SQL dialect detection functions based on the package path name gotten with
reflect(withreflect.TypeOf(db.Driver()).PkgPath()) will also break when using the wrapped driver.Proposed solution
Similarly to the
Unwrapfunction of packageerrors(https://golang.org/pkg/errors/#Unwrap), packagedatabase/sql/drivercould provide theUnwrapperinterface allowing a driver wrapper to return its underlying SQL driver, but also let third-party packages know about it:When a driver wrapper implements the
Unwrapperinterface, a third-party package is able to:And probably other use-cases I haven't considered :-)