diff --git a/.gitignore b/.gitignore index 4d7cf444..98008af1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ _testmain.go *.exe vendor + +*.log diff --git a/base_test.go b/base_test.go index 4ef655b1..365fd240 100644 --- a/base_test.go +++ b/base_test.go @@ -339,16 +339,25 @@ func testdelete(engine *Engine, t *testing.T) { panic(err) } - _, err = engine.Id(2).Get(&user) + user.Uid = 0 + has, err := engine.Id(3).Get(&user) if err != nil { t.Error(err) panic(err) } - _, err = engine.Delete(&user) - if err != nil { - t.Error(err) - panic(err) + if has { + //var tt time.Time + //user.Created = tt + cnt, err := engine.UseBool().Delete(&user) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + t.Error(errors.New("delete failed")) + panic(err) + } } } @@ -937,8 +946,8 @@ type allCols struct { Text string `xorm:"TEXT"` MediumText string `xorm:"MEDIUMTEXT"` LongText string `xorm:"LONGTEXT"` - Binary string `xorm:"BINARY"` - VarBinary string `xorm:"VARBINARY(12)"` + Binary []byte `xorm:"BINARY(23)"` + VarBinary []byte `xorm:"VARBINARY(12)"` Date time.Time `xorm:"DATE"` DateTime time.Time `xorm:"DATETIME"` @@ -976,6 +985,79 @@ func testColTypes(engine *Engine, t *testing.T) { t.Error(err) panic(err) } + + ac := &allCols{ + 1, + 4, + 8, + 16, + 32, + 64, + 128, + + "123", + "fafdafa", + "fafafafdsafdsafdaf", + "fdsafafdsafdsaf", + "fafdsafdsafdsfadasfsfafd", + "fadfdsafdsafasfdasfds", + []byte("fdafsafdasfdsafsa"), + []byte("fdsafsdafs"), + + time.Now(), + time.Now(), + time.Now(), + time.Now(), + + 1.34, + 2.44302346, + + 1.3344, + 2.59693523, + 3.2342523543, + + []byte("fafdasf"), + []byte("fafdfdsafdsafasf"), + []byte("faffadsfdsdasf"), + []byte("faffdasfdsadasf"), + []byte("fafasdfsadffdasf"), + + true, + + 21, + } + + _, err = engine.Insert(ac) + if err != nil { + t.Error(err) + panic(err) + } + newAc := &allCols{} + has, err := engine.Get(newAc) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + err = errors.New("error no ideas") + t.Error(err) + panic(err) + } + + // don't use this type as query condition + newAc.Real = 0 + newAc.Float = 0 + newAc.Double = 0 + cnt, err := engine.Delete(newAc) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("delete error") + t.Error(err) + panic(err) + } } type MyInt int @@ -1068,6 +1150,18 @@ func testCustomType(engine *Engine, t *testing.T) { panic(err) } fmt.Println(sss) + + if has { + cnt, err := engine.Delete(&sss) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + t.Error(errors.New("delete error")) + panic(err) + } + } } type UserCU struct { diff --git a/cache.go b/cache.go index c16fe15b..9fcbcdef 100644 --- a/cache.go +++ b/cache.go @@ -136,6 +136,8 @@ func (m *LRUCacher) RunGC() { // GC check ids lit and sql list to remove all element expired func (m *LRUCacher) GC() { + //fmt.Println("begin gc ...") + //defer fmt.Println("end gc ...") m.mutex.Lock() defer m.mutex.Unlock() var removedNum int @@ -149,10 +151,12 @@ func (m *LRUCacher) GC() { m.delBean(node.tbName, node.id) e = next } else { + //fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.idList.Len()) break } } + removedNum = 0 for e := m.sqlList.Front(); e != nil; { if removedNum <= CacheGcMaxRemoved && time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired { @@ -160,9 +164,10 @@ func (m *LRUCacher) GC() { next := e.Next() //fmt.Println("removing ...", e.Value) node := e.Value.(*sqlNode) - m.DelIds(node.tbName, node.sql) + m.delIds(node.tbName, node.sql) e = next } else { + //fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.sqlList.Len()) break } } @@ -322,8 +327,8 @@ func (m *LRUCacher) DelIds(tableName, sql string) { func (m *LRUCacher) delBean(tableName string, id int64) { tid := genId(tableName, id) - if el, ok := m.idIndex[tableName][tid]; ok { - delete(m.idIndex[tableName], tid) + if el, ok := m.idIndex[tableName][id]; ok { + delete(m.idIndex[tableName], id) m.idList.Remove(el) m.clearIds(tableName) } diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 8d13f57c..03b6a256 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -506,13 +506,14 @@ engine.ClearCache(new(User)) ## 14.案例 +* [Gowalker](http://gowalker.org),源代码 [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) + * [GoDaily Go语言学习网站](http://godaily.org),源代码 [github.com/govc/godaily](http://github.com/govc/godaily) * [Sudochina](http://sudochina.com) 和对应的源代码[github.com/insionng/toropress](http://github.com/insionng/toropress) * [VeryHour](http://veryhour.com) - ## 15.讨论 请加入QQ群:280360085 进行讨论。 diff --git a/session.go b/session.go index 63e87219..9784c3b1 100644 --- a/session.go +++ b/session.go @@ -575,8 +575,8 @@ func (session *Session) cacheFind(t reflect.Type, sql string, rowsSlicePtr inter return err } // 查询数目太大,采用缓存将不是一个很好的方式。 - if len(resultsSlice) > 100 { - session.Engine.LogDebug("[xorm:cacheFind] ids length %v > 100, no cache", len(resultsSlice)) + if len(resultsSlice) > 500 { + session.Engine.LogDebug("[xorm:cacheFind] ids length %v > 500, no cache", len(resultsSlice)) return ErrCacheFailed } @@ -1155,29 +1155,31 @@ func row2map(rows *sql.Rows, fields []string) (resultsMap map[string][]byte, err case reflect.Float32, reflect.Float64: str = strconv.FormatFloat(vv.Float(), 'f', -1, 64) result[key] = []byte(str) + case reflect.String: + str = vv.String() + result[key] = []byte(str) case reflect.Array, reflect.Slice: switch aa.Elem().Kind() { case reflect.Uint8: result[key] = rawValue.Interface().([]byte) + str = string(result[key]) default: - //session.Engine.LogError("Unsupported type") + return nil, errors.New(fmt.Sprintf("Unsupported struct type %v", vv.Type().Name())) } - case reflect.String: - str = vv.String() - result[key] = []byte(str) //时间类型 case reflect.Struct: if aa.String() == "time.Time" { - str = rawValue.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700") + str = rawValue.Interface().(time.Time).Format("2006-01-02 15:04:05.000000 -0700") result[key] = []byte(str) } else { return nil, errors.New(fmt.Sprintf("Unsupported struct type %v", vv.Type().Name())) } case reflect.Bool: - str := strconv.FormatBool(vv.Bool()) + str = strconv.FormatBool(vv.Bool()) result[key] = []byte(str) case reflect.Complex128, reflect.Complex64: - result[key] = []byte(fmt.Sprintf("%v", vv.Complex())) + str = fmt.Sprintf("%v", vv.Complex()) + result[key] = []byte(str) /* TODO: unsupported types below case reflect.Map: case reflect.Ptr: @@ -1488,14 +1490,30 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data fieldValue.SetString(string(data)) case reflect.Bool: d := string(data) - //fmt.Println("------", d, "-------") v, err := strconv.ParseBool(d) if err != nil { return errors.New("arg " + key + " as bool: " + err.Error()) } fieldValue.Set(reflect.ValueOf(v)) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - x, err := strconv.ParseInt(string(data), 10, 64) + sdata := string(data) + var x int64 + var err error + if col.SQLType.Name == Bit && + strings.Contains(session.Engine.DriverName, "mysql") { + if len(data) == 1 { + x = int64(data[0]) + } else { + x = 0 + } + fmt.Println("######", x, data) + } else if strings.HasPrefix(sdata, "0x") { + x, err = strconv.ParseInt(sdata, 16, 64) + } else if strings.HasPrefix(sdata, "0") { + x, err = strconv.ParseInt(sdata, 8, 64) + } else { + x, err = strconv.ParseInt(sdata, 10, 64) + } if err != nil { return errors.New("arg " + key + " as int: " + err.Error()) } @@ -1515,13 +1533,24 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data //Now only support Time type case reflect.Struct: if fieldValue.Type().String() == "time.Time" { - x, err := time.Parse("2006-01-02 15:04:05", string(data)) - if err != nil { - x, err = time.Parse("2006-01-02 15:04:05.000 -0700", string(data)) - - if err != nil { - return errors.New("unsupported time format: " + string(data)) + sdata := string(data) + var x time.Time + var err error + if len(sdata) > 19 { + x, err = time.Parse("2006-01-02 15:04:05.000000 -0700", sdata) + } else if len(sdata) == 19 { + x, err = time.Parse("2006-01-02 15:04:05", sdata) + } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { + x, err = time.Parse("2006-01-02", sdata) + } else if col.SQLType.Name == Time { + if len(sdata) > 8 { + sdata = sdata[len(sdata)-8:] } + st := "2012-03-04 " + sdata + x, err = time.Parse("2006-01-02 15:04:05", st) + } + if err != nil { + return errors.New(fmt.Sprintf("unsupported time format %v: %v", string(data), err)) } v = x @@ -1584,8 +1613,15 @@ func (session *Session) value2Interface(col *Column, fieldValue reflect.Value) ( return fieldValue.String(), nil case reflect.Struct: if fieldValue.Type().String() == "time.Time" { - //return fieldValue.Interface().(time.Time).Format(time.RFC3339Nano), nil - //return fieldValue.Interface().(time.Time).Format("2006-01-02 15:04:05 -0700"), nil + if col.SQLType.Name == Time { + return fieldValue.Interface().(time.Time).Format("2006-01-02 15:04:05"), nil + } else if col.SQLType.Name == Date { + return fieldValue.Interface().(time.Time).Format("2006-01-02"), nil + } + // crying... + if session.Engine.DriverName == POSTGRES { + return fieldValue.Interface().(time.Time).Format("2006-01-02 15:04:05.000000 -0700"), nil + } return fieldValue.Interface(), nil } if fieldTable, ok := session.Engine.Tables[fieldValue.Type()]; ok { diff --git a/statement.go b/statement.go index 94daa433..c91dc8c6 100644 --- a/statement.go +++ b/statement.go @@ -155,7 +155,15 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, includeVers if t.IsZero() { continue } - val = t + var str string + if col.SQLType.Name == Time { + str = strings.Split(t.Format("2006-01-02 15:04:05"), " ")[1] + } else if col.SQLType.Name == Date { + str = t.Format("2006-01-02") + } else { + str = t.Format("2006-01-02 15:04:05.000000 -0700") + } + val = str } else { engine.AutoMapType(fieldValue.Type()) if table, ok := engine.Tables[fieldValue.Type()]; ok { @@ -189,7 +197,11 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, includeVers var err error if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) && fieldType.Elem().Kind() == reflect.Uint8 { - val = fieldValue.Bytes() + if fieldValue.Len() > 0 { + val = fieldValue.Bytes() + } else { + continue + } } else { bytes, err = json.Marshal(fieldValue.Interface()) if err != nil { @@ -289,6 +301,11 @@ func (statement *Statement) Omit(columns ...string) { statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", "))) } +func (statement *Statement) Top(limit int) *Statement { + statement.Limit(limit) + return statement +} + func (statement *Statement) Limit(limit int, start ...int) { statement.LimitN = limit if len(start) > 0 { diff --git a/xorm.go b/xorm.go index 9a6c30b5..80d17fe5 100644 --- a/xorm.go +++ b/xorm.go @@ -10,7 +10,7 @@ import ( ) const ( - version string = "0.2.0" + version string = "0.2.2" ) func close(engine *Engine) {