I have a challenging SWE issue regarding the sql.Row of database/sql
package.
I have the following interface:
type SqlQuerier interface {
QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
}
The SqlQuerier
is an interface that has the QueryRowContext
function signature. That function is implemented by various sql db clients, like Tx, SQLite3.
I have my own type:
func (db *XDB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
// operation
// check if the operation is successful, if not return error
// otherwise return sql.Row result
return db.innerDB.QueryRowContext(ctx, query, args...)
}
XDB
is an infrastructure wrapper to sqlx.DB (db.innerDB
) which in case the first operation was successful calls its own implementation of QueryRowContext
.
My issue is that I can't implant Error inside a sql.Row
result because:
- There isn't a factory function like
NewRow
or setters/getters to its unexported fields. - Returning
nil
isn't a quite good habit and don't have a quite indicator about the error reason. - Returning an empty
sql.Row{}
struct is problematic since it'll panic when trying to Scan its values afterwards .Scan(...). - Can't set values to unexported fields via reflection.
- Another limitation is that I can't change the function signature to return
(*sql.Row, error)
, because of its various dependencies on the other clients.
I'm open to any suggestions.
Caveat - this is ugly, and not ideal, and I would personally figure out a different way, but you could implement a convention where if the last argument you pass is a
*error
, you set the error it points to be the error you care aboutand then you can do