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  }