github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/models/model.go (about) 1 //TODO 下一版本重构数据库表结构 采用空间换时间 通过数据的冗余,实现去关联查询 2 3 package models 4 5 import ( 6 _ "github.com/insionng/yougam/libraries/go-sql-driver/mysql" 7 _ "github.com/insionng/yougam/libraries/lib/pq" 8 //_ "github.com/insionng/yougam/libraries/mattn/go-sqlite3" // need cgo! 9 10 //"github.com/go-xorm/core" 11 //"github.com/go-xorm/xorm" 12 _ "github.com/insionng/yougam/libraries/go-xorm/tidb" 13 _ "github.com/insionng/yougam/libraries/pingcap/tidb" 14 //_ "github.com/go-xorm/tidb" 15 16 "github.com/insionng/yougam/libraries/go-xorm/core" 17 "github.com/insionng/yougam/libraries/go-xorm/xorm" 18 19 "errors" 20 "fmt" 21 "log" 22 "os" 23 "path" 24 "time" 25 "github.com/insionng/yougam/helper" 26 ) 27 28 var ( 29 Engine *xorm.Engine 30 HasEngine bool 31 32 DataType = helper.DataType 33 DBConnect = helper.DBConnect 34 ) 35 36 /* 37 设计索引时,最好能够选择具有唯一性的字段或者重复性比较少的字段 38 如此设置索引对于数据库性能来说才有比较大的价值 39 40 通常情况下,只有当经常查询索引列中的数据时,才需要在表上创建索引。 41 索引将占用磁盘空间,并且降低添加、删除和更新行的速度。 42 不过在多数情况下,索引所带来的数据检索速度的优势大大超过它的不足之处。 43 然而,如果应用程序非常频繁地更新数据,或磁盘空间有限,那么最好限制索引的数量。 44 45 频繁变化的字段尽量不要设置索引 46 */ 47 48 //Usergroup,Pid:root 49 type Usergroup struct { 50 Id int64 51 Pid int64 `xorm:"index"` 52 Uid int64 `xorm:"index"` //创建者ID 53 Sort int64 54 Ctype int64 `xorm:"index"` 55 Title string `xorm:"index"` 56 Content string `xorm:"text"` 57 Attachment string `xorm:"text"` 58 Created int64 `xorm:"created index"` 59 Updated int64 `xorm:"updated"` 60 Hotness float64 `xorm:"index"` 61 Hotup int64 `xorm:"index"` 62 Hotdown int64 `xorm:"index"` 63 Hotscore int64 `xorm:"index"` //Hotup - Hotdown 64 Hotvote int64 `xorm:"index"` //Hotup + Hotdown 65 Views int64 66 Author string `xorm:"index"` //这里指本用户组创建者 67 UserTime int64 68 UserCount int64 69 UserLastUserId int64 70 } 71 72 type Timeline struct { 73 Id int64 74 Cid int64 `xorm:"index"` 75 Nid int64 `xorm:"index"` 76 Uid int64 `xorm:"index"` 77 Sort int64 78 Ctype int64 `xorm:"index"` 79 Title string `xorm:"index"` 80 Content string `xorm:"text"` 81 Attachment string `xorm:"text"` 82 Created int64 `xorm:"created index"` 83 Updated int64 `xorm:"updated"` 84 Hotness float64 `xorm:"index"` 85 Hotup int64 `xorm:"index"` 86 Hotdown int64 `xorm:"index"` 87 Hotscore int64 `xorm:"index"` //Hotup - Hotdown 88 Hotvote int64 `xorm:"index"` //Hotup + Hotdown 89 Views int64 `xorm:"index"` 90 Author string `xorm:"index"` 91 AuthorSignature string `xorm:"index"` 92 Category string `xorm:"index"` 93 Node string `xorm:"index"` 94 ReplyTime int64 95 ReplyCount int64 `xorm:"index"` 96 ReplyLastUserId int64 97 ReplyLastUsername string 98 ReplyLastNickname string 99 } 100 101 type ReportMark struct { 102 Id int64 103 Uid int64 `xorm:"index"` //举报人 104 Rid int64 `xorm:"index"` //被举报项id 105 Ctype int64 `xorm:"index"` // 1为topic类型 -1是comment类型 106 Title string `xorm:"index"` //举报标题 107 Content string `xorm:"text"` //举报内容 108 } 109 110 func ConDb() (*xorm.Engine, error) { 111 switch { 112 case DataType == "memory": 113 return xorm.NewEngine("tidb", "memory://tidb/tidb") 114 115 case DataType == "goleveldb": 116 if DBConnect != "" { 117 return xorm.NewEngine("tidb", DBConnect) 118 } 119 return xorm.NewEngine("tidb", "goleveldb://"+helper.FileStorageDir+"data/tidb/tidb") 120 121 case DataType == "boltdb": 122 if DBConnect != "" { 123 return xorm.NewEngine("tidb", DBConnect) 124 } 125 return xorm.NewEngine("tidb", "boltdb://"+helper.FileStorageDir+"data/tidb/tidb") 126 case DataType == "sqlite": 127 if DBConnect != "" { 128 return xorm.NewEngine("sqlite3", DBConnect) 129 } 130 return xorm.NewEngine("sqlite3", helper.FileStorageDir+"data/sqlite.db") 131 132 case DataType == "mysql": 133 return xorm.NewEngine("mysql", DBConnect) 134 //return xorm.NewEngine("mysql", "root:YouPass@/db?charset=utf8") 135 136 case DataType == "postgres": 137 return xorm.NewEngine("postgres", DBConnect) 138 //return xorm.NewEngine("postgres", "user=postgres password=jn!@#$%^&* dbname=pgsql sslmode=disable") 139 140 // "user=postgres password=jn!@#$%^&* dbname=yougam sslmode=disable maxcons=10 persist=true" 141 //return xorm.NewEngine("postgres", "host=192.168.1.113 user=postgres password=jn!@#$%^&* dbname=yougam sslmode=disable") 142 //return xorm.NewEngine("postgres", "host=127.0.0.1 port=6432 user=postgres password=jn!@#$%^&* dbname=yougam sslmode=disable") 143 } 144 return nil, errors.New("Unknown database type..") 145 } 146 147 func SetEngine() (*xorm.Engine, error) { 148 var _error error 149 if Engine, _error = ConDb(); _error != nil { 150 return nil, fmt.Errorf("Fail to connect to database: %s", _error.Error()) 151 } else { 152 Engine.SetTableMapper(core.NewPrefixMapper(core.GonicMapper{}, helper.DBTablePrefix)) 153 Engine.SetColumnMapper(core.GonicMapper{}) 154 155 cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 10240) 156 Engine.SetDefaultCacher(cacher) 157 158 logPath := path.Join(helper.FileStorageDir+"logs", "xorm.log") 159 os.MkdirAll(path.Dir(logPath), os.ModePerm) 160 f, err := os.Create(logPath) 161 if err != nil { 162 return Engine, fmt.Errorf("Fail to create xorm.log: %s", err.Error()) 163 } 164 165 Engine.SetLogger(xorm.NewSimpleLogger(f)) 166 Engine.ShowSQL(false) 167 168 if location, err := time.LoadLocation("Asia/Shanghai"); err == nil { 169 Engine.TZLocation = location 170 } 171 172 return Engine, err 173 } 174 } 175 176 func NewEngine() error { 177 var _error error 178 Engine, _error = SetEngine() 179 return _error 180 } 181 182 func init() { 183 184 var _error error 185 if Engine, _error = SetEngine(); _error != nil { 186 log.Fatal("yougam.models.init() errors:", _error.Error()) 187 } 188 189 if _error = createTables(Engine); _error != nil { 190 log.Fatal("Fail to creatTables errors:", _error.Error()) 191 } 192 193 initData() 194 195 } 196 197 func Ping() error { 198 return Engine.Ping() 199 } 200 201 func createTables(Engine *xorm.Engine) error { 202 return Engine.Sync2(&User{}, &Balance{}, &Message{}, &HistoryMessage{}, &Friend{}, &Category{}, &Node{}, &Topic{}, &Page{}, &Reply{}, &Attachment{}, &Link{}, &Notification{}, &UserMark{}, &TopicMark{}, &ReplyMark{}, &NodeMark{}, &ReportMark{}, &IssueMark{}) 203 } 204 205 func initData() { 206 //用户等级划分:正数是普通用户,负数是管理员各种等级划分,为0则尚未注册 207 if usr, err := GetUserByRole(-1000); usr == nil && err == nil { 208 if row, err := AddUser("root@yougam.com", "root", "root", "root", helper.EncryptHash("rootpass", nil), "", "", "", 1, -1000); err == nil && row > 0 { 209 log.Println("Default Email:root@yougam.com ,Username:root ,Password:rootpass") 210 211 if usr, err := GetUserByRole(-1000); usr != nil && err == nil { 212 SetAmountByUid(usr.Id, 2, 2000, "注册收益2000金币") 213 } 214 215 } else { 216 log.Println("create root got errors:", err) 217 } 218 219 } 220 221 if cats, err := GetCategories(0, 0, "id"); cats == nil && err == nil { 222 log.Println(AddCategory("默认分类", "默认分类内容简介", "", 0)) 223 } 224 225 fmt.Println("-----------------------------------------------------------") 226 fmt.Println("The yougam system has started!") 227 } 228 229 func Counts() (categories int, nodes int, topics int, users int, replys int) { 230 231 var err error 232 var cnt int64 233 if cnt, err = Engine.Count(new(Category)); err != nil { 234 log.Println(err) 235 } 236 categories = int(cnt) 237 238 if cnt, err = Engine.Count(new(Node)); err != nil { 239 log.Println(err) 240 } 241 nodes = int(cnt) 242 243 if cnt, err = Engine.Count(new(Topic)); err != nil { 244 log.Println(err) 245 } 246 topics = int(cnt) 247 248 if cnt, err = Engine.Count(new(User)); err != nil { 249 log.Println(err) 250 } 251 users = int(cnt) 252 253 if cnt, err = GetReplysByPid4Count(0, 0, 0, 0); err != nil { 254 log.Println(err) 255 } 256 replys = int(cnt) 257 return categories, nodes, topics, users, replys 258 } 259 260 func SearchTopic(content string, offset int, limit int, field string) (*[]*Topic, error) { 261 //排序首先是热值优先,然后是时间优先。 262 if len(content) > 0 { 263 264 keyword := "%" + content + "%" 265 266 tps := new([]*Topic) 267 268 err := Engine.Where("title like ? or content like ?", keyword, keyword).Limit(limit, offset).Desc(field, "views", "reply_count", "created").Find(tps) 269 return tps, err 270 } 271 return nil, errors.New("搜索内容为空!") 272 } 273 274 func SearchSubject(content string, offset int, limit int, field string) (*[]*Topic, error) { 275 //排序首先是热值优先,然后是时间优先。 276 if len(content) > 0 { 277 278 keyword := "%" + content + "%" 279 280 tps := new([]*Topic) 281 282 err := Engine.Table("topic").Where("topic.pid=0 and (topic.title like ? or topic.content like ?)", keyword, keyword).Limit(limit, offset).Desc("topic."+field, "topic.views", "topic.reply_count", "topic.created").Find(tps) 283 return tps, err 284 } 285 return nil, errors.New("搜索内容为空!") 286 } 287 288 func SearchSubjectJoinUser(content string, offset int, limit int, field string) (*[]*Topicjuser, error) { 289 //排序首先是热值优先,然后是时间优先。 290 if len(content) > 0 { 291 292 keyword := "%" + content + "%" 293 294 tps := new([]*Topicjuser) 295 296 err := Engine.Table("topic").Where("topic.pid=0 and (topic.title like ? or topic.content like ?)", keyword, keyword).Limit(limit, offset).Desc("topic."+field, "topic.views", "topic.reply_count", "topic.created").Join("LEFT", "user", "user.id = topic.uid").Find(tps) 297 return tps, err 298 } 299 return nil, errors.New("搜索内容为空!") 300 } 301 302 //SearchUser 搜索用户 303 func SearchUser(content string, offset int, limit int, field string) (*[]*User, error) { 304 //排序首先是热值优先,然后是时间优先。 305 if len(content) > 0 { 306 307 keyword := "%" + content + "%" 308 309 usr := new([]*User) 310 311 err := Engine.Where("username like ?", keyword).Limit(limit, offset).Desc(field, "views", "reply_count", "created").Find(usr) 312 return usr, err 313 } 314 return nil, errors.New("搜索用户为空!") 315 } 316 317 //SearchNode 搜索节点 318 func SearchNode(content string, offset int, limit int, field string) (*[]*Node, error) { 319 //排序首先是热值优先,然后是时间优先。 320 if len(content) > 0 { 321 322 keyword := "%" + content + "%" 323 324 nds := new([]*Node) 325 326 err := Engine.Where("title like ? or content like ?", keyword, keyword).Limit(limit, offset).Desc(field, "views", "topic_count", "created").Find(nds) 327 return nds, err 328 } 329 return nil, errors.New("搜索内容为空!") 330 } 331 332 //SearchCategory 搜索分类 333 func SearchCategory(content string, offset int, limit int, field string) (*[]*Category, error) { 334 //排序首先是热值优先,然后是时间优先。 335 if len(content) > 0 { 336 337 keyword := "%" + content + "%" 338 339 cats := new([]*Category) 340 341 err := Engine.Where("title like ? or content like ?", keyword, keyword).Limit(limit, offset).Desc(field, "views", "node_count", "created").Find(cats) 342 return cats, err 343 } 344 return nil, errors.New("搜索内容为空!") 345 } 346 347 //SetReportMark 设置举报标记 348 func SetReportMark(uid int64, rid int64, ctype int64, content string) (int64, error) { 349 rptm := &ReportMark{Uid: uid, Rid: rid, Ctype: ctype, Content: content} 350 rows, err := Engine.Insert(rptm) 351 return rows, err 352 } 353 354 func IsReportMark(uid int64, rid int64, ctype int64) bool { 355 356 rptm := &ReportMark{} 357 358 if has, err := Engine.Where("uid=? and rid=? and ctype=?", uid, rid, ctype).Get(rptm); err != nil { 359 fmt.Println(err) 360 return false 361 } else { 362 if has { 363 if rptm.Uid == uid { 364 return true 365 } else { 366 return false 367 } 368 369 } else { 370 return false 371 } 372 } 373 374 } 375 376 func GetReport(rid int64) (*ReportMark, error) { 377 378 rm := &ReportMark{} 379 380 has, err := Engine.Id(rid).Get(rm) 381 if has { 382 return rm, err 383 } else { 384 385 return nil, err 386 } 387 } 388 389 func GetReports(offset int, limit int, field string, ctype int64) (*[]*ReportMark, error) { 390 391 rms := new([]*ReportMark) 392 393 if ctype == 0 { //同时查询两种类型举报项 394 err := Engine.Limit(limit, offset).Desc(field).Find(rms) 395 return rms, err 396 397 } else if (ctype == 1) || (ctype == -1) { //1为topic类型 -1是comment类型 按指定类型查询举报项目 398 399 err := Engine.Where("ctype=?", ctype).Limit(limit, offset).Desc(field).Find(rms) 400 return rms, err 401 } else { 402 403 return nil, nil 404 } 405 } 406 407 func GetNodeCountByPid(cid int64) int64 { 408 n, _ := Engine.Where("pid=?", cid).Count(&Node{Pid: cid}) 409 return n 410 } 411 412 func AddTimeline(title string, content string, cid int64, nid int64, uid int64, author string, author_signature string) (int64, error) { 413 414 id, err := Engine.Insert(&Timeline{Cid: cid, Nid: nid, Uid: uid, Title: title, Content: content, Author: author, AuthorSignature: author_signature, Created: time.Now().Unix()}) 415 416 return id, err 417 } 418 419 func DelTimeline(lid int64) error { 420 if row, err := Engine.Id(lid).Delete(new(Timeline)); err != nil || row == 0 { 421 return errors.New("删除时光记录错误!") 422 } else { 423 return nil 424 } 425 426 } 427 428 func GetTimeline(lid int64) (*Timeline, error) { 429 tl := new(Timeline) 430 _, err := Engine.Where("id=?", lid).Get(tl) 431 432 return tl, err 433 } 434 435 func GetTimelines(offset int, limit int, path string, uid int64) (*[]*Timeline, error) { 436 tls := new([]*Timeline) 437 err := errors.New("") 438 if uid == 0 { 439 err = Engine.Limit(limit, offset).Desc(path).Find(tls) 440 } else { 441 if err = Engine.Where("uid=?", uid).Limit(limit, offset).Desc(path).Find(tls); err != nil { 442 err = Engine.Where("uid=?", uid).NoCache().Limit(limit, offset).Desc(path).Find(tls) 443 } 444 } 445 return tls, err 446 }