diff --git a/.travis.yml b/.travis.yml index e9fe2128..1011bfcd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ services: go_import_path: gopkg.in/doug-martin/goqu.v4 env: - - GO_VERSION="1.6" - - GO_VERSION="1.7" + - GO_VERSION="1.8" + - GO_VERSION="1.9" - GO_VERSION="latest" before_install: diff --git a/crud_exec.go b/crud_exec.go index e7dfeea6..61b7a756 100644 --- a/crud_exec.go +++ b/crud_exec.go @@ -1,6 +1,7 @@ package goqu import ( + "context" "database/sql" "fmt" "reflect" @@ -33,10 +34,14 @@ func newCrudExec(database database, err error, sql string, args ...interface{}) } func (me CrudExec) Exec() (sql.Result, error) { + return me.ExecContext(context.Background()) +} + +func (me CrudExec) ExecContext(ctx context.Context) (sql.Result, error) { if me.err != nil { return nil, me.err } - return me.database.Exec(me.Sql, me.Args...) + return me.database.ExecContext(ctx, me.Sql, me.Args...) } //This will execute the SQL and append results to the slice @@ -49,6 +54,19 @@ func (me CrudExec) Exec() (sql.Result, error) { // //i: A pointer to a slice of structs. func (me CrudExec) ScanStructs(i interface{}) error { + return me.ScanStructsContext(context.Background(), i) +} + +//This will execute the SQL and append results to the slice +// var myStructs []MyStruct +// if err := From("test").ScanStructsContext(ctx, &myStructs); err != nil{ +// panic(err.Error() +// } +// //use your structs +// +// +//i: A pointer to a slice of structs. +func (me CrudExec) ScanStructsContext(ctx context.Context, i interface{}) error { if me.err != nil { return me.err } @@ -59,7 +77,7 @@ func (me CrudExec) ScanStructs(i interface{}) error { if reflect.Indirect(val).Kind() != reflect.Slice { return NewGoquError("Type must be a pointer to a slice when calling ScanStructs") } - _, err := me.scan(i, me.Sql, me.Args...) + _, err := me.scanContext(ctx, i, me.Sql, me.Args...) return err } @@ -75,6 +93,21 @@ func (me CrudExec) ScanStructs(i interface{}) error { // //i: A pointer to a struct func (me CrudExec) ScanStruct(i interface{}) (bool, error) { + return me.ScanStructContext(context.Background(), i) +} + +//This will execute the SQL and fill out the struct with the fields returned. This method returns a boolean value that is false if no record was found +// var myStruct MyStruct +// found, err := From("test").Limit(1).ScanStructContext(ctx, &myStruct) +// if err != nil{ +// panic(err.Error() +// } +// if !found{ +// fmt.Println("NOT FOUND") +// } +// +//i: A pointer to a struct +func (me CrudExec) ScanStructContext(ctx context.Context, i interface{}) (bool, error) { if me.err != nil { return false, me.err } @@ -85,7 +118,7 @@ func (me CrudExec) ScanStruct(i interface{}) (bool, error) { if reflect.Indirect(val).Kind() != reflect.Struct { return false, NewGoquError("Type must be a pointer to a struct when calling ScanStruct") } - return me.scan(i, me.Sql, me.Args...) + return me.scanContext(ctx, i, me.Sql, me.Args...) } //This will execute the SQL and append results to the slice. @@ -96,6 +129,17 @@ func (me CrudExec) ScanStruct(i interface{}) (bool, error) { // //i: Takes a pointer to a slice of primitive values. func (me CrudExec) ScanVals(i interface{}) error { + return me.ScanValsContext(context.Background(), i) +} + +//This will execute the SQL and append results to the slice. +// var ids []uint32 +// if err := From("test").Select("id").ScanValsContext(ctx, &ids); err != nil{ +// panic(err.Error() +// } +// +//i: Takes a pointer to a slice of primitive values. +func (me CrudExec) ScanValsContext(ctx context.Context, i interface{}) error { if me.err != nil { return me.err } @@ -108,7 +152,7 @@ func (me CrudExec) ScanVals(i interface{}) error { return NewGoquError("Type must be a pointer to a slice when calling ScanVals") } t, _, isSliceOfPointers := getTypeInfo(i, val) - rows, err := me.database.Query(me.Sql, me.Args...) + rows, err := me.database.QueryContext(ctx, me.Sql, me.Args...) if err != nil { return err } @@ -128,7 +172,6 @@ func (me CrudExec) ScanVals(i interface{}) error { return err } return nil - } //This will execute the SQL and set the value of the primitive. This method will return false if no record is found. @@ -143,6 +186,21 @@ func (me CrudExec) ScanVals(i interface{}) error { // // i: Takes a pointer to a primitive value. func (me CrudExec) ScanVal(i interface{}) (bool, error) { + return me.ScanValContext(context.Background(), i) +} + +//This will execute the SQL and set the value of the primitive. This method will return false if no record is found. +// var id uint32 +// found, err := From("test").Select("id").Limit(1).ScanValContext(ctx, &id) +// if err != nil{ +// panic(err.Error() +// } +// if !found{ +// fmt.Println("NOT FOUND") +// } +// +// i: Takes a pointer to a primitive value. +func (me CrudExec) ScanValContext(ctx context.Context, i interface{}) (bool, error) { if me.err != nil { return false, me.err } @@ -154,7 +212,7 @@ func (me CrudExec) ScanVal(i interface{}) (bool, error) { if val.Kind() == reflect.Slice { return false, NewGoquError("Cannot scan into a slice when calling ScanVal") } - rows, err := me.database.Query(me.Sql, me.Args...) + rows, err := me.database.QueryContext(ctx, me.Sql, me.Args...) if err != nil { return false, err } @@ -172,7 +230,7 @@ func (me CrudExec) ScanVal(i interface{}) (bool, error) { return count != 0, nil } -func (me CrudExec) scan(i interface{}, query string, args ...interface{}) (bool, error) { +func (me CrudExec) scanContext(ctx context.Context, i interface{}, query string, args ...interface{}) (bool, error) { var ( found bool results []Record @@ -181,7 +239,7 @@ func (me CrudExec) scan(i interface{}, query string, args ...interface{}) (bool, if err != nil { return found, err } - rows, err := me.database.Query(query, args...) + rows, err := me.database.QueryContext(ctx, query, args...) if err != nil { return false, err } diff --git a/crud_exec_test.go b/crud_exec_test.go index 89f7db6c..ce7844f5 100644 --- a/crud_exec_test.go +++ b/crud_exec_test.go @@ -1,6 +1,7 @@ package goqu import ( + "context" "fmt" "sync" "testing" @@ -10,24 +11,24 @@ import ( "gopkg.in/DATA-DOG/go-sqlmock.v1" ) -type testCrudActionItem struct { +type TestCrudActionItem struct { Address string `db:"address"` Name string `db:"name"` } -type testCrudActionNoTagsItem struct { +type TestCrudActionNoTagsItem struct { Address string Name string } -type testComposedCrudActionItem struct { - testCrudActionItem +type TestComposedCrudActionItem struct { + TestCrudActionItem PhoneNumber string `db:"phone_number"` Age int64 `db:"age"` } -type testEmbeddedPtrCrudActionItem struct { - *testCrudActionItem +type TestEmbeddedPtrCrudActionItem struct { + *TestCrudActionItem PhoneNumber string `db:"phone_number"` Age int64 `db:"age"` } @@ -38,52 +39,82 @@ type crudExecTest struct { func (me *crudExecTest) TestWithError() { t := me.T() + ctx := context.Background() mDb, _, err := sqlmock.New() assert.NoError(t, err) db := New("db-mock", mDb) expectedErr := fmt.Errorf("crud exec error") exec := newCrudExec(db, expectedErr, `SELECT * FROM "items"`) - var items []testCrudActionItem + var items []TestCrudActionItem assert.EqualError(t, exec.ScanStructs(&items), expectedErr.Error()) - found, err := exec.ScanStruct(&testCrudActionItem{}) + assert.EqualError(t, exec.ScanStructsContext(ctx, &items), expectedErr.Error()) + found, err := exec.ScanStruct(&TestCrudActionItem{}) + assert.EqualError(t, err, expectedErr.Error()) + assert.False(t, found) + found, err = exec.ScanStructContext(ctx, &TestCrudActionItem{}) assert.EqualError(t, err, expectedErr.Error()) assert.False(t, found) var vals []string assert.EqualError(t, exec.ScanVals(&vals), expectedErr.Error()) + assert.EqualError(t, exec.ScanValsContext(ctx, &vals), expectedErr.Error()) var val string found, err = exec.ScanVal(&val) assert.EqualError(t, err, expectedErr.Error()) assert.False(t, found) + found, err = exec.ScanValContext(ctx, &val) + assert.EqualError(t, err, expectedErr.Error()) + assert.False(t, found) } func (me *crudExecTest) TestScanStructs() { t := me.T() + ctx := context.Background() mDb, mock, err := sqlmock.New() assert.NoError(t, err) + mock.ExpectQuery(`SELECT \* FROM "items"`). + WillReturnError(fmt.Errorf("query error")) mock.ExpectQuery(`SELECT \* FROM "items"`). WillReturnError(fmt.Errorf("query error")) + mock.ExpectQuery(`SELECT \* FROM "items"`). + WithArgs(). + WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2")) mock.ExpectQuery(`SELECT \* FROM "items"`). WithArgs(). WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2")) + mock.ExpectQuery(`SELECT \* FROM "items"`). + WithArgs(). + WillReturnRows(sqlmock.NewRows([]string{"address", "name", "phone_number", "age"}).FromCSVString("111 Test Addr,Test1,111-111-1111,20\n211 Test Addr,Test2,222-222-2222,30")) mock.ExpectQuery(`SELECT \* FROM "items"`). WithArgs(). WillReturnRows(sqlmock.NewRows([]string{"address", "name", "phone_number", "age"}).FromCSVString("111 Test Addr,Test1,111-111-1111,20\n211 Test Addr,Test2,222-222-2222,30")) + mock.ExpectQuery(`SELECT \* FROM "items"`). + WithArgs(). + WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2")) mock.ExpectQuery(`SELECT \* FROM "items"`). WithArgs(). WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2")) + mock.ExpectQuery(`SELECT \* FROM "items"`). + WithArgs(). + WillReturnRows(sqlmock.NewRows([]string{"address", "name", "phone_number", "age"}).FromCSVString("111 Test Addr,Test1,111-111-1111,20\n211 Test Addr,Test2,222-222-2222,30")) mock.ExpectQuery(`SELECT \* FROM "items"`). WithArgs(). WillReturnRows(sqlmock.NewRows([]string{"address", "name", "phone_number", "age"}).FromCSVString("111 Test Addr,Test1,111-111-1111,20\n211 Test Addr,Test2,222-222-2222,30")) + mock.ExpectQuery(`SELECT \* FROM "items"`). + WithArgs(). + WillReturnRows(sqlmock.NewRows([]string{"address", "name", "phone_number", "age"}).FromCSVString("111 Test Addr,Test1,111-111-1111,20\n211 Test Addr,Test2,222-222-2222,30")) mock.ExpectQuery(`SELECT \* FROM "items"`). WithArgs(). WillReturnRows(sqlmock.NewRows([]string{"address", "name", "phone_number", "age"}).FromCSVString("111 Test Addr,Test1,111-111-1111,20\n211 Test Addr,Test2,222-222-2222,30")) + mock.ExpectQuery(`SELECT \* FROM "items"`). + WithArgs(). + WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2")) mock.ExpectQuery(`SELECT \* FROM "items"`). WithArgs(). WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2")) @@ -91,10 +122,13 @@ func (me *crudExecTest) TestScanStructs() { db := New("db-mock", mDb) exec := newCrudExec(db, nil, `SELECT * FROM "items"`) - var items []testCrudActionItem + var items []TestCrudActionItem assert.EqualError(t, exec.ScanStructs(items), "goqu: Type must be a pointer to a slice when calling ScanStructs") - assert.EqualError(t, exec.ScanStructs(&testCrudActionItem{}), "goqu: Type must be a pointer to a slice when calling ScanStructs") + assert.EqualError(t, exec.ScanStructsContext(ctx, items), "goqu: Type must be a pointer to a slice when calling ScanStructs") + assert.EqualError(t, exec.ScanStructs(&TestCrudActionItem{}), "goqu: Type must be a pointer to a slice when calling ScanStructs") + assert.EqualError(t, exec.ScanStructsContext(ctx, &TestCrudActionItem{}), "goqu: Type must be a pointer to a slice when calling ScanStructs") assert.EqualError(t, exec.ScanStructs(&items), "query error") + assert.EqualError(t, exec.ScanStructsContext(ctx, &items), "query error") assert.NoError(t, exec.ScanStructs(&items)) assert.Len(t, items, 2) @@ -104,7 +138,16 @@ func (me *crudExecTest) TestScanStructs() { assert.Equal(t, items[1].Address, "211 Test Addr") assert.Equal(t, items[1].Name, "Test2") - var composed []testComposedCrudActionItem + items = nil + assert.NoError(t, exec.ScanStructsContext(ctx, &items)) + assert.Len(t, items, 2) + assert.Equal(t, items[0].Address, "111 Test Addr") + assert.Equal(t, items[0].Name, "Test1") + + assert.Equal(t, items[1].Address, "211 Test Addr") + assert.Equal(t, items[1].Name, "Test2") + + var composed []TestComposedCrudActionItem assert.NoError(t, exec.ScanStructs(&composed)) assert.Len(t, composed, 2) assert.Equal(t, composed[0].Address, "111 Test Addr") @@ -117,7 +160,20 @@ func (me *crudExecTest) TestScanStructs() { assert.Equal(t, composed[1].PhoneNumber, "222-222-2222") assert.Equal(t, composed[1].Age, 30) - var pointers []*testCrudActionItem + composed = nil + assert.NoError(t, exec.ScanStructsContext(ctx, &composed)) + assert.Len(t, composed, 2) + assert.Equal(t, composed[0].Address, "111 Test Addr") + assert.Equal(t, composed[0].Name, "Test1") + assert.Equal(t, composed[0].PhoneNumber, "111-111-1111") + assert.Equal(t, composed[0].Age, 20) + + assert.Equal(t, composed[1].Address, "211 Test Addr") + assert.Equal(t, composed[1].Name, "Test2") + assert.Equal(t, composed[1].PhoneNumber, "222-222-2222") + assert.Equal(t, composed[1].Age, 30) + + var pointers []*TestCrudActionItem assert.NoError(t, exec.ScanStructs(&pointers)) assert.Len(t, pointers, 2) assert.Equal(t, pointers[0].Address, "111 Test Addr") @@ -126,7 +182,16 @@ func (me *crudExecTest) TestScanStructs() { assert.Equal(t, pointers[1].Address, "211 Test Addr") assert.Equal(t, pointers[1].Name, "Test2") - var composedPointers []*testComposedCrudActionItem + pointers = nil + assert.NoError(t, exec.ScanStructsContext(ctx, &pointers)) + assert.Len(t, pointers, 2) + assert.Equal(t, pointers[0].Address, "111 Test Addr") + assert.Equal(t, pointers[0].Name, "Test1") + + assert.Equal(t, pointers[1].Address, "211 Test Addr") + assert.Equal(t, pointers[1].Name, "Test2") + + var composedPointers []*TestComposedCrudActionItem assert.NoError(t, exec.ScanStructs(&composedPointers)) assert.Len(t, composedPointers, 2) assert.Equal(t, composedPointers[0].Address, "111 Test Addr") @@ -139,7 +204,20 @@ func (me *crudExecTest) TestScanStructs() { assert.Equal(t, composedPointers[1].PhoneNumber, "222-222-2222") assert.Equal(t, composedPointers[1].Age, 30) - var embeddedPtrs []*testEmbeddedPtrCrudActionItem + composedPointers = nil + assert.NoError(t, exec.ScanStructsContext(ctx, &composedPointers)) + assert.Len(t, composedPointers, 2) + assert.Equal(t, composedPointers[0].Address, "111 Test Addr") + assert.Equal(t, composedPointers[0].Name, "Test1") + assert.Equal(t, composedPointers[0].PhoneNumber, "111-111-1111") + assert.Equal(t, composedPointers[0].Age, 20) + + assert.Equal(t, composedPointers[1].Address, "211 Test Addr") + assert.Equal(t, composedPointers[1].Name, "Test2") + assert.Equal(t, composedPointers[1].PhoneNumber, "222-222-2222") + assert.Equal(t, composedPointers[1].Age, 30) + + var embeddedPtrs []*TestEmbeddedPtrCrudActionItem assert.NoError(t, exec.ScanStructs(&embeddedPtrs)) assert.Len(t, embeddedPtrs, 2) assert.Equal(t, embeddedPtrs[0].Address, "111 Test Addr") @@ -152,7 +230,20 @@ func (me *crudExecTest) TestScanStructs() { assert.Equal(t, embeddedPtrs[1].PhoneNumber, "222-222-2222") assert.Equal(t, embeddedPtrs[1].Age, 30) - var noTags []testCrudActionNoTagsItem + embeddedPtrs = nil + assert.NoError(t, exec.ScanStructsContext(ctx, &embeddedPtrs)) + assert.Len(t, embeddedPtrs, 2) + assert.Equal(t, embeddedPtrs[0].Address, "111 Test Addr") + assert.Equal(t, embeddedPtrs[0].Name, "Test1") + assert.Equal(t, embeddedPtrs[0].PhoneNumber, "111-111-1111") + assert.Equal(t, embeddedPtrs[0].Age, 20) + + assert.Equal(t, embeddedPtrs[1].Address, "211 Test Addr") + assert.Equal(t, embeddedPtrs[1].Name, "Test2") + assert.Equal(t, embeddedPtrs[1].PhoneNumber, "222-222-2222") + assert.Equal(t, embeddedPtrs[1].Age, 30) + + var noTags []TestCrudActionNoTagsItem assert.NoError(t, exec.ScanStructs(&noTags)) assert.Len(t, noTags, 2) assert.Equal(t, noTags[0].Address, "111 Test Addr") @@ -161,6 +252,14 @@ func (me *crudExecTest) TestScanStructs() { assert.Equal(t, noTags[1].Address, "211 Test Addr") assert.Equal(t, noTags[1].Name, "Test2") + noTags = nil + assert.NoError(t, exec.ScanStructsContext(ctx, &noTags)) + assert.Len(t, noTags, 2) + assert.Equal(t, noTags[0].Address, "111 Test Addr") + assert.Equal(t, noTags[0].Name, "Test1") + + assert.Equal(t, noTags[1].Address, "211 Test Addr") + assert.Equal(t, noTags[1].Name, "Test2") } func (me *crudExecTest) TestScanStruct() { @@ -190,8 +289,8 @@ func (me *crudExecTest) TestScanStruct() { db := New("db-mock", mDb) exec := newCrudExec(db, nil, `SELECT * FROM "items"`) - var slicePtr []testCrudActionItem - var item testCrudActionItem + var slicePtr []TestCrudActionItem + var item TestCrudActionItem found, err := exec.ScanStruct(item) assert.EqualError(t, err, "goqu: Type must be a pointer to a struct when calling ScanStruct") assert.False(t, found) @@ -208,7 +307,7 @@ func (me *crudExecTest) TestScanStruct() { assert.Equal(t, item.Address, "111 Test Addr") assert.Equal(t, item.Name, "Test1") - var composed testComposedCrudActionItem + var composed TestComposedCrudActionItem found, err = exec.ScanStruct(&composed) assert.NoError(t, err) assert.True(t, found) @@ -217,7 +316,7 @@ func (me *crudExecTest) TestScanStruct() { assert.Equal(t, composed.PhoneNumber, "111-111-1111") assert.Equal(t, composed.Age, 20) - var embeddedPtr testEmbeddedPtrCrudActionItem + var embeddedPtr TestEmbeddedPtrCrudActionItem found, err = exec.ScanStruct(&embeddedPtr) assert.NoError(t, err) assert.True(t, found) @@ -226,7 +325,7 @@ func (me *crudExecTest) TestScanStruct() { assert.Equal(t, embeddedPtr.PhoneNumber, "111-111-1111") assert.Equal(t, embeddedPtr.Age, 20) - var noTag testCrudActionNoTagsItem + var noTag TestCrudActionNoTagsItem found, err = exec.ScanStruct(&noTag) assert.NoError(t, err) assert.True(t, found) diff --git a/database.go b/database.go index fdb457e5..7d902076 100644 --- a/database.go +++ b/database.go @@ -1,6 +1,9 @@ package goqu -import "database/sql" +import ( + "context" + "database/sql" +) type ( database interface { @@ -8,13 +11,21 @@ type ( From(cols ...interface{}) *Dataset Logger(logger Logger) Exec(query string, args ...interface{}) (sql.Result, error) + ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) Prepare(query string) (*sql.Stmt, error) + PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) Query(query string, args ...interface{}) (*sql.Rows, error) + QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row + QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row ScanStructs(i interface{}, query string, args ...interface{}) error + ScanStructsContext(ctx context.Context, i interface{}, query string, args ...interface{}) error ScanStruct(i interface{}, query string, args ...interface{}) (bool, error) + ScanStructContext(ctx context.Context, i interface{}, query string, args ...interface{}) (bool, error) ScanVals(i interface{}, query string, args ...interface{}) error + ScanValsContext(ctx context.Context, i interface{}, query string, args ...interface{}) error ScanVal(i interface{}, query string, args ...interface{}) (bool, error) + ScanValContext(ctx context.Context, i interface{}, query string, args ...interface{}) (bool, error) } //This struct is the wrapper for a Db. The struct delegates most calls to either an Exec instance or to the Db passed into the constructor. Database struct { @@ -110,6 +121,16 @@ func (me *Database) Exec(query string, args ...interface{}) (sql.Result, error) return me.Db.Exec(query, args...) } +//Uses the db to Execute the query with arguments and return the sql.Result +// +//query: The SQL to execute +// +//args...: for any placeholder parameters in the query +func (me *Database) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { + me.Trace("EXEC", query, args...) + return me.Db.ExecContext(ctx, query, args...) +} + //Can be used to prepare a query. // //You can use this in tandem with a dataset by doing the following. @@ -140,6 +161,36 @@ func (me *Database) Prepare(query string) (*sql.Stmt, error) { return me.Db.Prepare(query) } +//Can be used to prepare a query. +// +//You can use this in tandem with a dataset by doing the following. +// sql, args, err := db.From("items").Where(goqu.I("id").Gt(10)).ToSql(true) +// if err != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// stmt, err := db.Prepare(sql) +// if err != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// defer stmt.Close() +// rows, err := stmt.QueryContext(ctx, args) +// if err != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// defer rows.Close() +// for rows.Next(){ +// //scan your rows +// } +// if rows.Err() != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// +//query: The SQL statement to prepare. +func (me *Database) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) { + me.Trace("PREPARE", query) + return me.Db.PrepareContext(ctx, query) +} + //Used to query for multiple rows. // //You can use this in tandem with a dataset by doing the following. @@ -167,6 +218,33 @@ func (me *Database) Query(query string, args ...interface{}) (*sql.Rows, error) return me.Db.Query(query, args...) } +//Used to query for multiple rows. +// +//You can use this in tandem with a dataset by doing the following. +// sql, err := db.From("items").Where(goqu.I("id").Gt(10)).Sql() +// if err != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// rows, err := stmt.QueryContext(ctx, args) +// if err != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// defer rows.Close() +// for rows.Next(){ +// //scan your rows +// } +// if rows.Err() != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// +//query: The SQL to execute +// +//args...: for any placeholder parameters in the query +func (me *Database) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { + me.Trace("QUERY", query, args...) + return me.Db.QueryContext(ctx, query, args...) +} + //Used to query for a single row. // //You can use this in tandem with a dataset by doing the following. @@ -188,6 +266,27 @@ func (me *Database) QueryRow(query string, args ...interface{}) *sql.Row { return me.Db.QueryRow(query, args...) } +//Used to query for a single row. +// +//You can use this in tandem with a dataset by doing the following. +// sql, err := db.From("items").Where(goqu.I("id").Gt(10)).Limit(1).Sql() +// if err != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// rows, err := stmt.QueryRowContext(ctx, args) +// if err != nil{ +// panic(err.Error()) //you could gracefully handle the error also +// } +// //scan your row +// +//query: The SQL to execute +// +//args...: for any placeholder parameters in the query +func (me *Database) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { + me.Trace("QUERY ROW", query, args...) + return me.Db.QueryRowContext(ctx, query, args...) +} + //Queries the database using the supplied query, and args and uses CrudExec.ScanStructs to scan the results into a slice of structs // //i: A pointer to a slice of structs @@ -200,6 +299,18 @@ func (me *Database) ScanStructs(i interface{}, query string, args ...interface{} return exec.ScanStructs(i) } +//Queries the database using the supplied context, query, and args and uses CrudExec.ScanStructsContext to scan the results into a slice of structs +// +//i: A pointer to a slice of structs +// +//query: The SQL to execute +// +//args...: for any placeholder parameters in the query +func (me *Database) ScanStructsContext(ctx context.Context, i interface{}, query string, args ...interface{}) error { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanStructsContext(ctx, i) +} + //Queries the database using the supplied query, and args and uses CrudExec.ScanStruct to scan the results into a struct // //i: A pointer to a struct @@ -212,6 +323,18 @@ func (me *Database) ScanStruct(i interface{}, query string, args ...interface{}) return exec.ScanStruct(i) } +//Queries the database using the supplied context, query, and args and uses CrudExec.ScanStructContext to scan the results into a struct +// +//i: A pointer to a struct +// +//query: The SQL to execute +// +//args...: for any placeholder parameters in the query +func (me *Database) ScanStructContext(ctx context.Context, i interface{}, query string, args ...interface{}) (bool, error) { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanStructContext(ctx, i) +} + //Queries the database using the supplied query, and args and uses CrudExec.ScanVals to scan the results into a slice of primitive values // //i: A pointer to a slice of primitive values @@ -224,6 +347,18 @@ func (me *Database) ScanVals(i interface{}, query string, args ...interface{}) e return exec.ScanVals(i) } +//Queries the database using the supplied context, query, and args and uses CrudExec.ScanValsContext to scan the results into a slice of primitive values +// +//i: A pointer to a slice of primitive values +// +//query: The SQL to execute +// +//args...: for any placeholder parameters in the query +func (me *Database) ScanValsContext(ctx context.Context, i interface{}, query string, args ...interface{}) error { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanValsContext(ctx, i) +} + //Queries the database using the supplied query, and args and uses CrudExec.ScanVal to scan the results into a primitive value // //i: A pointer to a primitive value @@ -236,6 +371,18 @@ func (me *Database) ScanVal(i interface{}, query string, args ...interface{}) (b return exec.ScanVal(i) } +//Queries the database using the supplied context, query, and args and uses CrudExec.ScanValContext to scan the results into a primitive value +// +//i: A pointer to a primitive value +// +//query: The SQL to execute +// +//args...: for any placeholder parameters in the query +func (me *Database) ScanValContext(ctx context.Context, i interface{}, query string, args ...interface{}) (bool, error) { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanValContext(ctx, i) +} + //A wrapper around a sql.Tx and works the same way as Database type TxDatabase struct { logger Logger @@ -279,48 +426,96 @@ func (me *TxDatabase) Exec(query string, args ...interface{}) (sql.Result, error return me.Tx.Exec(query, args...) } +//See Database#ExecContext +func (me *TxDatabase) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { + me.Trace("EXEC", query, args...) + return me.Tx.ExecContext(ctx, query, args...) +} + //See Database#Prepare func (me *TxDatabase) Prepare(query string) (*sql.Stmt, error) { me.Trace("PREPARE", query) return me.Tx.Prepare(query) } +//See Database#PrepareContext +func (me *TxDatabase) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) { + me.Trace("PREPARE", query) + return me.Tx.PrepareContext(ctx, query) +} + //See Database#Query func (me *TxDatabase) Query(query string, args ...interface{}) (*sql.Rows, error) { me.Trace("QUERY", query, args...) return me.Tx.Query(query, args...) } +//See Database#QueryContext +func (me *TxDatabase) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { + me.Trace("QUERY", query, args...) + return me.Tx.QueryContext(ctx, query, args...) +} + //See Database#QueryRow func (me *TxDatabase) QueryRow(query string, args ...interface{}) *sql.Row { me.Trace("QUERY ROW", query, args...) return me.Tx.QueryRow(query, args...) } +//See Database#QueryRowContext +func (me *TxDatabase) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { + me.Trace("QUERY ROW", query, args...) + return me.Tx.QueryRowContext(ctx, query, args...) +} + //See Database#ScanStructs func (me *TxDatabase) ScanStructs(i interface{}, query string, args ...interface{}) error { exec := newCrudExec(me, nil, query, args...) return exec.ScanStructs(i) } +//See Database#ScanStructsContext +func (me *TxDatabase) ScanStructsContext(ctx context.Context, i interface{}, query string, args ...interface{}) error { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanStructsContext(ctx, i) +} + //See Database#ScanStruct func (me *TxDatabase) ScanStruct(i interface{}, query string, args ...interface{}) (bool, error) { exec := newCrudExec(me, nil, query, args...) return exec.ScanStruct(i) } +//See Database#ScanStructContext +func (me *TxDatabase) ScanStructContext(ctx context.Context, i interface{}, query string, args ...interface{}) (bool, error) { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanStructContext(ctx, i) +} + //See Database#ScanVals func (me *TxDatabase) ScanVals(i interface{}, query string, args ...interface{}) error { exec := newCrudExec(me, nil, query, args...) return exec.ScanVals(i) } +//See Database#ScanValsContext +func (me *TxDatabase) ScanValsContext(ctx context.Context, i interface{}, query string, args ...interface{}) error { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanValsContext(ctx, i) +} + //See Database#ScanVal func (me *TxDatabase) ScanVal(i interface{}, query string, args ...interface{}) (bool, error) { exec := newCrudExec(me, nil, query, args...) return exec.ScanVal(i) } +//See Database#ScanValContext +func (me *TxDatabase) ScanValContext(ctx context.Context, i interface{}, query string, args ...interface{}) (bool, error) { + exec := newCrudExec(me, nil, query, args...) + return exec.ScanValContext(ctx, i) +} + //COMMIT the transaction func (me *TxDatabase) Commit() error { me.Trace("COMMIT", "") diff --git a/dataset_actions.go b/dataset_actions.go index b8d61421..d29047ae 100644 --- a/dataset_actions.go +++ b/dataset_actions.go @@ -1,5 +1,7 @@ package goqu +import "context" + //Generates the SELECT sql for this dataset and uses Exec#ScanStructs to scan the results into a slice of structs. // //ScanStructs will only select the columns that can be scanned in to the struct unless you have explicitly selected certain columns. See examples. @@ -14,6 +16,20 @@ func (me *Dataset) ScanStructs(i interface{}) error { return newCrudExec(me.database, err, sql, args...).ScanStructs(i) } +//Generates the SELECT sql for this dataset and uses Exec#ScanStructsContext to scan the results into a slice of structs. +// +//ScanStructsContext will only select the columns that can be scanned in to the struct unless you have explicitly selected certain columns. See examples. +// +//i: A pointer to a slice of structs +func (me *Dataset) ScanStructsContext(ctx context.Context, i interface{}) error { + ds := me + if me.isDefaultSelect() { + ds = ds.Select(i) + } + sql, args, err := ds.ToSql() + return newCrudExec(me.database, err, sql, args...).ScanStructsContext(ctx, i) +} + //Generates the SELECT sql for this dataset and uses Exec#ScanStruct to scan the result into a slice of structs // //ScanStruct will only select the columns that can be scanned in to the struct unless you have explicitly selected certain columns. See examples. @@ -28,6 +44,20 @@ func (me *Dataset) ScanStruct(i interface{}) (bool, error) { return newCrudExec(me.database, err, sql, args...).ScanStruct(i) } +//Generates the SELECT sql for this dataset and uses Exec#ScanStructContext to scan the result into a slice of structs +// +//ScanStructContext will only select the columns that can be scanned in to the struct unless you have explicitly selected certain columns. See examples. +// +//i: A pointer to a structs +func (me *Dataset) ScanStructContext(ctx context.Context, i interface{}) (bool, error) { + ds := me.Limit(1) + if me.isDefaultSelect() { + ds = ds.Select(i) + } + sql, args, err := ds.ToSql() + return newCrudExec(me.database, err, sql, args...).ScanStructContext(ctx, i) +} + //Generates the SELECT sql for this dataset and uses Exec#ScanVals to scan the results into a slice of primitive values // //i: A pointer to a slice of primitive values @@ -36,6 +66,14 @@ func (me *Dataset) ScanVals(i interface{}) error { return newCrudExec(me.database, err, sql, args...).ScanVals(i) } +//Generates the SELECT sql for this dataset and uses Exec#ScanValsContext to scan the results into a slice of primitive values +// +//i: A pointer to a slice of primitive values +func (me *Dataset) ScanValsContext(ctx context.Context, i interface{}) error { + sql, args, err := me.ToSql() + return newCrudExec(me.database, err, sql, args...).ScanValsContext(ctx, i) +} + //Generates the SELECT sql for this dataset and uses Exec#ScanVal to scan the result into a primitive value // //i: A pointer to a primitive value @@ -44,6 +82,14 @@ func (me *Dataset) ScanVal(i interface{}) (bool, error) { return newCrudExec(me.database, err, sql, args...).ScanVal(i) } +//Generates the SELECT sql for this dataset and uses Exec#ScanValContext to scan the result into a primitive value +// +//i: A pointer to a primitive value +func (me *Dataset) ScanValContext(ctx context.Context, i interface{}) (bool, error) { + sql, args, err := me.Limit(1).ToSql() + return newCrudExec(me.database, err, sql, args...).ScanValContext(ctx, i) +} + //Generates the SELECT COUNT(*) sql for this dataset and uses Exec#ScanVal to scan the result into an int64. func (me *Dataset) Count() (int64, error) { var count int64 @@ -51,6 +97,13 @@ func (me *Dataset) Count() (int64, error) { return count, err } +//Generates the SELECT COUNT(*) sql for this dataset and uses Exec#ScanValContext to scan the result into an int64. +func (me *Dataset) CountContext(ctx context.Context) (int64, error) { + var count int64 + _, err := me.Select(COUNT(Star()).As("count")).ScanValContext(ctx, &count) + return count, err +} + //Generates the SELECT sql only selecting the passed in column and uses Exec#ScanVals to scan the result into a slice of primitive values. // //i: A slice of primitive values @@ -60,6 +113,15 @@ func (me *Dataset) Pluck(i interface{}, col string) error { return me.Select(col).ScanVals(i) } +//Generates the SELECT sql only selecting the passed in column and uses Exec#ScanValsContext to scan the result into a slice of primitive values. +// +//i: A slice of primitive values +// +//col: The column to select when generative the SQL +func (me *Dataset) PluckContext(ctx context.Context, i interface{}, col string) error { + return me.Select(col).ScanValsContext(ctx, i) +} + //Generates the UPDATE sql, and returns an Exec struct with the sql set to the UPDATE statement // db.From("test").Update(Record{"name":"Bob", update: time.Now()}).Exec() //