Skip to content

Commit 659d466

Browse files
authored
Merge pull request #352 from MatthewDolan/dolan-2017-08-30-add-context
Add new Context parameter
2 parents 2ae7d17 + fe96e85 commit 659d466

12 files changed

Lines changed: 312 additions & 43 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ _obj
77
6.out
88
gorptest.bin
99
tmp
10+
.idea
11+
coverage.out

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
language: go
22
go:
3-
- 1.6
43
- 1.7
4+
- 1.8
5+
- 1.9
56
- tip
67

78
matrix:

db.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ package gorp
1313

1414
import (
1515
"bytes"
16+
"context"
1617
"database/sql"
1718
"database/sql/driver"
1819
"errors"
@@ -33,6 +34,8 @@ import (
3334
// dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
3435
//
3536
type DbMap struct {
37+
ctx context.Context
38+
3639
// Db handle to use with this map
3740
Db *sql.DB
3841

@@ -69,8 +72,14 @@ func (m *DbMap) dynamicTableMap() map[string]*TableMap {
6972
return m.tablesDynamic
7073
}
7174

72-
func (m *DbMap) CreateIndex() error {
75+
func (m *DbMap) WithContext(ctx context.Context) SqlExecutor {
76+
copy := &DbMap{}
77+
*copy = *m
78+
copy.ctx = ctx
79+
return copy
80+
}
7381

82+
func (m *DbMap) CreateIndex() error {
7483
var err error
7584
dialect := reflect.TypeOf(m.Dialect)
7685
for _, table := range m.tables {
@@ -602,7 +611,7 @@ func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) {
602611
now := time.Now()
603612
defer m.trace(now, query, args...)
604613
}
605-
return exec(m, query, args...)
614+
return maybeExpandNamedQueryAndExec(m, query, args...)
606615
}
607616

608617
// SelectInt is a convenience wrapper around the gorp.SelectInt function
@@ -646,11 +655,15 @@ func (m *DbMap) Begin() (*Transaction, error) {
646655
now := time.Now()
647656
defer m.trace(now, "begin;")
648657
}
649-
tx, err := m.Db.Begin()
658+
tx, err := begin(m)
650659
if err != nil {
651660
return nil, err
652661
}
653-
return &Transaction{m, tx, false}, nil
662+
return &Transaction{
663+
dbmap: m,
664+
tx: tx,
665+
closed: false,
666+
}, nil
654667
}
655668

656669
// TableFor returns the *TableMap corresponding to the given Go Type
@@ -698,7 +711,7 @@ func (m *DbMap) Prepare(query string) (*sql.Stmt, error) {
698711
now := time.Now()
699712
defer m.trace(now, query, nil)
700713
}
701-
return m.Db.Prepare(query)
714+
return prepare(m, query)
702715
}
703716

704717
func tableOrNil(m *DbMap, t reflect.Type, name string) *TableMap {
@@ -751,15 +764,15 @@ func (m *DbMap) QueryRow(query string, args ...interface{}) *sql.Row {
751764
now := time.Now()
752765
defer m.trace(now, query, args...)
753766
}
754-
return m.Db.QueryRow(query, args...)
767+
return queryRow(m, query, args...)
755768
}
756769

757-
func (m *DbMap) Query(query string, args ...interface{}) (*sql.Rows, error) {
770+
func (m *DbMap) Query(q string, args ...interface{}) (*sql.Rows, error) {
758771
if m.logger != nil {
759772
now := time.Now()
760-
defer m.trace(now, query, args...)
773+
defer m.trace(now, q, args...)
761774
}
762-
return m.Db.Query(query, args...)
775+
return query(m, q, args...)
763776
}
764777

765778
func (m *DbMap) trace(started time.Time, query string, args ...interface{}) {

dialect.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111

1212
package gorp
1313

14-
import "reflect"
14+
import (
15+
"reflect"
16+
)
1517

1618
// The Dialect interface encapsulates behaviors that differ across
1719
// SQL databases. At present the Dialect is only used by CreateTables()
1820
// but this could change in the future
1921
type Dialect interface {
20-
2122
// adds a suffix to any query, usually ";"
2223
QuerySuffix() string
2324

@@ -67,7 +68,7 @@ type Dialect interface {
6768
// table - The table name
6869
QuotedTableForQuery(schema string, table string) string
6970

70-
// Existance clause for table creation / deletion
71+
// Existence clause for table creation / deletion
7172
IfSchemaNotExists(command, schema string) string
7273
IfTableExists(command, schema, table string) string
7374
IfTableNotExists(command, schema, table string) string

dialect_mysql.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"fmt"
1616
"reflect"
1717
"strings"
18+
"time"
1819
)
1920

2021
// Implementation of Dialect for MySQL databases.
@@ -125,18 +126,22 @@ func (d MySQLDialect) CreateTableSuffix() string {
125126
return fmt.Sprintf(" engine=%s charset=%s", d.Engine, d.Encoding)
126127
}
127128

128-
func (m MySQLDialect) CreateIndexSuffix() string {
129+
func (d MySQLDialect) CreateIndexSuffix() string {
129130
return "using"
130131
}
131132

132-
func (m MySQLDialect) DropIndexSuffix() string {
133+
func (d MySQLDialect) DropIndexSuffix() string {
133134
return "on"
134135
}
135136

136-
func (m MySQLDialect) TruncateClause() string {
137+
func (d MySQLDialect) TruncateClause() string {
137138
return "truncate"
138139
}
139140

141+
func (d MySQLDialect) SleepClause(s time.Duration) string {
142+
return fmt.Sprintf("sleep(%f)", s.Seconds())
143+
}
144+
140145
// Returns "?"
141146
func (d MySQLDialect) BindVar(i int) string {
142147
return "?"

dialect_mysql_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ var _ = Describe("MySQLDialect", func() {
138138
})
139139
})
140140

141+
Describe("SleepClause", func() {
142+
It("returns the clause for sleeping", func() {
143+
Expect(dialect.SleepClause(1 * time.Second)).To(Equal("sleep(1.000000)"))
144+
Expect(dialect.SleepClause(100 * time.Millisecond)).To(Equal("sleep(0.100000)"))
145+
})
146+
})
147+
141148
Describe("BindVar", func() {
142149
It("returns the variable binding sequence", func() {
143150
Expect(dialect.BindVar(0)).To(Equal("?"))

dialect_postgres.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"fmt"
1616
"reflect"
1717
"strings"
18+
"time"
1819
)
1920

2021
type PostgresDialect struct {
@@ -98,6 +99,10 @@ func (d PostgresDialect) TruncateClause() string {
9899
return "truncate"
99100
}
100101

102+
func (d PostgresDialect) SleepClause(s time.Duration) string {
103+
return fmt.Sprintf("pg_sleep(%f)", s.Seconds())
104+
}
105+
101106
// Returns "$(i+1)"
102107
func (d PostgresDialect) BindVar(i int) string {
103108
return fmt.Sprintf("$%d", i+1)

gorp.go

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package gorp
1313

1414
import (
15+
"context"
1516
"database/sql"
1617
"database/sql/driver"
1718
"fmt"
@@ -83,26 +84,20 @@ type TypeConverter interface {
8384
FromDb(target interface{}) (CustomScanner, bool)
8485
}
8586

86-
// Executor exposes the sql.DB and sql.Tx Exec function so that it can be used
87-
// on internal functions that convert named parameters for the Exec function.
88-
type executor interface {
89-
Exec(query string, args ...interface{}) (sql.Result, error)
90-
}
91-
9287
// SqlExecutor exposes gorp operations that can be run from Pre/Post
9388
// hooks. This hides whether the current operation that triggered the
9489
// hook is in a transaction.
9590
//
9691
// See the DbMap function docs for each of the functions below for more
9792
// information.
9893
type SqlExecutor interface {
94+
WithContext(ctx context.Context) SqlExecutor
9995
Get(i interface{}, keys ...interface{}) (interface{}, error)
10096
Insert(list ...interface{}) error
10197
Update(list ...interface{}) (int64, error)
10298
Delete(list ...interface{}) (int64, error)
10399
Exec(query string, args ...interface{}) (sql.Result, error)
104-
Select(i interface{}, query string,
105-
args ...interface{}) ([]interface{}, error)
100+
Select(i interface{}, query string, args ...interface{}) ([]interface{}, error)
106101
SelectInt(query string, args ...interface{}) (int64, error)
107102
SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error)
108103
SelectFloat(query string, args ...interface{}) (float64, error)
@@ -152,23 +147,34 @@ func argsString(args ...interface{}) string {
152147

153148
// Calls the Exec function on the executor, but attempts to expand any eligible named
154149
// query arguments first.
155-
func exec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
156-
var dbMap *DbMap
157-
var executor executor
150+
func maybeExpandNamedQueryAndExec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
151+
dbMap := extractDbMap(e)
152+
153+
if len(args) == 1 {
154+
query, args = maybeExpandNamedQuery(dbMap, query, args)
155+
}
156+
157+
return exec(e, query, args...)
158+
}
159+
160+
func extractDbMap(e SqlExecutor) *DbMap {
158161
switch m := e.(type) {
159162
case *DbMap:
160-
executor = m.Db
161-
dbMap = m
163+
return m
162164
case *Transaction:
163-
executor = m.tx
164-
dbMap = m.dbmap
165+
return m.dbmap
165166
}
167+
return nil
168+
}
166169

167-
if len(args) == 1 {
168-
query, args = maybeExpandNamedQuery(dbMap, query, args)
170+
func extractExecutorAndContext(e SqlExecutor) (executor, context.Context) {
171+
switch m := e.(type) {
172+
case *DbMap:
173+
return m.Db, m.ctx
174+
case *Transaction:
175+
return m.tx, m.ctx
169176
}
170-
171-
return executor.Exec(query, args...)
177+
return nil, nil
172178
}
173179

174180
// maybeExpandNamedQuery checks the given arg to see if it's eligible to be used

gorp_go17.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2012 James Cooper. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package gorp provides a simple way to marshal Go structs to and from
6+
// SQL databases. It uses the database/sql package, and should work with any
7+
// compliant database/sql driver.
8+
//
9+
// Source code and project home:
10+
// https://github.com/go-gorp/gorp
11+
//
12+
13+
// +build !go1.8
14+
15+
package gorp
16+
17+
import "database/sql"
18+
19+
// Executor exposes the sql.DB and sql.Tx functions so that it can be used
20+
// on internal functions that need to be agnostic to the underlying object.
21+
type executor interface {
22+
Exec(query string, args ...interface{}) (sql.Result, error)
23+
Prepare(query string) (*sql.Stmt, error)
24+
QueryRow(query string, args ...interface{}) *sql.Row
25+
Query(query string, args ...interface{}) (*sql.Rows, error)
26+
}
27+
28+
func exec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
29+
executor, _ := extractExecutorAndContext(e)
30+
31+
return executor.Exec(query, args...)
32+
}
33+
34+
func prepare(e SqlExecutor, query string) (*sql.Stmt, error) {
35+
executor, _ := extractExecutorAndContext(e)
36+
37+
return executor.Prepare(query)
38+
}
39+
40+
func queryRow(e SqlExecutor, query string, args ...interface{}) *sql.Row {
41+
executor, _ := extractExecutorAndContext(e)
42+
43+
return executor.QueryRow(query, args...)
44+
}
45+
46+
func query(e SqlExecutor, query string, args ...interface{}) (*sql.Rows, error) {
47+
executor, _ := extractExecutorAndContext(e)
48+
49+
return executor.Query(query, args...)
50+
}
51+
52+
func begin(m *DbMap) (*sql.Tx, error) {
53+
return m.Db.Begin()
54+
}

0 commit comments

Comments
 (0)