add BeforeSet processor and Dump function

This commit is contained in:
Lunny Xiao 2014-05-04 13:53:38 +08:00
parent 93209fa5b2
commit 9e147d2fde
6 changed files with 154 additions and 31 deletions

View File

@ -6,6 +6,7 @@ import (
"database/sql" "database/sql"
"errors" "errors"
"fmt" "fmt"
"io"
"os" "os"
"reflect" "reflect"
"strconv" "strconv"
@ -265,6 +266,77 @@ func (engine *Engine) DBMetas() ([]*core.Table, error) {
return tables, nil return tables, nil
} }
func (engine *Engine) DumpAllToFile(fp string) error {
f, err := os.Create(fp)
if err != nil {
return err
}
defer f.Close()
return engine.DumpAll(f)
}
func (engine *Engine) DumpAll(w io.Writer) error {
tables, err := engine.DBMetas()
if err != nil {
return err
}
for _, table := range tables {
_, err = io.WriteString(w, engine.dialect.CreateTableSql(table, "", "", "")+"\n\n")
if err != nil {
return err
}
for _, index := range table.Indexes {
_, err = io.WriteString(w, engine.dialect.CreateIndexSql(table.Name, index)+"\n\n")
if err != nil {
return err
}
}
rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(table.Name))
if err != nil {
return err
}
cols, err := rows.Columns()
if err != nil {
return err
}
if len(cols) == 0 {
continue
}
for rows.Next() {
dest := make([]interface{}, len(cols))
err = rows.ScanSlice(&dest)
if err != nil {
return err
}
_, err = io.WriteString(w, "INSERT INTO "+engine.Quote(table.Name)+" ("+engine.Quote(strings.Join(cols, engine.Quote(", ")))+") VALUES (")
if err != nil {
return err
}
var temp string
for _, d := range dest {
if d == nil {
temp += ", NULL"
} else if reflect.TypeOf(d).Kind() == reflect.String {
temp += ", '" + strings.Replace(d.(string), "'", "''", -1) + "'"
} else if reflect.TypeOf(d).Kind() == reflect.Slice {
temp += fmt.Sprintf(", %s", engine.dialect.FormatBytes(d.([]byte)))
} else {
temp += fmt.Sprintf(", %v", d)
}
}
_, err = io.WriteString(w, temp[2:]+");\n\n")
if err != nil {
return err
}
}
}
return nil
}
// use cascade or not // use cascade or not
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session { func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
session := engine.NewSession() session := engine.NewSession()

34
examples/tables.go Normal file
View File

@ -0,0 +1,34 @@
package main
import (
"fmt"
"os"
"github.com/go-xorm/xorm"
_ "github.com/mattn/go-sqlite3"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("need db path")
return
}
orm, err := xorm.NewEngine("sqlite3", os.Args[1])
if err != nil {
fmt.Println(err)
return
}
defer orm.Close()
orm.ShowSQL = true
tables, err := orm.DBMetas()
if err != nil {
fmt.Println(err)
return
}
for _, table := range tables {
fmt.Println(table.Name)
}
}

View File

@ -15,6 +15,10 @@ type BeforeDeleteProcessor interface {
BeforeDelete() BeforeDelete()
} }
type BeforeSetProcessor interface {
BeforeSet(string, Cell)
}
// !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations // !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations
//// Executed before an object is validated //// Executed before an object is validated
//type BeforeValidateProcessor interface { //type BeforeValidateProcessor interface {

View File

@ -883,7 +883,6 @@ func (session *Session) Rows(bean interface{}) (*Rows, error) {
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct // map[int64]*Struct
func (session *Session) Iterate(bean interface{}, fun IterFunc) error { func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
rows, err := session.Rows(bean) rows, err := session.Rows(bean)
if err != nil { if err != nil {
return err return err
@ -982,24 +981,6 @@ func (session *Session) Get(bean interface{}) (bool, error) {
} else { } else {
return false, nil return false, nil
} }
// resultsSlice, err := session.query(sqlStr, args...)
// if err != nil {
// return false, err
// }
// if len(resultsSlice) < 1 {
// return false, nil
// }
// err = session.scanMapIntoStruct(bean, resultsSlice[0])
// if err != nil {
// return true, err
// }
// if len(resultsSlice) == 1 {
// return true, nil
// } else {
// return true, errors.New("More than one record")
// }
} }
// Count counts the records. bean's non-empty fields // Count counts the records. bean's non-empty fields
@ -1441,6 +1422,8 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *c
return fieldValue return fieldValue
} }
type Cell *interface{}
func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error { func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error {
dataStruct := rValue(bean) dataStruct := rValue(bean)
if dataStruct.Kind() != reflect.Struct { if dataStruct.Kind() != reflect.Struct {
@ -1449,18 +1432,24 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
table := session.Engine.autoMapType(dataStruct) table := session.Engine.autoMapType(dataStruct)
scanResultContainers := make([]interface{}, len(fields)) scanResults := make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ { for i := 0; i < len(fields); i++ {
var scanResultContainer interface{} var cell interface{}
scanResultContainers[i] = &scanResultContainer scanResults[i] = &cell
} }
if err := rows.Scan(scanResultContainers...); err != nil { if err := rows.Scan(scanResults...); err != nil {
return err return err
} }
b, hasBeforeSet := bean.(BeforeSetProcessor)
for ii, key := range fields { for ii, key := range fields {
if hasBeforeSet {
b.BeforeSet(fields[ii], Cell(scanResults[ii].(*interface{})))
}
if fieldValue := session.getField(&dataStruct, key, table); fieldValue != nil { if fieldValue := session.getField(&dataStruct, key, table); fieldValue != nil {
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
//if row is null then ignore //if row is null then ignore
if rawValue.Interface() == nil { if rawValue.Interface() == nil {
@ -1468,6 +1457,7 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
continue continue
} }
if fieldValue.CanAddr() {
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
if data, err := value2Bytes(&rawValue); err == nil { if data, err := value2Bytes(&rawValue); err == nil {
structConvert.FromDB(data) structConvert.FromDB(data)
@ -1476,6 +1466,16 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
} }
continue continue
} }
}
if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
if data, err := value2Bytes(&rawValue); err == nil {
structConvert.FromDB(data)
} else {
session.Engine.LogError(err)
}
continue
}
rawValueType := reflect.TypeOf(rawValue.Interface()) rawValueType := reflect.TypeOf(rawValue.Interface())
vv := reflect.ValueOf(rawValue.Interface()) vv := reflect.ValueOf(rawValue.Interface())
@ -2451,6 +2451,16 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
} }
} }
} }
if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
data, err := fieldConvert.ToDB()
if err != nil {
return 0, err
} else {
return string(data), nil
}
}
fieldType := fieldValue.Type() fieldType := fieldValue.Type()
k := fieldType.Kind() k := fieldType.Kind()
if k == reflect.Ptr { if k == reflect.Ptr {
@ -2470,11 +2480,6 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
switch k { switch k {
case reflect.Bool: case reflect.Bool:
return fieldValue.Bool(), nil return fieldValue.Bool(), nil
/*if fieldValue.Bool() {
return 1, nil
} else {
return 0, nil
}*/
case reflect.String: case reflect.String:
return fieldValue.String(), nil return fieldValue.String(), nil
case reflect.Struct: case reflect.Struct:

View File

@ -1,6 +1,7 @@
package xorm package xorm
import ( import (
"fmt"
"strings" "strings"
"github.com/go-xorm/core" "github.com/go-xorm/core"
@ -44,6 +45,10 @@ func (db *sqlite3) SqlType(c *core.Column) string {
} }
} }
func (db *sqlite3) FormatBytes(bs []byte) string {
return fmt.Sprintf("X'%x'", bs)
}
func (db *sqlite3) SupportInsertMany() bool { func (db *sqlite3) SupportInsertMany() bool {
return true return true
} }

View File

@ -451,8 +451,11 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
} }
fieldValue := *fieldValuePtr fieldValue := *fieldValuePtr
fieldType := reflect.TypeOf(fieldValue.Interface()) if fieldValue.Interface() == nil {
continue
}
fieldType := reflect.TypeOf(fieldValue.Interface())
requiredField := useAllCols requiredField := useAllCols
if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok { if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok {
if b { if b {