diff --git a/.circleci/config.yml b/.circleci/config.yml index 825ce68..ce15f60 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ jobs: build: docker: # specify the version - - image: circleci/golang:1.8 + - image: circleci/golang:1.10 # CircleCI PostgreSQL images available at: https://hub.docker.com/r/circleci/postgres/ - image: circleci/mysql:5.7 @@ -14,7 +14,7 @@ jobs: MYSQL_ALLOW_EMPTY_PASSWORD: true MYSQL_DATABASE: core_test MYSQL_HOST: 127.0.0.1 - MYSQL_ROOT_HOST: % + MYSQL_ROOT_HOST: '%' MYSQL_USER: root # Specify service dependencies here if necessary @@ -31,7 +31,7 @@ jobs: - checkout # specify any bash command here prefixed with `run: ` - - run: mysql -u root -e "CREATE DATABASE core_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" + #- run: mysql -u root -e "CREATE DATABASE core_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - run: go get -u github.com/golang/lint/golint - run: go get -u github.com/wadey/gocovmerge - run: golint ./... diff --git a/cache.go b/cache.go index 8f9531d..dc4992d 100644 --- a/cache.go +++ b/cache.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/column.go b/column.go index 20912b7..40d8f92 100644 --- a/column.go +++ b/column.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( @@ -41,6 +45,7 @@ type Column struct { Comment string } +// NewColumn creates a new column func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column { return &Column{ Name: name, @@ -66,7 +71,7 @@ func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable } } -// generate column description string according dialect +// String generate column description string according dialect func (col *Column) String(d Dialect) string { sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " @@ -94,6 +99,7 @@ func (col *Column) String(d Dialect) string { return sql } +// StringNoPk generate column description string according dialect without primary keys func (col *Column) StringNoPk(d Dialect) string { sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " @@ -114,12 +120,13 @@ func (col *Column) StringNoPk(d Dialect) string { return sql } -// return col's filed of struct's value +// ValueOf returns column's filed of struct's value func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) { dataStruct := reflect.Indirect(reflect.ValueOf(bean)) return col.ValueOfV(&dataStruct) } +// ValueOfV returns column's filed of struct's value accept reflevt value func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) { var fieldValue reflect.Value fieldPath := strings.Split(col.FieldName, ".") diff --git a/converstion.go b/converstion.go index 18522fb..9703c36 100644 --- a/converstion.go +++ b/converstion.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core // Conversion is an interface. A type implements Conversion will according diff --git a/db.go b/db.go index 9969fa4..3e50a14 100644 --- a/db.go +++ b/db.go @@ -1,9 +1,13 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( + "context" "database/sql" "database/sql/driver" - "errors" "fmt" "reflect" "regexp" @@ -68,6 +72,7 @@ type cacheStruct struct { idx int } +// DB is a wrap of sql.DB with extra contents type DB struct { *sql.DB Mapper IMapper @@ -75,6 +80,7 @@ type DB struct { reflectCacheMutex sync.RWMutex } +// Open opens a database func Open(driverName, dataSourceName string) (*DB, error) { db, err := sql.Open(driverName, dataSourceName) if err != nil { @@ -87,6 +93,7 @@ func Open(driverName, dataSourceName string) (*DB, error) { }, nil } +// FromDB creates a DB from a sql.DB func FromDB(db *sql.DB) *DB { return &DB{ DB: db, @@ -108,8 +115,9 @@ func (db *DB) reflectNew(typ reflect.Type) reflect.Value { return cs.value.Index(cs.idx).Addr() } -func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { - rows, err := db.DB.Query(query, args...) +// QueryContext overwrites sql.DB.QueryContext +func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { + rows, err := db.DB.QueryContext(ctx, query, args...) if err != nil { if rows != nil { rows.Close() @@ -119,161 +127,69 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { return &Rows{rows, db}, nil } -func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) { - query, args, err := MapToSlice(query, mp) - if err != nil { - return nil, err - } - return db.Query(query, args...) +// Query overwrites sql.DB.Query +func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { + return db.QueryContext(context.Background(), query, args...) } -func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) { - query, args, err := StructToSlice(query, st) +func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) { + query, args, err := MapToSlice(query, mp) if err != nil { return nil, err } - return db.Query(query, args...) + return db.QueryContext(ctx, query, args...) } -func (db *DB) QueryRow(query string, args ...interface{}) *Row { - rows, err := db.Query(query, args...) - if err != nil { - return &Row{nil, err} - } - return &Row{rows, nil} -} - -func (db *DB) QueryRowMap(query string, mp interface{}) *Row { - query, args, err := MapToSlice(query, mp) - if err != nil { - return &Row{nil, err} - } - return db.QueryRow(query, args...) +func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) { + return db.QueryMapContext(context.Background(), query, mp) } -func (db *DB) QueryRowStruct(query string, st interface{}) *Row { +func (db *DB) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) { query, args, err := StructToSlice(query, st) - if err != nil { - return &Row{nil, err} - } - return db.QueryRow(query, args...) -} - -type Stmt struct { - *sql.Stmt - db *DB - names map[string]int -} - -func (db *DB) Prepare(query string) (*Stmt, error) { - names := make(map[string]int) - var i int - query = re.ReplaceAllStringFunc(query, func(src string) string { - names[src[1:]] = i - i += 1 - return "?" - }) - - stmt, err := db.DB.Prepare(query) if err != nil { return nil, err } - return &Stmt{stmt, db, names}, nil -} - -func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) { - vv := reflect.ValueOf(mp) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() - } - return s.Stmt.Exec(args...) + return db.QueryContext(ctx, query, args...) } -func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) { - vv := reflect.ValueOf(st) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().FieldByName(k).Interface() - } - return s.Stmt.Exec(args...) +func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) { + return db.QueryStructContext(context.Background(), query, st) } -func (s *Stmt) Query(args ...interface{}) (*Rows, error) { - rows, err := s.Stmt.Query(args...) +func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row { + rows, err := db.QueryContext(ctx, query, args...) if err != nil { - return nil, err + return &Row{nil, err} } - return &Rows{rows, s.db}, nil + return &Row{rows, nil} } -func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) { - vv := reflect.ValueOf(mp) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() - } - - return s.Query(args...) +func (db *DB) QueryRow(query string, args ...interface{}) *Row { + return db.QueryRowContext(context.Background(), query, args...) } -func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) { - vv := reflect.ValueOf(st) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { - return nil, errors.New("mp should be a map's pointer") - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().FieldByName(k).Interface() +func (db *DB) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row { + query, args, err := MapToSlice(query, mp) + if err != nil { + return &Row{nil, err} } - - return s.Query(args...) + return db.QueryRowContext(ctx, query, args...) } -func (s *Stmt) QueryRow(args ...interface{}) *Row { - rows, err := s.Query(args...) - return &Row{rows, err} +func (db *DB) QueryRowMap(query string, mp interface{}) *Row { + return db.QueryRowMapContext(context.Background(), query, mp) } -func (s *Stmt) QueryRowMap(mp interface{}) *Row { - vv := reflect.ValueOf(mp) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { - return &Row{nil, errors.New("mp should be a map's pointer")} - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() +func (db *DB) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row { + query, args, err := StructToSlice(query, st) + if err != nil { + return &Row{nil, err} } - - return s.QueryRow(args...) + return db.QueryRowContext(ctx, query, args...) } -func (s *Stmt) QueryRowStruct(st interface{}) *Row { - vv := reflect.ValueOf(st) - if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { - return &Row{nil, errors.New("st should be a struct's pointer")} - } - - args := make([]interface{}, len(s.names)) - for k, i := range s.names { - args[i] = vv.Elem().FieldByName(k).Interface() - } - - return s.QueryRow(args...) +func (db *DB) QueryRowStruct(query string, st interface{}) *Row { + return db.QueryRowStructContext(context.Background(), query, st) } var ( @@ -282,120 +198,26 @@ var ( // insert into (name) values (?) // insert into (name) values (?name) -func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) { - query, args, err := MapToSlice(query, mp) - if err != nil { - return nil, err - } - return db.DB.Exec(query, args...) -} - -func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) { - query, args, err := StructToSlice(query, st) - if err != nil { - return nil, err - } - return db.DB.Exec(query, args...) -} - -type EmptyScanner struct { -} - -func (EmptyScanner) Scan(src interface{}) error { - return nil -} - -type Tx struct { - *sql.Tx - db *DB -} - -func (db *DB) Begin() (*Tx, error) { - tx, err := db.DB.Begin() - if err != nil { - return nil, err - } - return &Tx{tx, db}, nil -} - -func (tx *Tx) Prepare(query string) (*Stmt, error) { - names := make(map[string]int) - var i int - query = re.ReplaceAllStringFunc(query, func(src string) string { - names[src[1:]] = i - i += 1 - return "?" - }) - - stmt, err := tx.Tx.Prepare(query) - if err != nil { - return nil, err - } - return &Stmt{stmt, tx.db, names}, nil -} - -func (tx *Tx) Stmt(stmt *Stmt) *Stmt { - // TODO: - return stmt -} - -func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) { +func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) { query, args, err := MapToSlice(query, mp) if err != nil { return nil, err } - return tx.Tx.Exec(query, args...) -} - -func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) { - query, args, err := StructToSlice(query, st) - if err != nil { - return nil, err - } - return tx.Tx.Exec(query, args...) -} - -func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { - rows, err := tx.Tx.Query(query, args...) - if err != nil { - return nil, err - } - return &Rows{rows, tx.db}, nil + return db.DB.ExecContext(ctx, query, args...) } -func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) { - query, args, err := MapToSlice(query, mp) - if err != nil { - return nil, err - } - return tx.Query(query, args...) +func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) { + return db.ExecMapContext(context.Background(), query, mp) } -func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) { +func (db *DB) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) { query, args, err := StructToSlice(query, st) if err != nil { return nil, err } - return tx.Query(query, args...) -} - -func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { - rows, err := tx.Query(query, args...) - return &Row{rows, err} -} - -func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row { - query, args, err := MapToSlice(query, mp) - if err != nil { - return &Row{nil, err} - } - return tx.QueryRow(query, args...) + return db.DB.ExecContext(ctx, query, args...) } -func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row { - query, args, err := StructToSlice(query, st) - if err != nil { - return &Row{nil, err} - } - return tx.QueryRow(query, args...) +func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) { + return db.ExecStructContext(context.Background(), query, st) } diff --git a/db_test.go b/db_test.go index 43637e8..5505bc5 100644 --- a/db_test.go +++ b/db_test.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/dialect.go b/dialect.go index c288a08..5d35a4f 100644 --- a/dialect.go +++ b/dialect.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/driver.go b/driver.go index 0f1020b..ceef4ba 100644 --- a/driver.go +++ b/driver.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core type Driver interface { diff --git a/error.go b/error.go index 640e603..63ea53e 100644 --- a/error.go +++ b/error.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import "errors" diff --git a/filter.go b/filter.go index 35b0ece..6aeed42 100644 --- a/filter.go +++ b/filter.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/ilogger.go b/ilogger.go index c8d7849..348ab88 100644 --- a/ilogger.go +++ b/ilogger.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core type LogLevel int diff --git a/index.go b/index.go index 3786f52..ac97b68 100644 --- a/index.go +++ b/index.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/mapper.go b/mapper.go index bb72a15..ec44ea0 100644 --- a/mapper.go +++ b/mapper.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/mapper_test.go b/mapper_test.go index 043087a..aa21c5c 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/pk.go b/pk.go index 1810dd9..05a7672 100644 --- a/pk.go +++ b/pk.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/pk_test.go b/pk_test.go index 7986ae4..8430f95 100644 --- a/pk_test.go +++ b/pk_test.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/rows.go b/rows.go index 580de4f..2b046d8 100644 --- a/rows.go +++ b/rows.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/scan.go b/scan.go index b7c159b..897b534 100644 --- a/scan.go +++ b/scan.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( @@ -53,3 +57,10 @@ func convertTime(dest *NullTime, src interface{}) error { } return nil } + +type EmptyScanner struct { +} + +func (EmptyScanner) Scan(src interface{}) error { + return nil +} diff --git a/stmt.go b/stmt.go new file mode 100644 index 0000000..20ee202 --- /dev/null +++ b/stmt.go @@ -0,0 +1,165 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package core + +import ( + "context" + "database/sql" + "errors" + "reflect" +) + +type Stmt struct { + *sql.Stmt + db *DB + names map[string]int +} + +func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) { + names := make(map[string]int) + var i int + query = re.ReplaceAllStringFunc(query, func(src string) string { + names[src[1:]] = i + i += 1 + return "?" + }) + + stmt, err := db.DB.PrepareContext(ctx, query) + if err != nil { + return nil, err + } + return &Stmt{stmt, db, names}, nil +} + +func (db *DB) Prepare(query string) (*Stmt, error) { + return db.PrepareContext(context.Background(), query) +} + +func (s *Stmt) ExecMapContext(ctx context.Context, mp interface{}) (sql.Result, error) { + vv := reflect.ValueOf(mp) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() + } + return s.Stmt.ExecContext(ctx, args...) +} + +func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) { + return s.ExecMapContext(context.Background(), mp) +} + +func (s *Stmt) ExecStructContext(ctx context.Context, st interface{}) (sql.Result, error) { + vv := reflect.ValueOf(st) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().FieldByName(k).Interface() + } + return s.Stmt.ExecContext(ctx, args...) +} + +func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) { + return s.ExecStructContext(context.Background(), st) +} + +func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) { + rows, err := s.Stmt.QueryContext(ctx, args...) + if err != nil { + return nil, err + } + return &Rows{rows, s.db}, nil +} + +func (s *Stmt) Query(args ...interface{}) (*Rows, error) { + return s.QueryContext(context.Background(), args...) +} + +func (s *Stmt) QueryMapContext(ctx context.Context, mp interface{}) (*Rows, error) { + vv := reflect.ValueOf(mp) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() + } + + return s.QueryContext(ctx, args...) +} + +func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) { + return s.QueryMapContext(context.Background(), mp) +} + +func (s *Stmt) QueryStructContext(ctx context.Context, st interface{}) (*Rows, error) { + vv := reflect.ValueOf(st) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { + return nil, errors.New("mp should be a map's pointer") + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().FieldByName(k).Interface() + } + + return s.Query(args...) +} + +func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) { + return s.QueryStructContext(context.Background(), st) +} + +func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row { + rows, err := s.QueryContext(ctx, args...) + return &Row{rows, err} +} + +func (s *Stmt) QueryRow(args ...interface{}) *Row { + return s.QueryRowContext(context.Background(), args...) +} + +func (s *Stmt) QueryRowMapContext(ctx context.Context, mp interface{}) *Row { + vv := reflect.ValueOf(mp) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map { + return &Row{nil, errors.New("mp should be a map's pointer")} + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface() + } + + return s.QueryRowContext(ctx, args...) +} + +func (s *Stmt) QueryRowMap(mp interface{}) *Row { + return s.QueryRowMapContext(context.Background(), mp) +} + +func (s *Stmt) QueryRowStructContext(ctx context.Context, st interface{}) *Row { + vv := reflect.ValueOf(st) + if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct { + return &Row{nil, errors.New("st should be a struct's pointer")} + } + + args := make([]interface{}, len(s.names)) + for k, i := range s.names { + args[i] = vv.Elem().FieldByName(k).Interface() + } + + return s.QueryRowContext(ctx, args...) +} + +func (s *Stmt) QueryRowStruct(st interface{}) *Row { + return s.QueryRowStructContext(context.Background(), st) +} diff --git a/table.go b/table.go index b5d0794..d129e60 100644 --- a/table.go +++ b/table.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/table_test.go b/table_test.go index efa3fac..ea31afb 100644 --- a/table_test.go +++ b/table_test.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import ( diff --git a/tx.go b/tx.go new file mode 100644 index 0000000..a56b700 --- /dev/null +++ b/tx.go @@ -0,0 +1,153 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package core + +import ( + "context" + "database/sql" +) + +type Tx struct { + *sql.Tx + db *DB +} + +func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { + tx, err := db.DB.BeginTx(ctx, opts) + if err != nil { + return nil, err + } + return &Tx{tx, db}, nil +} + +func (db *DB) Begin() (*Tx, error) { + tx, err := db.DB.Begin() + if err != nil { + return nil, err + } + return &Tx{tx, db}, nil +} + +func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) { + names := make(map[string]int) + var i int + query = re.ReplaceAllStringFunc(query, func(src string) string { + names[src[1:]] = i + i += 1 + return "?" + }) + + stmt, err := tx.Tx.PrepareContext(ctx, query) + if err != nil { + return nil, err + } + return &Stmt{stmt, tx.db, names}, nil +} + +func (tx *Tx) Prepare(query string) (*Stmt, error) { + return tx.PrepareContext(context.Background(), query) +} + +func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt { + stmt.Stmt = tx.Tx.StmtContext(ctx, stmt.Stmt) + return stmt +} + +func (tx *Tx) Stmt(stmt *Stmt) *Stmt { + return tx.StmtContext(context.Background(), stmt) +} + +func (tx *Tx) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) { + query, args, err := MapToSlice(query, mp) + if err != nil { + return nil, err + } + return tx.Tx.ExecContext(ctx, query, args...) +} + +func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) { + return tx.ExecMapContext(context.Background(), query, mp) +} + +func (tx *Tx) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) { + query, args, err := StructToSlice(query, st) + if err != nil { + return nil, err + } + return tx.Tx.ExecContext(ctx, query, args...) +} + +func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) { + return tx.ExecStructContext(context.Background(), query, st) +} + +func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { + rows, err := tx.Tx.QueryContext(ctx, query, args...) + if err != nil { + return nil, err + } + return &Rows{rows, tx.db}, nil +} + +func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { + return tx.QueryContext(context.Background(), query, args...) +} + +func (tx *Tx) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) { + query, args, err := MapToSlice(query, mp) + if err != nil { + return nil, err + } + return tx.QueryContext(ctx, query, args...) +} + +func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) { + return tx.QueryMapContext(context.Background(), query, mp) +} + +func (tx *Tx) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) { + query, args, err := StructToSlice(query, st) + if err != nil { + return nil, err + } + return tx.QueryContext(ctx, query, args...) +} + +func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) { + return tx.QueryStructContext(context.Background(), query, st) +} + +func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row { + rows, err := tx.QueryContext(ctx, query, args...) + return &Row{rows, err} +} + +func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { + return tx.QueryRowContext(context.Background(), query, args...) +} + +func (tx *Tx) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row { + query, args, err := MapToSlice(query, mp) + if err != nil { + return &Row{nil, err} + } + return tx.QueryRowContext(ctx, query, args...) +} + +func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row { + return tx.QueryRowMapContext(context.Background(), query, mp) +} + +func (tx *Tx) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row { + query, args, err := StructToSlice(query, st) + if err != nil { + return &Row{nil, err} + } + return tx.QueryRowContext(ctx, query, args...) +} + +func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row { + return tx.QueryRowStructContext(context.Background(), query, st) +} diff --git a/type.go b/type.go index 5cbf930..81dc191 100644 --- a/type.go +++ b/type.go @@ -1,3 +1,7 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package core import (