Added support for offsets and max counts to the query generator.

Early draft of the ForumStore. Not much to see here yet!

Fixed a race condition in forum creation.
Fixed a race condition in group creation.
Fixed a race condition in forum deletion.
Moved four queries to the query generator.
Renamed StaticTopicStore to MemoryTopicStore.
Renamed StaticUserStore to MemoryUserStore.
SimpleSessionCheck is now pluggable.

We no longer have any raw queries outside mysql.go or the query generator, yay.
This commit is contained in:
Azareal 2017-06-15 12:40:35 +01:00
parent 8c1d8d5c64
commit 1ccd4479ae
17 changed files with 261 additions and 158 deletions

View File

@ -3,6 +3,11 @@ package main
import "log" import "log"
import "fmt" import "fmt"
import "encoding/json" import "encoding/json"
import "database/sql"
var db *sql.DB
var db_version string
var db_collation string = "utf8mb4_general_ci"
func init_database() (err error) { func init_database() (err error) {
// Engine specific code // Engine specific code
@ -66,6 +71,7 @@ func init_database() (err error) {
if err != nil { if err != nil {
return err return err
} }
fstore = NewStaticForumStore()
log.Print("Loading the settings.") log.Print("Loading the settings.")
err = LoadSettings() err = LoadSettings()

View File

@ -41,16 +41,6 @@ type ForumSimple struct
Preset string Preset string
} }
/*type ForumStore interface
{
Get(int) (*Forum, error)
CascadeGet(int) (*Forum, error)
Update(Forum) error
CascadeUpdate(Forum) error
Delete(int) error
CascadeDelete(int) error
}*/
func LoadForums() error { func LoadForums() error {
//if debug { //if debug {
log.Print("Adding the uncategorised forum") log.Print("Adding the uncategorised forum")
@ -95,6 +85,7 @@ func LoadForums() error {
} }
var forum_update_mutex sync.Mutex var forum_update_mutex sync.Mutex
var forum_create_mutex sync.Mutex
func create_forum(forum_name string, forum_desc string, active bool, preset string) (int, error) { func create_forum(forum_name string, forum_desc string, active bool, preset string) (int, error) {
var fid int var fid int
err := forum_entry_exists_stmt.QueryRow().Scan(&fid) err := forum_entry_exists_stmt.QueryRow().Scan(&fid)
@ -115,6 +106,7 @@ func create_forum(forum_name string, forum_desc string, active bool, preset stri
return fid, nil return fid, nil
} }
forum_create_mutex.Lock()
res, err := create_forum_stmt.Exec(forum_name, forum_desc, active, preset) res, err := create_forum_stmt.Exec(forum_name, forum_desc, active, preset)
if err != nil { if err != nil {
return 0, err return 0, err
@ -127,15 +119,18 @@ func create_forum(forum_name string, forum_desc string, active bool, preset stri
fid = int(fid64) fid = int(fid64)
forums = append(forums, Forum{fid,forum_name,forum_desc,active,preset,0,"",0,"",0,""}) forums = append(forums, Forum{fid,forum_name,forum_desc,active,preset,0,"",0,"",0,""})
forum_create_mutex.Unlock()
return fid, nil return fid, nil
} }
func delete_forum(fid int) error { func delete_forum(fid int) error {
forum_update_mutex.Lock()
_, err := delete_forum_stmt.Exec(fid) _, err := delete_forum_stmt.Exec(fid)
if err != nil { if err != nil {
return err return err
} }
forums[fid].Name = "" forums[fid].Name = ""
forum_update_mutex.Unlock()
return nil return nil
} }

70
forum_store.go Normal file
View File

@ -0,0 +1,70 @@
/* Work in progress. Check back later! */
package main
import "log"
import "errors"
import "database/sql"
import "./query_gen/lib"
var err_noforum = errors.New("This forum doesn't exist")
type ForumStore interface
{
Get(int) (*Forum, error)
CascadeGet(int) (*Forum, error)
BypassGet(int) (*Forum, error)
//Update(Forum) error
//CascadeUpdate(Forum) error
//Delete(int) error
//CascadeDelete(int) error
//QuickCreate(string, string, bool, string) (*Forum, error)
Exists(int) bool
}
type StaticForumStore struct
{
get *sql.Stmt
get_all *sql.Stmt
}
func NewStaticForumStore() *StaticForumStore {
get_stmt, err := qgen.Builder.SimpleSelect("forums","name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","fid = ?","","")
if err != nil {
log.Fatal(err)
}
get_all_stmt, err := qgen.Builder.SimpleSelect("forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
if err != nil {
log.Fatal(err)
}
return &StaticForumStore{
get: get_stmt,
get_all: get_all_stmt,
}
}
func (sfs *StaticForumStore) Get(id int) (*Forum, error) {
if !((id <= forumCapCount) && (id >= 0) && forums[id].Name!="") {
return nil, err_noforum
}
return &forums[id], nil
}
func (sfs *StaticForumStore) CascadeGet(id int) (*Forum, error) {
if !((id <= forumCapCount) && (id >= 0) && forums[id].Name!="") {
return nil, err_noforum
}
return &forums[id], nil
}
func (sfs *StaticForumStore) BypassGet(id int) (*Forum, error) {
var forum Forum = Forum{ID:id}
err := sfs.get.QueryRow(id).Scan(&forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
if err != nil {
return nil, err
}
return &forum, nil
}
func (sfs *StaticForumStore) Exists(id int) bool {
return (id <= forumCapCount) && (id >= 0) && forums[id].Name != ""
}

View File

@ -37,6 +37,10 @@ var get_user_group_stmt *sql.Stmt
var get_emails_by_user_stmt *sql.Stmt var get_emails_by_user_stmt *sql.Stmt
var get_topic_basic_stmt *sql.Stmt var get_topic_basic_stmt *sql.Stmt
var get_activity_entry_stmt *sql.Stmt var get_activity_entry_stmt *sql.Stmt
var forum_entry_exists_stmt *sql.Stmt
var group_entry_exists_stmt *sql.Stmt
var get_topic_replies_offset_stmt *sql.Stmt
var get_forum_topics_offset_stmt *sql.Stmt
var get_topic_list_stmt *sql.Stmt var get_topic_list_stmt *sql.Stmt
var get_topic_user_stmt *sql.Stmt var get_topic_user_stmt *sql.Stmt
var get_topic_by_reply_stmt *sql.Stmt var get_topic_by_reply_stmt *sql.Stmt
@ -297,6 +301,30 @@ func gen_mysql() (err error) {
return err return err
} }
log.Print("Preparing forum_entry_exists statement.")
forum_entry_exists_stmt, err = db.Prepare("SELECT `fid` FROM `forums` WHERE `name` = '' ORDER BY fid ASC LIMIT 0,1")
if err != nil {
return err
}
log.Print("Preparing group_entry_exists statement.")
group_entry_exists_stmt, err = db.Prepare("SELECT `gid` FROM `users_groups` WHERE `name` = '' ORDER BY gid ASC LIMIT 0,1")
if err != nil {
return err
}
log.Print("Preparing get_topic_replies_offset statement.")
get_topic_replies_offset_stmt, err = db.Prepare("SELECT `replies`.`rid`,`replies`.`content`,`replies`.`createdBy`,`replies`.`createdAt`,`replies`.`lastEdit`,`replies`.`lastEditBy`,`users`.`avatar`,`users`.`name`,`users`.`group`,`users`.`url_prefix`,`users`.`url_name`,`users`.`level`,`replies`.`ipaddress`,`replies`.`likeCount`,`replies`.`actionType` FROM `replies` LEFT JOIN `users` ON `replies`.`createdBy` = `users`.`uid` WHERE `tid` = ? LIMIT ?,?")
if err != nil {
return err
}
log.Print("Preparing get_forum_topics_offset statement.")
get_forum_topics_offset_stmt, err = db.Prepare("SELECT `topics`.`tid`,`topics`.`title`,`topics`.`content`,`topics`.`createdBy`,`topics`.`is_closed`,`topics`.`sticky`,`topics`.`createdAt`,`topics`.`lastReplyAt`,`topics`.`parentID`,`topics`.`postCount`,`topics`.`likeCount`,`users`.`name`,`users`.`avatar` FROM `topics` LEFT JOIN `users` ON `topics`.`createdBy` = `users`.`uid` WHERE `topics`.`parentID` = ? ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC LIMIT ?,?")
if err != nil {
return err
}
log.Print("Preparing get_topic_list statement.") log.Print("Preparing get_topic_list statement.")
get_topic_list_stmt, err = db.Prepare("SELECT `topics`.`tid`,`topics`.`title`,`topics`.`content`,`topics`.`createdBy`,`topics`.`is_closed`,`topics`.`sticky`,`topics`.`createdAt`,`topics`.`parentID`,`users`.`name`,`users`.`avatar` FROM `topics` LEFT JOIN `users` ON `topics`.`createdBy` = `users`.`uid` ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC") get_topic_list_stmt, err = db.Prepare("SELECT `topics`.`tid`,`topics`.`title`,`topics`.`content`,`topics`.`createdBy`,`topics`.`is_closed`,`topics`.`sticky`,`topics`.`createdAt`,`topics`.`parentID`,`users`.`name`,`users`.`avatar` FROM `topics` LEFT JOIN `users` ON `topics`.`createdBy` = `users`.`uid` ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC")
if err != nil { if err != nil {

View File

@ -55,8 +55,8 @@ func gloinit() {
} }
if cache_topicuser == CACHE_STATIC { if cache_topicuser == CACHE_STATIC {
users = NewStaticUserStore(user_cache_capacity) users = NewMemoryUserStore(user_cache_capacity)
topics = NewStaticTopicStore(topic_cache_capacity) topics = NewMemoryTopicStore(topic_cache_capacity)
} else { } else {
users = NewSqlUserStore() users = NewSqlUserStore()
topics = NewSqlTopicStore() topics = NewSqlTopicStore()

View File

@ -31,6 +31,7 @@ type Group struct
CanSee []int // The IDs of the forums this group can see CanSee []int // The IDs of the forums this group can see
} }
var group_create_mutex sync.Mutex
func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_banned bool) (int, error) { func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_banned bool) (int, error) {
var gid int var gid int
err := group_entry_exists_stmt.QueryRow().Scan(&gid) err := group_entry_exists_stmt.QueryRow().Scan(&gid)
@ -58,6 +59,7 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
return gid, nil return gid, nil
} }
group_create_mutex.Lock()
var permstr string = "{}" var permstr string = "{}"
res, err := create_group_stmt.Exec(group_name, tag, is_admin, is_mod, is_banned, permstr) res, err := create_group_stmt.Exec(group_name, tag, is_admin, is_mod, is_banned, permstr)
if err != nil { if err != nil {
@ -73,6 +75,7 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
var blankForums []ForumPerms var blankForums []ForumPerms
var blankIntList []int var blankIntList []int
groups = append(groups, Group{gid,group_name,is_mod,is_admin,is_banned,tag,perms,[]byte(permstr),blankForums,blankIntList}) groups = append(groups, Group{gid,group_name,is_mod,is_admin,is_banned,tag,perms,[]byte(permstr),blankForums,blankIntList})
group_create_mutex.Unlock()
// Generate the forum permissions based on the presets... // Generate the forum permissions based on the presets...
fdata := forums fdata := forums

View File

@ -43,6 +43,7 @@ var external_sites map[string]string = make(map[string]string)
var groups []Group var groups []Group
var forums []Forum // The IDs for a forum tend to be low and sequential for the most part, so we can get more performance out of using a slice instead of a map AND it has better concurrency var forums []Forum // The IDs for a forum tend to be low and sequential for the most part, so we can get more performance out of using a slice instead of a map AND it has better concurrency
var forum_perms map[int]map[int]ForumPerms // [gid][fid]Perms var forum_perms map[int]map[int]ForumPerms // [gid][fid]Perms
var fstore ForumStore // :soon:
var groupCapCount, forumCapCount int var groupCapCount, forumCapCount int
var static_files map[string]SFile = make(map[string]SFile) var static_files map[string]SFile = make(map[string]SFile)
@ -185,8 +186,8 @@ func main(){
} }
if cache_topicuser == CACHE_STATIC { if cache_topicuser == CACHE_STATIC {
users = NewStaticUserStore(user_cache_capacity) users = NewMemoryUserStore(user_cache_capacity)
topics = NewStaticTopicStore(topic_cache_capacity) topics = NewMemoryTopicStore(topic_cache_capacity)
} else { } else {
users = NewSqlUserStore() users = NewSqlUserStore()
topics = NewSqlTopicStore() topics = NewSqlTopicStore()

View File

@ -3,23 +3,14 @@
package main package main
import "log" import "log"
import "strconv" import "strings"
import "database/sql" import "database/sql"
import _ "github.com/go-sql-driver/mysql" import _ "github.com/go-sql-driver/mysql"
import "./query_gen/lib" import "./query_gen/lib"
var db *sql.DB
var db_version string
var db_collation string = "utf8mb4_general_ci"
var get_topic_replies_offset_stmt *sql.Stmt // I'll need to rewrite this one to stop it hard-coding the per page setting before moving it to the query generator
var get_forum_topics_offset_stmt *sql.Stmt
var notify_watchers_stmt *sql.Stmt var notify_watchers_stmt *sql.Stmt
var get_activity_feed_by_watcher_stmt *sql.Stmt var get_activity_feed_by_watcher_stmt *sql.Stmt
var get_activity_count_by_watcher_stmt *sql.Stmt var get_activity_count_by_watcher_stmt *sql.Stmt
var forum_entry_exists_stmt *sql.Stmt
var group_entry_exists_stmt *sql.Stmt
var add_forum_perms_to_forum_admins_stmt *sql.Stmt var add_forum_perms_to_forum_admins_stmt *sql.Stmt
var add_forum_perms_to_forum_staff_stmt *sql.Stmt var add_forum_perms_to_forum_staff_stmt *sql.Stmt
var add_forum_perms_to_forum_members_stmt *sql.Stmt var add_forum_perms_to_forum_members_stmt *sql.Stmt
@ -65,18 +56,6 @@ func _init_database() (err error) {
return err return err
} }
log.Print("Preparing get_topic_replies_offset statement.")
get_topic_replies_offset_stmt, err = db.Prepare("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType from replies left join users on replies.createdBy = users.uid where tid = ? limit ?, " + strconv.Itoa(items_per_page))
if err != nil {
return err
}
log.Print("Preparing get_forum_topics_offset statement.")
get_forum_topics_offset_stmt, err = db.Prepare("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid WHERE topics.parentID = ? order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC limit ?, " + strconv.Itoa(items_per_page))
if err != nil {
return err
}
log.Print("Preparing notify_watchers statement.") log.Print("Preparing notify_watchers statement.")
notify_watchers_stmt, err = db.Prepare("INSERT INTO activity_stream_matches(watcher, asid) SELECT activity_subscriptions.user, activity_stream.asid FROM activity_stream INNER JOIN activity_subscriptions ON activity_subscriptions.targetType = activity_stream.elementType and activity_subscriptions.targetID = activity_stream.elementID and activity_subscriptions.user != activity_stream.actor where asid = ?") notify_watchers_stmt, err = db.Prepare("INSERT INTO activity_stream_matches(watcher, asid) SELECT activity_subscriptions.user, activity_stream.asid FROM activity_stream INNER JOIN activity_subscriptions ON activity_subscriptions.targetType = activity_stream.elementType and activity_subscriptions.targetID = activity_stream.elementID and activity_subscriptions.user != activity_stream.actor where asid = ?")
if err != nil { if err != nil {
@ -95,18 +74,6 @@ func _init_database() (err error) {
return err return err
} }
log.Print("Preparing forum_entry_exists statement.")
forum_entry_exists_stmt, err = db.Prepare("SELECT `fid` FROM `forums` WHERE `name` = '' order by fid asc limit 1")
if err != nil {
return err
}
log.Print("Preparing group_entry_exists statement.")
group_entry_exists_stmt, err = db.Prepare("SELECT `gid` FROM `users_groups` WHERE `name` = '' order by gid asc limit 1")
if err != nil {
return err
}
log.Print("Preparing add_forum_perms_to_forum_admins statement.") log.Print("Preparing add_forum_perms_to_forum_admins statement.")
add_forum_perms_to_forum_admins_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset,? AS permissions FROM users_groups WHERE is_admin = 1") add_forum_perms_to_forum_admins_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset,? AS permissions FROM users_groups WHERE is_admin = 1")
if err != nil { if err != nil {
@ -151,3 +118,8 @@ func _init_database() (err error) {
return nil return nil
} }
// Temporary hack so that we can move all the raw queries out of the other files and into here
func topic_list_query(visible_fids []string) string {
return "select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where parentID in("+strings.Join(visible_fids,",")+") order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC"
}

View File

@ -28,8 +28,8 @@ func (build *builder) SetAdapter(name string) error {
return nil return nil
} }
func (build *builder) SimpleSelect(table string, columns string, where string, orderby string/*, offset int, maxCount int*/) (stmt *sql.Stmt, err error) { func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby /*, offset, maxCount*/) res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)
if err != nil { if err != nil {
return stmt, err return stmt, err
} }

View File

@ -11,8 +11,6 @@ func init() {
) )
} }
type Mysql_Adapter struct type Mysql_Adapter struct
{ {
Name string Name string
@ -210,7 +208,7 @@ func (adapter *Mysql_Adapter) Purge(name string, table string) (string, error) {
return "DELETE FROM `" + table + "`", nil return "DELETE FROM `" + table + "`", nil
} }
func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string/*, offset int, maxCount int*/) (string, error) { func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -264,12 +262,16 @@ func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns st
querystr = querystr[0:len(querystr) - 1] querystr = querystr[0:len(querystr) - 1]
} }
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr) querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr) adapter.push_statement(name,querystr)
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string/*, offset int, maxCount int*/) (string, error) { func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -350,12 +352,16 @@ func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2
querystr = querystr[0:len(querystr) - 1] querystr = querystr[0:len(querystr) - 1]
} }
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr) querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr) adapter.push_statement(name,querystr)
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string/*, offset int, maxCount int*/) (string, error) { func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -436,12 +442,16 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2
querystr = querystr[0:len(querystr) - 1] querystr = querystr[0:len(querystr) - 1]
} }
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr) querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr) adapter.push_statement(name,querystr)
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where string/*, offset int, maxCount int*/) (string, error) { func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -472,6 +482,10 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
querystr = querystr[0:len(querystr) - 4] querystr = querystr[0:len(querystr) - 4]
} }
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr) querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr) adapter.push_statement(name,querystr)
return querystr, nil return querystr, nil

View File

@ -56,6 +56,11 @@ type DB_Setter struct {
Expr []DB_Token // Simple expressions, the innards of functions are opaque for now. Expr []DB_Token // Simple expressions, the innards of functions are opaque for now.
} }
type DB_Limit struct {
Offset string // ? or int
MaxCount string // ? or int
}
type DB_Adapter interface { type DB_Adapter interface {
GetName() string GetName() string
SimpleInsert(string,string,string,string) (string, error) SimpleInsert(string,string,string,string) (string, error)
@ -63,10 +68,10 @@ type DB_Adapter interface {
SimpleUpdate(string,string,string,string) (string, error) SimpleUpdate(string,string,string,string) (string, error)
SimpleDelete(string,string,string) (string, error) SimpleDelete(string,string,string) (string, error)
Purge(string,string) (string, error) Purge(string,string) (string, error)
SimpleSelect(string,string,string,string,string/*,int,int*/) (string, error) SimpleSelect(string,string,string,string,string,string) (string, error)
SimpleLeftJoin(string,string,string,string,string,string,string/*,int,int*/) (string, error) SimpleLeftJoin(string,string,string,string,string,string,string,string) (string, error)
SimpleInnerJoin(string,string,string,string,string,string,string/*,int,int*/) (string, error) SimpleInnerJoin(string,string,string,string,string,string,string,string) (string, error)
SimpleCount(string,string,string/*,int,int*/) (string, error) SimpleCount(string,string,string,string) (string, error)
Write() error Write() error
// TO-DO: Add a simple query builder // TO-DO: Add a simple query builder

View File

@ -243,6 +243,17 @@ func _process_set(setstr string) (setter []DB_Setter) {
return setter return setter
} }
func _process_limit(limitstr string) (limiter DB_Limit) {
halves := strings.Split(limitstr,",")
if len(halves) == 2 {
limiter.Offset = halves[0]
limiter.MaxCount = halves[1]
} else {
limiter.MaxCount = halves[0]
}
return limiter
}
func _is_op_byte(char byte) bool { func _is_op_byte(char byte) bool {
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/' return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
} }

View File

@ -51,92 +51,100 @@ func write_statements(adapter qgen.DB_Adapter) error {
func write_selects(adapter qgen.DB_Adapter) error { func write_selects(adapter qgen.DB_Adapter) error {
// url_prefix and url_name will be removed from this query in a later commit // url_prefix and url_name will be removed from this query in a later commit
adapter.SimpleSelect("get_user","users","name, group, is_super_admin, avatar, message, url_prefix, url_name, level","uid = ?","") adapter.SimpleSelect("get_user","users","name, group, is_super_admin, avatar, message, url_prefix, url_name, level","uid = ?","","")
// Looking for get_topic? Your statement is in another castle // Looking for get_topic? Your statement is in another castle
adapter.SimpleSelect("get_reply","replies","tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount","rid = ?","") adapter.SimpleSelect("get_reply","replies","tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount","rid = ?","","")
adapter.SimpleSelect("get_user_reply","users_replies","uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress","rid = ?","") adapter.SimpleSelect("get_user_reply","users_replies","uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress","rid = ?","","")
adapter.SimpleSelect("login","users","uid, name, password, salt","name = ?","") adapter.SimpleSelect("login","users","uid, name, password, salt","name = ?","","")
adapter.SimpleSelect("get_password","users","password,salt","uid = ?","") adapter.SimpleSelect("get_password","users","password,salt","uid = ?","","")
adapter.SimpleSelect("username_exists","users","name","name = ?","") adapter.SimpleSelect("username_exists","users","name","name = ?","","")
adapter.SimpleSelect("get_settings","settings","name, content, type","","") adapter.SimpleSelect("get_settings","settings","name, content, type","","","")
adapter.SimpleSelect("get_setting","settings","content, type","name = ?","") adapter.SimpleSelect("get_setting","settings","content, type","name = ?","","")
adapter.SimpleSelect("get_full_setting","settings","name, type, constraints","name = ?","") adapter.SimpleSelect("get_full_setting","settings","name, type, constraints","name = ?","","")
adapter.SimpleSelect("get_full_settings","settings","name, content, type, constraints","","") adapter.SimpleSelect("get_full_settings","settings","name, content, type, constraints","","","")
adapter.SimpleSelect("get_groups","users_groups","gid, name, permissions, is_mod, is_admin, is_banned, tag","","") adapter.SimpleSelect("get_groups","users_groups","gid, name, permissions, is_mod, is_admin, is_banned, tag","","","")
adapter.SimpleSelect("get_forums","forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC") adapter.SimpleSelect("get_forums","forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
adapter.SimpleSelect("get_forums_permissions","forums_permissions","gid, fid, permissions","","gid ASC, fid ASC") adapter.SimpleSelect("get_forums_permissions","forums_permissions","gid, fid, permissions","","gid ASC, fid ASC","")
adapter.SimpleSelect("get_plugins","plugins","uname, active","","") adapter.SimpleSelect("get_plugins","plugins","uname, active","","","")
adapter.SimpleSelect("get_themes","themes","uname, default","","") adapter.SimpleSelect("get_themes","themes","uname, default","","","")
adapter.SimpleSelect("is_plugin_active","plugins","active","uname = ?","") adapter.SimpleSelect("is_plugin_active","plugins","active","uname = ?","","")
adapter.SimpleSelect("get_users","users","uid, name, group, active, is_super_admin, avatar","","") adapter.SimpleSelect("get_users","users","uid, name, group, active, is_super_admin, avatar","","","")
adapter.SimpleSelect("is_theme_default","themes","default","uname = ?","") adapter.SimpleSelect("is_theme_default","themes","default","uname = ?","","")
adapter.SimpleSelect("get_modlogs","moderation_logs","action, elementID, elementType, ipaddress, actorID, doneAt","","") adapter.SimpleSelect("get_modlogs","moderation_logs","action, elementID, elementType, ipaddress, actorID, doneAt","","","")
adapter.SimpleSelect("get_reply_tid","replies","tid","rid = ?","") adapter.SimpleSelect("get_reply_tid","replies","tid","rid = ?","","")
adapter.SimpleSelect("get_topic_fid","topics","parentID","tid = ?","") adapter.SimpleSelect("get_topic_fid","topics","parentID","tid = ?","","")
adapter.SimpleSelect("get_user_reply_uid","users_replies","uid","rid = ?","") adapter.SimpleSelect("get_user_reply_uid","users_replies","uid","rid = ?","","")
adapter.SimpleSelect("has_liked_topic","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'topics'","") adapter.SimpleSelect("has_liked_topic","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'topics'","","")
adapter.SimpleSelect("has_liked_reply","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'replies'","") adapter.SimpleSelect("has_liked_reply","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'replies'","","")
adapter.SimpleSelect("get_user_name","users","name","uid = ?","") adapter.SimpleSelect("get_user_name","users","name","uid = ?","","")
adapter.SimpleSelect("get_user_rank","users","group, is_super_admin","uid = ?","") adapter.SimpleSelect("get_user_rank","users","group, is_super_admin","uid = ?","","")
adapter.SimpleSelect("get_user_active","users","active","uid = ?","") adapter.SimpleSelect("get_user_active","users","active","uid = ?","","")
adapter.SimpleSelect("get_user_group","users","group","uid = ?","") adapter.SimpleSelect("get_user_group","users","group","uid = ?","","")
adapter.SimpleSelect("get_emails_by_user","emails","email, validated, token","uid = ?","") adapter.SimpleSelect("get_emails_by_user","emails","email, validated, token","uid = ?","","")
adapter.SimpleSelect("get_topic_basic","topics","title, content","tid = ?","") adapter.SimpleSelect("get_topic_basic","topics","title, content","tid = ?","","")
adapter.SimpleSelect("get_activity_entry","activity_stream","actor, targetUser, event, elementType, elementID","asid = ?","") adapter.SimpleSelect("get_activity_entry","activity_stream","actor, targetUser, event, elementType, elementID","asid = ?","","")
adapter.SimpleSelect("forum_entry_exists","forums","fid","name = ''","fid ASC","0,1") // Is '' empty?
adapter.SimpleSelect("group_entry_exists","users_groups","gid","name = ''","gid ASC","0,1") // Is '' empty?
return nil return nil
} }
func write_left_joins(adapter qgen.DB_Adapter) error { func write_left_joins(adapter qgen.DB_Adapter) error {
adapter.SimpleLeftJoin("get_topic_list","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC") adapter.SimpleLeftJoin("get_topic_replies_offset","replies","users","replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType","replies.createdBy = users.uid","tid = ?","","?,?")
adapter.SimpleLeftJoin("get_topic_user","topics","users","topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level","topics.createdBy = users.uid","tid = ?","") adapter.SimpleLeftJoin("get_forum_topics_offset","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar","topics.createdBy = users.uid","topics.parentID = ?","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC","?,?")
adapter.SimpleLeftJoin("get_topic_by_reply","replies","topics","topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data","replies.tid = topics.tid","rid = ?","") adapter.SimpleLeftJoin("get_topic_list","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC","")
adapter.SimpleLeftJoin("get_topic_replies","replies","users","replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress","replies.createdBy = users.uid","tid = ?","") adapter.SimpleLeftJoin("get_topic_user","topics","users","topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level","topics.createdBy = users.uid","tid = ?","","")
adapter.SimpleLeftJoin("get_forum_topics","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","topics.parentID = ?","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc") adapter.SimpleLeftJoin("get_topic_by_reply","replies","topics","topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data","replies.tid = topics.tid","rid = ?","","")
adapter.SimpleLeftJoin("get_profile_replies","users_replies","users","users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.group","users_replies.createdBy = users.uid","users_replies.uid = ?","") adapter.SimpleLeftJoin("get_topic_replies","replies","users","replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress","replies.createdBy = users.uid","tid = ?","","")
adapter.SimpleLeftJoin("get_forum_topics","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","topics.parentID = ?","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc","")
adapter.SimpleLeftJoin("get_profile_replies","users_replies","users","users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.group","users_replies.createdBy = users.uid","users_replies.uid = ?","","")
return nil return nil
} }
func write_inner_joins(adapter qgen.DB_Adapter) error { func write_inner_joins(adapter qgen.DB_Adapter) error {
adapter.SimpleInnerJoin("get_watchers","activity_stream","activity_subscriptions","activity_subscriptions.user","activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor","asid = ?","") adapter.SimpleInnerJoin("get_watchers","activity_stream","activity_subscriptions","activity_subscriptions.user","activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor","asid = ?","","")
return nil return nil
} }
@ -283,7 +291,7 @@ func write_deletes(adapter qgen.DB_Adapter) error {
} }
func write_simple_counts(adapter qgen.DB_Adapter) error { func write_simple_counts(adapter qgen.DB_Adapter) error {
adapter.SimpleCount("report_exists","topics","data = ? and data != '' and parentID = 1") adapter.SimpleCount("report_exists","topics","data = ? and data != '' and parentID = 1","")
return nil return nil
} }

View File

@ -111,8 +111,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
} }
var topicList []TopicsRow var topicList []TopicsRow
rows, err := db.Query("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where parentID in("+strings.Join(fidList,",")+") order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC") rows, err := db.Query(topic_list_query(fidList))
//rows, err := get_topic_list_stmt.Query()
if err != nil { if err != nil {
InternalError(err,w,r) InternalError(err,w,r)
return return
@ -201,7 +200,7 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
} else { } else {
page = 1 page = 1
} }
rows, err := get_forum_topics_offset_stmt.Query(fid,offset) rows, err := get_forum_topics_offset_stmt.Query(fid,offset,items_per_page)
if err != nil { if err != nil {
InternalError(err,w,r) InternalError(err,w,r)
return return
@ -364,7 +363,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} }
// Get the replies.. // Get the replies..
rows, err := get_topic_replies_offset_stmt.Query(topic.ID, offset) rows, err := get_topic_replies_offset_stmt.Query(topic.ID, offset, items_per_page)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.",w,r,user) LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.",w,r,user)
return return

View File

@ -23,7 +23,7 @@ type TopicStore interface {
GetCapacity() int GetCapacity() int
} }
type StaticTopicStore struct { type MemoryTopicStore struct {
items map[int]*Topic items map[int]*Topic
length int length int
capacity int capacity int
@ -31,19 +31,19 @@ type StaticTopicStore struct {
sync.RWMutex sync.RWMutex
} }
func NewStaticTopicStore(capacity int) *StaticTopicStore { func NewMemoryTopicStore(capacity int) *MemoryTopicStore {
stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","") stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","","")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
return &StaticTopicStore{ return &MemoryTopicStore{
items:make(map[int]*Topic), items:make(map[int]*Topic),
capacity:capacity, capacity:capacity,
get:stmt, get:stmt,
} }
} }
func (sts *StaticTopicStore) Get(id int) (*Topic, error) { func (sts *MemoryTopicStore) Get(id int) (*Topic, error) {
sts.RLock() sts.RLock()
item, ok := sts.items[id] item, ok := sts.items[id]
sts.RUnlock() sts.RUnlock()
@ -53,7 +53,7 @@ func (sts *StaticTopicStore) Get(id int) (*Topic, error) {
return item, sql.ErrNoRows return item, sql.ErrNoRows
} }
func (sts *StaticTopicStore) GetUnsafe(id int) (*Topic, error) { func (sts *MemoryTopicStore) GetUnsafe(id int) (*Topic, error) {
item, ok := sts.items[id] item, ok := sts.items[id]
if ok { if ok {
return item, nil return item, nil
@ -61,7 +61,7 @@ func (sts *StaticTopicStore) GetUnsafe(id int) (*Topic, error) {
return item, sql.ErrNoRows return item, sql.ErrNoRows
} }
func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) { func (sts *MemoryTopicStore) CascadeGet(id int) (*Topic, error) {
sts.RLock() sts.RLock()
topic, ok := sts.items[id] topic, ok := sts.items[id]
sts.RUnlock() sts.RUnlock()
@ -77,13 +77,13 @@ func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
return topic, err return topic, err
} }
func (sts *StaticTopicStore) BypassGet(id int) (*Topic, error) { func (sts *MemoryTopicStore) BypassGet(id int) (*Topic, error) {
topic := &Topic{ID:id} topic := &Topic{ID:id}
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
return topic, err return topic, err
} }
func (sts *StaticTopicStore) Load(id int) error { func (sts *MemoryTopicStore) Load(id int) error {
topic := &Topic{ID:id} topic := &Topic{ID:id}
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
if err == nil { if err == nil {
@ -94,7 +94,7 @@ func (sts *StaticTopicStore) Load(id int) error {
return err return err
} }
func (sts *StaticTopicStore) Set(item *Topic) error { func (sts *MemoryTopicStore) Set(item *Topic) error {
sts.Lock() sts.Lock()
_, ok := sts.items[item.ID] _, ok := sts.items[item.ID]
if ok { if ok {
@ -110,7 +110,7 @@ func (sts *StaticTopicStore) Set(item *Topic) error {
return nil return nil
} }
func (sts *StaticTopicStore) Add(item *Topic) error { func (sts *MemoryTopicStore) Add(item *Topic) error {
if sts.length >= sts.capacity { if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow return ErrStoreCapacityOverflow
} }
@ -121,7 +121,7 @@ func (sts *StaticTopicStore) Add(item *Topic) error {
return nil return nil
} }
func (sts *StaticTopicStore) AddUnsafe(item *Topic) error { func (sts *MemoryTopicStore) AddUnsafe(item *Topic) error {
if sts.length >= sts.capacity { if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow return ErrStoreCapacityOverflow
} }
@ -130,7 +130,7 @@ func (sts *StaticTopicStore) AddUnsafe(item *Topic) error {
return nil return nil
} }
func (sts *StaticTopicStore) Remove(id int) error { func (sts *MemoryTopicStore) Remove(id int) error {
sts.Lock() sts.Lock()
delete(sts.items,id) delete(sts.items,id)
sts.Unlock() sts.Unlock()
@ -138,40 +138,35 @@ func (sts *StaticTopicStore) Remove(id int) error {
return nil return nil
} }
func (sts *StaticTopicStore) RemoveUnsafe(id int) error { func (sts *MemoryTopicStore) RemoveUnsafe(id int) error {
delete(sts.items,id) delete(sts.items,id)
sts.length-- sts.length--
return nil return nil
} }
func (sts *StaticTopicStore) AddLastTopic(item *Topic, fid int) error { func (sts *MemoryTopicStore) AddLastTopic(item *Topic, fid int) error {
// Coming Soon... // Coming Soon...
return nil return nil
} }
func (sts *StaticTopicStore) GetLength() int { func (sts *MemoryTopicStore) GetLength() int {
return sts.length return sts.length
} }
func (sts *StaticTopicStore) SetCapacity(capacity int) { func (sts *MemoryTopicStore) SetCapacity(capacity int) {
sts.capacity = capacity sts.capacity = capacity
} }
func (sts *StaticTopicStore) GetCapacity() int { func (sts *MemoryTopicStore) GetCapacity() int {
return sts.capacity return sts.capacity
} }
//type DynamicTopicStore struct {
// items_expiries list.List
// items map[int]*Topic
//}
type SqlTopicStore struct { type SqlTopicStore struct {
get *sql.Stmt get *sql.Stmt
} }
func NewSqlTopicStore() *SqlTopicStore { func NewSqlTopicStore() *SqlTopicStore {
stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","") stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","","")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -11,6 +11,7 @@ import (
) )
var guest_user User = User{ID:0,Group:6,Perms:GuestPerms} var guest_user User = User{ID:0,Group:6,Perms:GuestPerms}
var SimpleSessionCheck func(http.ResponseWriter, *http.Request) (User,bool) = _simple_session_check
type User struct type User struct
{ {
@ -145,7 +146,7 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, noticeList
return user, noticeList, success return user, noticeList, success
} }
func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (User,bool) { func _simple_session_check(w http.ResponseWriter, r *http.Request) (User,bool) {
// Are there any session cookies..? // Are there any session cookies..?
cookie, err := r.Cookie("uid") cookie, err := r.Cookie("uid")
if err != nil { if err != nil {

View File

@ -26,7 +26,7 @@ type UserStore interface {
GetCapacity() int GetCapacity() int
} }
type StaticUserStore struct { type MemoryUserStore struct {
items map[int]*User items map[int]*User
length int length int
capacity int capacity int
@ -34,19 +34,19 @@ type StaticUserStore struct {
sync.RWMutex sync.RWMutex
} }
func NewStaticUserStore(capacity int) *StaticUserStore { func NewMemoryUserStore(capacity int) *MemoryUserStore {
stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","") stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","","")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
return &StaticUserStore{ return &MemoryUserStore{
items:make(map[int]*User), items:make(map[int]*User),
capacity:capacity, capacity:capacity,
get:stmt, get:stmt,
} }
} }
func (sus *StaticUserStore) Get(id int) (*User, error) { func (sus *MemoryUserStore) Get(id int) (*User, error) {
sus.RLock() sus.RLock()
item, ok := sus.items[id] item, ok := sus.items[id]
sus.RUnlock() sus.RUnlock()
@ -56,7 +56,7 @@ func (sus *StaticUserStore) Get(id int) (*User, error) {
return item, sql.ErrNoRows return item, sql.ErrNoRows
} }
func (sus *StaticUserStore) GetUnsafe(id int) (*User, error) { func (sus *MemoryUserStore) GetUnsafe(id int) (*User, error) {
item, ok := sus.items[id] item, ok := sus.items[id]
if ok { if ok {
return item, nil return item, nil
@ -64,7 +64,7 @@ func (sus *StaticUserStore) GetUnsafe(id int) (*User, error) {
return item, sql.ErrNoRows return item, sql.ErrNoRows
} }
func (sus *StaticUserStore) CascadeGet(id int) (*User, error) { func (sus *MemoryUserStore) CascadeGet(id int) (*User, error) {
sus.RLock() sus.RLock()
user, ok := sus.items[id] user, ok := sus.items[id]
sus.RUnlock() sus.RUnlock()
@ -90,7 +90,7 @@ func (sus *StaticUserStore) CascadeGet(id int) (*User, error) {
return user, err return user, err
} }
func (sus *StaticUserStore) BypassGet(id int) (*User, error) { func (sus *MemoryUserStore) BypassGet(id int) (*User, error) {
user := &User{ID:id,Loggedin:true} user := &User{ID:id,Loggedin:true}
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP) err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
@ -106,7 +106,7 @@ func (sus *StaticUserStore) BypassGet(id int) (*User, error) {
return user, err return user, err
} }
func (sus *StaticUserStore) Load(id int) error { func (sus *MemoryUserStore) Load(id int) error {
user := &User{ID:id,Loggedin:true} user := &User{ID:id,Loggedin:true}
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP) err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
if err != nil { if err != nil {
@ -127,7 +127,7 @@ func (sus *StaticUserStore) Load(id int) error {
return nil return nil
} }
func (sus *StaticUserStore) Set(item *User) error { func (sus *MemoryUserStore) Set(item *User) error {
sus.Lock() sus.Lock()
user, ok := sus.items[item.ID] user, ok := sus.items[item.ID]
if ok { if ok {
@ -144,7 +144,7 @@ func (sus *StaticUserStore) Set(item *User) error {
return nil return nil
} }
func (sus *StaticUserStore) Add(item *User) error { func (sus *MemoryUserStore) Add(item *User) error {
if sus.length >= sus.capacity { if sus.length >= sus.capacity {
return ErrStoreCapacityOverflow return ErrStoreCapacityOverflow
} }
@ -155,7 +155,7 @@ func (sus *StaticUserStore) Add(item *User) error {
return nil return nil
} }
func (sus *StaticUserStore) AddUnsafe(item *User) error { func (sus *MemoryUserStore) AddUnsafe(item *User) error {
if sus.length >= sus.capacity { if sus.length >= sus.capacity {
return ErrStoreCapacityOverflow return ErrStoreCapacityOverflow
} }
@ -164,7 +164,7 @@ func (sus *StaticUserStore) AddUnsafe(item *User) error {
return nil return nil
} }
func (sus *StaticUserStore) Remove(id int) error { func (sus *MemoryUserStore) Remove(id int) error {
sus.Lock() sus.Lock()
delete(sus.items,id) delete(sus.items,id)
sus.Unlock() sus.Unlock()
@ -172,35 +172,30 @@ func (sus *StaticUserStore) Remove(id int) error {
return nil return nil
} }
func (sus *StaticUserStore) RemoveUnsafe(id int) error { func (sus *MemoryUserStore) RemoveUnsafe(id int) error {
delete(sus.items,id) delete(sus.items,id)
sus.length-- sus.length--
return nil return nil
} }
func (sus *StaticUserStore) GetLength() int { func (sus *MemoryUserStore) GetLength() int {
return sus.length return sus.length
} }
func (sus *StaticUserStore) SetCapacity(capacity int) { func (sus *MemoryUserStore) SetCapacity(capacity int) {
sus.capacity = capacity sus.capacity = capacity
} }
func (sus *StaticUserStore) GetCapacity() int { func (sus *MemoryUserStore) GetCapacity() int {
return sus.capacity return sus.capacity
} }
//type DynamicUserStore struct {
// items_expiries list.List
// items map[int]*User
//}
type SqlUserStore struct { type SqlUserStore struct {
get *sql.Stmt get *sql.Stmt
} }
func NewSqlUserStore() *SqlUserStore { func NewSqlUserStore() *SqlUserStore {
stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","") stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","","")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }