add PrefixMapper & SuffixMapper

This commit is contained in:
Lunny Xiao 2013-11-27 15:53:05 +08:00
parent 59d72d2ca3
commit ec2c685583
8 changed files with 232 additions and 32 deletions

View File

@ -429,6 +429,13 @@ func find(engine *Engine, t *testing.T) {
for _, user := range users { for _, user := range users {
fmt.Println(user) fmt.Println(user)
} }
users2 := make([]Userinfo, 0)
err = engine.Sql("select * from userinfo").Find(&users2)
if err != nil {
t.Error(err)
panic(err)
}
} }
func find2(engine *Engine, t *testing.T) { func find2(engine *Engine, t *testing.T) {
@ -1439,57 +1446,76 @@ type Version struct {
} }
func testVersion(engine *Engine, t *testing.T) { func testVersion(engine *Engine, t *testing.T) {
err := engine.DropTables(new(Version)) /*err := engine.DropTables(new(Version))
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return panic(err)
} }
err = engine.CreateTables(new(Version)) err = engine.CreateTables(new(Version))
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return panic(err)
} }
ver := &Version{Name: "sfsfdsfds"} ver := &Version{Name: "sfsfdsfds"}
_, err = engine.Cols("name").Insert(ver) _, err = engine.Insert(ver)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return panic(err)
}
fmt.Println(ver)
if ver.Ver != 1 {
err = errors.New("insert error")
t.Error(err)
panic(err)
} }
newVer := new(Version) newVer := new(Version)
has, err := engine.Id(ver.Id).Get(newVer) has, err := engine.Id(ver.Id).Get(newVer)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return panic(err)
} }
if !has { if !has {
t.Error(errors.New(fmt.Sprintf("no version id is %v", ver.Id))) t.Error(errors.New(fmt.Sprintf("no version id is %v", ver.Id)))
return panic(err)
}
fmt.Println(newVer)
if newVer.Ver != 1 {
err = errors.New("insert error")
t.Error(err)
panic(err)
} }
newVer.Name = "-------" newVer.Name = "-------"
_, err = engine.Id(ver.Id).Update(newVer, &Version{Ver: newVer.Ver}) _, err = engine.Id(ver.Id).Update(newVer)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return panic(err)
} }
newVer = new(Version)
has, err = engine.Id(ver.Id).Get(newVer) has, err = engine.Id(ver.Id).Get(newVer)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return panic(err)
} }
fmt.Println(ver) fmt.Println(newVer)
if newVer.Ver != 2 {
newVer.Name = "-------" err = errors.New("insert error")
_, err = engine.Id(ver.Id).Update(newVer, &Version{Ver: newVer.Ver})
if err != nil {
t.Error(err) t.Error(err)
return panic(err)
} }*/
/*
newVer.Name = "-------"
_, err = engine.Id(ver.Id).Update(newVer)
if err != nil {
t.Error(err)
return
}*/
} }
func testDistinct(engine *Engine, t *testing.T) { func testDistinct(engine *Engine, t *testing.T) {
@ -1603,6 +1629,74 @@ func testBool(engine *Engine, t *testing.T) {
} }
} }
type TTime struct {
Id int64
T time.Time
}
func testTime(engine *Engine, t *testing.T) {
err := engine.Sync(&TTime{})
if err != nil {
t.Error(err)
panic(err)
}
tt := &TTime{}
_, err = engine.Insert(tt)
if err != nil {
t.Error(err)
panic(err)
}
tt2 := &TTime{Id: tt.Id}
has, err := engine.Get(tt2)
if err != nil {
t.Error(err)
panic(err)
}
if !has {
err = errors.New("no record error")
t.Error(err)
panic(err)
}
tt3 := &TTime{T: time.Now()}
_, err = engine.Insert(tt3)
if err != nil {
t.Error(err)
panic(err)
}
}
func testPrefixTableName(engine *Engine, t *testing.T) {
tempEngine, err := NewEngine(engine.DriverName, engine.DataSourceName)
if err != nil {
t.Error(err)
panic(err)
}
tempEngine.ShowSQL = true
mapper := NewPrefixMapper(SnakeMapper{}, "xlw_")
//tempEngine.SetMapper(mapper)
tempEngine.SetTableMapper(mapper)
exist, err := tempEngine.IsTableExist(&Userinfo{})
if err != nil {
t.Error(err)
panic(err)
}
if exist {
err = tempEngine.DropTables(&Userinfo{})
if err != nil {
t.Error(err)
panic(err)
}
}
err = tempEngine.CreateTables(&Userinfo{})
if err != nil {
t.Error(err)
panic(err)
}
}
func testAll(engine *Engine, t *testing.T) { func testAll(engine *Engine, t *testing.T) {
fmt.Println("-------------- directCreateTable --------------") fmt.Println("-------------- directCreateTable --------------")
directCreateTable(engine, t) directCreateTable(engine, t)
@ -1693,6 +1787,10 @@ func testAll2(engine *Engine, t *testing.T) {
testUseBool(engine, t) testUseBool(engine, t)
fmt.Println("-------------- testBool --------------") fmt.Println("-------------- testBool --------------")
testBool(engine, t) testBool(engine, t)
fmt.Println("-------------- testTime --------------")
testTime(engine, t)
fmt.Println("-------------- testPrefixTableName --------------")
testPrefixTableName(engine, t)
fmt.Println("-------------- transaction --------------") fmt.Println("-------------- transaction --------------")
transaction(engine, t) transaction(engine, t)
} }

View File

@ -120,7 +120,7 @@ engine.Mapper = SameMapper{}
如果所有的命名都是按照IMapper的映射来操作的那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时我们就需要别的机制来改变。 如果所有的命名都是按照IMapper的映射来操作的那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时我们就需要别的机制来改变。
通过`engine.Table()`方法可以改变struct对应的数据库表的名称通过sturct中field对应的Tag中使用`xorm:"'table_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况单引号也可以不使用。 通过`engine.Table()`方法可以改变struct对应的数据库表的名称通过sturct中field对应的Tag中使用`xorm:"'column_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况单引号也可以不使用。
<a name="23" id="23"></a> <a name="23" id="23"></a>
### 2.3.Column属性定义 ### 2.3.Column属性定义

View File

@ -40,7 +40,8 @@ type dialect interface {
// Engine is the major struct of xorm, it means a database manager. // Engine is the major struct of xorm, it means a database manager.
// Commonly, an application only need one engine // Commonly, an application only need one engine
type Engine struct { type Engine struct {
Mapper IMapper columnMapper IMapper
tableMapper IMapper
TagIdentifier string TagIdentifier string
DriverName string DriverName string
DataSourceName string DataSourceName string
@ -58,6 +59,19 @@ type Engine struct {
UseCache bool UseCache bool
} }
func (engine *Engine) SetMapper(mapper IMapper) {
engine.SetTableMapper(mapper)
engine.SetColumnMapper(mapper)
}
func (engine *Engine) SetTableMapper(mapper IMapper) {
engine.tableMapper = mapper
}
func (engine *Engine) SetColumnMapper(mapper IMapper) {
engine.columnMapper = mapper
}
// If engine's database support batch insert records like // If engine's database support batch insert records like
// "insert into user values (name, age), (name, age)". // "insert into user values (name, age), (name, age)".
// When the return is ture, then engine.Insert(&users) will // When the return is ture, then engine.Insert(&users) will
@ -396,13 +410,14 @@ func (engine *Engine) newTable() *Table {
table.Indexes = make(map[string]*Index) table.Indexes = make(map[string]*Index)
table.Columns = make(map[string]*Column) table.Columns = make(map[string]*Column)
table.ColumnsSeq = make([]string, 0) table.ColumnsSeq = make([]string, 0)
table.Created = make(map[string]bool)
table.Cacher = engine.Cacher table.Cacher = engine.Cacher
return table return table
} }
func (engine *Engine) mapType(t reflect.Type) *Table { func (engine *Engine) mapType(t reflect.Type) *Table {
table := engine.newTable() table := engine.newTable()
table.Name = engine.Mapper.Obj2Table(t.Name()) table.Name = engine.tableMapper.Obj2Table(t.Name())
table.Type = t table.Type = t
var idFieldColName string var idFieldColName string
@ -510,7 +525,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table {
col.Length2 = col.SQLType.DefaultLength2 col.Length2 = col.SQLType.DefaultLength2
} }
if col.Name == "" { if col.Name == "" {
col.Name = engine.Mapper.Obj2Table(t.Field(i).Name) col.Name = engine.columnMapper.Obj2Table(t.Field(i).Name)
} }
if indexType == IndexType { if indexType == IndexType {
if indexName == "" { if indexName == "" {
@ -542,7 +557,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table {
} }
} else { } else {
sqlType := Type2SQLType(fieldType) sqlType := Type2SQLType(fieldType)
col = &Column{engine.Mapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType, col = &Column{engine.columnMapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType,
sqlType.DefaultLength, sqlType.DefaultLength2, true, "", make(map[string]bool), false, false, sqlType.DefaultLength, sqlType.DefaultLength2, true, "", make(map[string]bool), false, false,
TWOSIDES, false, false, false, false} TWOSIDES, false, false, false, false}
} }

View File

@ -92,3 +92,39 @@ func titleCasedName(name string) string {
func (mapper SnakeMapper) Table2Obj(name string) string { func (mapper SnakeMapper) Table2Obj(name string) string {
return titleCasedName(name) return titleCasedName(name)
} }
// provide prefix table name support
type PrefixMapper struct {
Mapper IMapper
Prefix string
}
func (mapper PrefixMapper) Obj2Table(name string) string {
return mapper.Prefix + mapper.Mapper.Obj2Table(name)
}
func (mapper PrefixMapper) Table2Obj(name string) string {
return mapper.Mapper.Table2Obj(name[len(mapper.Prefix):])
}
func NewPrefixMapper(mapper IMapper, prefix string) PrefixMapper {
return PrefixMapper{mapper, prefix}
}
// provide suffix table name support
type SuffixMapper struct {
Mapper IMapper
Suffix string
}
func (mapper SuffixMapper) Obj2Table(name string) string {
return mapper.Suffix + mapper.Mapper.Obj2Table(name)
}
func (mapper SuffixMapper) Table2Obj(name string) string {
return mapper.Mapper.Table2Obj(name[len(mapper.Suffix):])
}
func NewSuffixMapper(mapper IMapper, suffix string) SuffixMapper {
return SuffixMapper{mapper, suffix}
}

View File

@ -1706,6 +1706,13 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
session.cacheInsert(session.Statement.TableName()) session.cacheInsert(session.Statement.TableName())
} }
if table.Version != "" && session.Statement.checkVersion {
verValue := table.VersionColumn().ValueOf(bean)
if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
}
}
if table.PrimaryKey == "" { if table.PrimaryKey == "" {
return res.RowsAffected() return res.RowsAffected()
} }
@ -1742,6 +1749,13 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
session.cacheInsert(session.Statement.TableName()) session.cacheInsert(session.Statement.TableName())
} }
if table.Version != "" && session.Statement.checkVersion {
verValue := table.VersionColumn().ValueOf(bean)
if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
}
}
if len(res) < 1 { if len(res) < 1 {
return 0, errors.New("insert no error but not returned id") return 0, errors.New("insert no error but not returned id")
} }
@ -1916,7 +1930,13 @@ func (session *Session) cacheUpdate(sql string, args ...interface{}) error {
if col, ok := table.Columns[colName]; ok { if col, ok := table.Columns[colName]; ok {
fieldValue := col.ValueOf(bean) fieldValue := col.ValueOf(bean)
session.Engine.LogDebug("[xorm:cacheUpdate] set bean field", bean, colName, fieldValue.Interface()) session.Engine.LogDebug("[xorm:cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
fieldValue.Set(reflect.ValueOf(args[idx])) if col.IsVersion && session.Statement.checkVersion {
fieldValue.SetInt(fieldValue.Int() + 1)
fmt.Println("-----", fieldValue)
} else {
fieldValue.Set(reflect.ValueOf(args[idx]))
fmt.Println("xxxxxx", fieldValue)
}
} else { } else {
session.Engine.LogError("[xorm:cacheUpdate] ERROR: column %v is not table %v's", session.Engine.LogError("[xorm:cacheUpdate] ERROR: column %v is not table %v's",
colName, table.Name) colName, table.Name)
@ -2001,27 +2021,38 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
st := session.Statement st := session.Statement
defer session.Statement.Init() defer session.Statement.Init()
if st.WhereStr != "" { if st.WhereStr != "" {
condition = fmt.Sprintf("WHERE %v", st.WhereStr) condition = fmt.Sprintf("%v", st.WhereStr)
} }
if condition == "" { if condition == "" {
if len(condiColNames) > 0 { if len(condiColNames) > 0 {
condition = fmt.Sprintf("WHERE %v ", strings.Join(condiColNames, " and ")) condition = fmt.Sprintf("%v", strings.Join(condiColNames, " AND "))
} }
} else { } else {
if len(condiColNames) > 0 { if len(condiColNames) > 0 {
condition = fmt.Sprintf("%v and %v", condition, strings.Join(condiColNames, " and ")) condition = fmt.Sprintf("(%v) AND (%v)", condition, strings.Join(condiColNames, " AND "))
} }
} }
var sql string var sql string
if table.Version != "" { if table.Version != "" && session.Statement.checkVersion {
if condition != "" {
condition = fmt.Sprintf("WHERE (%v) AND %v = ?", condition,
session.Engine.Quote(table.Version))
} else {
condition = fmt.Sprintf("WHERE %v = ?", session.Engine.Quote(table.Version))
}
sql = fmt.Sprintf("UPDATE %v SET %v, %v %v", sql = fmt.Sprintf("UPDATE %v SET %v, %v %v",
session.Engine.Quote(session.Statement.TableName()), session.Engine.Quote(session.Statement.TableName()),
strings.Join(colNames, ", "), strings.Join(colNames, ", "),
session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1", session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1",
condition) condition)
condiArgs = append(condiArgs, table.VersionColumn().ValueOf(bean).Interface())
} else { } else {
if condition != "" {
condition = "WHERE " + condition
}
sql = fmt.Sprintf("UPDATE %v SET %v %v", sql = fmt.Sprintf("UPDATE %v SET %v %v",
session.Engine.Quote(session.Statement.TableName()), session.Engine.Quote(session.Statement.TableName()),
strings.Join(colNames, ", "), strings.Join(colNames, ", "),
@ -2034,6 +2065,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
if err != nil { if err != nil {
return 0, err return 0, err
} }
if table.Cacher != nil && session.Statement.UseCache { if table.Cacher != nil && session.Statement.UseCache {
session.cacheUpdate(sql, args...) session.cacheUpdate(sql, args...)
} }

View File

@ -37,6 +37,7 @@ type Statement struct {
UseAutoTime bool UseAutoTime bool
IsDistinct bool IsDistinct bool
allUseBool bool allUseBool bool
checkVersion bool
boolColumnMap map[string]bool boolColumnMap map[string]bool
} }
@ -65,6 +66,7 @@ func (statement *Statement) Init() {
statement.IsDistinct = false statement.IsDistinct = false
statement.allUseBool = false statement.allUseBool = false
statement.boolColumnMap = make(map[string]bool) statement.boolColumnMap = make(map[string]bool)
statement.checkVersion = true
} }
// add the raw sql statement // add the raw sql statement
@ -164,7 +166,7 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, includeVers
case reflect.Struct: case reflect.Struct:
if fieldType == reflect.TypeOf(time.Now()) { if fieldType == reflect.TypeOf(time.Now()) {
t := fieldValue.Interface().(time.Time) t := fieldValue.Interface().(time.Time)
if t.IsZero() { if t.IsZero() || !fieldValue.IsValid() {
continue continue
} }
var str string var str string

View File

@ -272,17 +272,31 @@ type Table struct {
Columns map[string]*Column Columns map[string]*Column
Indexes map[string]*Index Indexes map[string]*Index
PrimaryKey string PrimaryKey string
Created string Created map[string]bool
Updated string Updated string
Version string Version string
Cacher Cacher Cacher Cacher
} }
/*
func NewTable(name string, t reflect.Type) *Table {
return &Table{Name: name, Type: t,
ColumnsSeq: make([]string, 0),
Columns: make(map[string]*Column),
Indexes: make(map[string]*Index),
Created: make(map[string]bool),
}
}*/
// if has primary key, return column // if has primary key, return column
func (table *Table) PKColumn() *Column { func (table *Table) PKColumn() *Column {
return table.Columns[table.PrimaryKey] return table.Columns[table.PrimaryKey]
} }
func (table *Table) VersionColumn() *Column {
return table.Columns[table.Version]
}
// add a column to table // add a column to table
func (table *Table) AddColumn(col *Column) { func (table *Table) AddColumn(col *Column) {
table.ColumnsSeq = append(table.ColumnsSeq, col.Name) table.ColumnsSeq = append(table.ColumnsSeq, col.Name)
@ -291,7 +305,7 @@ func (table *Table) AddColumn(col *Column) {
table.PrimaryKey = col.Name table.PrimaryKey = col.Name
} }
if col.IsCreated { if col.IsCreated {
table.Created = col.Name table.Created[col.Name] = true
} }
if col.IsUpdated { if col.IsUpdated {
table.Updated = col.Name table.Updated = col.Name
@ -311,7 +325,7 @@ func (table *Table) genCols(session *Session, bean interface{}, useCol bool, inc
args := make([]interface{}, 0) args := make([]interface{}, 0)
for _, col := range table.Columns { for _, col := range table.Columns {
if useCol { if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
if _, ok := session.Statement.columnMap[col.Name]; !ok { if _, ok := session.Statement.columnMap[col.Name]; !ok {
continue continue
} }
@ -338,6 +352,8 @@ func (table *Table) genCols(session *Session, bean interface{}, useCol bool, inc
if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime { if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
args = append(args, time.Now()) args = append(args, time.Now())
} else if col.IsVersion && session.Statement.checkVersion {
args = append(args, 1)
} else { } else {
arg, err := session.value2Interface(col, fieldValue) arg, err := session.value2Interface(col, fieldValue)
if err != nil { if err != nil {

View File

@ -20,8 +20,9 @@ func close(engine *Engine) {
// new a db manager according to the parameter. Currently support four // new a db manager according to the parameter. Currently support four
// drivers // drivers
func NewEngine(driverName string, dataSourceName string) (*Engine, error) { func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
engine := &Engine{DriverName: driverName, Mapper: SnakeMapper{}, engine := &Engine{DriverName: driverName,
DataSourceName: dataSourceName, Filters: make([]Filter, 0)} DataSourceName: dataSourceName, Filters: make([]Filter, 0)}
engine.SetMapper(SnakeMapper{})
if driverName == SQLITE { if driverName == SQLITE {
engine.dialect = &sqlite3{} engine.dialect = &sqlite3{}