Skip to content

Commit d6e094b

Browse files
committed
use Execer and Querier for impl funcs
1 parent 5c3a217 commit d6e094b

File tree

9 files changed

+77
-98
lines changed

9 files changed

+77
-98
lines changed

connection.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ type Connection interface {
5959
// Exec executes a query with optional args.
6060
Exec(query string, args ...any) error
6161

62+
// QueryRow queries a single row and returns a RowScanner for the results.
63+
QueryRow(query string, args ...any) RowScanner
64+
65+
// QueryRows queries multiple rows and returns a RowsScanner for the results.
66+
QueryRows(query string, args ...any) RowsScanner
67+
6268
// Insert a new row into table using the values.
6369
Insert(table string, values Values) error
6470

@@ -80,9 +86,6 @@ type Connection interface {
8086
// as new rows into table using the connection's
8187
// StructFieldMapper to map struct fields to column names.
8288
// Optional ColumnFilter can be passed to ignore mapped columns.
83-
//
84-
// TODO optimized version with single query if possible
85-
// split into multiple queries depending or maxArgs for query
8689
InsertStructs(table string, rowStructs any, ignoreColumns ...ColumnFilter) error
8790

8891
// InsertUniqueStruct inserts a new row into table using the connection's
@@ -120,12 +123,6 @@ type Connection interface {
120123
// If inserting conflicts on the primary key column(s), then an update is performed.
121124
UpsertStruct(table string, rowStruct any, ignoreColumns ...ColumnFilter) error
122125

123-
// QueryRow queries a single row and returns a RowScanner for the results.
124-
QueryRow(query string, args ...any) RowScanner
125-
126-
// QueryRows queries multiple rows and returns a RowsScanner for the results.
127-
QueryRows(query string, args ...any) RowsScanner
128-
129126
// IsTransaction returns if the connection is a transaction
130127
IsTransaction() bool
131128

errors.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ func (e connectionWithError) StructFieldMapper() StructFieldMapper {
8989
return DefaultStructFieldMapping
9090
}
9191

92+
func (e connectionWithError) ValidateColumnName(name string) error {
93+
return e.err
94+
}
95+
9296
func (e connectionWithError) Ping(time.Duration) error {
9397
return e.err
9498
}
@@ -101,10 +105,6 @@ func (e connectionWithError) Config() *Config {
101105
return &Config{Err: e.err}
102106
}
103107

104-
func (e connectionWithError) ValidateColumnName(name string) error {
105-
return e.err
106-
}
107-
108108
func (e connectionWithError) Now() (time.Time, error) {
109109
return time.Time{}, e.err
110110
}
@@ -113,6 +113,14 @@ func (e connectionWithError) Exec(query string, args ...any) error {
113113
return e.err
114114
}
115115

116+
func (e connectionWithError) QueryRow(query string, args ...any) RowScanner {
117+
return RowScannerWithError(e.err)
118+
}
119+
120+
func (e connectionWithError) QueryRows(query string, args ...any) RowsScanner {
121+
return RowsScannerWithError(e.err)
122+
}
123+
116124
func (e connectionWithError) Insert(table string, values Values) error {
117125
return e.err
118126
}
@@ -157,14 +165,6 @@ func (e connectionWithError) UpsertStruct(table string, rowStruct any, ignoreCol
157165
return e.err
158166
}
159167

160-
func (e connectionWithError) QueryRow(query string, args ...any) RowScanner {
161-
return RowScannerWithError(e.err)
162-
}
163-
164-
func (e connectionWithError) QueryRows(query string, args ...any) RowsScanner {
165-
return RowsScannerWithError(e.err)
166-
}
167-
168168
func (e connectionWithError) IsTransaction() bool {
169169
return false
170170
}

impl/genericconnection.go

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func (conn *genericConn) Config() *sqldb.Config {
9191
}
9292

9393
func (conn *genericConn) Now() (time.Time, error) {
94-
return Now(conn)
94+
return QueryNow(conn)
9595
}
9696

9797
func (conn *genericConn) execer() Execer {
@@ -112,6 +112,14 @@ func (conn *genericConn) Exec(query string, args ...any) error {
112112
return Exec(conn.ctx, conn.execer(), conn.argFmt, query, args)
113113
}
114114

115+
func (conn *genericConn) QueryRow(query string, args ...any) sqldb.RowScanner {
116+
return QueryRow(conn.ctx, conn.queryer(), conn.structFieldMapper, conn.argFmt, query, args)
117+
}
118+
119+
func (conn *genericConn) QueryRows(query string, args ...any) sqldb.RowsScanner {
120+
return QueryRows(conn.ctx, conn.queryer(), conn.structFieldMapper, conn.argFmt, query, args)
121+
}
122+
115123
func (conn *genericConn) Insert(table string, columValues sqldb.Values) error {
116124
return Insert(conn.ctx, conn.execer(), table, conn.argFmt, columValues)
117125
}
@@ -121,59 +129,40 @@ func (conn *genericConn) InsertUnique(table string, values sqldb.Values, onConfl
121129
}
122130

123131
func (conn *genericConn) InsertReturning(table string, values sqldb.Values, returning string) sqldb.RowScanner {
124-
return InsertReturning(conn, table, conn.argFmt, values, returning)
132+
return InsertReturning(conn.ctx, conn.queryer(), conn.structFieldMapper, conn.argFmt, table, values, returning)
125133
}
126134

127135
func (conn *genericConn) InsertStruct(table string, rowStruct any, ignoreColumns ...sqldb.ColumnFilter) error {
128-
return InsertStruct(conn, table, rowStruct, conn.structFieldMapper, conn.argFmt, ignoreColumns)
136+
return InsertStruct(conn.ctx, conn.execer(), table, rowStruct, conn.structFieldMapper, conn.argFmt, ignoreColumns)
129137
}
130138

131139
func (conn *genericConn) InsertStructs(table string, rowStructs any, ignoreColumns ...sqldb.ColumnFilter) error {
140+
// TODO optimized version with single query if possible, split into multiple queries depending or maxArgs for query
132141
return InsertStructs(conn, table, rowStructs, ignoreColumns...)
133142
}
134143

135144
func (conn *genericConn) InsertUniqueStruct(table string, rowStruct any, onConflict string, ignoreColumns ...sqldb.ColumnFilter) (inserted bool, err error) {
136-
return InsertUniqueStruct(conn, table, rowStruct, onConflict, conn.structFieldMapper, conn.argFmt, ignoreColumns)
145+
return InsertUniqueStruct(conn.ctx, conn.queryer(), conn.structFieldMapper, conn.argFmt, table, rowStruct, onConflict, ignoreColumns)
137146
}
138147

139148
func (conn *genericConn) Update(table string, values sqldb.Values, where string, args ...any) error {
140-
return Update(conn, table, values, where, conn.argFmt, args)
149+
return Update(conn.ctx, conn.execer(), table, values, where, conn.argFmt, args)
141150
}
142151

143152
func (conn *genericConn) UpdateReturningRow(table string, values sqldb.Values, returning, where string, args ...any) sqldb.RowScanner {
144-
return UpdateReturningRow(conn, table, values, returning, where, args)
153+
return UpdateReturningRow(conn.ctx, conn.queryer(), conn.structFieldMapper, conn.argFmt, table, values, returning, where, args)
145154
}
146155

147156
func (conn *genericConn) UpdateReturningRows(table string, values sqldb.Values, returning, where string, args ...any) sqldb.RowsScanner {
148-
return UpdateReturningRows(conn, table, values, returning, where, args)
157+
return UpdateReturningRows(conn.ctx, conn.queryer(), conn.structFieldMapper, conn.argFmt, table, values, returning, where, args)
149158
}
150159

151160
func (conn *genericConn) UpdateStruct(table string, rowStruct any, ignoreColumns ...sqldb.ColumnFilter) error {
152-
return UpdateStruct(conn, table, rowStruct, conn.structFieldMapper, conn.argFmt, ignoreColumns)
161+
return UpdateStruct(conn.ctx, conn.execer(), table, rowStruct, conn.structFieldMapper, conn.argFmt, ignoreColumns)
153162
}
154163

155164
func (conn *genericConn) UpsertStruct(table string, rowStruct any, ignoreColumns ...sqldb.ColumnFilter) error {
156-
return UpsertStruct(conn, table, rowStruct, conn.structFieldMapper, conn.argFmt, ignoreColumns)
157-
}
158-
159-
func (conn *genericConn) QueryRow(query string, args ...any) sqldb.RowScanner {
160-
var queryer Queryer
161-
if conn.tx != nil {
162-
queryer = conn.tx
163-
} else {
164-
queryer = conn.db
165-
}
166-
return QueryRow(conn.ctx, queryer, conn.structFieldMapper, conn.argFmt, query, args)
167-
}
168-
169-
func (conn *genericConn) QueryRows(query string, args ...any) sqldb.RowsScanner {
170-
var queryer Queryer
171-
if conn.tx != nil {
172-
queryer = conn.tx
173-
} else {
174-
queryer = conn.db
175-
}
176-
return QueryRows(conn.ctx, queryer, conn.structFieldMapper, conn.argFmt, query, args)
165+
return UpsertStruct(conn.ctx, conn.execer(), table, rowStruct, conn.structFieldMapper, conn.argFmt, ignoreColumns)
177166
}
178167

179168
func (conn *genericConn) IsTransaction() bool {

impl/insert.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,12 @@ func InsertUnique(ctx context.Context, conn Queryer, mapper sqldb.StructFieldMap
4343
fmt.Fprintf(&query, " ON CONFLICT (%s) DO NOTHING RETURNING TRUE", onConflict)
4444

4545
err = QueryRow(ctx, conn, mapper, argFmt, query.String(), vals).Scan(&inserted)
46-
47-
err = sqldb.ReplaceErrNoRows(err, nil)
48-
err = WrapNonNilErrorWithQuery(err, query.String(), argFmt, vals)
49-
return inserted, err
46+
return inserted, sqldb.ReplaceErrNoRows(err, nil)
5047
}
5148

5249
// InsertReturning inserts a new row into table using values
5350
// and returns values from the inserted row listed in returning.
54-
func InsertReturning(conn sqldb.Connection, table, argFmt string, values sqldb.Values, returning string) sqldb.RowScanner {
51+
func InsertReturning(ctx context.Context, conn Queryer, mapper sqldb.StructFieldMapper, argFmt, table string, values sqldb.Values, returning string) sqldb.RowScanner {
5552
if len(values) == 0 {
5653
return sqldb.RowScannerWithError(fmt.Errorf("InsertReturning into table %s: no values", table))
5754
}
@@ -61,7 +58,8 @@ func InsertReturning(conn sqldb.Connection, table, argFmt string, values sqldb.V
6158
writeInsertQuery(&query, table, argFmt, names)
6259
query.WriteString(" RETURNING ")
6360
query.WriteString(returning)
64-
return conn.QueryRow(query.String(), vals...)
61+
62+
return QueryRow(ctx, conn, mapper, argFmt, query.String(), vals)
6563
}
6664

6765
func writeInsertQuery(w *strings.Builder, table, argFmt string, names []string) {
@@ -87,7 +85,7 @@ func writeInsertQuery(w *strings.Builder, table, argFmt string, names []string)
8785
// InsertStruct inserts a new row into table using the connection's
8886
// StructFieldMapper to map struct fields to column names.
8987
// Optional ColumnFilter can be passed to ignore mapped columns.
90-
func InsertStruct(conn sqldb.Connection, table string, rowStruct any, mapper sqldb.StructFieldMapper, argFmt string, ignoreColumns []sqldb.ColumnFilter) error {
88+
func InsertStruct(ctx context.Context, conn Execer, table string, rowStruct any, mapper sqldb.StructFieldMapper, argFmt string, ignoreColumns []sqldb.ColumnFilter) error {
9189
columns, vals, err := insertStructValues(table, rowStruct, mapper, ignoreColumns)
9290
if err != nil {
9391
return err
@@ -97,7 +95,7 @@ func InsertStruct(conn sqldb.Connection, table string, rowStruct any, mapper sql
9795
writeInsertQuery(&b, table, argFmt, columns)
9896
query := b.String()
9997

100-
err = conn.Exec(query, vals...)
98+
_, err = conn.ExecContext(ctx, query, vals...)
10199

102100
return WrapNonNilErrorWithQuery(err, query, argFmt, vals)
103101
}
@@ -107,7 +105,7 @@ func InsertStruct(conn sqldb.Connection, table string, rowStruct any, mapper sql
107105
// Optional ColumnFilter can be passed to ignore mapped columns.
108106
// Does nothing if the onConflict statement applies
109107
// and returns if a row was inserted.
110-
func InsertUniqueStruct(conn sqldb.Connection, table string, rowStruct any, onConflict string, mapper sqldb.StructFieldMapper, argFmt string, ignoreColumns []sqldb.ColumnFilter) (inserted bool, err error) {
108+
func InsertUniqueStruct(ctx context.Context, conn Queryer, mapper sqldb.StructFieldMapper, argFmt string, table string, rowStruct any, onConflict string, ignoreColumns []sqldb.ColumnFilter) (inserted bool, err error) {
111109
columns, vals, err := insertStructValues(table, rowStruct, mapper, ignoreColumns)
112110
if err != nil {
113111
return false, err
@@ -122,10 +120,8 @@ func InsertUniqueStruct(conn sqldb.Connection, table string, rowStruct any, onCo
122120
fmt.Fprintf(&b, " ON CONFLICT (%s) DO NOTHING RETURNING TRUE", onConflict)
123121
query := b.String()
124122

125-
err = conn.QueryRow(query, vals...).Scan(&inserted)
126-
err = sqldb.ReplaceErrNoRows(err, nil)
127-
128-
return inserted, WrapNonNilErrorWithQuery(err, query, argFmt, vals)
123+
err = QueryRow(ctx, conn, mapper, argFmt, query, vals).Scan(&inserted)
124+
return inserted, sqldb.ReplaceErrNoRows(err, nil)
129125
}
130126

131127
func insertStructValues(table string, rowStruct any, mapper sqldb.StructFieldMapper, ignoreColumns []sqldb.ColumnFilter) (columns []string, vals []any, err error) {
@@ -149,6 +145,7 @@ func insertStructValues(table string, rowStruct any, mapper sqldb.StructFieldMap
149145
// The inserts are performed within a new transaction
150146
// if the passed conn is not already a transaction.
151147
func InsertStructs(conn sqldb.Connection, table string, rowStructs any, ignoreColumns ...sqldb.ColumnFilter) error {
148+
// TODO optimized version with single query if possible, split into multiple queries depending or maxArgs for query
152149
v := reflect.ValueOf(rowStructs)
153150
if k := v.Type().Kind(); k != reflect.Slice && k != reflect.Array {
154151
return fmt.Errorf("InsertStructs expects a slice or array as rowStructs, got %T", rowStructs)

impl/now.go

Lines changed: 0 additions & 15 deletions
This file was deleted.

impl/query.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package impl
33
import (
44
"context"
55
"database/sql"
6+
"time"
67

78
"github.com/domonda/go-sqldb"
89
)
@@ -28,3 +29,11 @@ func QueryRows(ctx context.Context, conn Queryer, mapper sqldb.StructFieldMapper
2829
}
2930
return NewRowsScanner(ctx, rows, mapper, query, argFmt, args)
3031
}
32+
33+
func QueryNow(conn sqldb.Connection) (now time.Time, err error) {
34+
err = conn.QueryRow(`select now()`).Scan(&now)
35+
if err != nil {
36+
return time.Time{}, err
37+
}
38+
return now, nil
39+
}

impl/update.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,48 @@
11
package impl
22

33
import (
4+
"context"
45
"fmt"
56
"reflect"
67
"strings"
78

8-
sqldb "github.com/domonda/go-sqldb"
99
"golang.org/x/exp/slices"
10+
11+
"github.com/domonda/go-sqldb"
1012
)
1113

1214
// Update table rows(s) with values using the where statement with passed in args starting at $1.
13-
func Update(conn sqldb.Connection, table string, values sqldb.Values, where, argFmt string, args []any) error {
15+
func Update(ctx context.Context, conn Execer, table string, values sqldb.Values, where, argFmt string, args []any) error {
1416
if len(values) == 0 {
1517
return fmt.Errorf("Update table %s: no values passed", table)
1618
}
1719

1820
query, vals := buildUpdateQuery(table, values, where, args)
19-
err := conn.Exec(query, vals...)
20-
return WrapNonNilErrorWithQuery(err, query, argFmt, vals)
21+
return Exec(ctx, conn, argFmt, query, vals)
2122
}
2223

2324
// UpdateReturningRow updates a table row with values using the where statement with passed in args starting at $1
2425
// and returning a single row with the columns specified in returning argument.
25-
func UpdateReturningRow(conn sqldb.Connection, table string, values sqldb.Values, returning, where string, args ...any) sqldb.RowScanner {
26+
func UpdateReturningRow(ctx context.Context, conn Queryer, mapper sqldb.StructFieldMapper, argFmt, table string, values sqldb.Values, returning, where string, args ...any) sqldb.RowScanner {
2627
if len(values) == 0 {
2728
return sqldb.RowScannerWithError(fmt.Errorf("UpdateReturningRow table %s: no values passed", table))
2829
}
2930

3031
query, vals := buildUpdateQuery(table, values, where, args)
3132
query += " RETURNING " + returning
32-
return conn.QueryRow(query, vals...)
33+
return QueryRow(ctx, conn, mapper, argFmt, query, vals)
3334
}
3435

3536
// UpdateReturningRows updates table rows with values using the where statement with passed in args starting at $1
3637
// and returning multiple rows with the columns specified in returning argument.
37-
func UpdateReturningRows(conn sqldb.Connection, table string, values sqldb.Values, returning, where string, args ...any) sqldb.RowsScanner {
38+
func UpdateReturningRows(ctx context.Context, conn Queryer, mapper sqldb.StructFieldMapper, argFmt, table string, values sqldb.Values, returning, where string, args ...any) sqldb.RowsScanner {
3839
if len(values) == 0 {
3940
return sqldb.RowsScannerWithError(fmt.Errorf("UpdateReturningRows table %s: no values passed", table))
4041
}
4142

4243
query, vals := buildUpdateQuery(table, values, where, args)
4344
query += " RETURNING " + returning
44-
return conn.QueryRows(query, vals...)
45+
return QueryRows(ctx, conn, mapper, argFmt, query, vals)
4546
}
4647

4748
func buildUpdateQuery(table string, values sqldb.Values, where string, args []any) (string, []any) {
@@ -66,7 +67,7 @@ func buildUpdateQuery(table string, values sqldb.Values, where string, args []an
6667
// Struct fields with a `db` tag matching any of the passed ignoreColumns will not be used.
6768
// If restrictToColumns are provided, then only struct fields with a `db` tag
6869
// matching any of the passed column names will be used.
69-
func UpdateStruct(conn sqldb.Connection, table string, rowStruct any, mapper sqldb.StructFieldMapper, argFmt string, ignoreColumns []sqldb.ColumnFilter) error {
70+
func UpdateStruct(ctx context.Context, conn Execer, table string, rowStruct any, mapper sqldb.StructFieldMapper, argFmt string, ignoreColumns []sqldb.ColumnFilter) error {
7071
v := reflect.ValueOf(rowStruct)
7172
for v.Kind() == reflect.Ptr && !v.IsNil() {
7273
v = v.Elem()
@@ -108,7 +109,7 @@ func UpdateStruct(conn sqldb.Connection, table string, rowStruct any, mapper sql
108109

109110
query := b.String()
110111

111-
err := conn.Exec(query, vals...)
112+
_, err := conn.ExecContext(ctx, query, vals...)
112113

113114
return WrapNonNilErrorWithQuery(err, query, argFmt, vals)
114115
}

impl/upsert.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package impl
22

33
import (
4+
"context"
45
"fmt"
56
"reflect"
67
"strings"
@@ -15,7 +16,7 @@ import (
1516
// If restrictToColumns are provided, then only struct fields with a `db` tag
1617
// matching any of the passed column names will be used.
1718
// If inserting conflicts on pkColumn, then an update of the existing row is performed.
18-
func UpsertStruct(conn sqldb.Connection, table string, rowStruct any, mapper sqldb.StructFieldMapper, argFmt string, ignoreColumns []sqldb.ColumnFilter) error {
19+
func UpsertStruct(ctx context.Context, conn Execer, table string, rowStruct any, mapper sqldb.StructFieldMapper, argFmt string, ignoreColumns []sqldb.ColumnFilter) error {
1920
v := reflect.ValueOf(rowStruct)
2021
for v.Kind() == reflect.Ptr && !v.IsNil() {
2122
v = v.Elem()
@@ -57,7 +58,7 @@ func UpsertStruct(conn sqldb.Connection, table string, rowStruct any, mapper sql
5758
}
5859
query := b.String()
5960

60-
err := conn.Exec(query, vals...)
61+
_, err := conn.ExecContext(ctx, query, vals...)
6162

6263
return WrapNonNilErrorWithQuery(err, query, argFmt, vals)
6364
}

0 commit comments

Comments
 (0)