Merge 48d0897d3e391ba6a0e3b814c9d1b546b00b4c2e into 9acaa33324bbcc78239a1c913d4f1292c12177b9
This commit is contained in:
commit
6cbd6648dc
@ -16,6 +16,8 @@ var (
|
|||||||
ErrCantStartTransaction = errors.New("can't start transaction")
|
ErrCantStartTransaction = errors.New("can't start transaction")
|
||||||
// ErrUnaddressable unaddressable value
|
// ErrUnaddressable unaddressable value
|
||||||
ErrUnaddressable = errors.New("using unaddressable value")
|
ErrUnaddressable = errors.New("using unaddressable value")
|
||||||
|
// ErrUnsupportedType unsupported type
|
||||||
|
ErrUnsupportedType = errors.New("using unsupported type")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors contains all happened errors
|
// Errors contains all happened errors
|
||||||
|
52
main.go
52
main.go
@ -284,6 +284,58 @@ func (s *DB) Find(out interface{}, where ...interface{}) *DB {
|
|||||||
return s.clone().NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
|
return s.clone().NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindInBatches find records in batches for large tables and allow callbacks to operate
|
||||||
|
// on each batch
|
||||||
|
func (s *DB) FindInBatches(out interface{}, cb func(), where ...interface{}) *DB {
|
||||||
|
var limit interface{}
|
||||||
|
newDB := s.clone()
|
||||||
|
if len(newDB.search.orders) != 0 {
|
||||||
|
//ordering by non primary col not supported - can cause infinite loop
|
||||||
|
newDB.search.orders = []interface{}{}
|
||||||
|
}
|
||||||
|
value := indirect(reflect.ValueOf(out))
|
||||||
|
if value.Kind() != reflect.Array && value.Kind() != reflect.Slice {
|
||||||
|
newDB.AddError(ErrUnsupportedType)
|
||||||
|
return newDB
|
||||||
|
}
|
||||||
|
if newDB.search.limit == -1 {
|
||||||
|
limit = 1000
|
||||||
|
} else {
|
||||||
|
limit = newDB.search.limit
|
||||||
|
}
|
||||||
|
err := newDB.Limit(limit).Find(out, where...).Error
|
||||||
|
records := indirect(reflect.ValueOf(out))
|
||||||
|
for err == nil && records.Len() > 0 {
|
||||||
|
cb()
|
||||||
|
lastRecord := records.Index(records.Len() - 1).Interface()
|
||||||
|
scope := s.NewScope(lastRecord)
|
||||||
|
err = newDB.Limit(limit).
|
||||||
|
Where(fmt.Sprintf("`%v` > '%v'", scope.PrimaryKey(), scope.PrimaryKeyValue())).
|
||||||
|
Find(out, where...).Error
|
||||||
|
records = indirect(reflect.ValueOf(out))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
newDB.AddError(err)
|
||||||
|
}
|
||||||
|
return newDB
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindEach find records in batches for large tables and allow callbacks to operate
|
||||||
|
// on each of them between iterations
|
||||||
|
func (s *DB) FindEach(out interface{}, cb func(), where ...interface{}) *DB {
|
||||||
|
c := s.clone()
|
||||||
|
v := indirect(reflect.ValueOf(&out)).Interface()
|
||||||
|
slice := makeSlice(reflect.TypeOf(v))
|
||||||
|
c = c.FindInBatches(slice, func() {
|
||||||
|
valueOfSlice := indirect(reflect.ValueOf(slice))
|
||||||
|
for i := 0; i < valueOfSlice.Len(); i++ {
|
||||||
|
reflect.ValueOf(out).Elem().Set(indirect(valueOfSlice.Index(i)))
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
}, where...)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// Scan scan value to a struct
|
// Scan scan value to a struct
|
||||||
func (s *DB) Scan(dest interface{}) *DB {
|
func (s *DB) Scan(dest interface{}) *DB {
|
||||||
return s.clone().NewScope(s.Value).Set("gorm:query_destination", dest).callCallbacks(s.parent.callbacks.queries).db
|
return s.clone().NewScope(s.Value).Set("gorm:query_destination", dest).callCallbacks(s.parent.callbacks.queries).db
|
||||||
|
86
main_test.go
86
main_test.go
@ -381,6 +381,92 @@ func TestTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindInBatches(t *testing.T) {
|
||||||
|
type SomeProduct struct {
|
||||||
|
gorm.Model
|
||||||
|
Code int
|
||||||
|
Price uint
|
||||||
|
}
|
||||||
|
type NoTableStruct struct {
|
||||||
|
gorm.Model
|
||||||
|
}
|
||||||
|
DB.DropTable(&SomeProduct{})
|
||||||
|
DB.AutoMigrate(&SomeProduct{})
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
m := SomeProduct{Code: i}
|
||||||
|
err := DB.Save(&m).Error
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var arr []SomeProduct
|
||||||
|
var products []SomeProduct
|
||||||
|
|
||||||
|
DB.Limit(3).FindInBatches(&arr, func() {
|
||||||
|
for i := 0; i < len(arr); i++ {
|
||||||
|
products = append(products, arr[i])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if len(products) != 10 {
|
||||||
|
t.Errorf("not all products were returned in find in batches")
|
||||||
|
}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if products[i].Code != i {
|
||||||
|
t.Errorf("product %d didn't match %d", products[i].Code, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//test errors
|
||||||
|
err := DB.FindInBatches(SomeProduct{}, func() {}).Error
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("FindInBatches was supposed to fail when given a struct")
|
||||||
|
} else if err != gorm.ErrUnsupportedType {
|
||||||
|
t.Errorf("FindInBatches was supposed to return an ErrUnsupportedType")
|
||||||
|
}
|
||||||
|
err = DB.FindInBatches(&[]NoTableStruct{}, func() {}).Error
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("FindInBatches was supposed to return the underlying error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindEach(t *testing.T) {
|
||||||
|
type SomeProduct struct {
|
||||||
|
gorm.Model
|
||||||
|
Code int
|
||||||
|
Price uint
|
||||||
|
}
|
||||||
|
type NoTableStruct struct {
|
||||||
|
gorm.Model
|
||||||
|
}
|
||||||
|
DB.DropTable(&SomeProduct{})
|
||||||
|
DB.AutoMigrate(&SomeProduct{})
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
m := SomeProduct{Code: i}
|
||||||
|
err := DB.Save(&m).Error
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var out SomeProduct
|
||||||
|
var products []SomeProduct
|
||||||
|
|
||||||
|
DB.Limit(3).FindEach(&out, func() {
|
||||||
|
products = append(products, out)
|
||||||
|
})
|
||||||
|
if len(products) != 10 {
|
||||||
|
t.Errorf("not all products were returned in find in batches")
|
||||||
|
}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if products[i].Code != i {
|
||||||
|
t.Errorf("product %d didn't match %d", products[i].Code, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//test errors
|
||||||
|
err := DB.FindEach(&NoTableStruct{}, func() {}).Error
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("find each was supposed to return the underlying error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRow(t *testing.T) {
|
func TestRow(t *testing.T) {
|
||||||
user1 := User{Name: "RowUser1", Age: 1, Birthday: parseTime("2000-1-1")}
|
user1 := User{Name: "RowUser1", Age: 1, Birthday: parseTime("2000-1-1")}
|
||||||
user2 := User{Name: "RowUser2", Age: 10, Birthday: parseTime("2010-1-1")}
|
user2 := User{Name: "RowUser2", Age: 10, Birthday: parseTime("2010-1-1")}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user