Skip to content

Commit 5b8562f

Browse files
committed
Update Context support
- Preserve backward compatibility in interfaces - Support all statement builders - Support PrepareContext in stmtCacher - Update Travis config
1 parent df374c1 commit 5b8562f

19 files changed

+545
-115
lines changed

.travis.yml

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
language: go
22

33
go:
4-
- 1.1
5-
- 1.2
6-
- 1.3
7-
- 1.4
8-
- 1.5
4+
- 1.7
5+
- 1.8
96
- tip
107

118
# Setting sudo access to false will let Travis CI use containers rather than

delete_ctx.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// +build go1.8
2+
3+
package squirrel
4+
5+
import (
6+
"context"
7+
"database/sql"
8+
9+
"github.com/lann/builder"
10+
)
11+
12+
func (d *deleteData) ExecContext(ctx context.Context) (sql.Result, error) {
13+
if d.RunWith == nil {
14+
return nil, RunnerNotSet
15+
}
16+
ctxRunner, ok := d.RunWith.(ExecerContext)
17+
if !ok {
18+
return nil, NoContextSupport
19+
}
20+
return ExecContextWith(ctx, ctxRunner, d)
21+
}
22+
23+
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
24+
func (b DeleteBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
25+
data := builder.GetStruct(b).(deleteData)
26+
return data.ExecContext(ctx)
27+
}

delete_ctx_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// +build go1.8
2+
3+
package squirrel
4+
5+
import (
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestDeleteBuilderContextRunners(t *testing.T) {
12+
db := &DBStub{}
13+
b := Delete("test").Where("x = ?", 1).RunWith(db)
14+
15+
expectedSql := "DELETE FROM test WHERE x = ?"
16+
17+
b.ExecContext(ctx)
18+
assert.Equal(t, expectedSql, db.LastExecSql)
19+
}
20+
21+
func TestDeleteBuilderContextNoRunner(t *testing.T) {
22+
b := Delete("test")
23+
24+
_, err := b.ExecContext(ctx)
25+
assert.Equal(t, RunnerNotSet, err)
26+
}

insert_ctx.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// +build go1.8
2+
3+
package squirrel
4+
5+
import (
6+
"context"
7+
"database/sql"
8+
9+
"github.com/lann/builder"
10+
)
11+
12+
func (d *insertData) ExecContext(ctx context.Context) (sql.Result, error) {
13+
if d.RunWith == nil {
14+
return nil, RunnerNotSet
15+
}
16+
ctxRunner, ok := d.RunWith.(ExecerContext)
17+
if !ok {
18+
return nil, NoContextSupport
19+
}
20+
return ExecContextWith(ctx, ctxRunner, d)
21+
}
22+
23+
func (d *insertData) QueryContext(ctx context.Context) (*sql.Rows, error) {
24+
if d.RunWith == nil {
25+
return nil, RunnerNotSet
26+
}
27+
ctxRunner, ok := d.RunWith.(QueryerContext)
28+
if !ok {
29+
return nil, NoContextSupport
30+
}
31+
return QueryContextWith(ctx, ctxRunner, d)
32+
}
33+
34+
func (d *insertData) QueryRowContext(ctx context.Context) RowScanner {
35+
if d.RunWith == nil {
36+
return &Row{err: RunnerNotSet}
37+
}
38+
queryRower, ok := d.RunWith.(QueryRowerContext)
39+
if !ok {
40+
if _, ok := d.RunWith.(QueryerContext); !ok {
41+
return &Row{err: RunnerNotQueryRunner}
42+
}
43+
return &Row{err: NoContextSupport}
44+
}
45+
return QueryRowContextWith(ctx, queryRower, d)
46+
}
47+
48+
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
49+
func (b InsertBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
50+
data := builder.GetStruct(b).(insertData)
51+
return data.ExecContext(ctx)
52+
}
53+
54+
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
55+
func (b InsertBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
56+
data := builder.GetStruct(b).(insertData)
57+
return data.QueryContext(ctx)
58+
}
59+
60+
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
61+
func (b InsertBuilder) QueryRowContext(ctx context.Context) RowScanner {
62+
data := builder.GetStruct(b).(insertData)
63+
return data.QueryRowContext(ctx)
64+
}
65+
66+
// ScanContext is a shortcut for QueryRowContext().Scan.
67+
func (b InsertBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
68+
return b.QueryRowContext(ctx).Scan(dest...)
69+
}

insert_ctx_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// +build go1.8
2+
3+
package squirrel
4+
5+
import (
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestInsertBuilderContextRunners(t *testing.T) {
12+
db := &DBStub{}
13+
b := Insert("test").Values(1).RunWith(db)
14+
15+
expectedSql := "INSERT INTO test VALUES (?)"
16+
17+
b.ExecContext(ctx)
18+
assert.Equal(t, expectedSql, db.LastExecSql)
19+
20+
b.QueryContext(ctx)
21+
assert.Equal(t, expectedSql, db.LastQuerySql)
22+
23+
b.QueryRowContext(ctx)
24+
assert.Equal(t, expectedSql, db.LastQueryRowSql)
25+
26+
err := b.ScanContext(ctx)
27+
assert.NoError(t, err)
28+
}
29+
30+
func TestInsertBuilderContextNoRunner(t *testing.T) {
31+
b := Insert("test").Values(1)
32+
33+
_, err := b.ExecContext(ctx)
34+
assert.Equal(t, RunnerNotSet, err)
35+
36+
_, err = b.QueryContext(ctx)
37+
assert.Equal(t, RunnerNotSet, err)
38+
39+
err = b.ScanContext(ctx)
40+
assert.Equal(t, RunnerNotSet, err)
41+
}
42+

select_go18.go renamed to select_ctx.go

+20-4
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,34 @@ func (d *selectData) ExecContext(ctx context.Context) (sql.Result, error) {
1313
if d.RunWith == nil {
1414
return nil, RunnerNotSet
1515
}
16-
return ExecContextWith(ctx, d.RunWith, d)
16+
ctxRunner, ok := d.RunWith.(ExecerContext)
17+
if !ok {
18+
return nil, NoContextSupport
19+
}
20+
return ExecContextWith(ctx, ctxRunner, d)
1721
}
1822

1923
func (d *selectData) QueryContext(ctx context.Context) (*sql.Rows, error) {
2024
if d.RunWith == nil {
2125
return nil, RunnerNotSet
2226
}
23-
return QueryContextWith(ctx, d.RunWith, d)
27+
ctxRunner, ok := d.RunWith.(QueryerContext)
28+
if !ok {
29+
return nil, NoContextSupport
30+
}
31+
return QueryContextWith(ctx, ctxRunner, d)
2432
}
2533

2634
func (d *selectData) QueryRowContext(ctx context.Context) RowScanner {
2735
if d.RunWith == nil {
2836
return &Row{err: RunnerNotSet}
2937
}
30-
queryRower, ok := d.RunWith.(QueryRower)
38+
queryRower, ok := d.RunWith.(QueryRowerContext)
3139
if !ok {
32-
return &Row{err: RunnerNotQueryRunner}
40+
if _, ok := d.RunWith.(QueryerContext); !ok {
41+
return &Row{err: RunnerNotQueryRunner}
42+
}
43+
return &Row{err: NoContextSupport}
3344
}
3445
return QueryRowContextWith(ctx, queryRower, d)
3546
}
@@ -51,3 +62,8 @@ func (b SelectBuilder) QueryRowContext(ctx context.Context) RowScanner {
5162
data := builder.GetStruct(b).(selectData)
5263
return data.QueryRowContext(ctx)
5364
}
65+
66+
// ScanContext is a shortcut for QueryRowContext().Scan.
67+
func (b SelectBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
68+
return b.QueryRowContext(ctx).Scan(dest...)
69+
}

select_ctx_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// +build go1.8
2+
3+
package squirrel
4+
5+
import (
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestSelectBuilderContextRunners(t *testing.T) {
12+
db := &DBStub{}
13+
b := Select("test").RunWith(db)
14+
15+
expectedSql := "SELECT test"
16+
17+
b.ExecContext(ctx)
18+
assert.Equal(t, expectedSql, db.LastExecSql)
19+
20+
b.QueryContext(ctx)
21+
assert.Equal(t, expectedSql, db.LastQuerySql)
22+
23+
b.QueryRowContext(ctx)
24+
assert.Equal(t, expectedSql, db.LastQueryRowSql)
25+
26+
err := b.ScanContext(ctx)
27+
assert.NoError(t, err)
28+
}
29+
30+
func TestSelectBuilderContextNoRunner(t *testing.T) {
31+
b := Select("test")
32+
33+
_, err := b.ExecContext(ctx)
34+
assert.Equal(t, RunnerNotSet, err)
35+
36+
_, err = b.QueryContext(ctx)
37+
assert.Equal(t, RunnerNotSet, err)
38+
39+
err = b.ScanContext(ctx)
40+
assert.Equal(t, RunnerNotSet, err)
41+
}
42+

squirrel.go

+21
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ type Sqlizer interface {
2020
ToSql() (string, []interface{}, error)
2121
}
2222

23+
// Execer is the interface that wraps the Exec method.
24+
//
25+
// Exec executes the given query as implemented by database/sql.Exec.
26+
type Execer interface {
27+
Exec(query string, args ...interface{}) (sql.Result, error)
28+
}
29+
30+
// Queryer is the interface that wraps the Query method.
31+
//
32+
// Query executes the given query as implemented by database/sql.Query.
33+
type Queryer interface {
34+
Query(query string, args ...interface{}) (*sql.Rows, error)
35+
}
36+
37+
// QueryRower is the interface that wraps the QueryRow method.
38+
//
39+
// QueryRow executes the given query as implemented by database/sql.QueryRow.
40+
type QueryRower interface {
41+
QueryRow(query string, args ...interface{}) RowScanner
42+
}
43+
2344
// BaseRunner groups the Execer and Queryer interfaces.
2445
type BaseRunner interface {
2546
Execer

squirrel_go18.go renamed to squirrel_ctx.go

+16-15
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,30 @@ package squirrel
55
import (
66
"context"
77
"database/sql"
8+
"errors"
89
)
910

10-
// Execer is the interface that wraps the Exec method.
11+
// NoContextSupport is returned if a db doesn't support Context.
12+
var NoContextSupport = errors.New("DB does not support Context")
13+
14+
// ExecerContext is the interface that wraps the ExecContext method.
1115
//
12-
// Exec executes the given query as implemented by database/sql.Exec.
13-
type Execer interface {
14-
Exec(query string, args ...interface{}) (sql.Result, error)
16+
// Exec executes the given query as implemented by database/sql.ExecContext.
17+
type ExecerContext interface {
1518
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
1619
}
1720

18-
// Queryer is the interface that wraps the Query method.
21+
// QueryerContext is the interface that wraps the QueryContext method.
1922
//
20-
// Query executes the given query as implemented by database/sql.Query.
21-
type Queryer interface {
22-
Query(query string, args ...interface{}) (*sql.Rows, error)
23+
// QueryContext executes the given query as implemented by database/sql.QueryContext.
24+
type QueryerContext interface {
2325
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
2426
}
2527

26-
// QueryRower is the interface that wraps the QueryRow method.
28+
// QueryRowerContext is the interface that wraps the QueryRowContext method.
2729
//
28-
// QueryRow executes the given query as implemented by database/sql.QueryRow.
29-
type QueryRower interface {
30-
QueryRow(query string, args ...interface{}) RowScanner
30+
// QueryRowContext executes the given query as implemented by database/sql.QueryRowContext.
31+
type QueryRowerContext interface {
3132
QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner
3233
}
3334

@@ -40,7 +41,7 @@ func (r *txRunner) QueryRowContext(ctx context.Context, query string, args ...in
4041
}
4142

4243
// ExecContextWith ExecContexts the SQL returned by s with db.
43-
func ExecContextWith(ctx context.Context, db Execer, s Sqlizer) (res sql.Result, err error) {
44+
func ExecContextWith(ctx context.Context, db ExecerContext, s Sqlizer) (res sql.Result, err error) {
4445
query, args, err := s.ToSql()
4546
if err != nil {
4647
return
@@ -49,7 +50,7 @@ func ExecContextWith(ctx context.Context, db Execer, s Sqlizer) (res sql.Result,
4950
}
5051

5152
// QueryContextWith QueryContexts the SQL returned by s with db.
52-
func QueryContextWith(ctx context.Context, db Queryer, s Sqlizer) (rows *sql.Rows, err error) {
53+
func QueryContextWith(ctx context.Context, db QueryerContext, s Sqlizer) (rows *sql.Rows, err error) {
5354
query, args, err := s.ToSql()
5455
if err != nil {
5556
return
@@ -58,7 +59,7 @@ func QueryContextWith(ctx context.Context, db Queryer, s Sqlizer) (rows *sql.Row
5859
}
5960

6061
// QueryRowContextWith QueryRowContexts the SQL returned by s with db.
61-
func QueryRowContextWith(ctx context.Context, db QueryRower, s Sqlizer) RowScanner {
62+
func QueryRowContextWith(ctx context.Context, db QueryRowerContext, s Sqlizer) RowScanner {
6263
query, args, err := s.ToSql()
6364
return &Row{RowScanner: db.QueryRowContext(ctx, query, args...), err: err}
6465
}

0 commit comments

Comments
 (0)