Selaa lähdekoodia

Handle xorm tags via tagHandler prepared for customerize tag

xormplus 8 vuotta sitten
vanhempi
commit
699297f870
7 muutettua tiedostoa jossa 191 lisäystä ja 166 poistoa
  1. 48 15
      engine.go
  2. 29 30
      session.go
  3. 60 57
      session_convert.go
  4. 9 2
      session_find.go
  5. 31 58
      session_plus.go
  6. 13 3
      statement.go
  7. 1 1
      tag.go

+ 48 - 15
engine.go

@@ -47,6 +47,8 @@ type Engine struct {
 	DatabaseTZ *time.Location // The timezone of the database
 
 	disableGlobalCache bool
+
+	tagHandlers map[string]tagHandler
 }
 
 // ShowSQL show SQL statement or not on logger if log level is great than INFO
@@ -218,10 +220,15 @@ func (engine *Engine) NoCascade() *Session {
 }
 
 // MapCacher Set a table use a special cacher
-func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
+func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) error {
 	v := rValue(bean)
-	tb := engine.autoMapType(v)
+	tb, err := engine.autoMapType(v)
+	if err != nil {
+		return err
+	}
+
 	tb.Cacher = cacher
+	return nil
 }
 
 // NewDB provides an interface to operate database directly
@@ -819,10 +826,19 @@ type Table struct {
 	Name string
 }
 
+// IsValid if table is valid
+func (t *Table) IsValid() bool {
+	return t.Table != nil && len(t.Name) > 0
+}
+
 // TableInfo get table info according to bean's content
 func (engine *Engine) TableInfo(bean interface{}) *Table {
 	v := rValue(bean)
-	return &Table{engine.autoMapType(v), engine.tbName(v)}
+	tb, err := engine.autoMapType(v)
+	if err != nil {
+		engine.logger.Error(err)
+	}
+	return &Table{tb, engine.tbName(v)}
 }
 
 func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
@@ -1072,8 +1088,21 @@ func (engine *Engine) IdOfV(rv reflect.Value) core.PK {
 
 // IDOfV get id from one value of struct
 func (engine *Engine) IDOfV(rv reflect.Value) core.PK {
+	pk, err := engine.idOfV(rv)
+	if err != nil {
+		engine.logger.Error(err)
+		return nil
+	}
+	return pk
+}
+
+func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) {
 	v := reflect.Indirect(rv)
-	table := engine.autoMapType(v)
+	table, err := engine.autoMapType(v)
+	if err != nil {
+		return nil, err
+	}
+
 	pk := make([]interface{}, len(table.PrimaryKeys))
 	for i, col := range table.PKColumns() {
 		pkField := v.FieldByName(col.FieldName)
@@ -1086,7 +1115,7 @@ func (engine *Engine) IDOfV(rv reflect.Value) core.PK {
 			pk[i] = pkField.Uint()
 		}
 	}
-	return core.PK(pk)
+	return core.PK(pk), nil
 }
 
 // CreateIndexes create indexes
@@ -1107,13 +1136,6 @@ func (engine *Engine) getCacher2(table *core.Table) core.Cacher {
 	return table.Cacher
 }
 
-func (engine *Engine) getCacher(v reflect.Value) core.Cacher {
-	if table := engine.autoMapType(v); table != nil {
-		return table.Cacher
-	}
-	return engine.Cacher
-}
-
 // ClearCacheBean if enabled cache, clear the cache bean
 func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
 	v := rValue(bean)
@@ -1122,7 +1144,10 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
 		return errors.New("error params")
 	}
 	tableName := engine.tbName(v)
-	table := engine.autoMapType(v)
+	table, err := engine.autoMapType(v)
+	if err != nil {
+		return err
+	}
 	cacher := table.Cacher
 	if cacher == nil {
 		cacher = engine.Cacher
@@ -1143,7 +1168,11 @@ func (engine *Engine) ClearCache(beans ...interface{}) error {
 			return errors.New("error params")
 		}
 		tableName := engine.tbName(v)
-		table := engine.autoMapType(v)
+		table, err := engine.autoMapType(v)
+		if err != nil {
+			return err
+		}
+
 		cacher := table.Cacher
 		if cacher == nil {
 			cacher = engine.Cacher
@@ -1163,7 +1192,11 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 	for _, bean := range beans {
 		v := rValue(bean)
 		tableName := engine.tbName(v)
-		table := engine.autoMapType(v)
+		table, err := engine.autoMapType(v)
+		fmt.Println(v, table, err)
+		if err != nil {
+			return err
+		}
 
 		s := engine.NewSession()
 		defer s.Close()

+ 29 - 30
session.go

@@ -612,40 +612,39 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
 						}
 					}
 				} else if session.Statement.UseCascade {
-					table := session.Engine.autoMapType(*fieldValue)
-					if table != nil {
-						hasAssigned = true
-						if len(table.PrimaryKeys) != 1 {
-							panic("unsupported non or composited primary key cascade")
-						}
-						var pk = make(core.PK, len(table.PrimaryKeys))
-						var err error
-						pk[0], err = asKind(vv, rawValueType)
+					table, err := session.Engine.autoMapType(*fieldValue)
+					if err != nil {
+						return nil, err
+					}
+
+					hasAssigned = true
+					if len(table.PrimaryKeys) != 1 {
+						panic("unsupported non or composited primary key cascade")
+					}
+					var pk = make(core.PK, len(table.PrimaryKeys))
+					pk[0], err = asKind(vv, rawValueType)
+					if err != nil {
+						return nil, err
+					}
+
+					if !isPKZero(pk) {
+						// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+						// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+						// property to be fetched lazily
+						structInter := reflect.New(fieldValue.Type())
+						newsession := session.Engine.NewSession()
+						defer newsession.Close()
+						has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
 						if err != nil {
 							return nil, err
 						}
-
-						if !isPKZero(pk) {
-							// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
-							// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
-							// property to be fetched lazily
-							structInter := reflect.New(fieldValue.Type())
-							newsession := session.Engine.NewSession()
-							defer newsession.Close()
-							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
-							if err != nil {
-								return nil, err
-							}
-							if has {
-								//v := structInter.Elem().Interface()
-								//fieldValue.Set(reflect.ValueOf(v))
-								fieldValue.Set(structInter.Elem())
-							} else {
-								return nil, errors.New("cascade obj is not exist")
-							}
+						if has {
+							//v := structInter.Elem().Interface()
+							//fieldValue.Set(reflect.ValueOf(v))
+							fieldValue.Set(structInter.Elem())
+						} else {
+							return nil, errors.New("cascade obj is not exist")
 						}
-					} else {
-						session.Engine.logger.Error("unsupported struct type in Scan: ", fieldValue.Type().String())
 					}
 				}
 			case reflect.Ptr:

+ 60 - 57
session_convert.go

@@ -208,40 +208,39 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
 				v = x
 				fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
 			} else if session.Statement.UseCascade {
-				table := session.Engine.autoMapType(*fieldValue)
-				if table != nil {
-					// TODO: current only support 1 primary key
-					if len(table.PrimaryKeys) > 1 {
-						panic("unsupported composited primary key cascade")
-					}
-					var pk = make(core.PK, len(table.PrimaryKeys))
-					rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
-					var err error
-					pk[0], err = str2PK(string(data), rawValueType)
+				table, err := session.Engine.autoMapType(*fieldValue)
+				if err != nil {
+					return err
+				}
+
+				// TODO: current only support 1 primary key
+				if len(table.PrimaryKeys) > 1 {
+					panic("unsupported composited primary key cascade")
+				}
+				var pk = make(core.PK, len(table.PrimaryKeys))
+				rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+				pk[0], err = str2PK(string(data), rawValueType)
+				if err != nil {
+					return err
+				}
+
+				if !isPKZero(pk) {
+					// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+					// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+					// property to be fetched lazily
+					structInter := reflect.New(fieldValue.Type())
+					newsession := session.Engine.NewSession()
+					defer newsession.Close()
+					has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
 					if err != nil {
 						return err
 					}
-
-					if !isPKZero(pk) {
-						// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
-						// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
-						// property to be fetched lazily
-						structInter := reflect.New(fieldValue.Type())
-						newsession := session.Engine.NewSession()
-						defer newsession.Close()
-						has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
-						if err != nil {
-							return err
-						}
-						if has {
-							v = structInter.Elem().Interface()
-							fieldValue.Set(reflect.ValueOf(v))
-						} else {
-							return errors.New("cascade obj is not exist")
-						}
+					if has {
+						v = structInter.Elem().Interface()
+						fieldValue.Set(reflect.ValueOf(v))
+					} else {
+						return errors.New("cascade obj is not exist")
 					}
-				} else {
-					return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
 				}
 			}
 		}
@@ -493,35 +492,36 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
 			default:
 				if session.Statement.UseCascade {
 					structInter := reflect.New(fieldType.Elem())
-					table := session.Engine.autoMapType(structInter.Elem())
-					if table != nil {
-						if len(table.PrimaryKeys) > 1 {
-							panic("unsupported composited primary key cascade")
-						}
-						var pk = make(core.PK, len(table.PrimaryKeys))
-						var err error
-						rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
-						pk[0], err = str2PK(string(data), rawValueType)
+					table, err := session.Engine.autoMapType(structInter.Elem())
+					if err != nil {
+						return err
+					}
+
+					if len(table.PrimaryKeys) > 1 {
+						panic("unsupported composited primary key cascade")
+					}
+					var pk = make(core.PK, len(table.PrimaryKeys))
+					rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+					pk[0], err = str2PK(string(data), rawValueType)
+					if err != nil {
+						return err
+					}
+
+					if !isPKZero(pk) {
+						// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+						// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+						// property to be fetched lazily
+						newsession := session.Engine.NewSession()
+						defer newsession.Close()
+						has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
 						if err != nil {
 							return err
 						}
-
-						if !isPKZero(pk) {
-							// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
-							// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
-							// property to be fetched lazily
-							newsession := session.Engine.NewSession()
-							defer newsession.Close()
-							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
-							if err != nil {
-								return err
-							}
-							if has {
-								v = structInter.Interface()
-								fieldValue.Set(reflect.ValueOf(v))
-							} else {
-								return errors.New("cascade obj is not exist")
-							}
+						if has {
+							v = structInter.Interface()
+							fieldValue.Set(reflect.ValueOf(v))
+						} else {
+							return errors.New("cascade obj is not exist")
 						}
 					}
 				} else {
@@ -603,7 +603,10 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
 				return v.Value()
 			}
 
-			fieldTable := session.Engine.autoMapType(fieldValue)
+			fieldTable, err := session.Engine.autoMapType(fieldValue)
+			if err != nil {
+				return nil, err
+			}
 			if len(fieldTable.PrimaryKeys) == 1 {
 				pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
 				return pkField.Interface(), nil

+ 9 - 2
session_find.go

@@ -258,7 +258,11 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va
 	if elemType.Kind() == reflect.Struct {
 		var newValue = newElemFunc(fields)
 		dataStruct := rValue(newValue.Interface())
-		return session.rows2Beans(rawRows, fields, len(fields), session.Engine.autoMapType(dataStruct), newElemFunc, containerValueSetFunc)
+		tb, err := session.Engine.autoMapType(dataStruct)
+		if err != nil {
+			return err
+		}
+		return session.rows2Beans(rawRows, fields, len(fields), tb, newElemFunc, containerValueSetFunc)
 	}
 
 	for rawRows.Next() {
@@ -431,7 +435,10 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 			if rv.Kind() != reflect.Ptr {
 				rv = rv.Addr()
 			}
-			id := session.Engine.IdOfV(rv)
+			id, err := session.Engine.idOfV(rv)
+			if err != nil {
+				return err
+			}
 			sid, err := id.ToString()
 			if err != nil {
 				return err

+ 31 - 58
session_plus.go

@@ -12,8 +12,6 @@ import (
 	"os"
 	"reflect"
 	"regexp"
-
-	"strconv"
 	"strings"
 	"time"
 
@@ -1026,64 +1024,39 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 						}
 					}
 				} else if session.Statement.UseCascade {
-					table := session.Engine.autoMapType(*fieldValue)
-					if table != nil {
-						hasAssigned = true
-						if len(table.PrimaryKeys) != 1 {
-							panic("unsupported non or composited primary key cascade")
-						}
-						var pk = make(core.PK, len(table.PrimaryKeys))
-
-						switch rawValueType.Kind() {
-						case reflect.Int64:
-							pk[0] = vv.Int()
-						case reflect.Int:
-							pk[0] = int(vv.Int())
-						case reflect.Int32:
-							pk[0] = int32(vv.Int())
-						case reflect.Int16:
-							pk[0] = int16(vv.Int())
-						case reflect.Int8:
-							pk[0] = int8(vv.Int())
-						case reflect.Uint64:
-							pk[0] = vv.Uint()
-						case reflect.Uint:
-							pk[0] = uint(vv.Uint())
-						case reflect.Uint32:
-							pk[0] = uint32(vv.Uint())
-						case reflect.Uint16:
-							pk[0] = uint16(vv.Uint())
-						case reflect.Uint8:
-							pk[0] = uint8(vv.Uint())
-						case reflect.String:
-							pk[0] = vv.String()
-						case reflect.Slice:
-							pk[0], _ = strconv.ParseInt(string(rawValue.Interface().([]byte)), 10, 64)
-						default:
-							panic(fmt.Sprintf("unsupported primary key type: %v, %v", rawValueType, fieldValue))
-						}
+					table, err := session.Engine.autoMapType(*fieldValue)
+					if err != nil {
+						return nil, err
+					}
 
-						if !isPKZero(pk) {
-							// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
-							// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
-							// property to be fetched lazily
-							structInter := reflect.New(fieldValue.Type())
-							newsession := session.Engine.NewSession()
-							defer newsession.Close()
-							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
-							if err != nil {
-								return nil, err
-							}
-							if has {
-								//v := structInter.Elem().Interface()
-								//fieldValue.Set(reflect.ValueOf(v))
-								fieldValue.Set(structInter.Elem())
-							} else {
-								return nil, errors.New("cascade obj is not exist")
-							}
+					hasAssigned = true
+					if len(table.PrimaryKeys) != 1 {
+						panic("unsupported non or composited primary key cascade")
+					}
+					var pk = make(core.PK, len(table.PrimaryKeys))
+					pk[0], err = asKind(vv, rawValueType)
+					if err != nil {
+						return nil, err
+					}
+
+					if !isPKZero(pk) {
+						// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+						// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+						// property to be fetched lazily
+						structInter := reflect.New(fieldValue.Type())
+						newsession := session.Engine.NewSession()
+						defer newsession.Close()
+						has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+						if err != nil {
+							return nil, err
+						}
+						if has {
+							//v := structInter.Elem().Interface()
+							//fieldValue.Set(reflect.ValueOf(v))
+							fieldValue.Set(structInter.Elem())
+						} else {
+							return nil, errors.New("cascade obj is not exist")
 						}
-					} else {
-						session.Engine.logger.Error("unsupported struct type in Scan: ", fieldValue.Type().String())
 					}
 				}
 			case reflect.Ptr:

+ 13 - 3
statement.go

@@ -207,9 +207,14 @@ func (statement *Statement) NotIn(column string, args ...interface{}) *Statement
 	return statement
 }
 
-func (statement *Statement) setRefValue(v reflect.Value) {
-	statement.RefTable = statement.Engine.autoMapType(reflect.Indirect(v))
+func (statement *Statement) setRefValue(v reflect.Value) error {
+	var err error
+	statement.RefTable, err = statement.Engine.autoMapType(reflect.Indirect(v))
+	if err != nil {
+		return err
+	}
 	statement.tableName = statement.Engine.tbName(v)
+	return nil
 }
 
 // Table tempororily set table name, the parameter could be a string or a pointer of struct
@@ -219,7 +224,12 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
 	if t.Kind() == reflect.String {
 		statement.AltTableName = tableNameOrBean.(string)
 	} else if t.Kind() == reflect.Struct {
-		statement.RefTable = statement.Engine.autoMapType(v)
+		var err error
+		statement.RefTable, err = statement.Engine.autoMapType(v)
+		if err != nil {
+			statement.Engine.logger.Error(err)
+			return statement
+		}
 		statement.AltTableName = statement.Engine.tbName(v)
 	}
 	return statement

+ 1 - 1
tag.go

@@ -11,7 +11,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/go-xorm/core"
+	"github.com/xormplus/core"
 )
 
 type tagContext struct {