First try for the Preload feature

This commit is contained in:
Jinzhu 2015-02-01 23:19:29 +08:00
parent 8aef600540
commit 3b784c37c4
4 changed files with 53 additions and 9 deletions

View File

@ -1092,8 +1092,9 @@ db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111
db.Mode(&User{}).Do("EditForm").Get("edit_form_html") db.Mode(&User{}).Do("EditForm").Get("edit_form_html")
DefaultTimeZone, R/W Splitting, Validation DefaultTimeZone, R/W Splitting, Validation
* Github Pages * Github Pages
* Includes
* AlertColumn, DropColumn * AlertColumn, DropColumn
* db.Preload("Addresses.Map", "active = ?", true).Preload("Profile").Find(&users)
* db.Find(&users).Related(&users)
# Author # Author

View File

@ -3,6 +3,8 @@ package gorm
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/jinzhu/gorm"
) )
func Query(scope *Scope) { func Query(scope *Scope) {
@ -13,6 +15,7 @@ func Query(scope *Scope) {
isPtr bool isPtr bool
anyRecordFound bool anyRecordFound bool
destType reflect.Type destType reflect.Type
primaryKeys []interface{}
) )
var dest = scope.IndirectValue() var dest = scope.IndirectValue()
@ -47,8 +50,9 @@ func Query(scope *Scope) {
return return
} }
columns, _ := rows.Columns() preloadMap := map[string]map[string]*gorm.Field{}
columns, _ := rows.Columns()
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
scope.db.RowsAffected += 1 scope.db.RowsAffected += 1
@ -62,6 +66,7 @@ func Query(scope *Scope) {
var values = make([]interface{}, len(columns)) var values = make([]interface{}, len(columns))
fields := scope.New(elem.Addr().Interface()).Fields() fields := scope.New(elem.Addr().Interface()).Fields()
var primaryKey interface{}
for index, column := range columns { for index, column := range columns {
if field, ok := fields[column]; ok { if field, ok := fields[column]; ok {
if field.Field.Kind() == reflect.Ptr { if field.Field.Kind() == reflect.Ptr {
@ -69,6 +74,10 @@ func Query(scope *Scope) {
} else { } else {
values[index] = reflect.New(reflect.PtrTo(field.Field.Type())).Interface() values[index] = reflect.New(reflect.PtrTo(field.Field.Type())).Interface()
} }
if field.IsPrimaryKey {
primaryKey = values[index]
primaryKeys = append(primaryKeys, primaryKey)
}
} else { } else {
var value interface{} var value interface{}
values[index] = &value values[index] = &value
@ -95,6 +104,34 @@ func Query(scope *Scope) {
dest.Set(reflect.Append(dest, elem)) dest.Set(reflect.Append(dest, elem))
} }
} }
if scope.Search.Preload != nil {
for key := range scope.Search.Preload {
if field := fields[key]; field != nil {
if preloadMap[key] == nil {
preloadMap[key] = map[string]reflect.Value{}
}
preloadMap[key][fmt.Sprintf("%v", primaryKey)] = field
}
}
}
}
for _, value := range preloadMap {
var typ reflect.Type
var relation *Relation
for _, v := range value {
typ = v.Field.Type()
relation = v.Relationship
break
}
sliceType := reflect.SliceOf(typ)
slice := reflect.MakeSlice(sliceType, 0, 0)
slicePtr := reflect.New(sliceType)
slicePtr.Elem().Set(slice)
if relation == "has_many" {
scope.NewDB().Find(slicePtr.Interface(), primaryKeys)
}
} }
if !anyRecordFound && !isSlice { if !anyRecordFound && !isSlice {

View File

@ -156,10 +156,6 @@ func (s *DB) Joins(query string) *DB {
return s.clone().search.joins(query).db return s.clone().search.joins(query).db
} }
func (s *DB) Includes(value interface{}) *DB {
return s.clone().search.includes(value).db
}
func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB { func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB {
c := s c := s
for _, f := range funcs { for _, f := range funcs {
@ -432,6 +428,10 @@ func (s *DB) Association(column string) *Association {
return &Association{Scope: scope, Column: column, Error: s.Error, PrimaryKey: primaryKey, PrimaryType: primaryType, Field: field} return &Association{Scope: scope, Column: column, Error: s.Error, PrimaryKey: primaryKey, PrimaryType: primaryType, Field: field}
} }
func (s *DB) Preload(column string, conditions ...interface{}) *DB {
return s.clone().search.preload(column, conditions...).db
}
// Set set value by name // Set set value by name
func (s *DB) Set(name string, value interface{}) *DB { func (s *DB) Set(name string, value interface{}) *DB {
return s.clone().InstantSet(name, value) return s.clone().InstantSet(name, value)

View File

@ -13,6 +13,7 @@ type search struct {
Orders []string Orders []string
Joins string Joins string
Selects []map[string]interface{} Selects []map[string]interface{}
Preload map[string][]interface{}
Offset string Offset string
Limit string Limit string
Group string Group string
@ -23,6 +24,7 @@ type search struct {
func (s *search) clone() *search { func (s *search) clone() *search {
return &search{ return &search{
Preload: s.Preload,
WhereConditions: s.WhereConditions, WhereConditions: s.WhereConditions,
OrConditions: s.OrConditions, OrConditions: s.OrConditions,
NotConditions: s.NotConditions, NotConditions: s.NotConditions,
@ -100,12 +102,16 @@ func (s *search) having(query string, values ...interface{}) *search {
return s return s
} }
func (s *search) includes(value interface{}) *search { func (s *search) joins(query string) *search {
s.Joins = query
return s return s
} }
func (s *search) joins(query string) *search { func (s *search) preload(column string, values ...interface{}) *search {
s.Joins = query if s.Preload == nil {
s.Preload = map[string][]interface{}{}
}
s.Preload[column] = values
return s return s
} }