Experimenting with speeding up the installer.
Added support for foreign keys to the MySQL adapter. activity_stream_matches now has a foreign key to help enforce referential integrity. Added the AddForeignKey method to the database adapters. Shortened a couple of API bits to ever slow slightly reduce the lengths of the strings. Fixed a phrase group I missed for logged out users in init.js Fixed a bug where deleting a topic would break the alert list when there is an alert event relating to it. You will need to run the updater / patcher for this commit.
This commit is contained in:
parent
634b03936c
commit
839df17de3
|
@ -14,7 +14,7 @@ func NewPrimaryKeySpitter() *PrimaryKeySpitter {
|
||||||
func (spit *PrimaryKeySpitter) Hook(name string, args ...interface{}) error {
|
func (spit *PrimaryKeySpitter) Hook(name string, args ...interface{}) error {
|
||||||
if name == "CreateTableStart" {
|
if name == "CreateTableStart" {
|
||||||
var found string
|
var found string
|
||||||
var table = args[0].(*qgen.DB_Install_Table)
|
var table = args[0].(*qgen.DBInstallTable)
|
||||||
for _, key := range table.Keys {
|
for _, key := range table.Keys {
|
||||||
if key.Type == "primary" {
|
if key.Type == "primary" {
|
||||||
expl := strings.Split(key.Columns, ",")
|
expl := strings.Split(key.Columns, ",")
|
||||||
|
|
|
@ -45,8 +45,8 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"temp_group", "int", 0, false, false, "0"}, // For temporary groups, set this to zero when a temporary group isn't in effect
|
tblColumn{"temp_group", "int", 0, false, false, "0"}, // For temporary groups, set this to zero when a temporary group isn't in effect
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uid", "primary"},
|
tblKey{"uid", "primary","",false},
|
||||||
tblKey{"name", "unique"},
|
tblKey{"name", "unique","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"tag", "varchar", 50, false, false, "''"},
|
tblColumn{"tag", "varchar", 50, false, false, "''"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"gid", "primary"},
|
tblKey{"gid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"createdAt", "createdAt", 0, false, false, ""},
|
tblColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uid", "primary"},
|
tblKey{"uid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"temporary", "boolean", 0, false, false, ""}, // special case for permanent bans to do the necessary bookkeeping, might be removed in the future
|
tblColumn{"temporary", "boolean", 0, false, false, ""}, // special case for permanent bans to do the necessary bookkeeping, might be removed in the future
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uid", "primary"},
|
tblKey{"uid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
tblColumn{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uid", "primary"},
|
tblKey{"uid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"lastReplyerID", "int", 0, false, false, "0"},
|
tblColumn{"lastReplyerID", "int", 0, false, false, "0"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"fid", "primary"},
|
tblKey{"fid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
// TODO: Test to see that the compound primary key works
|
// TODO: Test to see that the compound primary key works
|
||||||
tblKey{"fid,gid", "primary"},
|
tblKey{"fid,gid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -240,8 +240,8 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"data", "varchar", 200, false, false, "''"},
|
tblColumn{"data", "varchar", 200, false, false, "''"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"tid", "primary"},
|
tblKey{"tid", "primary","",false},
|
||||||
tblKey{"content", "fulltext"},
|
tblKey{"content", "fulltext","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -264,8 +264,8 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"poll", "int", 0, false, false, "0"},
|
tblColumn{"poll", "int", 0, false, false, "0"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"rid", "primary"},
|
tblKey{"rid", "primary","",false},
|
||||||
tblKey{"content", "fulltext"},
|
tblKey{"content", "fulltext","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"extra", "varchar", 200, false, false, ""},
|
tblColumn{"extra", "varchar", 200, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"attachID", "primary"},
|
tblKey{"attachID", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
// TODO: Add a createdBy column?
|
// TODO: Add a createdBy column?
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"reviseID", "primary"},
|
tblKey{"reviseID", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -309,7 +309,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"votes", "int", 0, false, false, "0"},
|
tblColumn{"votes", "int", 0, false, false, "0"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"pollID", "primary"},
|
tblKey{"pollID", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
|
tblColumn{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"rid", "primary"},
|
tblKey{"rid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -363,7 +363,10 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
[]tblColumn{
|
[]tblColumn{
|
||||||
tblColumn{"watcher", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
tblColumn{"watcher", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||||
tblColumn{"asid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
tblColumn{"asid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||||
}, nil,
|
},
|
||||||
|
[]tblKey{
|
||||||
|
tblKey{"asid,asid","foreign","activity_stream",true},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
qgen.Install.CreateTable("activity_stream", "", "",
|
qgen.Install.CreateTable("activity_stream", "", "",
|
||||||
|
@ -376,7 +379,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"elementID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
|
tblColumn{"elementID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"asid", "primary"},
|
tblKey{"asid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -398,7 +401,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"constraints", "varchar", 200, false, false, "''"},
|
tblColumn{"constraints", "varchar", 200, false, false, "''"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"name", "unique"},
|
tblKey{"name", "unique","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -409,7 +412,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"replacement", "varchar", 200, false, false, ""},
|
tblColumn{"replacement", "varchar", 200, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"wfid", "primary"},
|
tblKey{"wfid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -420,7 +423,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"installed", "boolean", 0, false, false, "0"},
|
tblColumn{"installed", "boolean", 0, false, false, "0"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uname", "unique"},
|
tblKey{"uname", "unique","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -431,7 +434,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
//tblColumn{"profileUserVars", "text", 0, false, false, "''"},
|
//tblColumn{"profileUserVars", "text", 0, false, false, "''"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uname", "unique"},
|
tblKey{"uname", "unique","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -446,7 +449,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"data", "text", 0, false, false, "''"},
|
tblColumn{"data", "text", 0, false, false, "''"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"wid", "primary"},
|
tblKey{"wid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -455,7 +458,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"mid", "int", 0, false, true, ""},
|
tblColumn{"mid", "int", 0, false, true, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"mid", "primary"},
|
tblKey{"mid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -479,7 +482,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"adminOnly", "boolean", 0, false, false, "0"},
|
tblColumn{"adminOnly", "boolean", 0, false, false, "0"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"miid", "primary"},
|
tblKey{"miid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -495,7 +498,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"menuID", "int", 0, false, false, "-1"}, // simple sidebar menu
|
tblColumn{"menuID", "int", 0, false, false, "-1"}, // simple sidebar menu
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"pid", "primary"},
|
tblKey{"pid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -510,7 +513,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"rlid", "primary"},
|
tblKey{"rlid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -523,7 +526,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"lid", "primary"},
|
tblKey{"lid", "primary","",false},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,8 @@ type TopicStmts struct {
|
||||||
createLike *sql.Stmt
|
createLike *sql.Stmt
|
||||||
addLikesToTopic *sql.Stmt
|
addLikesToTopic *sql.Stmt
|
||||||
delete *sql.Stmt
|
delete *sql.Stmt
|
||||||
|
deleteActivity *sql.Stmt
|
||||||
|
deleteActivitySubs *sql.Stmt
|
||||||
edit *sql.Stmt
|
edit *sql.Stmt
|
||||||
setPoll *sql.Stmt
|
setPoll *sql.Stmt
|
||||||
createAction *sql.Stmt
|
createAction *sql.Stmt
|
||||||
|
@ -204,6 +206,8 @@ func init() {
|
||||||
createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy, createdAt").Fields("?,?,?,?,UTC_TIMESTAMP()").Prepare(),
|
createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy, createdAt").Fields("?,?,?,?,UTC_TIMESTAMP()").Prepare(),
|
||||||
addLikesToTopic: acc.Update("topics").Set("likeCount = likeCount + ?").Where("tid = ?").Prepare(),
|
addLikesToTopic: acc.Update("topics").Set("likeCount = likeCount + ?").Where("tid = ?").Prepare(),
|
||||||
delete: acc.Delete("topics").Where("tid = ?").Prepare(),
|
delete: acc.Delete("topics").Where("tid = ?").Prepare(),
|
||||||
|
deleteActivity: acc.Delete("activity_stream").Where("elementID = ? AND elementType = 'topic'").Prepare(),
|
||||||
|
deleteActivitySubs: acc.Delete("activity_subscriptions").Where("targetID = ? AND targetType = 'topic'").Prepare(),
|
||||||
edit: acc.Update("topics").Set("title = ?, content = ?, parsed_content = ?").Where("tid = ?").Prepare(), // TODO: Only run the content update bits on non-polls, does this matter?
|
edit: acc.Update("topics").Set("title = ?, content = ?, parsed_content = ?").Where("tid = ?").Prepare(), // TODO: Only run the content update bits on non-polls, does this matter?
|
||||||
setPoll: acc.Update("topics").Set("content = '', parsed_content = '', poll = ?").Where("tid = ? AND poll = 0").Prepare(),
|
setPoll: acc.Update("topics").Set("content = '', parsed_content = '', poll = ?").Where("tid = ? AND poll = 0").Prepare(),
|
||||||
createAction: acc.Insert("replies").Columns("tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''").Prepare(),
|
createAction: acc.Insert("replies").Columns("tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''").Prepare(),
|
||||||
|
@ -325,6 +329,14 @@ func (topic *Topic) Delete() error {
|
||||||
|
|
||||||
_, err = topicStmts.delete.Exec(topic.ID)
|
_, err = topicStmts.delete.Exec(topic.ID)
|
||||||
topic.cacheRemove()
|
topic.cacheRemove()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = topicStmts.deleteActivitySubs.Exec(topic.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = topicStmts.deleteActivity.Exec(topic.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
131
install/mysql.go
131
install/mysql.go
|
@ -10,10 +10,12 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
"github.com/Azareal/Gosora/query_gen"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
@ -93,53 +95,140 @@ func (ins *MysqlInstaller) InitDatabase() (err error) {
|
||||||
fmt.Println("The database was successfully created")
|
fmt.Println("The database was successfully created")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Switching to database ", ins.dbName)
|
/*fmt.Println("Switching to database ", ins.dbName)
|
||||||
_, err = db.Exec("USE " + ins.dbName)
|
_, err = db.Exec("USE " + ins.dbName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}*/
|
||||||
|
db.Close()
|
||||||
|
|
||||||
|
db, err = sql.Open("mysql", ins.dbUsername+_dbPassword+"@tcp("+ins.dbHost+":"+ins.dbPort+")/" + ins.dbName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure that the connection is alive..
|
||||||
|
err = db.Ping()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println("Successfully connected to the database")
|
||||||
|
|
||||||
// Ready the query builder
|
// Ready the query builder
|
||||||
|
ins.db = db
|
||||||
qgen.Builder.SetConn(db)
|
qgen.Builder.SetConn(db)
|
||||||
return qgen.Builder.SetAdapter("mysql")
|
return qgen.Builder.SetAdapter("mysql")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func(ins *MysqlInstaller) createTable(f os.FileInfo) error {
|
||||||
|
table := strings.TrimPrefix(f.Name(), "query_")
|
||||||
|
ext := filepath.Ext(table)
|
||||||
|
if ext != ".sql" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
table = strings.TrimSuffix(table, ext)
|
||||||
|
|
||||||
|
// ? - This is mainly here for tests, although it might allow the installer to overwrite a production database, so we might want to proceed with caution
|
||||||
|
q := "DROP TABLE IF EXISTS `" + table + "`;"
|
||||||
|
_, err := ins.db.Exec(q)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed query:", q)
|
||||||
|
fmt.Println("e:",err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile("./schema/mysql/" + f.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data = bytes.TrimSpace(data)
|
||||||
|
|
||||||
|
_, err = ins.db.Exec(string(data))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed query:", string(data))
|
||||||
|
fmt.Println("e:",err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("Created table '%s'\n", table)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ins *MysqlInstaller) TableDefs() (err error) {
|
func (ins *MysqlInstaller) TableDefs() (err error) {
|
||||||
fmt.Println("Creating the tables")
|
fmt.Println("Creating the tables")
|
||||||
files, _ := ioutil.ReadDir("./schema/mysql/")
|
files, err := ioutil.ReadDir("./schema/mysql/")
|
||||||
for _, f := range files {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Can we reduce the amount of boilerplate here?
|
||||||
|
after := []string{"activity_stream_matches"}
|
||||||
|
c1 := make(chan os.FileInfo)
|
||||||
|
c2 := make(chan os.FileInfo)
|
||||||
|
e := make(chan error)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
r := func(c chan os.FileInfo) {
|
||||||
|
wg.Add(1)
|
||||||
|
for f := range c {
|
||||||
|
err := ins.createTable(f)
|
||||||
|
if err != nil {
|
||||||
|
e <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
go r(c1)
|
||||||
|
go r(c2)
|
||||||
|
|
||||||
|
var a []os.FileInfo
|
||||||
|
Outer:
|
||||||
|
for i, f := range files {
|
||||||
if !strings.HasPrefix(f.Name(), "query_") {
|
if !strings.HasPrefix(f.Name(), "query_") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
table := strings.TrimPrefix(f.Name(), "query_")
|
||||||
var table, ext string
|
ext := filepath.Ext(table)
|
||||||
table = strings.TrimPrefix(f.Name(), "query_")
|
|
||||||
ext = filepath.Ext(table)
|
|
||||||
if ext != ".sql" {
|
if ext != ".sql" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
table = strings.TrimSuffix(table, ext)
|
table = strings.TrimSuffix(table, ext)
|
||||||
|
for _, tbl := range after {
|
||||||
// ? - This is mainly here for tests, although it might allow the installer to overwrite a production database, so we might want to proceed with caution
|
if tbl == table {
|
||||||
_, err = ins.db.Exec("DROP TABLE IF EXISTS `" + table + "`;")
|
a = append(a, f)
|
||||||
if err != nil {
|
continue Outer
|
||||||
fmt.Println("Failed query:", "DROP TABLE IF EXISTS `"+table+"`;")
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
if i%2 == 0 {
|
||||||
fmt.Printf("Creating table '%s'\n", table)
|
c1 <- f
|
||||||
data, err := ioutil.ReadFile("./schema/mysql/" + f.Name())
|
} else {
|
||||||
if err != nil {
|
c2 <- f
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
data = bytes.TrimSpace(data)
|
}
|
||||||
|
close(c1)
|
||||||
|
close(c2)
|
||||||
|
wg.Wait()
|
||||||
|
close(e)
|
||||||
|
|
||||||
_, err = ins.db.Exec(string(data))
|
var first error
|
||||||
|
for err := range e {
|
||||||
|
if first == nil {
|
||||||
|
first = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if first != nil {
|
||||||
|
return first
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range a {
|
||||||
|
if !strings.HasPrefix(f.Name(), "query_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := ins.createTable(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed query:", string(data))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ func init() {
|
||||||
addPatch(17, patch17)
|
addPatch(17, patch17)
|
||||||
addPatch(18, patch18)
|
addPatch(18, patch18)
|
||||||
addPatch(19, patch19)
|
addPatch(19, patch19)
|
||||||
|
addPatch(20, patch20)
|
||||||
}
|
}
|
||||||
|
|
||||||
func patch0(scanner *bufio.Scanner) (err error) {
|
func patch0(scanner *bufio.Scanner) (err error) {
|
||||||
|
@ -49,7 +50,7 @@ func patch0(scanner *bufio.Scanner) (err error) {
|
||||||
tblColumn{"mid", "int", 0, false, true, ""},
|
tblColumn{"mid", "int", 0, false, true, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"mid", "primary"},
|
tblKey{"mid", "primary","",false},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -76,7 +77,7 @@ func patch0(scanner *bufio.Scanner) (err error) {
|
||||||
tblColumn{"adminOnly", "boolean", 0, false, false, "0"},
|
tblColumn{"adminOnly", "boolean", 0, false, false, "0"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"miid", "primary"},
|
tblKey{"miid", "primary","",false},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -183,7 +184,7 @@ func patch3(scanner *bufio.Scanner) error {
|
||||||
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"rlid", "primary"},
|
tblKey{"rlid", "primary","",false},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -246,7 +247,7 @@ func patch4(scanner *bufio.Scanner) error {
|
||||||
tblColumn{"menuID", "int", 0, false, false, "-1"},
|
tblColumn{"menuID", "int", 0, false, false, "-1"},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"pid", "primary"},
|
tblKey{"pid", "primary","",false},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -289,7 +290,7 @@ func patch5(scanner *bufio.Scanner) error {
|
||||||
tblColumn{"createdAt", "createdAt", 0, false, false, ""},
|
tblColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uid", "primary"},
|
tblKey{"uid", "primary","",false},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -309,7 +310,7 @@ func patch7(scanner *bufio.Scanner) error {
|
||||||
tblColumn{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
tblColumn{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"uid", "primary"},
|
tblKey{"uid", "primary","",false},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -391,7 +392,7 @@ func patch9(scanner *bufio.Scanner) error {
|
||||||
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
tblColumn{"doneAt", "createdAt", 0, false, false, ""},
|
||||||
},
|
},
|
||||||
[]tblKey{
|
[]tblKey{
|
||||||
tblKey{"lid", "primary"},
|
tblKey{"lid", "primary","",false},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -514,7 +515,7 @@ func patch12(scanner *bufio.Scanner) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func patch13(scanner *bufio.Scanner) error {
|
func patch13(scanner *bufio.Scanner) error {
|
||||||
err := execStmt(qgen.Builder.AddColumn("widgets", tblColumn{"wid", "int", 0, false, true, ""}, &tblKey{"wid", "primary"}))
|
err := execStmt(qgen.Builder.AddColumn("widgets", tblColumn{"wid", "int", 0, false, true, ""}, &tblKey{"wid", "primary","",false}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -523,15 +524,15 @@ func patch13(scanner *bufio.Scanner) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func patch14(scanner *bufio.Scanner) error {
|
func patch14(scanner *bufio.Scanner) error {
|
||||||
err := execStmt(qgen.Builder.AddKey("topics", "title", tblKey{"title", "fulltext"}))
|
err := execStmt(qgen.Builder.AddKey("topics", "title", tblKey{"title", "fulltext","",false}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = execStmt(qgen.Builder.AddKey("topics", "content", tblKey{"content", "fulltext"}))
|
err = execStmt(qgen.Builder.AddKey("topics", "content", tblKey{"content", "fulltext","",false}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = execStmt(qgen.Builder.AddKey("replies", "content", tblKey{"content", "fulltext"}))
|
err = execStmt(qgen.Builder.AddKey("replies", "content", tblKey{"content", "fulltext","",false}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -603,3 +604,26 @@ func patch19(scanner *bufio.Scanner) error {
|
||||||
}, nil,
|
}, nil,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func patch20(scanner *bufio.Scanner) error {
|
||||||
|
err := acc().Select("activity_stream_matches").Cols("asid").Each(func(rows *sql.Rows) error {
|
||||||
|
var asid int
|
||||||
|
err := rows.Scan(&asid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = acc().Select("activity_stream").Cols("asid").Where("asid = ?").QueryRow(asid).Scan(&asid)
|
||||||
|
if err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = acc().Delete("activity_stream_matches").Where("asid = ?").Run(asid)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return execStmt(qgen.Builder.AddForeignKey("activity_stream_matches", "asid","activity_stream","asid",true))
|
||||||
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ function loadAlerts(menuAlerts) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'get',
|
type: 'get',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
url:'/api/?action=get&module=alerts',
|
url:'/api/?module=alerts',
|
||||||
success: (data) => {
|
success: (data) => {
|
||||||
if("errmsg" in data) {
|
if("errmsg" in data) {
|
||||||
setAlertError(menuAlerts,data.errmsg)
|
setAlertError(menuAlerts,data.errmsg)
|
||||||
|
@ -147,8 +147,8 @@ function loadAlerts(menuAlerts) {
|
||||||
alertList = [];
|
alertList = [];
|
||||||
alertMapping = {};
|
alertMapping = {};
|
||||||
for(var i in data.msgs) addAlert(data.msgs[i]);
|
for(var i in data.msgs) addAlert(data.msgs[i]);
|
||||||
console.log("data.msgCount:",data.msgCount)
|
console.log("data.count:",data.count)
|
||||||
alertCount = data.msgCount;
|
alertCount = data.count;
|
||||||
updateAlertList(menuAlerts)
|
updateAlertList(menuAlerts)
|
||||||
},
|
},
|
||||||
error: (magic,theStatus,error) => {
|
error: (magic,theStatus,error) => {
|
||||||
|
|
|
@ -178,7 +178,7 @@ function initPhrases(loggedIn, panel = false) {
|
||||||
console.log("in initPhrases")
|
console.log("in initPhrases")
|
||||||
console.log("tmlInits:",tmplInits)
|
console.log("tmlInits:",tmplInits)
|
||||||
let e = "";
|
let e = "";
|
||||||
if(loggedIn && !panel) e = ",topic_list,topic";
|
if(loggedIn && !panel) e = ",status,topic_list,topic";
|
||||||
else if(panel) e = ",analytics,panel"; // TODO: Request phrases for just one section of the control panel?
|
else if(panel) e = ",analytics,panel"; // TODO: Request phrases for just one section of the control panel?
|
||||||
else e = ",status,topic_list";
|
else e = ",status,topic_list";
|
||||||
fetchPhrases("alerts,paginator"+e) // TODO: Break this up?
|
fetchPhrases("alerts,paginator"+e) // TODO: Break this up?
|
||||||
|
|
|
@ -120,6 +120,10 @@ func (build *builder) AddKey(table string, column string, key DBTableKey) (stmt
|
||||||
return build.prepare(build.adapter.AddKey("", table, column, key))
|
return build.prepare(build.adapter.AddKey("", table, column, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (build *builder) AddForeignKey(table string, column string, ftable string, fcolumn string, cascade bool) (stmt *sql.Stmt, err error) {
|
||||||
|
return build.prepare(build.adapter.AddForeignKey("", table, column, ftable, fcolumn, cascade))
|
||||||
|
}
|
||||||
|
|
||||||
func (build *builder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) {
|
func (build *builder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) {
|
||||||
return build.prepare(build.adapter.SimpleInsert("", table, columns, fields))
|
return build.prepare(build.adapter.SimpleInsert("", table, columns, fields))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,17 @@ package qgen
|
||||||
var Install *installer
|
var Install *installer
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Install = &installer{instructions: []DB_Install_Instruction{}}
|
Install = &installer{instructions: []DBInstallInstruction{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DB_Install_Instruction struct {
|
type DBInstallInstruction struct {
|
||||||
Table string
|
Table string
|
||||||
Contents string
|
Contents string
|
||||||
Type string
|
Type string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add methods to this to construct it OO-like
|
// TODO: Add methods to this to construct it OO-like
|
||||||
type DB_Install_Table struct {
|
type DBInstallTable struct {
|
||||||
Name string
|
Name string
|
||||||
Charset string
|
Charset string
|
||||||
Collation string
|
Collation string
|
||||||
|
@ -25,8 +25,8 @@ type DB_Install_Table struct {
|
||||||
// TODO: Re-implement the query generation, query builder and installer adapters as layers on-top of a query text adapter
|
// TODO: Re-implement the query generation, query builder and installer adapters as layers on-top of a query text adapter
|
||||||
type installer struct {
|
type installer struct {
|
||||||
adapter Adapter
|
adapter Adapter
|
||||||
instructions []DB_Install_Instruction
|
instructions []DBInstallInstruction
|
||||||
tables []*DB_Install_Table // TODO: Use this in Record() in the next commit to allow us to auto-migrate settings rather than manually patching them in on upgrade
|
tables []*DBInstallTable // TODO: Use this in Record() in the next commit to allow us to auto-migrate settings rather than manually patching them in on upgrade
|
||||||
plugins []QueryPlugin
|
plugins []QueryPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ func (install *installer) SetAdapter(name string) error {
|
||||||
|
|
||||||
func (install *installer) SetAdapterInstance(adapter Adapter) {
|
func (install *installer) SetAdapterInstance(adapter Adapter) {
|
||||||
install.adapter = adapter
|
install.adapter = adapter
|
||||||
install.instructions = []DB_Install_Instruction{}
|
install.instructions = []DBInstallInstruction{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (install *installer) AddPlugins(plugins ...QueryPlugin) {
|
func (install *installer) AddPlugins(plugins ...QueryPlugin) {
|
||||||
|
@ -49,7 +49,7 @@ func (install *installer) AddPlugins(plugins ...QueryPlugin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (install *installer) CreateTable(table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) error {
|
func (install *installer) CreateTable(table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) error {
|
||||||
tableStruct := &DB_Install_Table{table, charset, collation, columns, keys}
|
tableStruct := &DBInstallTable{table, charset, collation, columns, keys}
|
||||||
err := install.RunHook("CreateTableStart", tableStruct)
|
err := install.RunHook("CreateTableStart", tableStruct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -62,7 +62,7 @@ func (install *installer) CreateTable(table string, charset string, collation st
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "create-table"})
|
install.instructions = append(install.instructions, DBInstallInstruction{table, res, "create-table"})
|
||||||
install.tables = append(install.tables, tableStruct)
|
install.tables = append(install.tables, tableStruct)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func (install *installer) AddIndex(table string, iname string, colname string) e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "index"})
|
install.instructions = append(install.instructions, DBInstallInstruction{table, res, "index"})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ func (install *installer) SimpleInsert(table string, columns string, fields stri
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "insert"})
|
install.instructions = append(install.instructions, DBInstallInstruction{table, res, "insert"})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ func (adapter *MssqlAdapter) DropTable(name string, table string) (string, error
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add support for foreign keys?
|
||||||
// TODO: Convert any remaining stringy types to nvarchar
|
// TODO: Convert any remaining stringy types to nvarchar
|
||||||
// We may need to change the CreateTable API to better suit Mssql and the other database drivers which are coming up
|
// We may need to change the CreateTable API to better suit Mssql and the other database drivers which are coming up
|
||||||
func (adapter *MssqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error) {
|
func (adapter *MssqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error) {
|
||||||
|
@ -174,6 +175,25 @@ func (adapter *MssqlAdapter) AddKey(name string, table string, column string, ke
|
||||||
return "", errors.New("not implemented")
|
return "", errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Implement this
|
||||||
|
// TODO: Test to make sure everything works here
|
||||||
|
func (adapter *MssqlAdapter) AddForeignKey(name string, table string, column string, ftable string, fcolumn string, cascade bool) (out string, e error) {
|
||||||
|
var c = func(str string, val bool) {
|
||||||
|
if e != nil || !val {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e = errors.New("You need a "+str+" for this table")
|
||||||
|
}
|
||||||
|
c("name",table=="")
|
||||||
|
c("column",column=="")
|
||||||
|
c("ftable",ftable=="")
|
||||||
|
c("fcolumn",fcolumn=="")
|
||||||
|
if e != nil {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
return "", errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (adapter *MssqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
|
func (adapter *MssqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
|
||||||
if table == "" {
|
if table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
|
|
|
@ -112,11 +112,20 @@ func (adapter *MysqlAdapter) CreateTable(name string, table string, charset stri
|
||||||
if key.Type != "unique" {
|
if key.Type != "unique" {
|
||||||
querystr += " key"
|
querystr += " key"
|
||||||
}
|
}
|
||||||
querystr += "("
|
if key.Type == "foreign" {
|
||||||
for _, column := range strings.Split(key.Columns, ",") {
|
cols := strings.Split(key.Columns, ",")
|
||||||
querystr += "`" + column + "`,"
|
querystr += "(`" + cols[0] + "`) REFERENCES `" + key.FTable + "`(`" + cols[1] + "`)"
|
||||||
|
if key.Cascade {
|
||||||
|
querystr += " ON DELETE CASCADE"
|
||||||
|
}
|
||||||
|
querystr += ","
|
||||||
|
} else {
|
||||||
|
querystr += "("
|
||||||
|
for _, column := range strings.Split(key.Columns, ",") {
|
||||||
|
querystr += "`" + column + "`,"
|
||||||
|
}
|
||||||
|
querystr = querystr[0:len(querystr)-1] + "),"
|
||||||
}
|
}
|
||||||
querystr = querystr[0:len(querystr)-1] + "),"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,12 +182,12 @@ func (adapter *MysqlAdapter) parseColumn(column DBTableColumn) (col DBTableColum
|
||||||
|
|
||||||
// TODO: Support AFTER column
|
// TODO: Support AFTER column
|
||||||
// TODO: Test to make sure everything works here
|
// TODO: Test to make sure everything works here
|
||||||
func (adapter *MysqlAdapter) AddColumn(name string, table string, column DBTableColumn, key *DBTableKey) (string, error) {
|
func (a *MysqlAdapter) AddColumn(name string, table string, column DBTableColumn, key *DBTableKey) (string, error) {
|
||||||
if table == "" {
|
if table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
|
|
||||||
column, size, end := adapter.parseColumn(column)
|
column, size, end := a.parseColumn(column)
|
||||||
querystr := "ALTER TABLE `" + table + "` ADD COLUMN " + "`" + column.Name + "` " + column.Type + size + end
|
querystr := "ALTER TABLE `" + table + "` ADD COLUMN " + "`" + column.Name + "` " + column.Type + size + end
|
||||||
|
|
||||||
if key != nil {
|
if key != nil {
|
||||||
|
@ -191,12 +200,12 @@ func (adapter *MysqlAdapter) AddColumn(name string, table string, column DBTable
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator
|
// TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator
|
||||||
adapter.pushStatement(name, "add-column", querystr)
|
a.pushStatement(name, "add-column", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test to make sure everything works here
|
// TODO: Test to make sure everything works here
|
||||||
func (adapter *MysqlAdapter) AddIndex(name string, table string, iname string, colname string) (string, error) {
|
func (a *MysqlAdapter) AddIndex(name string, table string, iname string, colname string) (string, error) {
|
||||||
if table == "" {
|
if table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
|
@ -209,23 +218,50 @@ func (adapter *MysqlAdapter) AddIndex(name string, table string, iname string, c
|
||||||
|
|
||||||
querystr := "ALTER TABLE `" + table + "` ADD INDEX " + "`" + iname + "` (`" + colname + "`);"
|
querystr := "ALTER TABLE `" + table + "` ADD INDEX " + "`" + iname + "` (`" + colname + "`);"
|
||||||
// TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator
|
// TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator
|
||||||
adapter.pushStatement(name, "add-index", querystr)
|
a.pushStatement(name, "add-index", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test to make sure everything works here
|
// TODO: Test to make sure everything works here
|
||||||
// Only supports FULLTEXT right now
|
// Only supports FULLTEXT right now
|
||||||
func (adapter *MysqlAdapter) AddKey(name string, table string, column string, key DBTableKey) (string, error) {
|
func (a *MysqlAdapter) AddKey(name string, table string, column string, key DBTableKey) (string, error) {
|
||||||
if table == "" {
|
if table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
if key.Type != "fulltext" {
|
var querystr string
|
||||||
|
if key.Type == "fulltext" {
|
||||||
|
querystr = "ALTER TABLE `" + table + "` ADD FULLTEXT(`" + column + "`)"
|
||||||
|
} else {
|
||||||
return "", errors.New("Only fulltext is supported by AddKey right now")
|
return "", errors.New("Only fulltext is supported by AddKey right now")
|
||||||
}
|
}
|
||||||
querystr := "ALTER TABLE `" + table + "` ADD FULLTEXT(`" + column + "`)"
|
|
||||||
|
|
||||||
// TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator
|
// TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator
|
||||||
adapter.pushStatement(name, "add-key", querystr)
|
a.pushStatement(name, "add-key", querystr)
|
||||||
|
return querystr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MysqlAdapter) AddForeignKey(name string, table string, column string, ftable string, fcolumn string, cascade bool) (out string, e error) {
|
||||||
|
var c = func(str string, val bool) {
|
||||||
|
if e != nil || !val {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e = errors.New("You need a "+str+" for this table")
|
||||||
|
}
|
||||||
|
c("name",table=="")
|
||||||
|
c("column",column=="")
|
||||||
|
c("ftable",ftable=="")
|
||||||
|
c("fcolumn",fcolumn=="")
|
||||||
|
if e != nil {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
|
||||||
|
querystr := "ALTER TABLE `"+table+"` ADD CONSTRAINT `fk_"+column+"` FOREIGN KEY(`"+column+"`) REFERENCES `"+ftable+"`(`"+fcolumn+"`)"
|
||||||
|
if cascade {
|
||||||
|
querystr += " ON DELETE CASCADE"
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator
|
||||||
|
a.pushStatement(name, "add-foreign-key", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,25 @@ func (adapter *PgsqlAdapter) AddKey(name string, table string, column string, ke
|
||||||
return "", errors.New("not implemented")
|
return "", errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Implement this
|
||||||
|
// TODO: Test to make sure everything works here
|
||||||
|
func (adapter *PgsqlAdapter) AddForeignKey(name string, table string, column string, ftable string, fcolumn string, cascade bool) (out string, e error) {
|
||||||
|
var c = func(str string, val bool) {
|
||||||
|
if e != nil || !val {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e = errors.New("You need a "+str+" for this table")
|
||||||
|
}
|
||||||
|
c("name",table=="")
|
||||||
|
c("column",column=="")
|
||||||
|
c("ftable",ftable=="")
|
||||||
|
c("fcolumn",fcolumn=="")
|
||||||
|
if e != nil {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
return "", errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Test this
|
// TODO: Test this
|
||||||
// ! We need to get the last ID out of this somehow, maybe add returning to every query? Might require some sort of wrapper over the sql statements
|
// ! We need to get the last ID out of this somehow, maybe add returning to every query? Might require some sort of wrapper over the sql statements
|
||||||
func (adapter *PgsqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
|
func (adapter *PgsqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
|
||||||
|
|
|
@ -23,6 +23,10 @@ type DBTableColumn struct {
|
||||||
type DBTableKey struct {
|
type DBTableKey struct {
|
||||||
Columns string
|
Columns string
|
||||||
Type string
|
Type string
|
||||||
|
|
||||||
|
// Foreign keys only
|
||||||
|
FTable string
|
||||||
|
Cascade bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type DBSelect struct {
|
type DBSelect struct {
|
||||||
|
@ -111,6 +115,7 @@ type Adapter interface {
|
||||||
AddColumn(name string, table string, column DBTableColumn, key *DBTableKey) (string, error)
|
AddColumn(name string, table string, column DBTableColumn, key *DBTableKey) (string, error)
|
||||||
AddIndex(name string, table string, iname string, colname string) (string, error)
|
AddIndex(name string, table string, iname string, colname string) (string, error)
|
||||||
AddKey(name string, table string, column string, key DBTableKey) (string, error)
|
AddKey(name string, table string, column string, key DBTableKey) (string, error)
|
||||||
|
AddForeignKey(name string, table string, column string, ftable string, fcolumn string, cascade bool) (out string, e error)
|
||||||
SimpleInsert(name string, table string, columns string, fields string) (string, error)
|
SimpleInsert(name string, table string, columns string, fields string) (string, error)
|
||||||
SimpleUpdate(up *updatePrebuilder) (string, error)
|
SimpleUpdate(up *updatePrebuilder) (string, error)
|
||||||
SimpleUpdateSelect(up *updatePrebuilder) (string, error) // ! Experimental
|
SimpleUpdateSelect(up *updatePrebuilder) (string, error) // ! Experimental
|
||||||
|
|
16
routes.go
16
routes.go
|
@ -10,6 +10,7 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -27,7 +28,7 @@ var successJSONBytes = []byte(`{"success":"1"}`)
|
||||||
|
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
// TODO: Use the phrase system
|
// TODO: Use the phrase system
|
||||||
var phraseLoginAlerts = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}],"msgCount":0}`)
|
var phraseLoginAlerts = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}],"count":0}`)
|
||||||
|
|
||||||
// TODO: Refactor this endpoint
|
// TODO: Refactor this endpoint
|
||||||
// TODO: Move this into the routes package
|
// TODO: Move this into the routes package
|
||||||
|
@ -40,6 +41,9 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
|
||||||
}
|
}
|
||||||
|
|
||||||
action := r.FormValue("action")
|
action := r.FormValue("action")
|
||||||
|
if action == "" {
|
||||||
|
action = "get"
|
||||||
|
}
|
||||||
if action != "get" && action != "set" {
|
if action != "get" && action != "set" {
|
||||||
return c.PreErrorJS("Invalid Action", w, r)
|
return c.PreErrorJS("Invalid Action", w, r)
|
||||||
}
|
}
|
||||||
|
@ -86,8 +90,8 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
|
||||||
}
|
}
|
||||||
|
|
||||||
var msglist string
|
var msglist string
|
||||||
var msgCount int
|
var count int
|
||||||
err = stmts.getActivityCountByWatcher.QueryRow(user.ID).Scan(&msgCount)
|
err = stmts.getActivityCountByWatcher.QueryRow(user.ID).Scan(&count)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
return c.PreErrorJS("Couldn't find the parent topic", w, r)
|
return c.PreErrorJS("Couldn't find the parent topic", w, r)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -141,7 +145,7 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
|
||||||
if len(msglist) != 0 {
|
if len(msglist) != 0 {
|
||||||
msglist = msglist[0 : len(msglist)-1]
|
msglist = msglist[0 : len(msglist)-1]
|
||||||
}
|
}
|
||||||
_, _ = w.Write([]byte(`{"msgs":[` + msglist + `],"msgCount":` + strconv.Itoa(msgCount) + `}`))
|
_, _ = io.WriteString(w, `{"msgs":[` + msglist + `],"count":` + strconv.Itoa(count) + `}`)
|
||||||
default:
|
default:
|
||||||
return c.PreErrorJS("Invalid Module", w, r)
|
return c.PreErrorJS("Invalid Module", w, r)
|
||||||
}
|
}
|
||||||
|
@ -296,9 +300,9 @@ func routeJSAntispam(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
||||||
jsToken := hex.EncodeToString(h.Sum(nil))
|
jsToken := hex.EncodeToString(h.Sum(nil))
|
||||||
|
|
||||||
var innerCode = "`document.getElementByld('golden-watch').value = '" + jsToken + "';`"
|
var innerCode = "`document.getElementByld('golden-watch').value = '" + jsToken + "';`"
|
||||||
w.Write([]byte(`let hihi = ` + innerCode + `;
|
io.WriteString(w, `let hihi = ` + innerCode + `;
|
||||||
hihi = hihi.replace('ld','Id');
|
hihi = hihi.replace('ld','Id');
|
||||||
eval(hihi);`))
|
eval(hihi);`)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,8 +452,7 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctpage := c.CreateTopicPage{header, forumList, fid}
|
return renderTemplate("create_topic", w, r, header, c.CreateTopicPage{header, forumList, fid})
|
||||||
return renderTemplate("create_topic", w, r, header, ctpage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||||
|
@ -461,7 +460,6 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError("The provided ForumID is not a valid number.", w, r, user)
|
return c.LocalError("The provided ForumID is not a valid number.", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
// TODO: Add hooks to make use of headerLite
|
||||||
lite, ferr := c.SimpleForumUserCheck(w, r, &user, fid)
|
lite, ferr := c.SimpleForumUserCheck(w, r, &user, fid)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
CREATE TABLE [activity_stream_matches] (
|
CREATE TABLE [activity_stream_matches] (
|
||||||
[watcher] int not null,
|
[watcher] int not null,
|
||||||
[asid] int not null
|
[asid] int not null,
|
||||||
|
foreign key([asid],[asid])
|
||||||
);
|
);
|
|
@ -1,4 +1,5 @@
|
||||||
CREATE TABLE `activity_stream_matches` (
|
CREATE TABLE `activity_stream_matches` (
|
||||||
`watcher` int not null,
|
`watcher` int not null,
|
||||||
`asid` int not null
|
`asid` int not null,
|
||||||
|
foreign key(`asid`) REFERENCES `activity_stream`(`asid`) ON DELETE CASCADE
|
||||||
);
|
);
|
|
@ -1,4 +1,5 @@
|
||||||
CREATE TABLE "activity_stream_matches" (
|
CREATE TABLE "activity_stream_matches" (
|
||||||
`watcher` int not null,
|
`watcher` int not null,
|
||||||
`asid` int not null
|
`asid` int not null,
|
||||||
|
foreign key(`asid`,`asid`)
|
||||||
);
|
);
|
|
@ -7,7 +7,7 @@
|
||||||
{{range .Header.PreScriptsAsync}}
|
{{range .Header.PreScriptsAsync}}
|
||||||
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
||||||
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
|
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
|
||||||
<script type="text/javascript" src="/static/init.js?i=5"></script>
|
<script type="text/javascript" src="/static/init.js?i=6"></script>
|
||||||
{{range .Header.ScriptsAsync}}
|
{{range .Header.ScriptsAsync}}
|
||||||
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
||||||
<script type="text/javascript" src="/static/jquery-3.1.1.min.js"></script>
|
<script type="text/javascript" src="/static/jquery-3.1.1.min.js"></script>
|
||||||
|
|
20
tickloop.go
20
tickloop.go
|
@ -5,8 +5,10 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
|
"github.com/Azareal/Gosora/query_gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Name the tasks so we can figure out which one it was when something goes wrong? Or maybe toss it up WithStack down there?
|
// TODO: Name the tasks so we can figure out which one it was when something goes wrong? Or maybe toss it up WithStack down there?
|
||||||
|
@ -55,6 +57,7 @@ func tickLoop(thumbChan chan bool) {
|
||||||
secondTicker := time.NewTicker(time.Second)
|
secondTicker := time.NewTicker(time.Second)
|
||||||
fifteenMinuteTicker := time.NewTicker(15 * time.Minute)
|
fifteenMinuteTicker := time.NewTicker(15 * time.Minute)
|
||||||
hourTicker := time.NewTicker(time.Hour)
|
hourTicker := time.NewTicker(time.Hour)
|
||||||
|
dailyTicker := time.NewTicker(time.Hour * 24)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-halfSecondTicker.C:
|
case <-halfSecondTicker.C:
|
||||||
|
@ -122,6 +125,23 @@ func tickLoop(thumbChan chan bool) {
|
||||||
|
|
||||||
runTasks(c.ScheduledHourTasks)
|
runTasks(c.ScheduledHourTasks)
|
||||||
runHook("after_hour_tick")
|
runHook("after_hour_tick")
|
||||||
|
// TODO: Handle the instance going down a lot better
|
||||||
|
case <-dailyTicker.C:
|
||||||
|
// TODO: Find a more efficient way of doing this
|
||||||
|
err := qgen.NewAcc().Select("activity_stream").Cols("asid").EachInt(func(asid int) error {
|
||||||
|
count, err := qgen.NewAcc().Count("activity_stream_matches").Where("asid = ?").Total()
|
||||||
|
if err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err = qgen.NewAcc().Delete("activity_stream").Where("asid = ?").Run(asid)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
c.LogError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle the daily clean-up.
|
// TODO: Handle the daily clean-up.
|
||||||
|
|
Loading…
Reference in New Issue