diff --git a/engine.go b/engine.go index 8ed6903c..a097e4d3 100644 --- a/engine.go +++ b/engine.go @@ -2,7 +2,7 @@ package xorm import ( "database/sql" - //"fmt" + "fmt" "reflect" "strconv" "strings" @@ -154,7 +154,7 @@ func (engine *Engine) MapType(t reflect.Type) *Table { if ormTagStr != "" { col = Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false, - IsAutoIncrement: false} + IsAutoIncrement: false, MapType: TWOSIDES} ormTagStr = strings.ToLower(ormTagStr) tags := strings.Split(ormTagStr, " ") // TODO: @@ -162,9 +162,22 @@ func (engine *Engine) MapType(t reflect.Type) *Table { if tags[0] == "-" { continue } + if (tags[0] == "extends") && + (fieldType.Kind() == reflect.Struct) && + t.Field(i).Anonymous { + parentTable := engine.MapType(fieldType) + for name, col := range parentTable.Columns { + col.FieldName = fmt.Sprintf("%v.%v", fieldType.Name(), col.FieldName) + table.Columns[name] = col + } + } for j, key := range tags { k := strings.ToLower(key) switch { + case k == "<-": + col.MapType = ONLYFROMDB + case k == "->": + col.MapType = ONLYTODB case k == "pk": col.IsPrimaryKey = true col.Nullable = false @@ -230,7 +243,7 @@ func (engine *Engine) MapType(t reflect.Type) *Table { } else { sqlType := Type2SQLType(fieldType) col = Column{engine.Mapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType, - sqlType.DefaultLength, sqlType.DefaultLength2, true, "", false, false, false} + sqlType.DefaultLength, sqlType.DefaultLength2, true, "", false, false, false, TWOSIDES} if col.Name == "id" { col.IsPrimaryKey = true diff --git a/examples/derive.go b/examples/derive.go new file mode 100644 index 00000000..daa4325f --- /dev/null +++ b/examples/derive.go @@ -0,0 +1,65 @@ +package main + +import ( + "fmt" + _ "github.com/mattn/go-sqlite3" + "os" + . "xorm" +) + +type User struct { + Id int64 + Name string +} + +type LoginInfo struct { + Id int64 + IP string + UserId int64 +} + +type LoginInfo1 struct { + LoginInfo `xorm:"extends"` + UserName string +} + +func main() { + f := "derive.db" + os.Remove(f) + + Orm, err := NewEngine("sqlite3", f) + if err != nil { + fmt.Println(err) + return + } + Orm.ShowSQL = true + err = Orm.CreateTables(&User{}, &LoginInfo{}) + if err != nil { + fmt.Println(err) + return + } + + _, err = Orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1}) + if err != nil { + fmt.Println(err) + return + } + + info := LoginInfo{} + _, err = Orm.Id(1).Get(&info) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(info) + + infos := make([]LoginInfo1, 0) + err = Orm.Sql(`select *, (select name from user where id = login_info.user_id) as user_name from + login_info limit 10`).Find(&infos) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println(infos) +} diff --git a/examples/singlemapping.go b/examples/singlemapping.go new file mode 100644 index 00000000..b258c352 --- /dev/null +++ b/examples/singlemapping.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + _ "github.com/mattn/go-sqlite3" + "os" + . "xorm" +) + +type User struct { + Id int64 + Name string +} + +type LoginInfo struct { + Id int64 + IP string + UserId int64 + // timestamp should be updated by database, so only allow get from db + TimeStamp string `xorm:"<-"` + // assume + Nonuse int `xorm:"->"` +} + +func main() { + f := "singleMapping.db" + os.Remove(f) + + Orm, err := NewEngine("sqlite3", f) + if err != nil { + fmt.Println(err) + return + } + Orm.ShowSQL = true + err = Orm.CreateTables(&User{}, &LoginInfo{}) + if err != nil { + fmt.Println(err) + return + } + + _, err = Orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1, "", 23}) + if err != nil { + fmt.Println(err) + return + } + + info := LoginInfo{} + _, err = Orm.Id(1).Get(&info) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(info) +} diff --git a/session.go b/session.go index 4f9e5d0c..bd69a9d2 100644 --- a/session.go +++ b/session.go @@ -157,8 +157,21 @@ func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]b table := session.Engine.Tables[Type(obj)] for key, data := range objMap { - structField := dataStruct.FieldByName(table.Columns[key].FieldName) - if !structField.CanSet() { + fieldName := table.Columns[key].FieldName + fieldPath := strings.Split(fieldName, ".") + var structField reflect.Value + if len(fieldPath) > 2 { + fmt.Printf("xorm: Warning! Unsupported mutliderive %v\n", fieldName) + continue + } else if len(fieldPath) == 2 { + parentField := dataStruct.FieldByName(fieldPath[0]) + if parentField.IsValid() { + structField = parentField.FieldByName(fieldPath[1]) + } + } else { + structField = dataStruct.FieldByName(fieldName) + } + if !structField.IsValid() || !structField.CanSet() { continue } @@ -618,6 +631,9 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { if col.IsAutoIncrement && fieldValue.Int() == 0 { continue } + if col.MapType == ONLYFROMDB { + continue + } if table, ok := session.Engine.Tables[fieldValue.Type()]; ok { pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumn().FieldName) fmt.Println(pkField.Interface()) @@ -636,6 +652,9 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { if col.IsAutoIncrement && fieldValue.Int() == 0 { continue } + if col.MapType == ONLYFROMDB { + continue + } if table, ok := session.Engine.Tables[fieldValue.Type()]; ok { pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumn().FieldName) args = append(args, pkField.Interface()) @@ -681,6 +700,9 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) { if col.IsAutoIncrement && fieldValue.Int() == 0 { continue } + if col.MapType == ONLYFROMDB { + continue + } if fieldTable, ok := session.Engine.Tables[fieldValue.Type()]; ok { if fieldTable.PrimaryKey != "" { pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumn().FieldName) diff --git a/statement.go b/statement.go index 2e4b1f7c..9f4e0015 100644 --- a/statement.go +++ b/statement.go @@ -202,7 +202,9 @@ func (statement *Statement) selectColumnStr() string { table := statement.RefTable colNames := make([]string, 0) for _, col := range table.Columns { - colNames = append(colNames, statement.TableName()+"."+col.Name) + if col.MapType != ONLYTODB { + colNames = append(colNames, statement.TableName()+"."+col.Name) + } } return strings.Join(colNames, ", ") } diff --git a/table.go b/table.go index 81667b38..31540cd6 100644 --- a/table.go +++ b/table.go @@ -64,6 +64,12 @@ func Type2SQLType(t reflect.Type) (st SQLType) { return } +const ( + TWOSIDES = iota + 1 + ONLYTODB + ONLYFROMDB +) + type Column struct { Name string FieldName string @@ -75,6 +81,7 @@ type Column struct { IsUnique bool IsPrimaryKey bool IsAutoIncrement bool + MapType int } type Table struct {