diff --git a/README.md b/README.md index 2dc4c115..4002993f 100644 --- a/README.md +++ b/README.md @@ -818,16 +818,42 @@ db.Debug().Where("name = ?", "jinzhu").First(&User{}) Row & Rows is not chainable, it works just like `QueryRow` and `Query` ```go -row := db.Where("name = ?", "jinzhu").select("name, age").Row() // (*sql.Row) +row := db.Table("users").Where("name = ?", "jinzhu").select("name, age").Row() // (*sql.Row) row.Scan(&name, &age) -rows, err := db.Where("name = ?", "jinzhu").select("name, age, email").Rows() // (*sql.Rows, error) +rows, err := db.Model(User{}).Where("name = ?", "jinzhu").select("name, age, email").Rows() // (*sql.Rows, error) defer rows.Close() for rows.Next() { ... rows.Scan(&name, &age, &email) ... } + +// Rows() with raw sql +rows, err := db.Raw("select name, age, email from users where name = ?", "jinzhu").Rows() // (*sql.Rows, error) +defer rows.Close() +for rows.Next() { + ... + rows.Scan(&name, &age, &email) + ... +} +``` + +## Scan + +Scan sql results into strcut + +```go +type Result struct { + Name string + Age int +} + +var result Result +db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result) + +// Scan raw sql +db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result) ``` ## Group & Having diff --git a/do.go b/do.go index 06305fe0..19518fe1 100644 --- a/do.go +++ b/do.go @@ -327,7 +327,11 @@ func (s *Do) delete() *Do { } func (s *Do) prepareQuerySql() { - s.setSql(fmt.Sprintf("SELECT %v FROM %v %v", s.selectSql(), s.table(), s.combinedSql())) + if s.search.raw { + s.setSql(strings.TrimLeft(s.combinedSql(), "WHERE ")) + } else { + s.setSql(fmt.Sprintf("SELECT %v FROM %v %v", s.selectSql(), s.table(), s.combinedSql())) + } return } @@ -398,13 +402,18 @@ func (s *Do) rows() (*sql.Rows, error) { return s.db.db.Query(s.sql, s.sqlVars...) } -func (s *Do) query() *Do { +func (s *Do) query(dests ...interface{}) *Do { defer s.trace(time.Now()) var ( is_slice bool dest_type reflect.Type ) - dest_out := reflect.Indirect(reflect.ValueOf(s.value)) + var dest_out reflect.Value + if len(dests) > 0 { + dest_out = reflect.Indirect(reflect.ValueOf(dests[0])) + } else { + dest_out = reflect.Indirect(reflect.ValueOf(s.value)) + } if dest_out.Kind() == reflect.Slice { is_slice = true diff --git a/gorm_test.go b/gorm_test.go index d97e185d..014c383e 100644 --- a/gorm_test.go +++ b/gorm_test.go @@ -1527,6 +1527,42 @@ func TestRows(t *testing.T) { } } +type result struct { + Name string + Age int +} + +func TestScan(t *testing.T) { + var res result + db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&res) + if res.Name != "3" { + t.Errorf("Scan into struct should works") + } + + var ress []result + db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&ress) + if len(ress) != 2 || ress[0].Name != "3" || ress[1].Name != "3" { + t.Errorf("Scan into struct map") + } +} + +func TestRaw(t *testing.T) { + var ress []result + db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&ress) + if len(ress) != 2 || ress[0].Name != "3" || ress[1].Name != "3" { + t.Errorf("Raw with scan") + } + + rows, _ := db.Raw("select name, age from users where name = ?", 3).Rows() + count := 0 + for rows.Next() { + count++ + } + if count != 2 { + t.Errorf("Raw with Rows should find two records with name 3") + } +} + func TestGroup(t *testing.T) { rows, err := db.Select("name").Table("users").Group("name").Rows() diff --git a/main.go b/main.go index f14cab56..ae00ce9b 100644 --- a/main.go +++ b/main.go @@ -128,6 +128,10 @@ func (s *DB) Rows() (*sql.Rows, error) { return s.do(s.data).rows() } +func (s *DB) Scan(dest interface{}) *DB { + return s.do(s.data).query(dest).db +} + func (s *DB) Attrs(attrs ...interface{}) *DB { return s.clone().search.attrs(attrs...).db } @@ -180,6 +184,10 @@ func (s *DB) Delete(value interface{}) *DB { return s.clone().do(value).begin().delete().commit_or_rollback().db } +func (s *DB) Raw(sql string, values ...interface{}) *DB { + return s.clone().search.setraw(true).where(sql, values...).db +} + func (s *DB) Exec(sql string, values ...interface{}) *DB { return s.clone().do(nil).raw(sql, values...).exec().db } diff --git a/search.go b/search.go index b627a1e8..cb64ee5b 100644 --- a/search.go +++ b/search.go @@ -21,6 +21,7 @@ type search struct { groupStr string tableName string unscope bool + raw bool } func (s *search) clone() *search { @@ -39,6 +40,7 @@ func (s *search) clone() *search { groupStr: s.groupStr, joinsStr: s.joinsStr, tableName: s.tableName, + raw: s.raw, } } @@ -110,6 +112,11 @@ func (s *search) joins(query string) *search { return s } +func (s *search) setraw(b bool) *search { + s.raw = b + return s +} + func (s *search) unscoped() *search { s.unscope = true return s