diff --git a/database/sql.go b/database/sql.go index 5d141f571cf00f4311f863f23dbf9533c7f43318_ZGF0YWJhc2Uvc3FsLmdv..42db5ca3dedd60721287f4a698b6238b155be074_ZGF0YWJhc2Uvc3FsLmdv 100644 --- a/database/sql.go +++ b/database/sql.go @@ -57,6 +57,7 @@ GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error QueryxContext(context.Context, string, ...interface{}) (*sqlx.Rows, error) + QueryRowxContext(context.Context, string, ...interface{}) *sqlx.Row } func setPlaceHolderFormat(query squirrel.Sqlizer) squirrel.Sqlizer { @@ -135,6 +136,19 @@ return e.QueryxContext(ctx, sqlQuery, args...) } +// QueryRowContext runs a squirrel query on the given db or tx and return a single Row. +func QueryRowContext(ctx context.Context, e SQLExecutor, query squirrel.Sqlizer, log *zerolog.Logger) *Row { + query = setPlaceHolderFormat(query) + sqlQuery, args, err := query. + ToSql() + if err != nil { + return &Row{err: err} + } + SQLTrace(log, sqlQuery, args) + + return &Row{Row: e.QueryRowxContext(ctx, sqlQuery, args...)} +} + // ValuesMap returns the values for a list of columns as a map. If a column does // not exits, the corresponding value is set to nil. func ValuesMap(m Mapped, columns ...string) map[string]interface{} { diff --git a/database/sql_helper.go b/database/sql_helper.go index 5d141f571cf00f4311f863f23dbf9533c7f43318_ZGF0YWJhc2Uvc3FsX2hlbHBlci5nbw==..42db5ca3dedd60721287f4a698b6238b155be074_ZGF0YWJhc2Uvc3FsX2hlbHBlci5nbw== 100644 --- a/database/sql_helper.go +++ b/database/sql_helper.go @@ -123,6 +123,11 @@ return h.sqle.QueryxContext(h.ctx, sql, args...) } +// QueryRow executes a query that returns a single row. +func (h *SQLHelper) QueryRow(query sq.Sqlizer) *Row { + return QueryRowContext(h.ctx, h.sqle, query, &h.log) +} + // Insert inserts a Mapped into the db. func (h *SQLHelper) Insert(instances ...Mapped) (sql.Result, error) { query := SQLInsert(instances...) diff --git a/database/sql_row.go b/database/sql_row.go new file mode 100644 index 0000000000000000000000000000000000000000..42db5ca3dedd60721287f4a698b6238b155be074_ZGF0YWJhc2Uvc3FsX3Jvdy5nbw== --- /dev/null +++ b/database/sql_row.go @@ -0,0 +1,44 @@ +package database + +import ( + "database/sql" + + "github.com/jmoiron/sqlx" +) + +type Row struct { + *sqlx.Row + err error +} + +// Scan is a fixed implementation of sql.Row.Scan, which does not discard the +// underlying error from the internal rows object if it exists. +func (r *Row) Scan(dest ...interface{}) error { + if r.err != nil { + return r.err + } + + return r.Row.Scan(dest...) +} + +// Columns returns the underlying sql.Rows.Columns(), or the deferred error usually +// returned by Row.Scan() +func (r *Row) Columns() ([]string, error) { + if r.err != nil { + return []string{}, r.err + } + return r.Row.Columns() +} + +// ColumnTypes returns the underlying sql.Rows.ColumnTypes(), or the deferred error +func (r *Row) ColumnTypes() ([]*sql.ColumnType, error) { + if r.err != nil { + return []*sql.ColumnType{}, r.err + } + return r.Row.ColumnTypes() +} + +// Err returns the error encountered while scanning. +func (r *Row) Err() error { + return r.err +}