├── logo.jpg ├── marsharl_driver_sql.go ├── params_test.go ├── LICENSE ├── cache_serve.go ├── rows.go ├── README.md ├── docs └── mode.md ├── cache_test.go ├── cache_driver_redis.go ├── marsharl_driver_sqlite.go ├── marsharl_driver_mysql.go ├── marsharl_driver_postgres.go ├── consistent.go ├── params.go ├── mode.go └── cache.go /logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/server-nado/orm/HEAD/logo.jpg -------------------------------------------------------------------------------- /marsharl_driver_sql.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | type driversqlType func(param ParamsInterface) ModuleToSql 4 | 5 | var driversql = map[string]driversqlType{ 6 | "mysql": func(param ParamsInterface) ModuleToSql { return MysqlModeToSql{param} }, 7 | "sqlite": func(param ParamsInterface) ModuleToSql { return SqliteModeToSql{param} }, 8 | } 9 | 10 | func NewMarsharlDriverSql(driverName string, fun driversqlType) { 11 | driversql[driverName] = fun 12 | } 13 | 14 | type ModuleToSql interface { 15 | Select() (sql string, val []interface{}) 16 | Delete() (sql string, val []interface{}) 17 | Update() (sql string, val []interface{}) 18 | Insert() (sql string, val []interface{}) 19 | Count() (sql string, val []interface{}) 20 | Instance(ParamsInterface) 21 | } 22 | -------------------------------------------------------------------------------- /params_test.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import "testing" 4 | import "time" 5 | import "fmt" 6 | 7 | func Test_execSelect(t *testing.T) { 8 | OpenSyncUpdate = true 9 | 10 | params := Params{} 11 | params.SetField("a", "b", "c") 12 | params.SetTable("eeesfsfe") 13 | 14 | params.Filter("field__gt", 1) 15 | params.Filter("bbb__lt", 2) 16 | params.Change("a", 1) 17 | params.Change("b__sub", 1) 18 | params.Change("c__div", 1) 19 | //t.Log(params.execSelect()) 20 | str, _ := driversql["mysql"](params).Select() 21 | t.Log(str) 22 | str, _ = driversql["mysql"](params).Delete() 23 | t.Log(str) 24 | str, _ = driversql["mysql"](params).Insert() 25 | t.Log(str) 26 | go func() { 27 | sql := <-SqlSyncHook 28 | fmt.Println("SYNC ", sql) 29 | }() 30 | str, _ = driversql["mysql"](params).Update() 31 | t.Log(str) 32 | str, _ = driversql["mysql"](params).Count() 33 | t.Log(str) 34 | time.Sleep(2) 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Able 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /cache_serve.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | var cacheConsistent = NewConsistent() 4 | var cacheconn Cache 5 | 6 | //是否启用cache 的hash分布支持, 为不支持分布式集群的redis 2.x和其他cache缓存设置true 7 | var use_hash_cache bool = false 8 | 9 | func UseHashCache(b bool) { 10 | use_hash_cache = b 11 | } 12 | 13 | // 设置 cache 地址 14 | func AddCacheAddress(address, password string) { 15 | cacheconn = NewRedisCache(address, password) 16 | } 17 | func SetCacheAddress(keys []string, password string) { 18 | 19 | cacheconn = NewRedisCache(keys[0], password) 20 | 21 | } 22 | 23 | func DelCacheAddress(key string) { 24 | 25 | } 26 | 27 | var ( 28 | getCache = make(chan *comandGetCacheConn) 29 | 30 | updateCache = make(chan []string) 31 | CacheServer = map[string]Cache{} 32 | ) 33 | 34 | //获取目标地址的功能 35 | type comandGetCacheConn struct { 36 | Key string 37 | Call chan Cache 38 | } 39 | 40 | func init() { 41 | 42 | //go goCacheRuntime() 43 | 44 | } 45 | 46 | //守护服务 47 | func goCacheRuntime() { 48 | if use_hash_cache == false { 49 | return 50 | } 51 | /* 52 | for { 53 | select { 54 | case mapping := <-updateCache: 55 | cacheConsistent.Set(mapping) 56 | case t := <-getCache: 57 | addr, err := getCacheAddrByKey(t.Key) 58 | if err != nil { 59 | t.Call <- nil 60 | return 61 | } 62 | client, ok := CacheServer[addr] 63 | if !ok { 64 | client = NewRedisCache(addr) 65 | CacheServer[addr] = client 66 | } 67 | t.Call <- client 68 | 69 | } 70 | }*/ 71 | } 72 | 73 | //通过一致性hash服务, 得到当前key应该分配给哪个redis服务器 74 | func getCacheAddrByKey(key string) (string, error) { 75 | return cacheConsistent.Get(key) 76 | } 77 | 78 | func GetCacheClient(key string) Cache { 79 | if use_hash_cache == false { 80 | return cacheconn 81 | } 82 | return nil 83 | } 84 | -------------------------------------------------------------------------------- /rows.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "database/sql" 5 | "reflect" 6 | ) 7 | 8 | type Rows interface { 9 | Next() bool 10 | Scan(Module) error 11 | Close() error 12 | } 13 | 14 | type CacheRows struct { 15 | cache Cache 16 | keys []string 17 | dbName string 18 | index int 19 | key string 20 | } 21 | 22 | func (self *CacheRows) Next() bool { 23 | defer func() { 24 | self.index = self.index + 1 25 | self.keys = self.keys[len(self.keys):] 26 | }() 27 | 28 | if len(self.keys) > self.index { 29 | self.key = self.keys[self.index] 30 | return true 31 | } else { 32 | return false 33 | } 34 | } 35 | 36 | func (self *CacheRows) Close() error { 37 | self.keys = nil 38 | self.cache = nil 39 | return nil 40 | } 41 | 42 | func (self *CacheRows) Scan(mode Module) error { 43 | typ := reflect.TypeOf(mode).Elem() 44 | val := reflect.ValueOf(mode).Elem() 45 | 46 | err := self.cache.key2Mode(self.key, typ, val) 47 | if err != nil { 48 | Error.Println(err) 49 | return err 50 | } 51 | m := CacheHook{} 52 | m.Objects(val.Addr().Interface().(Module), self.dbName).Existed() 53 | val.FieldByName("CacheHook").Set(reflect.ValueOf(m)) 54 | 55 | return nil 56 | } 57 | 58 | type ModeRows struct { 59 | rows *sql.Rows 60 | val []interface{} 61 | dbName string 62 | } 63 | 64 | func (self *ModeRows) Next() bool { 65 | return self.rows.Next() 66 | } 67 | 68 | func (self *ModeRows) Close() error { 69 | defer func() { 70 | self.rows = nil 71 | }() 72 | err := self.rows.Close() 73 | if err != nil { 74 | return err 75 | } 76 | return nil 77 | } 78 | 79 | func (self *ModeRows) Scan(mode Module) (err error) { 80 | if self.val == nil { 81 | self.val = []interface{}{} 82 | } 83 | self.val = self.val[len(self.val):] 84 | defer func() { 85 | self.val = self.val[len(self.val):] 86 | }() 87 | m := reflect.ValueOf(mode).Elem() 88 | typ := reflect.TypeOf(mode).Elem() 89 | for i := 0; i < m.NumField(); i++ { 90 | if name := typ.Field(i).Tag.Get("field"); len(name) > 0 { 91 | self.val = append(self.val, m.Field(i).Addr().Interface()) 92 | } 93 | } 94 | err = self.rows.Scan(self.val...) 95 | if err != nil { 96 | return 97 | } 98 | if field := m.FieldByName("CacheHook"); field.IsValid() { 99 | obj := CacheHook{} 100 | obj.Objects(m.Addr().Interface().(Module), self.dbName).Existed() 101 | obj.SaveToCache() 102 | field.Set(reflect.ValueOf(obj)) 103 | 104 | } else { 105 | 106 | obj := DBHook{} //Object(m.Interface().(Module)) 107 | obj.Objects(m.Addr().Interface().(Module), self.dbName).Existed() 108 | m.FieldByName("DBHook").Set(reflect.ValueOf(obj)) 109 | } 110 | return 111 | } 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##About 2 | 3 | ![server-nado/orm](./logo.jpg) 4 | 5 | 一个数据库ORM. 6 | 7 | ## How to use? 8 | 9 | ### Insert 10 | go get github.com/server-nado/orm 11 | 12 | 13 | 14 | ## Super database 15 | 16 | sqlite3 "github.com/mattn/go-sqlite3" 17 | mysql "github.com/go-sql-driver/mysql" 18 | postgree "github.com/lib/pq" 19 | 20 | ##数据库DBHook 建立方法 21 | 22 | //引用模块 23 | import "github.com/server-nado/orm" 24 | 25 | //mysql 驱动 26 | import _ "github.com/go-sql-driver/mysql" 27 | 28 | //建立连接 29 | // 参数分别为 名称 , 驱动, 连接字符串 30 | // 注:必须包含一个default 连接, 作为默认连接。 31 | orm.NewDatabase("default" , "mysql" , "user:passwd@ip/database?charset=utf8&parseTime=true") 32 | 33 | 34 | 35 | //建立一个数据模型。 36 | type UserInfo struct**** { 37 | orm.DBHook 38 | Id int64 `field:"id" auto:"true" index:"pk"` 39 | Name string `field:"username"` 40 | Passwd string `field:"password"` 41 | } 42 | 43 | 44 | 45 | //读写分离: 46 | orm.NewDatabase("write-conname" , "mysql" , "user:passwd@tcp(ip:port)/database?charset=utf8&parseTime=true") 47 | orm.NewDatabase("read-conname" , "mysql" , "user:passwd@tcp(ip:port)/database?charset=utf8&parseTime=true") 48 | orm.SetWriteConnectName("write-conname") 49 | orm.SetReadConnectName("read-conname") 50 | 51 | 52 | 53 | //Cache (Redis) 54 | 55 | orm.AddCacheAddress("127.0.0.1:6379","PASSWD") //缓存服务器地址 56 | 57 | 58 | 59 | 60 | [更多信息>>](docs/mode.md) 61 | 62 | ##新增 CacheHook 模型, 支持分布式redis作为数据库缓存。 63 | 64 | import "github.com/server-nado/orm" 65 | import _ "github.com/go-sql-driver/mysql" 66 | 67 | type userB struct { 68 | orm.CacheHook 69 | Uid int64 `field:"Id" index:"pk" cache:"user" ` 70 | Alias string `field:"Alias"` 71 | Money int64 `field:"money" ` 72 | } 73 | 74 | func main(){ 75 | orm.AddCacheAddress("127.0.0.1:6379",PASSWD) //添加多个redis服务器 76 | orm.SetCachePrefix("nado") //默认nado . 将作为redis key 的前缀 77 | orm.NewDatabase("default", "mysql", "happy:passwd@tcp(127.0.0.1:3306)/mydatabase?charset=utf8&parseTime=true") 78 | 79 | orm.SetCachePrefix("nado") //cache 前缀。 80 | orm.SetDebug(false) //true 是否开启调试模式 81 | 82 | 83 | 84 | b := new(userB) 85 | b.Uid = 10000 86 | err:=b.Objects(b).One() 87 | if err!= nil { 88 | panic(err) 89 | } 90 | fmt.Println(b.Uid ,b.Alias ,b.Money) 91 | 92 | b.Incrby("Money" , 100) 93 | fmt.Println(b.Money) 94 | b.Save() //不执行不会保存到数据库 只会修改redis数据。 95 | 96 | //查询id小于10的所有数据 97 | user := new(userB) 98 | users := []*userB{} 99 | if err := user.Objects(user).Filter("Uid__lt",10).All(&users); err == nil{ 100 | for _,u:= range users{ 101 | fmt.Println(u.Uid , u.Alias) 102 | } 103 | } 104 | } 105 | 106 | ##一些说明, 这个ORM的目的: 107 | 108 | 1. 简化数据库操作方式 109 | 2. 降低数据库的操作压力 110 | 111 | 比较适合出现频繁,高性能要求的数据库读写操作。 使用CacheHook 模式操作数据时, 大多数情况下,热数据会被导入到缓存,这样的情况下, mysql的度频率会降低,读速度会提高很多,同时, 使用Set或者Incry等方式修改数据, 写速度会大大提升。 112 | -------------------------------------------------------------------------------- /docs/mode.md: -------------------------------------------------------------------------------- 1 | 2 | ### 例子 3 | 4 | //引用模块 5 | import "github.com/ablegao/orm" 6 | 7 | //mysql 驱动 8 | import _ "github.com/go-sql-driver/mysql" 9 | 10 | //建立连接 11 | // 参数分别为 名称 , 驱动, 连接字符串 12 | // 注:必须包含一个default 连接, 作为默认连接。 13 | orm.NewDatabase("default" , "mysql" , "user:passwd@ip/database?charset=utf8") 14 | 15 | 16 | //建立一个数据模型。 17 | type UserInfo struct { 18 | orm.Object 19 | Id int64 `field:"id" index:"pk"` 20 | Name string `field:"username"` 21 | Passwd string `field:"password"` 22 | } 23 | 24 | //数据库表名称 25 | func(self *UserInfo) GetTableName()string{ 26 | 27 | return "database.user_info" 28 | } 29 | 30 | //查询一个用户名为 "test1"的账户 31 | user:=new(UserInfo) 32 | err:=user.Objects(user).Filter("Name","test1").One() 33 | fmt.Println(user.Id , user.Passwd , user.Name) 34 | 35 | //Update 36 | user.Name="test2" 37 | user.Objects(user).Save() 38 | // or 39 | user.Objects(user).Filter("Id" , 1).Change("Name" , "test2").Save() 40 | 41 | 42 | //查询id小于10的所有数据 43 | user := new(UserInfo) 44 | users := []*UserInfo{} 45 | if err:=user.Objects(user).Filter("Id__lt",10).All(&users);err==nil{ 46 | for _,u:= range users{ 47 | fmt.Println(u.Id , u.Passwd , u.Name) 48 | } 49 | } 50 | 51 | //Create 52 | user:=new(UserInfo) 53 | user.Name ="test1" 54 | user.Passwd ="123456" 55 | id , err:=user.Objects(user).Save() 56 | 57 | 58 | 59 | //delete 60 | user.Objects(user).Delete() 61 | 62 | // User other Database connect 63 | orm.NewDatabase("other" , "mysql" , "user:passwd@ip/database?charset=utf8") 64 | user.Objects(user).Db("other").Filter(x ,x).Delete() 65 | // or 66 | user.Objects(user).Filter().Db("other").XXX() 67 | 68 | ## Filter or FilterOr 69 | .Filter(fieldname , val ) 70 | 71 | Filter 作为orm 的主要作用是过滤查询条件, 最终将会转换为sql 语句中的where 条件语句。 可以填写多次, 多次数据为and 关系 72 | 73 | FilterOr 作为Orm 的主要过滤查询条件, 最终将妆化为sql 语句的where 条件语句 , 可以填写多次, 多次数据以 or 连接 74 | 75 | user.Objects(user).Filter("Name" , "test1").FilterOr("Name" , "test2").All() 76 | //select id,username,passwd from database.user_info where username='test1' or username='test2' 77 | 78 | ##关于Filter字段的魔法参数 79 | 80 | ###目前支持: 81 | __exact 精确等于 like 'aaa' 82 | __iexact 精确等于 忽略大小写 ilike 'aaa' 83 | __contains 包含 like '%aaa%' 84 | __icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。 85 | __gt 大于 86 | __gte 大于等于 87 | __ne 不等于 88 | __lt 小于 89 | __lte 小于等于 90 | __startswith 以...开头 91 | __istartswith 以...开头 忽略大小写 92 | __endswith 以...结尾 93 | __iendswith 以...结尾,忽略大小写 94 | 95 | ###尚未支持: 96 | __in 存在于一个list范围内 97 | __range 在...范围内 98 | __year 日期字段的年份 99 | __month 日期字段的月份 100 | __day 日期字段的日 101 | __isnull=True/False 102 | 103 | 104 | ##Change 105 | 106 | 修改数据, 执行时,相当于 sql 语句中的set 107 | 108 | 传入一个结构字段 和值 109 | .Change("Field" , 1) 110 | 111 | update from xxx set field=1 112 | 113 | 可以添加魔法参数: 114 | 115 | .Change("Field__add" ,1 ) 116 | update from xxx set field=field+1 117 | 118 | __add 累加 field=field+1 119 | __sub 累减 field=field-1 120 | __mult 累乘 field=field*1 121 | __div 累计出发 field=field/1 122 | -------------------------------------------------------------------------------- /cache_test.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | //"time" 8 | 9 | _ "github.com/go-sql-driver/mysql" 10 | ) 11 | 12 | func init() { 13 | 14 | db, err := NewDatabase("default", "mysql", "root:@tcp(127.0.0.1:3306)/test?charset=utf8&parseTime=true") 15 | if err != nil { 16 | panic(err) 17 | } 18 | SetDebug(true) 19 | AddCacheAddress("127.0.0.1:6379", "") 20 | SetDefaultCacheDb(0) 21 | db.Exec("create table if not exists `user_disk`(id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, Alias varchar(255) NOT NULL default '', Lingshi BIGINT NOT NULL default 0) ") 22 | } 23 | 24 | type userB struct { 25 | CacheHook 26 | Uid int64 `field:"Id" index:"pk" cache:"user" ` 27 | Alias string `field:"Alias"` 28 | Lingshi int64 `field:"Lingshi"` 29 | //LogoutTime time.Time `field:"updated_at"` 30 | } 31 | type userA struct { 32 | DBHook 33 | Uid int64 `field:"Id" index:"pk" cache:"user" ` 34 | Alias string `field:"Alias"` 35 | Lingshi int64 `field:"Lingshi"` 36 | //LogoutTime time.Time `field:"updated_at"` 37 | } 38 | 39 | func (self *userB) GetTableName() string { 40 | return "user_disk" 41 | } 42 | func (self *userA) GetTableName() string { 43 | return "user_disk" 44 | } 45 | 46 | func Test_connect(t *testing.T) { 47 | OpenSyncUpdate = true 48 | OpenSyncDelete = true 49 | b := new(userB) 50 | 51 | users := []*userB{} 52 | b.Objects(b).Limit(1, 10).All(&users) 53 | 54 | for _, user := range users { 55 | t.Log(user) 56 | user.Incrby("Lingshi", 1) 57 | user.Save() 58 | 59 | //t.Log(user.Uid, user.Lingshi) 60 | //user.Incrby("Lingshi", 1) 61 | //t.Log(user.Uid, user.Lingshi) 62 | //go user.Save() 63 | user.Delete() 64 | } 65 | for i := 0; i < len(users); i++ { 66 | println(i) 67 | sql := <-SqlSyncHook 68 | t.Log(sql) 69 | } 70 | } 71 | 72 | func Test_alias(t *testing.T) { 73 | OpenSyncUpdate = false 74 | OpenSyncDelete = false 75 | b := new(userA) 76 | rows, _ := b.Objects(b).Query() 77 | for rows.Next() { 78 | nb := new(userA) 79 | err := rows.Scan(nb) 80 | t.Log(err, nb.Uid, nb.Lingshi) 81 | } 82 | } 83 | 84 | func Test_Delete(t *testing.T) { 85 | b := new(userB) 86 | b.Uid = 10000 87 | b.Objects(b).One() 88 | //b.Incrby("Lingshi", 1) 89 | b.Delete() 90 | } 91 | 92 | type User struct { 93 | sync.RWMutex 94 | Uid int 95 | N int 96 | } 97 | 98 | func (self *User) Set(n int) { 99 | self.Lock() 100 | defer self.Unlock() 101 | self.N += n 102 | } 103 | 104 | func (self *User) Save(uid, n int) { 105 | self.Lock() 106 | defer self.Unlock() 107 | fmt.Println(self.Uid, uid, self.N, n) 108 | 109 | } 110 | func Test_list(t *testing.T) { 111 | 112 | testList1 := []User{} 113 | testList1 = append(testList1, User{Uid: 1, N: 100}, User{Uid: 2, N: 200}, User{Uid: 3, N: 300}, User{Uid: 4, N: 400}) 114 | 115 | for _, user := range testList1 { 116 | user.Set(1) 117 | go user.Save(user.Uid, user.N) 118 | } 119 | 120 | testList2 := []*User{} 121 | testList2 = append(testList2, &User{Uid: 1, N: 100}, &User{Uid: 2, N: 200}, &User{Uid: 3, N: 300}, &User{Uid: 4, N: 400}) 122 | 123 | for _, user := range testList2 { 124 | user.Set(1) 125 | go user.Save(user.Uid, user.N) 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /cache_driver_redis.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | "time" 7 | 8 | "github.com/garyburd/redigo/redis" 9 | ) 10 | 11 | var Pool *redis.Pool = nil 12 | 13 | func NewRedisCacheWithRedisPool(pool *redis.Pool) *RedisCache { 14 | return &RedisCache{pool} 15 | } 16 | func SetCacheWithPool(pool *redis.Pool) { 17 | cacheconn = &RedisCache{pool} 18 | } 19 | 20 | func GetCachePool() Cache { 21 | return cacheconn 22 | } 23 | 24 | // 新建 Redis 连接 25 | func NewRedisCache(REDIS_HOST, PASSWD string) *RedisCache { 26 | Pool = &redis.Pool{ 27 | MaxIdle: 30, //最大的空闲连接数,表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态。 28 | MaxActive: 300, //最大的激活连接数,表示同时最多有N个连接 29 | IdleTimeout: 30 * time.Second, //最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭 30 | Dial: func() (redis.Conn, error) { 31 | c, err := redis.Dial("tcp", REDIS_HOST) 32 | if err != nil { 33 | return nil, err 34 | } 35 | if PASSWD != "" && len(PASSWD) > 0 { 36 | if _, err := c.Do("AUTH", PASSWD); err != nil { 37 | c.Close() 38 | return nil, err 39 | } 40 | } 41 | // 选择db 42 | c.Do("SELECT", cache_db) 43 | return c, nil 44 | }, 45 | TestOnBorrow: func(c redis.Conn, t time.Time) error { 46 | _, err := c.Do("PING") 47 | return err 48 | }, 49 | } 50 | return &RedisCache{Pool} 51 | } 52 | 53 | type RedisCache struct { 54 | *redis.Pool 55 | } 56 | 57 | func (c *RedisCache) ConnGet() redis.Conn { 58 | return c.Pool.Get() 59 | } 60 | 61 | func (c *RedisCache) Set(key string, b []byte) (err error) { 62 | conn := c.ConnGet() 63 | defer conn.Close() 64 | _, err = conn.Do("SET", key, b) 65 | return 66 | } 67 | func (c *RedisCache) Get(key string) ([]byte, error) { 68 | conn := c.ConnGet() 69 | defer conn.Close() 70 | return redis.Bytes(conn.Do("GET", key)) 71 | } 72 | func (c *RedisCache) Keys(key string) (keys []string, err error) { 73 | conn := c.ConnGet() 74 | defer conn.Close() 75 | keys, err = redis.Strings(conn.Do("KEYS", key)) 76 | return 77 | } 78 | func (c *RedisCache) Incrby(key string, n int64) (int64, error) { 79 | conn := c.ConnGet() 80 | defer conn.Close() 81 | if n == 0 { 82 | return redis.Int64(conn.Do("GET", key)) 83 | } 84 | return redis.Int64(conn.Do("INCRBY", key, n)) 85 | } 86 | func (c *RedisCache) Hset(key, field string, b []byte) (bool, error) { 87 | conn := c.ConnGet() 88 | defer conn.Close() 89 | _, err := conn.Do("HSET", key, field, b) 90 | if err != nil { 91 | return false, err 92 | } else { 93 | return true, nil 94 | } 95 | } 96 | func (c *RedisCache) Hmset(key string, maping interface{}) (err error) { 97 | 98 | switch maping.(type) { 99 | case map[string]interface{}: 100 | conn := c.ConnGet() 101 | defer conn.Close() 102 | conn.Do("MULTI") 103 | for k, v := range maping.(map[string]interface{}) { 104 | //setings = append(setings, k, v) 105 | conn.Do("HSET", key, k, v) 106 | //Debug.Println(key, k, v) 107 | } 108 | _, err = conn.Do("EXEC") 109 | default: 110 | Error.Println(err) 111 | err = errors.New("Hmset maping type error ") 112 | } 113 | return 114 | 115 | } 116 | func (c *RedisCache) Hget(key, field string) ([]byte, error) { 117 | conn := c.ConnGet() 118 | defer conn.Close() 119 | return redis.Bytes(conn.Do("HGET", key, field)) 120 | } 121 | func (c *RedisCache) Hincrby(key, field string, n int64) (int64, error) { 122 | conn := c.ConnGet() 123 | defer conn.Close() 124 | if n == 0 { 125 | return redis.Int64(conn.Do("HGET", key, field)) 126 | } 127 | return redis.Int64(conn.Do("HINCRBY", key, field, n)) 128 | } 129 | 130 | func (c *RedisCache) Exists(key string) (bool, error) { 131 | conn := c.ConnGet() 132 | defer conn.Close() 133 | return redis.Bool(conn.Do("EXISTS", key)) 134 | } 135 | func (c *RedisCache) Del(key string) (bool, error) { 136 | conn := c.ConnGet() 137 | defer conn.Close() 138 | return redis.Bool(conn.Do("DEL", key)) 139 | } 140 | 141 | func (c *RedisCache) key2Mode(key string, typ reflect.Type, val reflect.Value) error { 142 | conn := c.ConnGet() 143 | defer conn.Close() 144 | conn.Send("MULTI") 145 | vals := []interface{}{} 146 | timeField := []int{} 147 | for i := 0; i < typ.NumField(); i++ { 148 | conn.Send("HGET", key, typ.Field(i).Name) 149 | switch val.Field(i).Interface().(type) { 150 | case time.Time: 151 | timeField = append(timeField, i) 152 | var str string 153 | vals = append(vals, &str) 154 | default: 155 | vals = append(vals, val.Field(i).Addr().Interface()) 156 | } 157 | } 158 | 159 | reply, err := redis.Values(conn.Do("EXEC")) 160 | if err != nil { 161 | return err 162 | } 163 | if _, err := redis.Scan(reply, vals...); err == nil { 164 | var n int 165 | for _, n = range timeField { 166 | if time, e := time.Parse(time.RFC1123Z, string(reply[n].([]byte))); e == nil { 167 | val.Field(n).Set(reflect.ValueOf(time)) 168 | } 169 | } 170 | return nil 171 | } else { 172 | return err 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /marsharl_driver_sqlite.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type SqliteModeToSql struct { 9 | Params ParamsInterface 10 | } 11 | 12 | func (self SqliteModeToSql) Instance(param ParamsInterface) { 13 | self.Params = param 14 | } 15 | 16 | /*where 17 | 18 | where 条件: 19 | __exact 精确等于 like 'aaa' 20 | __iexact 精确等于 忽略大小写 ilike 'aaa' 21 | __contains 包含 like '%aaa%' 22 | __icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。 23 | __gt 大于 24 | __gte 大于等于 25 | __ne 不等于 26 | __lt 小于 27 | __lte 小于等于 28 | __in 存在于一个list范围内 29 | __startswith 以...开头 30 | __istartswith 以...开头 忽略大小写 31 | __endswith 以...结尾 32 | __iendswith 以...结尾,忽略大小写 33 | __range 在...范围内 34 | __year 日期字段的年份 35 | __month 日期字段的月份 36 | __day 日期字段的日 37 | __isnull=True/False 38 | **/ 39 | func (self SqliteModeToSql) _w(a string) string { 40 | typ := "" 41 | if bb := strings.Split(a, "__"); len(bb) > 1 { 42 | a = bb[0] 43 | typ = strings.ToLower(bb[1]) 44 | } 45 | patten := "" 46 | switch typ { 47 | case "iexact": 48 | patten = "`%s` like '?'" 49 | case "exact": 50 | patten = "binary `%s` like '?' " 51 | case "contains": 52 | patten = "binary `%s` like '%?%'" 53 | case "icontains": 54 | patten = "`%s` like '%?%'" 55 | case "startswith": 56 | patten = "binary `%s` like '?%' " 57 | case "istartswith": 58 | patten = "`%s` like '?%' " 59 | case "endswith": 60 | patten = "binary `%s` like '%?' " 61 | case "iendswith": 62 | patten = "`%s` like '%?' " 63 | 64 | case "gt": 65 | patten = "`%s`>?" 66 | case "gte": 67 | patten = "`%s`>=?" 68 | case "lt": 69 | patten = "`%s`?" 74 | case "add": 75 | return fmt.Sprintf("`%s`=`%s`+?", a, a) 76 | case "sub": 77 | return fmt.Sprintf("`%s`=`%s`-?", a, a) 78 | case "mult": 79 | return fmt.Sprintf("`%s`=`%s`*?", a, a) 80 | case "div": 81 | return fmt.Sprintf("`%s`=`%s`/?", a, a) 82 | case "asc": 83 | patten = "`%s` ASC" 84 | case "desc": 85 | patten = "`%s` DESC" 86 | default: 87 | patten = "`%s`=?" 88 | } 89 | return fmt.Sprintf(patten, a) 90 | } 91 | func (self SqliteModeToSql) _where() (sql string, val []interface{}) { 92 | whereLen := self.Params.GetWhereLen() 93 | orLen := self.Params.GetOrLen() 94 | 95 | where := make([]string, whereLen) 96 | or := make([]string, orLen) 97 | 98 | val = make([]interface{}, whereLen+orLen) 99 | 100 | i := 0 101 | for _, w := range self.Params.GetWhere() { 102 | 103 | //where = append(where, self.Params._w(w.name)) 104 | where[i] = self._w(w.name) 105 | val[i] = w.val 106 | i = i + 1 107 | } 108 | 109 | for _, w := range self.Params.GetOr() { 110 | or[i] = self._w(w.name) 111 | val[i] = w.val 112 | i = i + 1 113 | } 114 | 115 | sql = "" 116 | switch { 117 | case whereLen > 0 && orLen > 0: 118 | sql = sql + " WHERE " + strings.Join(where, " AND ") + " OR " + strings.Join(or, " OR ") 119 | case whereLen > 0 && orLen == 0: 120 | sql = sql + " WHERE " + strings.Join(where, " AND ") 121 | case orLen > 0 && whereLen == 0: 122 | sql = sql + " WHERE " + strings.Join(or, " OR ") 123 | } 124 | return 125 | } 126 | func (self SqliteModeToSql) _set() (sql string, val []interface{}) { 127 | sets := self.Params.GetSet() 128 | l := len(sets) 129 | set := make([]string, l) 130 | val = make([]interface{}, l) 131 | for i, v := range sets { 132 | set[i] = self._w(v.name) 133 | val[i] = v.val 134 | } 135 | sql = " SET " + strings.Join(set, ",") 136 | return 137 | } 138 | func (self SqliteModeToSql) Insert() (sql string, val []interface{}) { 139 | sql, val = self._set() 140 | sql = fmt.Sprintf("INSERT INTO %s %s ", 141 | self.Params.GetTableName(), 142 | sql, 143 | ) 144 | return 145 | } 146 | func (self SqliteModeToSql) Update() (sql string, val []interface{}) { 147 | sql, val = self._set() 148 | sql = fmt.Sprintf("UPDATE %s %s ", 149 | self.Params.GetTableName(), 150 | sql, 151 | ) 152 | s, v := self._where() 153 | sql = sql + s 154 | val = append(val, v...) 155 | return 156 | } 157 | 158 | func (self SqliteModeToSql) Delete() (sql string, val []interface{}) { 159 | sql, val = self._where() 160 | 161 | sql = fmt.Sprintf("DELETE FROM %s %s ", 162 | self.Params.GetTableName(), 163 | sql, 164 | ) 165 | 166 | return 167 | } 168 | func (self SqliteModeToSql) Select() (sql string, val []interface{}) { 169 | 170 | sql, val = self._where() 171 | sql = fmt.Sprintf("SELECT `%s` FROM %s %s", 172 | strings.Join(self.Params.GetFields(), "`,`"), 173 | self.Params.GetTableName(), 174 | sql, 175 | ) 176 | order := self.Params.GetOrder() 177 | if len(order) > 0 { 178 | sql = sql + " ORDER BY " 179 | ret := make([]string, len(order)) 180 | for id, v := range order { 181 | ret[id] = self._w(v) 182 | } 183 | sql = sql + strings.Join(ret, ",") 184 | } 185 | limit := self.Params.GetLimit() 186 | if limit != NULL_LIMIT { 187 | 188 | sql = sql + fmt.Sprintf(" LIMIT %d OFFSET %d", limit[1], (limit[0]-1)*limit[1]) 189 | } 190 | 191 | return 192 | } 193 | func (self SqliteModeToSql) Count() (sql string, val []interface{}) { 194 | sql, val = self._where() 195 | sql = fmt.Sprintf("SELECT COUNT(*) FROM %s %s ", 196 | self.Params.GetTableName(), 197 | sql, 198 | ) 199 | return 200 | } 201 | -------------------------------------------------------------------------------- /marsharl_driver_mysql.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type MysqlModeToSql struct { 9 | Params ParamsInterface 10 | } 11 | 12 | func (self MysqlModeToSql) Instance(param ParamsInterface) { 13 | self.Params = param 14 | } 15 | 16 | // where 17 | // where 条件: 18 | // __exact 精确等于 like 'aaa' 19 | // __iexact 精确等于 忽略大小写 ilike 'aaa' 20 | // __contains 包含 like '%aaa%' 21 | // __icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。 22 | // __gt 大于 23 | // __gte 大于等于 24 | // __ne 不等于 25 | // __lt 小于 26 | // __lte 小于等于 27 | // __in 存在于一个list范围内 28 | // __startswith 以...开头 29 | // __istartswith 以...开头 忽略大小写 30 | // __endswith 以...结尾 31 | // __iendswith 以...结尾,忽略大小写 32 | // __range 在...范围内 33 | // __year 日期字段的年份 34 | // __month 日期字段的月份 35 | // __day 日期字段的日 36 | // __isnull=True/False 37 | 38 | func (self MysqlModeToSql) _w(a string) string { 39 | typ := "" 40 | if bb := strings.Split(a, "__"); len(bb) > 1 { 41 | a = bb[0] 42 | typ = strings.ToLower(bb[1]) 43 | } 44 | patten := "" 45 | switch typ { 46 | case "iexact": 47 | patten = "`%s` like '?'" 48 | case "exact": 49 | patten = "binary `%s` like '?' " 50 | case "contains": 51 | patten = "binary `%s` like '%?%'" 52 | case "icontains": 53 | patten = "`%s` like '%?%'" 54 | case "startswith": 55 | patten = "binary `%s` like '?%' " 56 | case "istartswith": 57 | patten = "`%s` like '?%' " 58 | case "endswith": 59 | patten = "binary `%s` like '%?' " 60 | case "iendswith": 61 | patten = "`%s` like '%?' " 62 | 63 | case "gt": 64 | patten = "`%s`>?" 65 | case "gte": 66 | patten = "`%s`>=?" 67 | case "lt": 68 | patten = "`%s`?" 73 | case "add": 74 | return fmt.Sprintf("`%s`=`%s`+?", a, a) 75 | case "sub": 76 | return fmt.Sprintf("`%s`=`%s`-?", a, a) 77 | case "mult": 78 | return fmt.Sprintf("`%s`=`%s`*?", a, a) 79 | case "div": 80 | return fmt.Sprintf("`%s`=`%s`/?", a, a) 81 | case "asc": 82 | patten = "`%s` ASC" 83 | case "desc": 84 | patten = "`%s` DESC" 85 | default: 86 | patten = "`%s`=?" 87 | } 88 | return fmt.Sprintf(patten, a) 89 | } 90 | func (self MysqlModeToSql) _where() (sql string, val []interface{}) { 91 | whereLen := self.Params.GetWhereLen() 92 | orLen := self.Params.GetOrLen() 93 | 94 | where := make([]string, whereLen) 95 | or := make([]string, orLen) 96 | 97 | val = make([]interface{}, whereLen+orLen) 98 | 99 | i := 0 100 | for _, w := range self.Params.GetWhere() { 101 | 102 | //where = append(where, self.Params._w(w.name)) 103 | where[i] = self._w(w.name) 104 | val[i] = w.val 105 | i = i + 1 106 | } 107 | 108 | for _, w := range self.Params.GetOr() { 109 | or[i] = self._w(w.name) 110 | val[i] = w.val 111 | i = i + 1 112 | } 113 | 114 | sql = "" 115 | switch { 116 | case whereLen > 0 && orLen > 0: 117 | sql = sql + " WHERE " + strings.Join(where, " AND ") + " OR " + strings.Join(or, " OR ") 118 | case whereLen > 0 && orLen == 0: 119 | sql = sql + " WHERE " + strings.Join(where, " AND ") 120 | case orLen > 0 && whereLen == 0: 121 | sql = sql + " WHERE " + strings.Join(or, " OR ") 122 | } 123 | return 124 | } 125 | func (self MysqlModeToSql) _set() (sql string, val []interface{}) { 126 | sets := self.Params.GetSet() 127 | l := len(sets) 128 | set := make([]string, l) 129 | val = make([]interface{}, l) 130 | for i, v := range sets { 131 | set[i] = self._w(v.name) 132 | val[i] = v.val 133 | } 134 | sql = " SET " + strings.Join(set, ",") 135 | return 136 | } 137 | func (self MysqlModeToSql) Insert() (sql string, val []interface{}) { 138 | sql, val = self._set() 139 | sql = fmt.Sprintf("INSERT INTO %s %s ", 140 | self.Params.GetTableName(), 141 | sql, 142 | ) 143 | return 144 | } 145 | func (self MysqlModeToSql) Update() (sql string, val []interface{}) { 146 | sql, val = self._set() 147 | sql = fmt.Sprintf("UPDATE %s %s ", 148 | self.Params.GetTableName(), 149 | sql, 150 | ) 151 | s, v := self._where() 152 | sql = sql + s 153 | val = append(val, v...) 154 | return 155 | } 156 | 157 | func (self MysqlModeToSql) Delete() (sql string, val []interface{}) { 158 | sql, val = self._where() 159 | 160 | sql = fmt.Sprintf("DELETE FROM %s %s ", 161 | self.Params.GetTableName(), 162 | sql, 163 | ) 164 | 165 | return 166 | } 167 | func (self MysqlModeToSql) Select() (sql string, val []interface{}) { 168 | 169 | sql, val = self._where() 170 | sql = fmt.Sprintf("SELECT `%s` FROM %s %s", 171 | strings.Join(self.Params.GetFields(), "`,`"), 172 | self.Params.GetTableName(), 173 | sql, 174 | ) 175 | order := self.Params.GetOrder() 176 | if len(order) > 0 { 177 | sql = sql + " ORDER BY " 178 | ret := make([]string, len(order)) 179 | for id, v := range order { 180 | ret[id] = self._w(v) 181 | } 182 | sql = sql + strings.Join(ret, ",") 183 | } 184 | limit := self.Params.GetLimit() 185 | if limit != NULL_LIMIT { 186 | 187 | sql = sql + fmt.Sprintf(" LIMIT %d , %d", (limit[0]-1)*limit[1], limit[1]) 188 | } 189 | 190 | return 191 | } 192 | func (self MysqlModeToSql) Count() (sql string, val []interface{}) { 193 | sql, val = self._where() 194 | sql = fmt.Sprintf("SELECT COUNT(*) FROM %s %s ", 195 | self.Params.GetTableName(), 196 | sql, 197 | ) 198 | return 199 | } 200 | -------------------------------------------------------------------------------- /marsharl_driver_postgres.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | /* 9 | go get github.com/lib/pq 10 | 11 | import ( 12 | "github.com/ablegao/orm" 13 | _ "github.com/lib/pq" 14 | ) 15 | // http://godoc.org/github.com/lib/pq 16 | func main(){ 17 | orm.NewDatabase("default" ,"postgres" ,"user=pqgotest dbname=pqgotest sslmode=verify-full" ) 18 | } 19 | */ 20 | 21 | type PostgressModeToSql struct { 22 | Params ParamsInterface 23 | } 24 | 25 | func (self PostgressModeToSql) Instance(param ParamsInterface) { 26 | self.Params = param 27 | } 28 | 29 | /*where 30 | 31 | where 条件: 32 | __exact 精确等于 like 'aaa' 33 | __iexact 精确等于 忽略大小写 ilike 'aaa' 34 | __contains 包含 like '%aaa%' 35 | __icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。 36 | __gt 大于 37 | __gte 大于等于 38 | __ne 不等于 39 | __lt 小于 40 | __lte 小于等于 41 | __in 存在于一个list范围内 42 | __startswith 以...开头 43 | __istartswith 以...开头 忽略大小写 44 | __endswith 以...结尾 45 | __iendswith 以...结尾,忽略大小写 46 | __range 在...范围内 47 | __year 日期字段的年份 48 | __month 日期字段的月份 49 | __day 日期字段的日 50 | __isnull=True/False 51 | **/ 52 | func (self PostgressModeToSql) _w(a string) string { 53 | typ := "" 54 | if bb := strings.Split(a, "__"); len(bb) > 1 { 55 | a = bb[0] 56 | typ = strings.ToLower(bb[1]) 57 | } 58 | patten := "" 59 | switch typ { 60 | case "iexact": 61 | patten = "`%s` ilike '?'" 62 | case "exact": 63 | patten = "`%s` like '?' " 64 | case "contains": 65 | patten = "`%s` like '%?%'" 66 | case "icontains": 67 | patten = "`%s` ilike '%?%'" 68 | case "startswith": 69 | patten = "`%s` like '?%' " 70 | case "istartswith": 71 | patten = "`%s` ilike '?%' " 72 | case "endswith": 73 | patten = "`%s` like '%?' " 74 | case "iendswith": 75 | patten = "`%s` ilike '%?' " 76 | 77 | case "gt": 78 | patten = "`%s`>?" 79 | case "gte": 80 | patten = "`%s`>=?" 81 | case "lt": 82 | patten = "`%s`?" 87 | case "add": 88 | return fmt.Sprintf("`%s`=`%s`+?", a, a) 89 | case "sub": 90 | return fmt.Sprintf("`%s`=`%s`-?", a, a) 91 | case "mult": 92 | return fmt.Sprintf("`%s`=`%s`*?", a, a) 93 | case "div": 94 | return fmt.Sprintf("`%s`=`%s`/?", a, a) 95 | case "asc": 96 | patten = "`%s` ASC" 97 | case "desc": 98 | patten = "`%s` DESC" 99 | default: 100 | patten = "`%s`=?" 101 | } 102 | return fmt.Sprintf(patten, a) 103 | } 104 | func (self PostgressModeToSql) _where() (sql string, val []interface{}) { 105 | whereLen := self.Params.GetWhereLen() 106 | orLen := self.Params.GetOrLen() 107 | 108 | where := make([]string, whereLen) 109 | or := make([]string, orLen) 110 | 111 | val = make([]interface{}, whereLen+orLen) 112 | 113 | i := 0 114 | for _, w := range self.Params.GetWhere() { 115 | 116 | //where = append(where, self.Params._w(w.name)) 117 | where[i] = self._w(w.name) 118 | val[i] = w.val 119 | i = i + 1 120 | } 121 | 122 | for _, w := range self.Params.GetOr() { 123 | or[i] = self._w(w.name) 124 | val[i] = w.val 125 | i = i + 1 126 | } 127 | 128 | sql = "" 129 | switch { 130 | case whereLen > 0 && orLen > 0: 131 | sql = sql + " WHERE " + strings.Join(where, " AND ") + " OR " + strings.Join(or, " OR ") 132 | case whereLen > 0 && orLen == 0: 133 | sql = sql + " WHERE " + strings.Join(where, " AND ") 134 | case orLen > 0 && whereLen == 0: 135 | sql = sql + " WHERE " + strings.Join(or, " OR ") 136 | } 137 | return 138 | } 139 | func (self PostgressModeToSql) _set() (sql string, val []interface{}) { 140 | sets := self.Params.GetSet() 141 | l := len(sets) 142 | set := make([]string, l) 143 | val = make([]interface{}, l) 144 | for i, v := range sets { 145 | set[i] = self._w(v.name) 146 | val[i] = v.val 147 | } 148 | sql = " SET " + strings.Join(set, ",") 149 | return 150 | } 151 | func (self PostgressModeToSql) Insert() (sql string, val []interface{}) { 152 | sql, val = self._set() 153 | sql = fmt.Sprintf("INSERT INTO %s %s ", 154 | self.Params.GetTableName(), 155 | sql, 156 | ) 157 | return 158 | } 159 | func (self PostgressModeToSql) Update() (sql string, val []interface{}) { 160 | sql, val = self._set() 161 | sql = fmt.Sprintf("UPDATE %s %s ", 162 | self.Params.GetTableName(), 163 | sql, 164 | ) 165 | s, v := self._where() 166 | sql = sql + s 167 | val = append(val, v...) 168 | return 169 | } 170 | 171 | func (self PostgressModeToSql) Delete() (sql string, val []interface{}) { 172 | sql, val = self._where() 173 | 174 | sql = fmt.Sprintf("DELETE FROM %s %s ", 175 | self.Params.GetTableName(), 176 | sql, 177 | ) 178 | 179 | return 180 | } 181 | func (self PostgressModeToSql) Select() (sql string, val []interface{}) { 182 | 183 | sql, val = self._where() 184 | sql = fmt.Sprintf("SELECT `%s` FROM %s %s", 185 | strings.Join(self.Params.GetFields(), "`,`"), 186 | self.Params.GetTableName(), 187 | sql, 188 | ) 189 | order := self.Params.GetOrder() 190 | if len(order) > 0 { 191 | sql = sql + " ORDER BY " 192 | ret := make([]string, len(order)) 193 | for id, v := range order { 194 | ret[id] = self._w(v) 195 | } 196 | sql = sql + strings.Join(ret, ",") 197 | } 198 | limit := self.Params.GetLimit() 199 | if limit != NULL_LIMIT { 200 | 201 | sql = sql + fmt.Sprintf(" LIMIT %d OFFSET %d", limit[1], (limit[0]-1)*limit[1]) 202 | } 203 | 204 | return 205 | } 206 | func (self PostgressModeToSql) Count() (sql string, val []interface{}) { 207 | sql, val = self._where() 208 | sql = fmt.Sprintf("SELECT COUNT(*) FROM %s %s ", 209 | self.Params.GetTableName(), 210 | sql, 211 | ) 212 | return 213 | } 214 | -------------------------------------------------------------------------------- /consistent.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 Numerotron Inc. 2 | // Use of this source code is governed by an MIT-style license 3 | // that can be found in the LICENSE file. 4 | 5 | // Package consistent provides a consistent hashing function. 6 | // 7 | // Consistent hashing is often used to distribute requests to a changing set of servers. For example, 8 | // say you have some cache servers cacheA, cacheB, and cacheC. You want to decide which cache server 9 | // to use to look up information on a user. 10 | // 11 | // You could use a typical hash table and hash the user id 12 | // to one of cacheA, cacheB, or cacheC. But with a typical hash table, if you add or remove a server, 13 | // almost all keys will get remapped to different results, which basically could bring your service 14 | // to a grinding halt while the caches get rebuilt. 15 | // 16 | // With a consistent hash, adding or removing a server drastically reduces the number of keys that 17 | // get remapped. 18 | // 19 | // Read more about consistent hashing on wikipedia: http://en.wikipedia.org/wiki/Consistent_hashing 20 | // 21 | package orm 22 | 23 | import ( 24 | "errors" 25 | "hash/crc32" 26 | "sort" 27 | "strconv" 28 | "sync" 29 | ) 30 | 31 | type uints []uint32 32 | 33 | // Len returns the length of the uints array. 34 | func (x uints) Len() int { return len(x) } 35 | 36 | // Less returns true if element i is less than element j. 37 | func (x uints) Less(i, j int) bool { return x[i] < x[j] } 38 | 39 | // Swap exchanges elements i and j. 40 | func (x uints) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 41 | 42 | // ErrEmptyCircle is the error returned when trying to get an element when nothing has been added to hash. 43 | var ErrEmptyCircle = errors.New("empty circle") 44 | 45 | // Consistent holds the information about the members of the consistent hash circle. 46 | type Consistent struct { 47 | circle map[uint32]string 48 | members map[string]bool 49 | sortedHashes uints 50 | NumberOfReplicas int 51 | count int64 52 | scratch [64]byte 53 | sync.RWMutex 54 | } 55 | 56 | // New creates a new Consistent object with a default setting of 20 replicas for each entry. 57 | // 58 | // To change the number of replicas, set NumberOfReplicas before adding entries. 59 | func NewConsistent() *Consistent { 60 | c := new(Consistent) 61 | c.NumberOfReplicas = 20 62 | c.circle = make(map[uint32]string) 63 | c.members = make(map[string]bool) 64 | return c 65 | } 66 | func (c Consistent) GetCircle() map[uint32]string { 67 | return c.circle 68 | } 69 | 70 | // eltKey generates a string key for an element with an index. 71 | func (c *Consistent) eltKey(elt string, idx int) string { 72 | return elt + "|" + strconv.Itoa(idx) 73 | } 74 | 75 | // Add inserts a string element in the consistent hash. 76 | func (c *Consistent) Add(elt string) { 77 | c.Lock() 78 | defer c.Unlock() 79 | for i := 0; i < c.NumberOfReplicas; i++ { 80 | c.circle[c.hashKey(c.eltKey(elt, i))] = elt 81 | } 82 | c.members[elt] = true 83 | c.updateSortedHashes() 84 | c.count++ 85 | } 86 | 87 | // Remove removes an element from the hash. 88 | func (c *Consistent) Remove(elt string) { 89 | c.Lock() 90 | defer c.Unlock() 91 | for i := 0; i < c.NumberOfReplicas; i++ { 92 | delete(c.circle, c.hashKey(c.eltKey(elt, i))) 93 | } 94 | delete(c.members, elt) 95 | c.updateSortedHashes() 96 | c.count-- 97 | } 98 | 99 | // Set sets all the elements in the hash. If there are existing elements not present in elts, they will be removed. 100 | func (c *Consistent) Set(elts []string) { 101 | mems := c.Members() 102 | for _, k := range mems { 103 | found := false 104 | for _, v := range elts { 105 | if k == v { 106 | found = true 107 | break 108 | } 109 | } 110 | if !found { 111 | c.Remove(k) 112 | } 113 | } 114 | for _, v := range elts { 115 | c.RLock() 116 | _, exists := c.members[v] 117 | c.RUnlock() 118 | if exists { 119 | continue 120 | } 121 | c.Add(v) 122 | } 123 | } 124 | 125 | func (c *Consistent) Members() []string { 126 | c.RLock() 127 | defer c.RUnlock() 128 | var m []string 129 | for k := range c.members { 130 | m = append(m, k) 131 | } 132 | return m 133 | } 134 | 135 | // Get returns an element close to where name hashes to in the circle. 136 | func (c *Consistent) Get(name string) (string, error) { 137 | c.RLock() 138 | defer c.RUnlock() 139 | if len(c.circle) == 0 { 140 | return "", ErrEmptyCircle 141 | } 142 | key := c.hashKey(name) 143 | i := c.search(key) 144 | return c.circle[c.sortedHashes[i]], nil 145 | } 146 | 147 | func (c *Consistent) search(key uint32) (i int) { 148 | f := func(x int) bool { 149 | return c.sortedHashes[x] > key 150 | } 151 | i = sort.Search(len(c.sortedHashes), f) 152 | if i >= len(c.sortedHashes) { 153 | i = 0 154 | } 155 | return 156 | } 157 | 158 | // GetTwo returns the two closest distinct elements to the name input in the circle. 159 | func (c *Consistent) GetTwo(name string) (string, string, error) { 160 | c.RLock() 161 | defer c.RUnlock() 162 | if len(c.circle) == 0 { 163 | return "", "", ErrEmptyCircle 164 | } 165 | key := c.hashKey(name) 166 | i := c.search(key) 167 | a := c.circle[c.sortedHashes[i]] 168 | 169 | if c.count == 1 { 170 | return a, "", nil 171 | } 172 | 173 | start := i 174 | var b string 175 | for i = start + 1; i != start; i++ { 176 | if i >= len(c.sortedHashes) { 177 | i = 0 178 | } 179 | b = c.circle[c.sortedHashes[i]] 180 | if b != a { 181 | break 182 | } 183 | } 184 | return a, b, nil 185 | } 186 | 187 | // GetN returns the N closest distinct elements to the name input in the circle. 188 | func (c *Consistent) GetN(name string, n int) ([]string, error) { 189 | c.RLock() 190 | defer c.RUnlock() 191 | 192 | if len(c.circle) == 0 { 193 | return nil, ErrEmptyCircle 194 | } 195 | 196 | if c.count < int64(n) { 197 | n = int(c.count) 198 | } 199 | 200 | var ( 201 | key = c.hashKey(name) 202 | i = c.search(key) 203 | start = i 204 | res = make([]string, 0, n) 205 | elem = c.circle[c.sortedHashes[i]] 206 | ) 207 | 208 | res = append(res, elem) 209 | 210 | if len(res) == n { 211 | return res, nil 212 | } 213 | 214 | for i = start + 1; i != start; i++ { 215 | if i >= len(c.sortedHashes) { 216 | i = 0 217 | } 218 | elem = c.circle[c.sortedHashes[i]] 219 | if !sliceContainsMember(res, elem) { 220 | res = append(res, elem) 221 | } 222 | if len(res) == n { 223 | break 224 | } 225 | } 226 | 227 | return res, nil 228 | } 229 | 230 | func (c *Consistent) hashKey(key string) uint32 { 231 | if len(key) < 64 { 232 | var scratch [64]byte 233 | copy(scratch[:], key) 234 | return crc32.ChecksumIEEE(scratch[:len(key)]) 235 | } 236 | return crc32.ChecksumIEEE([]byte(key)) 237 | } 238 | 239 | func (c *Consistent) updateSortedHashes() { 240 | hashes := c.sortedHashes[:0] 241 | //reallocate if we're holding on to too much (1/4th) 242 | if cap(c.sortedHashes)/(c.NumberOfReplicas*4) > len(c.circle) { 243 | hashes = nil 244 | } 245 | for k := range c.circle { 246 | hashes = append(hashes, k) 247 | } 248 | sort.Sort(hashes) 249 | c.sortedHashes = hashes 250 | } 251 | 252 | func sliceContainsMember(set []string, member string) bool { 253 | for _, m := range set { 254 | if m == member { 255 | return true 256 | } 257 | } 258 | return false 259 | } 260 | -------------------------------------------------------------------------------- /params.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | var NULL_LIMIT = [2]int{0, 0} 10 | var databases = map[string]*Database{} 11 | var OpenSyncUpdate = false 12 | var OpenSyncDelete = false 13 | var SqlSyncHook = make(chan string, 1000) 14 | 15 | //读写数据库名称 16 | var readDbConnectName, writeDbConnectName string = "default", "default" 17 | 18 | // 读数据库名称 默认default 19 | func SetReadConnectName(name string) { 20 | readDbConnectName = name 21 | } 22 | 23 | // 写数据库名称 默认default 24 | func SetWriteConnectName(name string) { 25 | writeDbConnectName = name 26 | } 27 | 28 | type Database struct { 29 | *sql.DB 30 | Name string 31 | DriverName string 32 | DataSourceName string 33 | } 34 | 35 | func (self *Database) Conn() (err error) { 36 | self.DB, err = sql.Open(self.DriverName, self.DataSourceName) 37 | 38 | return 39 | } 40 | 41 | func NewDatabase(name, driverName, dataSourceName string) (database *Database, err error) { 42 | var ok bool 43 | if database, ok = databases[name]; !ok { 44 | database = new(Database) 45 | database.Name = name 46 | database.DriverName = driverName 47 | database.DataSourceName = dataSourceName 48 | databases[name] = database 49 | err = database.Conn() 50 | } else { 51 | err = database.Ping() 52 | } 53 | return 54 | } 55 | 56 | type ParmaField struct { 57 | name string 58 | val interface{} 59 | } 60 | 61 | type ParamsInterface interface { 62 | GetOrLen() int 63 | GetWhereLen() int 64 | GetSetLen() int 65 | GetOr() []ParmaField 66 | GetWhere() []ParmaField 67 | GetSet() []ParmaField 68 | GetFields() []string 69 | GetOrder() []string 70 | GetLimit() [2]int 71 | GetTableName() string 72 | } 73 | 74 | /** 75 | 传参解析 76 | **/ 77 | type Params struct { 78 | connname string 79 | tbname string 80 | where []ParmaField 81 | or []ParmaField 82 | set []ParmaField 83 | fields []string 84 | order []string 85 | limit [2]int 86 | insertsql string 87 | hasRow bool 88 | } 89 | 90 | func (self Params) GetWhereLen() int { 91 | return len(self.where) 92 | } 93 | func (self Params) GetOrLen() int { 94 | return len(self.or) 95 | } 96 | func (self Params) GetSetLen() int { 97 | return len(self.set) 98 | } 99 | 100 | func (self Params) GetWhere() []ParmaField { 101 | return self.where 102 | } 103 | func (self Params) GetOr() []ParmaField { 104 | return self.or 105 | } 106 | func (self Params) GetSet() []ParmaField { 107 | return self.set 108 | } 109 | 110 | func (self Params) GetFields() []string { 111 | return self.fields 112 | } 113 | func (self Params) GetOrder() []string { 114 | return self.order 115 | } 116 | func (self Params) GetLimit() [2]int { 117 | return self.limit 118 | } 119 | func (self *Params) Init() { 120 | self.connname = "" 121 | self.hasRow = false 122 | self.where = self.where[len(self.where):] 123 | 124 | self.or = self.or[len(self.or):] 125 | 126 | self.set = self.set[len(self.set):] 127 | self.fields = self.fields[len(self.fields):] 128 | self.order = self.order[len(self.order):] 129 | } 130 | 131 | func (self *Params) SetTable(tbname string) { 132 | self.tbname = tbname 133 | 134 | } 135 | 136 | func (self *Params) SetField(fields ...string) { 137 | self.fields = fields 138 | } 139 | 140 | func (self *Params) Filter(name string, val interface{}) *Params { 141 | 142 | self.where = append(self.where, ParmaField{name, val}) 143 | 144 | return self 145 | } 146 | func (self *Params) FilterOr(name string, val interface{}) *Params { 147 | self.or = append(self.or, ParmaField{name, val}) 148 | return self 149 | } 150 | 151 | // 添加修改 152 | func (self *Params) Change(name string, val interface{}) { 153 | self.set = append(self.set, ParmaField{name, val}) 154 | } 155 | func (self *Params) Limit(page, step int) *Params { 156 | self.limit[0] = page 157 | self.limit[1] = step 158 | return self 159 | } 160 | 161 | func (self *Params) Db(name string) *Params { 162 | self.connname = name 163 | return self 164 | } 165 | 166 | func (self *Params) getReadConnect() (*Database, ModuleToSql) { 167 | db_connect_name := readDbConnectName 168 | if self.connname != "" { 169 | db_connect_name = self.connname 170 | } 171 | if db, ok := databases[db_connect_name]; ok { 172 | return db, driversql[db.DriverName](*self) 173 | 174 | } else { 175 | panic("database name '" + db_connect_name + "' not exists!") 176 | } 177 | } 178 | func (self *Params) getWriteConnect() (*Database, ModuleToSql) { 179 | db_connect_name := writeDbConnectName 180 | if self.connname != "" { 181 | db_connect_name = self.connname 182 | } 183 | if db, ok := databases[db_connect_name]; ok { 184 | return db, driversql[db.DriverName](*self) 185 | } else { 186 | panic("database name '" + db_connect_name + "' not exists!") 187 | } 188 | } 189 | 190 | func (self *Params) All() (rows *sql.Rows, err error) { 191 | //rows, err = self.db.Query(self.execSelect()) 192 | // self.stmt, err = self.db.Prepare() 193 | db, query := self.getReadConnect() 194 | sqls, val := query.Select() 195 | if debug_sql { 196 | Debug.Println("select all ", sqls, val) 197 | } 198 | rows, err = db.Query(sqls, val...) 199 | if err != nil { 200 | Error.Println(err) 201 | } 202 | 203 | return 204 | } 205 | 206 | func (self *Params) One(vals ...interface{}) error { 207 | //rows, err = self.db.Query(self.execSelect()) 208 | // self.stmt, err = self.db.Prepare() 209 | db, query := self.getReadConnect() 210 | 211 | sqls, val := query.Select() 212 | err := db.QueryRow(sqls, val...).Scan(vals...) 213 | if debug_sql { 214 | 215 | Debug.Println("select One ", sqls, val, err) 216 | // Debug.Output(3, "callback1") 217 | // Debug.Output(4, "callback2") 218 | // Debug.Output(5, "callback3") 219 | } 220 | 221 | switch { 222 | case err == sql.ErrNoRows: 223 | return err 224 | case err != nil: 225 | return err 226 | default: 227 | self.hasRow = true 228 | return nil 229 | } 230 | } 231 | func (self *Params) Delete() (res sql.Result, err error) { 232 | 233 | db, query := self.getWriteConnect() 234 | sqls, val := query.Delete() 235 | if debug_sql { 236 | Debug.Println("delete ", sqls, val) 237 | } 238 | if OpenSyncDelete { 239 | sqls = strings.Replace(sqls, "?", "%v", -1) 240 | sqls = fmt.Sprintf(sqls, val...) 241 | SqlSyncHook <- sqls 242 | return nil, nil 243 | } else { 244 | var stmt *sql.Stmt 245 | stmt, err = db.Prepare(sqls) 246 | if err == nil { 247 | defer stmt.Close() 248 | } else { 249 | Error.Println(err) 250 | return 251 | } 252 | res, err = stmt.Exec(val...) 253 | if err != nil { 254 | Error.Println(err) 255 | } 256 | } 257 | return 258 | } 259 | 260 | func (self *Params) Count() (int64, error) { 261 | db, query := self.getReadConnect() 262 | 263 | sqls, val := query.Count() 264 | if debug_sql { 265 | Debug.Println("count ", sqls, val) 266 | } 267 | row := db.QueryRow(sqls, val...) 268 | 269 | var c int64 270 | if err := row.Scan(&c); err == nil { 271 | return c, nil 272 | } else { 273 | return 0, err 274 | } 275 | 276 | return 0, nil 277 | } 278 | 279 | func (self *Params) Save() (bool, int64, error) { 280 | db, query := self.getWriteConnect() 281 | defer func() { 282 | self.set = self.set[len(self.set):] 283 | }() 284 | var err error 285 | var stmt *sql.Stmt 286 | var res sql.Result 287 | //var n int64 288 | //if n , err= self.Count();err == nil && n >0 289 | if self.hasRow { 290 | sqls, val := query.Update() 291 | if OpenSyncUpdate { 292 | sqls = strings.Replace(sqls, "?", "%v", -1) 293 | sqls = fmt.Sprintf(sqls, val...) 294 | SqlSyncHook <- sqls 295 | return false, 0, nil 296 | } else { 297 | if debug_sql { 298 | Debug.Println("save update ", sqls, val) 299 | } 300 | stmt, err = db.Prepare(sqls) 301 | if err == nil { 302 | defer stmt.Close() 303 | } else { 304 | return false, 0, err 305 | } 306 | res, err = stmt.Exec(val...) 307 | 308 | if err != nil { 309 | return false, 0, err 310 | } 311 | a, b := res.RowsAffected() 312 | return false, a, b 313 | } 314 | } else { 315 | sqls, val := query.Insert() 316 | if debug_sql { 317 | Debug.Println("save insert ", sqls, val) 318 | } 319 | stmt, err = db.Prepare(sqls) 320 | if err == nil { 321 | defer stmt.Close() 322 | } else { 323 | return false, 0, err 324 | } 325 | res, err = stmt.Exec(val...) 326 | if err != nil { 327 | return true, 0, err 328 | } 329 | a, b := res.LastInsertId() 330 | self.hasRow = true 331 | return true, a, b 332 | } 333 | 334 | } 335 | 336 | func (self Params) GetTableName() string { 337 | tbname := "" 338 | if tb := strings.Split(self.tbname, "."); len(tb) > 1 { 339 | tbname = fmt.Sprintf("`%s`.`%s`", tb[0], tb[1]) 340 | } else { 341 | tbname = "`" + self.tbname + "`" 342 | } 343 | return tbname 344 | } 345 | -------------------------------------------------------------------------------- /mode.go: -------------------------------------------------------------------------------- 1 | // model解析支持 2 | 3 | package orm 4 | 5 | import ( 6 | "database/sql" 7 | "errors" 8 | "reflect" 9 | "strings" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | var ErrDoesNotExist = errors.New("DoesNotExist") 15 | 16 | type Module interface { 17 | GetTableName() string 18 | } 19 | 20 | type FuncParam struct { 21 | name string 22 | val func(interface{}) bool 23 | } 24 | 25 | type Object struct{ DBHook } 26 | 27 | type DBHook struct { 28 | sync.RWMutex 29 | Params 30 | mode Module 31 | funcWhere []FuncParam 32 | dbName string 33 | } 34 | 35 | func (self *DBHook) DoesNotExist() error { 36 | return ErrDoesNotExist 37 | } 38 | 39 | func (self *DBHook) Objects(mode Module, params ...string) *DBHook { 40 | self.Lock() 41 | defer self.Unlock() 42 | if len(params) == 1 && len(params[0]) > 1 { 43 | self.dbName = params[0] 44 | self.SetTable(self.dbName + "." + mode.GetTableName()) 45 | } else { 46 | self.SetTable(mode.GetTableName()) 47 | } 48 | 49 | self.Init() 50 | self.funcWhere = self.funcWhere[len(self.funcWhere):] 51 | typ := reflect.TypeOf(mode).Elem() 52 | vals := []string{} 53 | 54 | for i := 0; i < typ.NumField(); i++ { 55 | if field := typ.Field(i).Tag.Get("field"); len(field) > 0 { 56 | vals = append(vals, field) 57 | } 58 | } 59 | self.SetField(vals...) 60 | self.mode = mode 61 | return self 62 | } 63 | 64 | func (self *DBHook) Existed() *DBHook { 65 | self.Lock() 66 | defer self.Unlock() 67 | self.hasRow = true 68 | return self 69 | } 70 | 71 | //修改数据 72 | // name 结构字段名称 73 | // val 结构数据 74 | func (self *DBHook) Set(name string, val interface{}) *DBHook { 75 | self.Lock() 76 | defer self.Unlock() 77 | typ := reflect.TypeOf(self.mode).Elem() 78 | fieldName := strings.Split(name, "__") 79 | if field, ok := typ.FieldByName(fieldName[0]); ok && len(field.Tag.Get("field")) > 0 { 80 | name := field.Tag.Get("field") 81 | if len(fieldName) > 1 { 82 | name = name + "__" + fieldName[1] 83 | } 84 | self.Params.Change(name, val) 85 | } 86 | return self 87 | } 88 | 89 | func (self *DBHook) Change(name string, val interface{}) *DBHook { 90 | return self.Set(name, val) 91 | } 92 | 93 | //条件筛选 94 | // name 结构字段名称 95 | // val 需要过滤的数据值 96 | func (self *DBHook) Filter(name string, val interface{}) *DBHook { 97 | self.Lock() 98 | defer self.Unlock() 99 | switch val.(type) { 100 | case func(interface{}) bool: 101 | self.funcWhere = append(self.funcWhere, FuncParam{name, val.(func(interface{}) bool)}) 102 | default: 103 | typ := reflect.TypeOf(self.mode).Elem() 104 | fieldName := strings.Split(name, "__") 105 | if field, ok := typ.FieldByName(fieldName[0]); ok && len(field.Tag.Get("field")) > 0 { 106 | name := field.Tag.Get("field") 107 | if len(fieldName) > 1 { 108 | name = name + "__" + fieldName[1] 109 | } 110 | self.Params.Filter(name, val) 111 | } 112 | } 113 | 114 | return self 115 | } 116 | func (self *DBHook) FilterOr(name string, val interface{}) *DBHook { 117 | self.Lock() 118 | defer self.Unlock() 119 | typ := reflect.TypeOf(self.mode).Elem() 120 | fieldName := strings.Split(name, "__") 121 | if field, ok := typ.FieldByName(fieldName[0]); ok && len(field.Tag.Get("field")) > 0 { 122 | name := field.Tag.Get("field") 123 | if len(fieldName) > 1 { 124 | name = name + "__" + fieldName[1] 125 | } 126 | self.Params.FilterOr(name, val) 127 | } 128 | return self 129 | } 130 | 131 | // Filter 的一次传入版本 , 不建议使用 , 因为map 循序不可控 132 | func (self *DBHook) Filters(filters map[string]interface{}) *DBHook { 133 | for k, v := range filters { 134 | self.Filter(k, v) 135 | } 136 | return self 137 | } 138 | 139 | // Order by 排序 , 140 | // Field__asc Field__desc 141 | func (self *DBHook) Orderby(names ...string) *DBHook { 142 | typ := reflect.TypeOf(self.mode).Elem() 143 | for i, name := range names { 144 | fieldName := strings.Split(name, "__") 145 | if field, ok := typ.FieldByName(fieldName[0]); ok && len(field.Tag.Get("field")) > 0 { 146 | if name = field.Tag.Get("field"); len(name) > 0 { 147 | name = name + "__" + fieldName[1] 148 | names[i] = name 149 | } 150 | } 151 | } 152 | self.Params.order = names 153 | return self 154 | } 155 | 156 | // 分页支持 157 | func (self *DBHook) Limit(page, steq int) *DBHook { 158 | self.Lock() 159 | defer self.Unlock() 160 | self.Params.limit = [2]int{page, steq} 161 | return self 162 | } 163 | 164 | //选择数据库 165 | func (self *DBHook) Db(name string) *DBHook { 166 | self.Params.Db(name) 167 | return self 168 | } 169 | 170 | // 计算数量 171 | func (self *DBHook) Count() (int64, error) { 172 | self.RLock() 173 | defer self.RUnlock() 174 | return self.Params.Count() 175 | } 176 | 177 | //删除数据 178 | func (self *DBHook) Delete() (int64, error) { 179 | self.Lock() 180 | defer self.Unlock() 181 | self.autoWhere() 182 | if len(self.Params.where) > 0 { 183 | res, err := self.Params.Delete() 184 | if OpenSyncDelete { 185 | return 0, nil 186 | } 187 | 188 | if err != nil { 189 | return 0, err 190 | } 191 | return res.RowsAffected() 192 | } else { 193 | return 0, errors.New("where params is 0") 194 | } 195 | 196 | } 197 | 198 | func (self DBHook) printModel(name string) { 199 | valus := reflect.ValueOf(self.mode).Elem() 200 | Debug.Println("PRINT MODE =======================================", name, " Start ") 201 | for i := 0; i < valus.NumField(); i++ { 202 | Debug.Println("PRINT MODE ", valus.Type().Field(i).Name, valus.Field(i).Interface()) 203 | } 204 | Debug.Println("PRINT MODE =======================================", name, " END ") 205 | } 206 | 207 | //更新活添加 208 | func (self *DBHook) Save() (bool, int64, error) { 209 | self.Lock() 210 | defer self.Unlock() 211 | valus := reflect.ValueOf(self.mode).Elem() 212 | fieldNum := valus.NumField() 213 | if len(self.Params.set) == 0 { 214 | for i := 0; i < fieldNum; i++ { 215 | typ := valus.Type().Field(i) 216 | val := valus.Field(i) 217 | if self.hasRow { 218 | if len(typ.Tag.Get("field")) > 0 && typ.Tag.Get("index") != "pk" { 219 | self.Params.Change(typ.Tag.Get("field"), val.Interface()) 220 | } 221 | } else { 222 | if len(typ.Tag.Get("field")) > 0 { 223 | self.Params.Change(typ.Tag.Get("field"), val.Interface()) 224 | } 225 | } 226 | } 227 | } 228 | 229 | self.autoWhere() 230 | isNew, id, err := self.Params.Save() 231 | if isNew && err == nil { 232 | for i := 0; i < fieldNum; i++ { 233 | typ := valus.Type().Field(i) 234 | val := valus.Field(i) 235 | if typ.Tag.Get("index") == "pk" { 236 | switch val.Kind() { 237 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 238 | if val.Uint() == 0 { 239 | val.SetUint(uint64(id)) 240 | } 241 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 242 | if val.Int() == 0 { 243 | val.SetInt(id) 244 | } 245 | } 246 | } 247 | } 248 | } 249 | 250 | return isNew, id, err 251 | } 252 | 253 | func (self *DBHook) autoWhere() { 254 | valus := reflect.ValueOf(self.mode).Elem() 255 | if len(self.Params.where) == 0 { 256 | for i := 0; i < valus.NumField(); i++ { 257 | typ := valus.Type().Field(i) 258 | val := valus.Field(i) 259 | if len(typ.Tag.Get("field")) > 0 && typ.Tag.Get("index") == "pk" { 260 | switch val.Kind() { 261 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 262 | if val.Int() > 0 { 263 | self.Params.Filter(typ.Tag.Get("field"), val.Int()) 264 | } 265 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 266 | if val.Uint() > 0 { 267 | self.Params.Filter(typ.Tag.Get("field"), val.Uint()) 268 | } 269 | case reflect.Float32, reflect.Float64: 270 | if val.Float() > 0.0 { 271 | self.Params.Filter(typ.Tag.Get("field"), val.Float()) 272 | } 273 | case reflect.String: 274 | if len(val.String()) > 0 { 275 | self.Params.Filter(typ.Tag.Get("field"), val.String()) 276 | } 277 | default: 278 | switch val.Interface().(type) { 279 | case time.Time: 280 | self.Params.Filter(typ.Tag.Get("field"), val.Interface()) 281 | } 282 | 283 | } 284 | } 285 | } 286 | } 287 | 288 | } 289 | func (self *DBHook) Query() (Rows, error) { 290 | self.autoWhere() 291 | rows, err := self.Params.All() 292 | if err != nil { 293 | return nil, err 294 | } 295 | return &ModeRows{rows: rows, dbName: self.dbName}, nil 296 | } 297 | 298 | //查找数据 299 | func (self *DBHook) All(out interface{}) error { 300 | self.Lock() 301 | defer self.Unlock() 302 | if out == nil { 303 | return errors.New("params can't nil ") 304 | } 305 | self.autoWhere() 306 | rows, err := self.Params.All() 307 | 308 | if err == nil { 309 | defer rows.Close() 310 | val := []interface{}{} 311 | value := reflect.ValueOf(out).Elem() 312 | 313 | for rows.Next() { 314 | m := reflect.New(reflect.TypeOf(self.mode).Elem()).Elem() 315 | val = val[len(val):] 316 | 317 | for i := 0; i < m.NumField(); i++ { 318 | if name := m.Type().Field(i).Tag.Get("field"); len(name) > 0 { 319 | val = append(val, m.Field(i).Addr().Interface()) 320 | } 321 | } 322 | 323 | err = rows.Scan(val...) 324 | if err != nil { 325 | Error.Println(err) 326 | continue 327 | } 328 | //m.Field(0).MethodByName("Objects").Call([]reflect.Value{m.Addr()}) 329 | obj := DBHook{} //DBHook(m.Interface().(Module)) 330 | obj.Objects(m.Addr().Interface().(Module), self.dbName).Existed() 331 | m.FieldByName("DBHook").Set(reflect.ValueOf(obj)) 332 | add := true 333 | for _, param := range self.funcWhere { 334 | 335 | if param.val(m.FieldByName(param.name).Interface()) == false { 336 | add = false 337 | } 338 | } 339 | if add == true { 340 | value.Set(reflect.Append(value, m.Addr())) 341 | } 342 | 343 | } 344 | return err 345 | } else { 346 | Error.Println(err) 347 | return err 348 | } 349 | 350 | } 351 | 352 | //提取一个数据 353 | func (self *DBHook) One() error { 354 | self.RLock() 355 | defer self.RUnlock() 356 | self.autoWhere() 357 | valMode := reflect.ValueOf(self.mode).Elem() 358 | typeMode := reflect.TypeOf(self.mode).Elem() 359 | vals := []interface{}{} 360 | for i := 0; i < valMode.NumField(); i++ { 361 | if name := typeMode.Field(i).Tag.Get("field"); len(name) > 0 { 362 | //vals[i] = valMode.Field(i).Addr().Interface() 363 | vals = append(vals, valMode.Field(i).Addr().Interface()) 364 | } 365 | } 366 | err := self.Params.One(vals...) 367 | if err == nil { 368 | self.where = self.where[len(self.where):] 369 | return nil 370 | } else { 371 | 372 | switch err { 373 | case sql.ErrNoRows: 374 | return ErrDoesNotExist 375 | default: 376 | return err 377 | } 378 | } 379 | } 380 | 381 | func (self *DBHook) Field(name string) reflect.Value { 382 | valMode := reflect.ValueOf(self.mode).Elem() 383 | return valMode.FieldByName(name) 384 | } 385 | -------------------------------------------------------------------------------- /cache.go: -------------------------------------------------------------------------------- 1 | //Cache,用来沟通第一层cache 和同步数据到数据库 2 | 3 | package orm 4 | 5 | import ( 6 | "errors" 7 | "log" 8 | "os" 9 | "reflect" 10 | "sort" 11 | "strconv" 12 | "time" 13 | ) 14 | 15 | var Debug = log.New(os.Stdout, "ORM-DEBUG ", log.Lshortfile|log.LstdFlags) 16 | var Error = log.New(os.Stdout, "ORM-ERROR ", log.Lshortfile|log.LstdFlags) 17 | var cache_prefix []byte = []byte("nado") 18 | var cache_db = 0 19 | var st []byte = []byte("*") 20 | 21 | var ( 22 | ErrKeyNotExist = errors.New("keys not exists") 23 | ) 24 | var debug_sql bool = false 25 | 26 | func SetCachePrefix(str string) { 27 | cache_prefix = []byte(str) 28 | 29 | } 30 | func GetCachePrefix() []byte { 31 | return cache_prefix 32 | } 33 | func SetDefaultCacheDb(db int) { 34 | cache_db = db 35 | } 36 | 37 | func SetDebug(b bool) { 38 | debug_sql = b 39 | } 40 | 41 | type Cache interface { 42 | Set(key string, b []byte) error 43 | Get(key string) ([]byte, error) 44 | Keys(key string) ([]string, error) 45 | //Incy(key string) (int64, error) 46 | Incrby(key string, n int64) (int64, error) 47 | Hset(key, field string, b []byte) (bool, error) 48 | Hmset(key string, maping interface{}) error 49 | Hget(key, field string) ([]byte, error) 50 | Hincrby(key, filed string, n int64) (int64, error) 51 | Exists(key string) (bool, error) 52 | Del(key string) (bool, error) 53 | key2Mode(key string, typ reflect.Type, val reflect.Value) error 54 | } 55 | 56 | type CacheModule struct{ CacheHook } 57 | 58 | type CacheHook struct { 59 | Cache 60 | DBHook 61 | Object *DBHook 62 | cachekey string 63 | CacheFileds []string 64 | CacheNames []string 65 | cache_prefix string 66 | cache_address string 67 | modefield map[string]interface{} 68 | } 69 | 70 | func (self *CacheHook) Objects(mode Module, param ...string) *CacheHook { 71 | self.CacheFileds = []string{} 72 | self.CacheNames = []string{} 73 | self.DBHook.Objects(mode, param...) 74 | self.Object = &self.DBHook 75 | self.Lock() 76 | defer self.Unlock() 77 | typeOf := reflect.TypeOf(self.mode).Elem() 78 | valOf := reflect.ValueOf(self.mode).Elem() 79 | self.modefield = make(map[string]interface{}, typeOf.NumField()) 80 | 81 | if len(param) == 1 && len(param[0]) > 0 { 82 | self.cache_prefix = param[0] 83 | //self.dbName = param[0] 84 | } 85 | 86 | self.Cache = nil 87 | for i := 0; i < typeOf.NumField(); i++ { 88 | field := typeOf.Field(i) 89 | if name := field.Tag.Get("cache"); len(name) > 0 { 90 | self.CacheFileds = append(self.CacheFileds, field.Tag.Get("field")) 91 | self.CacheNames = append(self.CacheNames, name) 92 | } 93 | 94 | if prefix := field.Tag.Get("cache_prefix"); len(prefix) > 0 { 95 | self.cache_prefix = self.cache_prefix + prefix 96 | } 97 | 98 | //支持分布是hash key 99 | if use_hash_cache && field.Tag.Get("index") == "pk" && field.Tag.Get("distr") == "true" { 100 | self.cache_address, self.Cache = GetCacheConn(valOf.Field(i).Interface()) 101 | } 102 | if name := field.Tag.Get("field"); name != "" { 103 | self.modefield[typeOf.Field(i).Name] = valOf.Field(i).Interface() 104 | } 105 | } 106 | if self.Cache == nil { 107 | self.Cache = GetCacheClient("default") 108 | } 109 | 110 | return self 111 | } 112 | 113 | func (self *CacheHook) Db(name string) *CacheHook { 114 | self.Params.Db(name) 115 | return self 116 | } 117 | 118 | func GetCacheConn(key interface{}) (address string, c Cache) { 119 | 120 | value := reflect.ValueOf(key) 121 | typeOf := reflect.TypeOf(key) 122 | b := []byte{} 123 | switch typeOf.Kind() { 124 | case reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uint8, reflect.Uint16: 125 | b = strconv.AppendUint(b, value.Uint(), 10) 126 | case reflect.Int32, reflect.Int64, reflect.Int, reflect.Int8, reflect.Int16: 127 | b = strconv.AppendInt(b, value.Int(), 10) 128 | case reflect.Float32, reflect.Float64: 129 | b = strconv.AppendFloat(b, value.Float(), 'f', 0, 64) 130 | case reflect.String: 131 | b = append(b, []byte(value.String())...) 132 | case reflect.Bool: 133 | b = strconv.AppendBool(b, value.Bool()) 134 | } 135 | address = string(b) 136 | if use_hash_cache == false { 137 | return address, cacheconn 138 | } 139 | c = GetCacheClient(address) 140 | return 141 | } 142 | 143 | func (self *CacheHook) Ca(key interface{}) *CacheHook { 144 | if use_hash_cache { 145 | self.cache_address, self.Cache = GetCacheConn(key) 146 | if debug_sql { 147 | Debug.Println("Change cache address redis ", self.cache_address) 148 | } 149 | } 150 | return self 151 | } 152 | 153 | func (self *CacheHook) GetCacheKey() string { 154 | 155 | value := reflect.ValueOf(self.mode).Elem() 156 | typeOf := reflect.TypeOf(self.mode).Elem() 157 | str := cache_prefix 158 | str = append(str, []byte(self.cache_prefix)...) 159 | 160 | for i := 0; i < value.NumField(); i++ { 161 | field := typeOf.Field(i) 162 | self.CacheFileds = append(self.CacheFileds, field.Name) 163 | if name := field.Tag.Get("cache"); len(name) > 0 { 164 | val := value.Field(i) 165 | str = append(str, []byte(":")...) 166 | str = append(str, self.fieldToByte(val.Interface())...) 167 | str = append(str, []byte(":"+name)...) 168 | } 169 | } 170 | return string(str) 171 | } 172 | func (self *CacheHook) setModeField(field string, val interface{}) error { 173 | 174 | typ := reflect.TypeOf(self.mode).Elem() 175 | 176 | if mfield, ok := typ.FieldByName(field); ok { 177 | value := reflect.ValueOf(self.mode).Elem() 178 | item := value.FieldByName(field) 179 | switch mfield.Type.Kind() { 180 | case reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uint8, reflect.Uint16: 181 | 182 | item.SetUint(uint64(val.(int64))) 183 | case reflect.Int32, reflect.Int64, reflect.Int, reflect.Int8, reflect.Int16: 184 | item.SetInt(val.(int64)) 185 | case reflect.String: 186 | item.SetString(val.(string)) 187 | 188 | default: 189 | Error.Println("(CacheHook) setModeField", field, item.Type().Kind()) 190 | return errors.New("(CacheHook) setModeField type error ") 191 | } 192 | return nil 193 | } else { 194 | return errors.New("(CacheHook) setModeField field not exist") 195 | } 196 | } 197 | 198 | func (self *CacheHook) Incrby(key string, val int64) (ret int64, err error) { 199 | if self.cachekey == "" { 200 | self.cachekey = self.GetCacheKey() 201 | } 202 | 203 | ret, _ = self.Cache.Hincrby(self.cachekey, key, val) 204 | if val != 0 { 205 | 206 | self.Object.Change(key+"__add", val) 207 | 208 | err = self.setModeField(key, ret) 209 | } 210 | //self.modefield[key] = ret 211 | //go self.Object.Save() 212 | return 213 | } 214 | 215 | func (self *CacheHook) Incry(key string) (val int64, err error) { 216 | val, err = self.Incrby(key, 1) 217 | 218 | return 219 | } 220 | 221 | func (self *CacheHook) Set(key string, value interface{}) (err error) { 222 | 223 | b := []byte{} 224 | field := reflect.ValueOf(self.mode).Elem().FieldByName(key) 225 | 226 | val := reflect.ValueOf(value) 227 | 228 | switch field.Kind() { 229 | case reflect.Uint32, reflect.Uint64, reflect.Uint16, reflect.Uint8: 230 | b = strconv.AppendUint(b, val.Uint(), 10) 231 | field.SetUint(val.Uint()) 232 | case reflect.String: 233 | b = append(b, []byte(val.String())...) 234 | field.SetString(val.String()) 235 | 236 | case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: 237 | b = strconv.AppendInt(b, val.Int(), 10) 238 | field.SetInt(val.Int()) 239 | case reflect.Float64, reflect.Float32: 240 | b = strconv.AppendFloat(b, val.Float(), 'f', 0, 64) 241 | field.SetFloat(val.Float()) 242 | case reflect.Bool: 243 | b = strconv.AppendBool(b, val.Bool()) 244 | field.SetBool(val.Bool()) 245 | 246 | default: 247 | switch value.(type) { 248 | case time.Time: 249 | field.Set(reflect.ValueOf(value)) 250 | b = append(b, []byte(value.(time.Time).Format(time.RFC1123Z))...) 251 | default: 252 | Error.Println("undefined val type") 253 | } 254 | } 255 | if self.cachekey == "" { 256 | self.cachekey = self.GetCacheKey() 257 | } 258 | 259 | var over bool 260 | 261 | over, err = self.Cache.Hset(self.cachekey, key, b) 262 | if err != nil { 263 | return 264 | } 265 | if over == false { 266 | return errors.New(self.cachekey + " hset " + key + " error !") 267 | } 268 | self.Object.Change(key, value) 269 | //self.modefield[key] = value 270 | //go self.Object.Change(key, val).Save() 271 | 272 | return 273 | } 274 | 275 | func (self *CacheHook) Save() (isnew bool, id int64, err error) { 276 | /// 实现, 直接通过 self.xxx= xxx 这样的数据变动支持 277 | 278 | upgradecache := false 279 | if self.hasRow && len(self.set) == 0 { 280 | upgradecache = true 281 | } 282 | isnew, id, err = self.Object.Save() 283 | 284 | self.Lock() 285 | defer self.Unlock() 286 | if upgradecache == false { 287 | key := self.GetCacheKey() 288 | if i, err := self.Exists(key); err == nil && i == false { 289 | self.SaveToCache() 290 | } 291 | } else { 292 | self.SaveToCache() 293 | } 294 | return 295 | } 296 | 297 | func (self *CacheHook) Filter(name string, val interface{}) *CacheHook { 298 | self.Object.Filter(name, val) 299 | return self 300 | } 301 | func (self *CacheHook) Orderby(order ...string) *CacheHook { 302 | self.Object.Orderby(order...) 303 | return self 304 | } 305 | func (self *CacheHook) Limit(page, step int) *CacheHook { 306 | self.Object.Limit(page, step) 307 | return self 308 | } 309 | 310 | func (self *CacheHook) Query() (Rows, error) { 311 | key := self.getKey() 312 | keys, err := self.Keys(key) 313 | if err != nil { 314 | return nil, err 315 | } 316 | if len(keys) <= 0 { 317 | //return nil, errors.New(key + " not found") 318 | rows, err := self.Object.Query() 319 | return rows, err 320 | } else { 321 | sort.Sort(sort.StringSlice(keys)) 322 | if self.limit != NULL_LIMIT { 323 | page := (self.limit[0] - 1) * self.limit[1] 324 | step := self.limit[0] * self.limit[1] 325 | if step > len(keys) { 326 | step = len(keys) 327 | } 328 | keys = keys[page:step] 329 | } 330 | 331 | return &CacheRows{keys: keys, dbName: self.dbName, index: 0, cache: self.Cache}, nil 332 | } 333 | 334 | } 335 | 336 | func (self *CacheHook) AllOnCache(out interface{}) error { 337 | defer func() { 338 | val := reflect.ValueOf(out).Elem() 339 | for i := 0; i < val.Len(); i++ { 340 | if val.Index(i).Elem().FieldByName("CacheHook").FieldByName("Cache").IsNil() { 341 | m := CacheHook{} 342 | m.Objects(val.Index(i).Addr().Interface().(Module), self.dbName).Existed() 343 | val.Index(i).Elem().FieldByName("CacheHook").Set(reflect.ValueOf(m)) 344 | } 345 | } 346 | }() 347 | key := self.getKey() 348 | if keys, err := self.Keys(key); err == nil && len(keys) > 0 { 349 | //(keys) 350 | sort.Sort(sort.StringSlice(keys)) 351 | if self.limit != NULL_LIMIT { 352 | page := (self.limit[0] - 1) * self.limit[1] 353 | step := self.limit[0] * self.limit[1] 354 | if step > len(keys) { 355 | step = len(keys) 356 | } 357 | value := reflect.ValueOf(out).Elem() 358 | if page < len(keys) { 359 | keys = keys[page:step] 360 | for _, k := range keys { 361 | //vals[i] = self.key2Mode(k) 362 | if mode := self.key2Mode(k); mode.IsValid() { 363 | add := true 364 | for _, param := range self.funcWhere { 365 | if param.val(mode.FieldByName(param.name).Interface()) == false { 366 | add = false 367 | } 368 | } 369 | if add { 370 | value.Set(reflect.Append(value, mode.Addr())) 371 | } 372 | } 373 | } 374 | } 375 | } else { 376 | value := reflect.ValueOf(out).Elem() 377 | for _, k := range keys { 378 | 379 | if mode := self.key2Mode(k); mode.IsValid() { 380 | 381 | add := true 382 | for _, param := range self.funcWhere { 383 | if param.val(mode.FieldByName(param.name).Interface()) == false { 384 | add = false 385 | } 386 | } 387 | if add { 388 | value.Set(reflect.Append(value, mode.Addr())) 389 | } 390 | } 391 | } 392 | 393 | } 394 | 395 | return nil 396 | } else { 397 | return err 398 | } 399 | } 400 | func (self *CacheHook) All(out interface{}) error { 401 | 402 | if err := self.AllOnCache(out); err == nil && reflect.ValueOf(out).Elem().Len() > 0 { 403 | return err 404 | } else { 405 | //self.Object.All() 406 | if debug_sql { 407 | Debug.Println("========================== not in cache ", err, out) 408 | } 409 | if err := self.Object.All(out); err == nil { 410 | 411 | val := reflect.ValueOf(out).Elem() 412 | for i := 0; i < val.Len(); i++ { 413 | if val.Index(i).Elem().FieldByName("CacheHook").FieldByName("Cache").IsNil() { 414 | m := CacheHook{} 415 | m.Objects(val.Index(i).Interface().(Module), self.dbName).Existed() 416 | m.SaveToCache() 417 | val.Index(i).Elem().FieldByName("CacheHook").Set(reflect.ValueOf(m)) 418 | } 419 | } 420 | 421 | return nil 422 | } else { 423 | Error.Println(err) 424 | return err 425 | } 426 | } 427 | } 428 | func (self *CacheHook) Delete() (err error) { 429 | err = self.DeleteOnCache() 430 | if _, err = self.Object.Delete(); err != nil { 431 | return 432 | } 433 | 434 | return 435 | } 436 | func (self *CacheHook) DeleteOnCache() error { 437 | if len(self.cachekey) <= 0 { 438 | self.cachekey = self.getKey() 439 | } 440 | if _, err := self.Del(self.cachekey); err != nil { 441 | return err 442 | } 443 | 444 | return nil 445 | } 446 | func (self *CacheHook) OneOnCache() error { 447 | key := self.getKey() 448 | 449 | self.cachekey = key 450 | n, err := self.Cache.Exists(self.cachekey) 451 | if err != nil { 452 | if debug_sql { 453 | Error.Println(err) 454 | } 455 | 456 | return err 457 | } 458 | 459 | if debug_sql { 460 | Debug.Println("key ", self.cachekey, self.Cache, " is exists ", n) 461 | } 462 | if n == false { 463 | return ErrKeyNotExist 464 | } 465 | 466 | self.where = self.where[len(self.where):] 467 | val := reflect.ValueOf(self.mode).Elem() 468 | typ := reflect.TypeOf(self.mode).Elem() 469 | self.Cache.key2Mode(key, typ, val) 470 | 471 | for i := 0; i < val.NumField(); i++ { 472 | if index := typ.Field(i).Tag.Get("index"); len(index) > 0 { 473 | self.Object.Filter(typ.Field(i).Name, val.Field(i).Interface()) 474 | } 475 | } 476 | self.hasRow = true 477 | return nil 478 | } 479 | 480 | func (self *CacheHook) One() error { 481 | 482 | if err := self.OneOnCache(); err != nil { 483 | //return errors.New("key " + key + " not exists!") 484 | err = self.Object.One() 485 | if err == nil { 486 | 487 | err = self.SaveToCache() //self.saveToCache(self.mode) 488 | } 489 | return err 490 | } else { 491 | if debug_sql { 492 | Debug.Println("内存命中", self.cachekey) 493 | } 494 | } 495 | return nil 496 | } 497 | func (self *CacheHook) CountOnCache() (int64, error) { 498 | if keys, err := self.Cache.Keys(self.getKey()); err == nil { 499 | return int64(len(keys)), nil 500 | } else { 501 | return 0, err 502 | } 503 | } 504 | func (self *CacheHook) Count() (int64, error) { 505 | if keys, err := self.Cache.Keys(self.getKey()); err == nil && len(keys) > 0 { 506 | return int64(len(keys)), nil 507 | } 508 | return self.Object.Count() 509 | } 510 | 511 | func (self *CacheHook) getKey() string { 512 | key := "" 513 | if len(self.where) > 0 { 514 | key = self.where2Key() 515 | } else { 516 | key = self.GetCacheKey() 517 | } 518 | return key 519 | } 520 | func (self *CacheHook) where2Key() string { 521 | str := cache_prefix 522 | str = append(str, []byte(self.cache_prefix)...) 523 | for index, field := range self.CacheFileds { 524 | for _, wh := range self.where { 525 | if wh.name == field { 526 | str = append(str, []byte(":")...) 527 | str = append(str, self.fieldToByte(wh.val)...) 528 | str = append(str, []byte(":"+self.CacheNames[index])...) 529 | goto NEXT 530 | } 531 | 532 | } 533 | str = append(str, []byte(":*:"+self.CacheNames[index])...) 534 | NEXT: 535 | } 536 | return string(str) 537 | } 538 | 539 | func (self *CacheHook) fieldToByte(value interface{}) (str []byte) { 540 | typ := reflect.TypeOf(value) 541 | val := reflect.ValueOf(value) 542 | switch typ.Kind() { 543 | case reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uint8, reflect.Uint16: 544 | if val.Uint() <= 0 { 545 | str = append(str, st...) 546 | } else { 547 | str = strconv.AppendUint(str, val.Uint(), 10) 548 | } 549 | case reflect.Int32, reflect.Int64, reflect.Int, reflect.Int8, reflect.Int16: 550 | if val.Int() <= 0 { 551 | str = append(str, st...) 552 | } else { 553 | str = strconv.AppendInt(str, val.Int(), 10) 554 | } 555 | case reflect.Float32, reflect.Float64: 556 | if val.Float() == 0.0 { 557 | str = append(str, st...) 558 | } else { 559 | str = strconv.AppendFloat(str, val.Float(), 'f', 0, 64) 560 | } 561 | case reflect.String: 562 | if val.Len() <= 0 { 563 | str = append(str, st...) 564 | } else { 565 | str = append(str, []byte(val.String())...) 566 | } 567 | case reflect.Bool: 568 | switch val.Bool() { 569 | case true: 570 | str = append(str, []byte("true")...) 571 | case false: 572 | str = append(str, []byte("false")...) 573 | } 574 | default: 575 | switch value.(type) { 576 | case time.Time: 577 | str = append(str, []byte(value.(time.Time).Format(time.RFC1123Z))...) 578 | } 579 | } 580 | return 581 | } 582 | 583 | func (self *CacheHook) key2Mode(key string) reflect.Value { 584 | typ := reflect.TypeOf(self.mode).Elem() 585 | val := reflect.New(typ).Elem() 586 | 587 | var err error 588 | err = self.Cache.key2Mode(key, typ, val) 589 | if err != nil { 590 | Error.Println(err.Error()) 591 | } 592 | mode := CacheHook{} 593 | mode.Objects(val.Addr().Interface().(Module), self.dbName).Existed() 594 | val.FieldByName("CacheHook").Set(reflect.ValueOf(mode)) 595 | return val 596 | } 597 | 598 | func (self CacheHook) SaveToCache() error { 599 | key := self.GetCacheKey() 600 | 601 | maping := map[string]interface{}{} 602 | vals := reflect.ValueOf(self.mode).Elem() 603 | typ := reflect.TypeOf(self.mode).Elem() 604 | for i := 0; i < vals.NumField(); i++ { 605 | field := typ.Field(i) 606 | if name := field.Tag.Get("field"); len(name) > 0 { 607 | if nocache := field.Tag.Get("no_cache"); len(nocache) == 0 { 608 | switch vals.Field(i).Interface().(type) { 609 | case time.Time: 610 | maping[field.Name] = vals.Field(i).Interface().(time.Time).Format(time.RFC1123Z) 611 | default: 612 | maping[field.Name] = vals.Field(i).Interface() 613 | } 614 | } 615 | } 616 | //补充一个仅存在于cache中的字段。 617 | if name := field.Tag.Get("cache_only_field"); len(name) > 0 { 618 | switch vals.Field(i).Interface().(type) { 619 | case time.Time: 620 | maping[field.Name] = vals.Field(i).Interface().(time.Time).Format(time.RFC1123Z) 621 | default: 622 | maping[field.Name] = vals.Field(i).Interface() 623 | } 624 | } 625 | } 626 | err := self.Cache.Hmset(key, maping) 627 | if debug_sql { 628 | Debug.Println("转储倒内存", key, maping, err, self.Cache) 629 | } 630 | return nil 631 | } 632 | --------------------------------------------------------------------------------