Skip to content

Commit

Permalink
Add new Context parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewDolan committed Sep 17, 2017
1 parent 2ae7d17 commit fe96e85
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 43 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -7,3 +7,5 @@ _obj
6.out
gorptest.bin
tmp
.idea
coverage.out
3 changes: 2 additions & 1 deletion .travis.yml
@@ -1,7 +1,8 @@
language: go
go:
- 1.6
- 1.7
- 1.8
- 1.9
- tip

matrix:
Expand Down
31 changes: 22 additions & 9 deletions db.go
Expand Up @@ -13,6 +13,7 @@ package gorp

import (
"bytes"
"context"
"database/sql"
"database/sql/driver"
"errors"
Expand All @@ -33,6 +34,8 @@ import (
// dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
//
type DbMap struct {
ctx context.Context

// Db handle to use with this map
Db *sql.DB

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

func (m *DbMap) CreateIndex() error {
func (m *DbMap) WithContext(ctx context.Context) SqlExecutor {
copy := &DbMap{}
*copy = *m
copy.ctx = ctx
return copy
}

func (m *DbMap) CreateIndex() error {
var err error
dialect := reflect.TypeOf(m.Dialect)
for _, table := range m.tables {
Expand Down Expand Up @@ -602,7 +611,7 @@ func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) {
now := time.Now()
defer m.trace(now, query, args...)
}
return exec(m, query, args...)
return maybeExpandNamedQueryAndExec(m, query, args...)
}

// SelectInt is a convenience wrapper around the gorp.SelectInt function
Expand Down Expand Up @@ -646,11 +655,15 @@ func (m *DbMap) Begin() (*Transaction, error) {
now := time.Now()
defer m.trace(now, "begin;")
}
tx, err := m.Db.Begin()
tx, err := begin(m)
if err != nil {
return nil, err
}
return &Transaction{m, tx, false}, nil
return &Transaction{
dbmap: m,
tx: tx,
closed: false,
}, nil
}

// TableFor returns the *TableMap corresponding to the given Go Type
Expand Down Expand Up @@ -698,7 +711,7 @@ func (m *DbMap) Prepare(query string) (*sql.Stmt, error) {
now := time.Now()
defer m.trace(now, query, nil)
}
return m.Db.Prepare(query)
return prepare(m, query)
}

func tableOrNil(m *DbMap, t reflect.Type, name string) *TableMap {
Expand Down Expand Up @@ -751,15 +764,15 @@ func (m *DbMap) QueryRow(query string, args ...interface{}) *sql.Row {
now := time.Now()
defer m.trace(now, query, args...)
}
return m.Db.QueryRow(query, args...)
return queryRow(m, query, args...)
}

func (m *DbMap) Query(query string, args ...interface{}) (*sql.Rows, error) {
func (m *DbMap) Query(q string, args ...interface{}) (*sql.Rows, error) {
if m.logger != nil {
now := time.Now()
defer m.trace(now, query, args...)
defer m.trace(now, q, args...)
}
return m.Db.Query(query, args...)
return query(m, q, args...)
}

func (m *DbMap) trace(started time.Time, query string, args ...interface{}) {
Expand Down
7 changes: 4 additions & 3 deletions dialect.go
Expand Up @@ -11,13 +11,14 @@

package gorp

import "reflect"
import (
"reflect"
)

// The Dialect interface encapsulates behaviors that differ across
// SQL databases. At present the Dialect is only used by CreateTables()
// but this could change in the future
type Dialect interface {

// adds a suffix to any query, usually ";"
QuerySuffix() string

Expand Down Expand Up @@ -67,7 +68,7 @@ type Dialect interface {
// table - The table name
QuotedTableForQuery(schema string, table string) string

// Existance clause for table creation / deletion
// Existence clause for table creation / deletion
IfSchemaNotExists(command, schema string) string
IfTableExists(command, schema, table string) string
IfTableNotExists(command, schema, table string) string
Expand Down
11 changes: 8 additions & 3 deletions dialect_mysql.go
Expand Up @@ -15,6 +15,7 @@ import (
"fmt"
"reflect"
"strings"
"time"
)

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

func (m MySQLDialect) CreateIndexSuffix() string {
func (d MySQLDialect) CreateIndexSuffix() string {
return "using"
}

func (m MySQLDialect) DropIndexSuffix() string {
func (d MySQLDialect) DropIndexSuffix() string {
return "on"
}

func (m MySQLDialect) TruncateClause() string {
func (d MySQLDialect) TruncateClause() string {
return "truncate"
}

func (d MySQLDialect) SleepClause(s time.Duration) string {
return fmt.Sprintf("sleep(%f)", s.Seconds())
}

// Returns "?"
func (d MySQLDialect) BindVar(i int) string {
return "?"
Expand Down
7 changes: 7 additions & 0 deletions dialect_mysql_test.go
Expand Up @@ -138,6 +138,13 @@ var _ = Describe("MySQLDialect", func() {
})
})

Describe("SleepClause", func() {
It("returns the clause for sleeping", func() {
Expect(dialect.SleepClause(1 * time.Second)).To(Equal("sleep(1.000000)"))
Expect(dialect.SleepClause(100 * time.Millisecond)).To(Equal("sleep(0.100000)"))
})
})

Describe("BindVar", func() {
It("returns the variable binding sequence", func() {
Expect(dialect.BindVar(0)).To(Equal("?"))
Expand Down
5 changes: 5 additions & 0 deletions dialect_postgres.go
Expand Up @@ -15,6 +15,7 @@ import (
"fmt"
"reflect"
"strings"
"time"
)

type PostgresDialect struct {
Expand Down Expand Up @@ -98,6 +99,10 @@ func (d PostgresDialect) TruncateClause() string {
return "truncate"
}

func (d PostgresDialect) SleepClause(s time.Duration) string {
return fmt.Sprintf("pg_sleep(%f)", s.Seconds())
}

// Returns "$(i+1)"
func (d PostgresDialect) BindVar(i int) string {
return fmt.Sprintf("$%d", i+1)
Expand Down
44 changes: 25 additions & 19 deletions gorp.go
Expand Up @@ -12,6 +12,7 @@
package gorp

import (
"context"
"database/sql"
"database/sql/driver"
"fmt"
Expand Down Expand Up @@ -83,26 +84,20 @@ type TypeConverter interface {
FromDb(target interface{}) (CustomScanner, bool)
}

// Executor exposes the sql.DB and sql.Tx Exec function so that it can be used
// on internal functions that convert named parameters for the Exec function.
type executor interface {
Exec(query string, args ...interface{}) (sql.Result, error)
}

// SqlExecutor exposes gorp operations that can be run from Pre/Post
// hooks. This hides whether the current operation that triggered the
// hook is in a transaction.
//
// See the DbMap function docs for each of the functions below for more
// information.
type SqlExecutor interface {
WithContext(ctx context.Context) SqlExecutor
Get(i interface{}, keys ...interface{}) (interface{}, error)
Insert(list ...interface{}) error
Update(list ...interface{}) (int64, error)
Delete(list ...interface{}) (int64, error)
Exec(query string, args ...interface{}) (sql.Result, error)
Select(i interface{}, query string,
args ...interface{}) ([]interface{}, error)
Select(i interface{}, query string, args ...interface{}) ([]interface{}, error)
SelectInt(query string, args ...interface{}) (int64, error)
SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error)
SelectFloat(query string, args ...interface{}) (float64, error)
Expand Down Expand Up @@ -152,23 +147,34 @@ func argsString(args ...interface{}) string {

// Calls the Exec function on the executor, but attempts to expand any eligible named
// query arguments first.
func exec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
var dbMap *DbMap
var executor executor
func maybeExpandNamedQueryAndExec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
dbMap := extractDbMap(e)

if len(args) == 1 {
query, args = maybeExpandNamedQuery(dbMap, query, args)
}

return exec(e, query, args...)
}

func extractDbMap(e SqlExecutor) *DbMap {
switch m := e.(type) {
case *DbMap:
executor = m.Db
dbMap = m
return m
case *Transaction:
executor = m.tx
dbMap = m.dbmap
return m.dbmap
}
return nil
}

if len(args) == 1 {
query, args = maybeExpandNamedQuery(dbMap, query, args)
func extractExecutorAndContext(e SqlExecutor) (executor, context.Context) {
switch m := e.(type) {
case *DbMap:
return m.Db, m.ctx
case *Transaction:
return m.tx, m.ctx
}

return executor.Exec(query, args...)
return nil, nil
}

// maybeExpandNamedQuery checks the given arg to see if it's eligible to be used
Expand Down
54 changes: 54 additions & 0 deletions gorp_go17.go
@@ -0,0 +1,54 @@
// Copyright 2012 James Cooper. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Package gorp provides a simple way to marshal Go structs to and from
// SQL databases. It uses the database/sql package, and should work with any
// compliant database/sql driver.
//
// Source code and project home:
// https://github.com/go-gorp/gorp
//

// +build !go1.8

package gorp

import "database/sql"

// Executor exposes the sql.DB and sql.Tx functions so that it can be used
// on internal functions that need to be agnostic to the underlying object.
type executor interface {
Exec(query string, args ...interface{}) (sql.Result, error)
Prepare(query string) (*sql.Stmt, error)
QueryRow(query string, args ...interface{}) *sql.Row
Query(query string, args ...interface{}) (*sql.Rows, error)
}

func exec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
executor, _ := extractExecutorAndContext(e)

return executor.Exec(query, args...)
}

func prepare(e SqlExecutor, query string) (*sql.Stmt, error) {
executor, _ := extractExecutorAndContext(e)

return executor.Prepare(query)
}

func queryRow(e SqlExecutor, query string, args ...interface{}) *sql.Row {
executor, _ := extractExecutorAndContext(e)

return executor.QueryRow(query, args...)
}

func query(e SqlExecutor, query string, args ...interface{}) (*sql.Rows, error) {
executor, _ := extractExecutorAndContext(e)

return executor.Query(query, args...)
}

func begin(m *DbMap) (*sql.Tx, error) {
return m.Db.Begin()
}

0 comments on commit fe96e85

Please sign in to comment.