Optimise the database layer.
Refactor database adapters. Experimental last ip cutoff. More parser test cases.
This commit is contained in:
parent
d22021b022
commit
35ddc89009
|
@ -23,7 +23,7 @@ type DefaultIPSearcher struct {
|
||||||
func NewDefaultIPSearcher() (*DefaultIPSearcher, error) {
|
func NewDefaultIPSearcher() (*DefaultIPSearcher, error) {
|
||||||
acc := qgen.NewAcc()
|
acc := qgen.NewAcc()
|
||||||
return &DefaultIPSearcher{
|
return &DefaultIPSearcher{
|
||||||
searchUsers: acc.Select("users").Columns("uid").Where("last_ip = ?").Prepare(),
|
searchUsers: acc.Select("users").Columns("uid").Where("last_ip=? OR last_ip LIKE CONCAT('%-',?)").Prepare(),
|
||||||
searchTopics: acc.Select("users").Columns("uid").InQ("uid", acc.Select("topics").Columns("createdBy").Where("ipaddress=?")).Prepare(),
|
searchTopics: acc.Select("users").Columns("uid").InQ("uid", acc.Select("topics").Columns("createdBy").Where("ipaddress=?")).Prepare(),
|
||||||
searchReplies: acc.Select("users").Columns("uid").InQ("uid", acc.Select("replies").Columns("createdBy").Where("ipaddress=?")).Prepare(),
|
searchReplies: acc.Select("users").Columns("uid").InQ("uid", acc.Select("replies").Columns("createdBy").Where("ipaddress=?")).Prepare(),
|
||||||
searchUsersReplies: acc.Select("users").Columns("uid").InQ("uid", acc.Select("users_replies").Columns("createdBy").Where("ipaddress=?")).Prepare(),
|
searchUsersReplies: acc.Select("users").Columns("uid").InQ("uid", acc.Select("users_replies").Columns("createdBy").Where("ipaddress=?")).Prepare(),
|
||||||
|
@ -33,8 +33,7 @@ func NewDefaultIPSearcher() (*DefaultIPSearcher, error) {
|
||||||
func (s *DefaultIPSearcher) Lookup(ip string) (uids []int, err error) {
|
func (s *DefaultIPSearcher) Lookup(ip string) (uids []int, err error) {
|
||||||
var uid int
|
var uid int
|
||||||
reqUserList := make(map[int]bool)
|
reqUserList := make(map[int]bool)
|
||||||
runQuery := func(stmt *sql.Stmt) error {
|
runQuery2 := func(rows *sql.Rows, err error) error {
|
||||||
rows, err := stmt.Query(ip)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -49,8 +48,11 @@ func (s *DefaultIPSearcher) Lookup(ip string) (uids []int, err error) {
|
||||||
}
|
}
|
||||||
return rows.Err()
|
return rows.Err()
|
||||||
}
|
}
|
||||||
|
runQuery := func(stmt *sql.Stmt) error {
|
||||||
|
return runQuery2(stmt.Query(ip))
|
||||||
|
}
|
||||||
|
|
||||||
err = runQuery(s.searchUsers)
|
err = runQuery2(s.searchUsers.Query(ip, ip))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uids, err
|
return uids, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,24 @@ type DefaultPasswordResetter struct {
|
||||||
delete *sql.Stmt
|
delete *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
type PasswordReset struct {
|
||||||
|
Email string `q:"email"`
|
||||||
|
Uid int `q:"uid"`
|
||||||
|
Validated bool `q:"validated"`
|
||||||
|
Token string `q:"token"`
|
||||||
|
CreatedAt time.Time `q:"createdAt"`
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func NewDefaultPasswordResetter(acc *qgen.Accumulator) (*DefaultPasswordResetter, error) {
|
func NewDefaultPasswordResetter(acc *qgen.Accumulator) (*DefaultPasswordResetter, error) {
|
||||||
|
pr := "password_resets"
|
||||||
return &DefaultPasswordResetter{
|
return &DefaultPasswordResetter{
|
||||||
getTokens: acc.Select("password_resets").Columns("token").Where("uid = ?").Prepare(),
|
getTokens: acc.Select(pr).Columns("token").Where("uid = ?").Prepare(),
|
||||||
create: acc.Insert("password_resets").Columns("email, uid, validated, token, createdAt").Fields("?,?,0,?,UTC_TIMESTAMP()").Prepare(),
|
create: acc.Insert(pr).Columns("email, uid, validated, token, createdAt").Fields("?,?,0,?,UTC_TIMESTAMP()").Prepare(),
|
||||||
delete: acc.Delete("password_resets").Where("uid =?").Prepare(),
|
//create: acc.Insert(pr).Cols("email,uid,validated=0,token,createdAt=UTC_TIMESTAMP()").Prep(),
|
||||||
|
delete: acc.Delete(pr).Where("uid=?").Prepare(),
|
||||||
|
//model: acc.Model(w).Cols("email,uid,validated=0,token").Key("uid").CreatedAt("createdAt").Prep(),
|
||||||
}, acc.FirstError()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,16 +58,14 @@ func (r *DefaultPasswordResetter) ValidateToken(uid int, token string) error {
|
||||||
success := false
|
success := false
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var rtoken string
|
var rtoken string
|
||||||
err := rows.Scan(&rtoken)
|
if err := rows.Scan(&rtoken); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if subtle.ConstantTimeCompare([]byte(token), []byte(rtoken)) == 1 {
|
if subtle.ConstantTimeCompare([]byte(token), []byte(rtoken)) == 1 {
|
||||||
success = true
|
success = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
if err = rows.Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (s *DefaultReportStore) Create(title string, content string, u *User, itemT
|
||||||
return 0, ErrAlreadyReported
|
return 0, ErrAlreadyReported
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := s.create.Exec(title, content, ParseMessage(content, 0, "", nil), u.LastIP, u.ID, u.ID, itemType+"_"+strconv.Itoa(itemID), ReportForumID)
|
res, err := s.create.Exec(title, content, ParseMessage(content, 0, "", nil), u.GetIP(), u.ID, u.ID, itemType+"_"+strconv.Itoa(itemID), ReportForumID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,15 +316,15 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
usercpy.LastIP = host
|
if usercpy.Loggedin && host != usercpy.GetIP() {
|
||||||
|
mon := time.Now().Month()
|
||||||
if usercpy.Loggedin && host != usercpy.LastIP {
|
err = usercpy.UpdateIP(strconv.Itoa(int(mon)) + "-" + host)
|
||||||
err = usercpy.UpdateIP(host)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w, r)
|
InternalError(err, w, r)
|
||||||
return *usercpy, false
|
return *usercpy, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
usercpy.LastIP = host
|
||||||
|
|
||||||
return *usercpy, true
|
return *usercpy, true
|
||||||
}
|
}
|
||||||
|
@ -350,11 +350,11 @@ func UploadAvatar(w http.ResponseWriter, r *http.Request, user User, tuid int) (
|
||||||
if hdr.Filename == "" {
|
if hdr.Filename == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
infile, err := hdr.Open()
|
inFile, err := hdr.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", LocalError("Upload failed", w, r, user)
|
return "", LocalError("Upload failed", w, r, user)
|
||||||
}
|
}
|
||||||
defer infile.Close()
|
defer inFile.Close()
|
||||||
|
|
||||||
if ext == "" {
|
if ext == "" {
|
||||||
extarr := strings.Split(hdr.Filename, ".")
|
extarr := strings.Split(hdr.Filename, ".")
|
||||||
|
@ -377,13 +377,13 @@ func UploadAvatar(w http.ResponseWriter, r *http.Request, user User, tuid int) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Centralise this string, so we don't have to change it in two different places when it changes
|
// TODO: Centralise this string, so we don't have to change it in two different places when it changes
|
||||||
outfile, err := os.Create("./uploads/avatar_" + strconv.Itoa(tuid) + "." + ext)
|
outFile, err := os.Create("./uploads/avatar_" + strconv.Itoa(tuid) + "." + ext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", LocalError("Upload failed [File Creation Failed]", w, r, user)
|
return "", LocalError("Upload failed [File Creation Failed]", w, r, user)
|
||||||
}
|
}
|
||||||
defer outfile.Close()
|
defer outFile.Close()
|
||||||
|
|
||||||
_, err = io.Copy(outfile, infile)
|
_, err = io.Copy(outFile, inFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", LocalError("Upload failed [Copy Failed]", w, r, user)
|
return "", LocalError("Upload failed [Copy Failed]", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,6 +222,12 @@ func ProcessConfig() (err error) {
|
||||||
if Config.LogPruneCutoff == 0 {
|
if Config.LogPruneCutoff == 0 {
|
||||||
Config.LogPruneCutoff = 180 // Default cutoff
|
Config.LogPruneCutoff = 180 // Default cutoff
|
||||||
}
|
}
|
||||||
|
if Config.LastIPCutoff == 0 {
|
||||||
|
Config.LastIPCutoff = 3 // Default cutoff
|
||||||
|
}
|
||||||
|
if Config.LastIPCutoff > 12 {
|
||||||
|
Config.LastIPCutoff = 12
|
||||||
|
}
|
||||||
if Config.NoEmbed {
|
if Config.NoEmbed {
|
||||||
DefaultParseSettings.NoEmbed = true
|
DefaultParseSettings.NoEmbed = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,9 +338,14 @@ func (u *User) ChangeGroup(group int) (err error) {
|
||||||
return u.bindStmt(userStmts.changeGroup, group)
|
return u.bindStmt(userStmts.changeGroup, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) GetIP() string {
|
||||||
|
spl := strings.Split(u.LastIP,"-")
|
||||||
|
return spl[len(spl)-1]
|
||||||
|
}
|
||||||
|
|
||||||
// ! Only updates the database not the *User for safety reasons
|
// ! Only updates the database not the *User for safety reasons
|
||||||
func (u *User) UpdateIP(host string) error {
|
func (u *User) UpdateIP(ip string) error {
|
||||||
_, err := userStmts.updateLastIP.Exec(host, u.ID)
|
_, err := userStmts.updateLastIP.Exec(ip, u.ID)
|
||||||
if uc := Users.GetCache(); uc != nil {
|
if uc := Users.GetCache(); uc != nil {
|
||||||
uc.Remove(u.ID)
|
uc.Remove(u.ID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,9 +84,11 @@ BuildSlugs - Whether you want the title appear in the URL. For instance: `/topic
|
||||||
|
|
||||||
ServerCount - The number of instances you're running. This setting is currently experimental.
|
ServerCount - The number of instances you're running. This setting is currently experimental.
|
||||||
|
|
||||||
PostIPCutoff - The number of days which need to pass before the IP data for a post is automatically deleted. 0 defaults to whatever the current default is, currently 180 and -1 disables this feature. Default: 0
|
LastIPCutoff - The number of months which need to pass before the last IP stored for a user is automatically deleted. Capped at 12. 0 defaults to whatever the current default is, currently 3 and -1 disables this feature.
|
||||||
|
|
||||||
LogPruneCutoff - The number of days which need to pass before the login and registration logs are pruned. 0 defaults to whatever the current default is, currently 365 and -1 disables this feature. Default: 0
|
PostIPCutoff - The number of days which need to pass before the IP data for a post is automatically deleted. 0 defaults to whatever the current default is, currently 120 and -1 disables this feature. Default: 0
|
||||||
|
|
||||||
|
LogPruneCutoff - The number of days which need to pass before the login and registration logs are pruned. 0 defaults to whatever the current default is, currently 180 and -1 disables this feature. Default: 0
|
||||||
|
|
||||||
DisableLiveTopicList - This switch allows you to disable the live topic list. Default: false
|
DisableLiveTopicList - This switch allows you to disable the live topic list. Default: false
|
||||||
|
|
||||||
|
|
|
@ -74,24 +74,25 @@ func BbcodeRegexParse(msg string) string {
|
||||||
// Only does the simple BBCode like [u], [b], [i] and [s]
|
// Only does the simple BBCode like [u], [b], [i] and [s]
|
||||||
func bbcodeSimpleParse(msg string) string {
|
func bbcodeSimpleParse(msg string) string {
|
||||||
var hasU, hasB, hasI, hasS bool
|
var hasU, hasB, hasI, hasS bool
|
||||||
msgbytes := []byte(msg)
|
mbytes := []byte(msg)
|
||||||
for i := 0; (i + 2) < len(msgbytes); i++ {
|
for i := 0; (i + 2) < len(mbytes); i++ {
|
||||||
if msgbytes[i] == '[' && msgbytes[i+2] == ']' {
|
if mbytes[i] == '[' && mbytes[i+2] == ']' {
|
||||||
if msgbytes[i+1] == 'b' && !hasB {
|
ch := mbytes[i+1]
|
||||||
msgbytes[i] = '<'
|
if ch == 'b' && !hasB {
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i] = '<'
|
||||||
|
mbytes[i+2] = '>'
|
||||||
hasB = true
|
hasB = true
|
||||||
} else if msgbytes[i+1] == 'i' && !hasI {
|
} else if ch == 'i' && !hasI {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasI = true
|
hasI = true
|
||||||
} else if msgbytes[i+1] == 'u' && !hasU {
|
} else if ch == 'u' && !hasU {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasU = true
|
hasU = true
|
||||||
} else if msgbytes[i+1] == 's' && !hasS {
|
} else if ch == 's' && !hasS {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasS = true
|
hasS = true
|
||||||
}
|
}
|
||||||
i += 2
|
i += 2
|
||||||
|
@ -105,46 +106,47 @@ func bbcodeSimpleParse(msg string) string {
|
||||||
closeBold := []byte("</b>")
|
closeBold := []byte("</b>")
|
||||||
closeStrike := []byte("</s>")
|
closeStrike := []byte("</s>")
|
||||||
if hasI {
|
if hasI {
|
||||||
msgbytes = append(msgbytes, closeItalic...)
|
mbytes = append(mbytes, closeItalic...)
|
||||||
}
|
}
|
||||||
if hasU {
|
if hasU {
|
||||||
msgbytes = append(msgbytes, closeUnder...)
|
mbytes = append(mbytes, closeUnder...)
|
||||||
}
|
}
|
||||||
if hasB {
|
if hasB {
|
||||||
msgbytes = append(msgbytes, closeBold...)
|
mbytes = append(mbytes, closeBold...)
|
||||||
}
|
}
|
||||||
if hasS {
|
if hasS {
|
||||||
msgbytes = append(msgbytes, closeStrike...)
|
mbytes = append(mbytes, closeStrike...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string(msgbytes)
|
return string(mbytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here for benchmarking purposes. Might add a plugin setting for disabling [code] as it has it's paws everywhere
|
// Here for benchmarking purposes. Might add a plugin setting for disabling [code] as it has it's paws everywhere
|
||||||
func BbcodeParseWithoutCode(msg string) string {
|
func BbcodeParseWithoutCode(msg string) string {
|
||||||
var hasU, hasB, hasI, hasS bool
|
var hasU, hasB, hasI, hasS bool
|
||||||
var complexBbc bool
|
var complexBbc bool
|
||||||
msgbytes := []byte(msg)
|
mbytes := []byte(msg)
|
||||||
for i := 0; (i + 3) < len(msgbytes); i++ {
|
for i := 0; (i + 3) < len(mbytes); i++ {
|
||||||
if msgbytes[i] == '[' {
|
if mbytes[i] == '[' {
|
||||||
if msgbytes[i+2] != ']' {
|
if mbytes[i+2] != ']' {
|
||||||
if msgbytes[i+1] == '/' {
|
if mbytes[i+1] == '/' {
|
||||||
if msgbytes[i+3] == ']' {
|
if mbytes[i+3] == ']' {
|
||||||
if msgbytes[i+2] == 'b' {
|
switch mbytes[i+2] {
|
||||||
msgbytes[i] = '<'
|
case 'b':
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i] = '<'
|
||||||
|
mbytes[i+3] = '>'
|
||||||
hasB = false
|
hasB = false
|
||||||
} else if msgbytes[i+2] == 'i' {
|
case 'i':
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i+3] = '>'
|
||||||
hasI = false
|
hasI = false
|
||||||
} else if msgbytes[i+2] == 'u' {
|
case 'u':
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i+3] = '>'
|
||||||
hasU = false
|
hasU = false
|
||||||
} else if msgbytes[i+2] == 's' {
|
case 's':
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i+3] = '>'
|
||||||
hasS = false
|
hasS = false
|
||||||
}
|
}
|
||||||
i += 3
|
i += 3
|
||||||
|
@ -155,21 +157,22 @@ func BbcodeParseWithoutCode(msg string) string {
|
||||||
complexBbc = true
|
complexBbc = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if msgbytes[i+1] == 'b' && !hasB {
|
ch := mbytes[i+1]
|
||||||
msgbytes[i] = '<'
|
if ch == 'b' && !hasB {
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i] = '<'
|
||||||
|
mbytes[i+2] = '>'
|
||||||
hasB = true
|
hasB = true
|
||||||
} else if msgbytes[i+1] == 'i' && !hasI {
|
} else if ch == 'i' && !hasI {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasI = true
|
hasI = true
|
||||||
} else if msgbytes[i+1] == 'u' && !hasU {
|
} else if ch == 'u' && !hasU {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasU = true
|
hasU = true
|
||||||
} else if msgbytes[i+1] == 's' && !hasS {
|
} else if ch == 's' && !hasS {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasS = true
|
hasS = true
|
||||||
}
|
}
|
||||||
i += 2
|
i += 2
|
||||||
|
@ -184,29 +187,29 @@ func BbcodeParseWithoutCode(msg string) string {
|
||||||
closeBold := []byte("</b>")
|
closeBold := []byte("</b>")
|
||||||
closeStrike := []byte("</s>")
|
closeStrike := []byte("</s>")
|
||||||
if hasI {
|
if hasI {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeItalic...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeItalic...)
|
||||||
}
|
}
|
||||||
if hasU {
|
if hasU {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeUnder...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeUnder...)
|
||||||
}
|
}
|
||||||
if hasB {
|
if hasB {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeBold...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeBold...)
|
||||||
}
|
}
|
||||||
if hasS {
|
if hasS {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeStrike...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeStrike...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the new complex parser over once the rough edges have been smoothed over
|
// Copy the new complex parser over once the rough edges have been smoothed over
|
||||||
if complexBbc {
|
if complexBbc {
|
||||||
msg = string(msgbytes)
|
msg = string(mbytes)
|
||||||
msg = bbcodeURL.ReplaceAllString(msg, "<a href='$1$2//$3' rel='ugc'>$1$2//$3</i>")
|
msg = bbcodeURL.ReplaceAllString(msg, "<a href='$1$2//$3' rel='ugc'>$1$2//$3</i>")
|
||||||
msg = bbcodeURLLabel.ReplaceAllString(msg, "<a href='$1$2//$3' rel='ugc'>$4</i>")
|
msg = bbcodeURLLabel.ReplaceAllString(msg, "<a href='$1$2//$3' rel='ugc'>$4</i>")
|
||||||
msg = bbcodeSpoiler.ReplaceAllString(msg, "<spoiler>$1</spoiler>")
|
msg = bbcodeSpoiler.ReplaceAllString(msg, "<spoiler>$1</spoiler>")
|
||||||
msg = bbcodeQuotes.ReplaceAllString(msg, "<blockquote>$1</blockquote>")
|
msg = bbcodeQuotes.ReplaceAllString(msg, "<blockquote>$1</blockquote>")
|
||||||
return bbcodeCode.ReplaceAllString(msg, "<span class='codequotes'>$1</span>")
|
return bbcodeCode.ReplaceAllString(msg, "<span class='codequotes'>$1</span>")
|
||||||
}
|
}
|
||||||
return string(msgbytes)
|
return string(mbytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does every type of BBCode
|
// Does every type of BBCode
|
||||||
|
@ -214,63 +217,66 @@ func BbcodeFullParse(msg string) string {
|
||||||
var hasU, hasB, hasI, hasS, hasC bool
|
var hasU, hasB, hasI, hasS, hasC bool
|
||||||
var complexBbc bool
|
var complexBbc bool
|
||||||
|
|
||||||
msgbytes := []byte(msg)
|
mbytes := []byte(msg)
|
||||||
msgbytes = append(msgbytes, c.SpaceGap...)
|
mbytes = append(mbytes, c.SpaceGap...)
|
||||||
for i := 0; i < len(msgbytes); i++ {
|
for i := 0; i < len(mbytes); i++ {
|
||||||
if msgbytes[i] == '[' {
|
if mbytes[i] == '[' {
|
||||||
if msgbytes[i+2] != ']' {
|
if mbytes[i+2] != ']' {
|
||||||
if msgbytes[i+1] == '/' {
|
if mbytes[i+1] == '/' {
|
||||||
if msgbytes[i+3] == ']' {
|
if mbytes[i+3] == ']' {
|
||||||
if !hasC {
|
if !hasC {
|
||||||
if msgbytes[i+2] == 'b' {
|
switch mbytes[i+2] {
|
||||||
msgbytes[i] = '<'
|
case 'b':
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i] = '<'
|
||||||
|
mbytes[i+3] = '>'
|
||||||
hasB = false
|
hasB = false
|
||||||
} else if msgbytes[i+2] == 'i' {
|
case 'i':
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i+3] = '>'
|
||||||
hasI = false
|
hasI = false
|
||||||
} else if msgbytes[i+2] == 'u' {
|
case 'u':
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i+3] = '>'
|
||||||
hasU = false
|
hasU = false
|
||||||
} else if msgbytes[i+2] == 's' {
|
case 's':
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
mbytes[i+3] = '>'
|
||||||
hasS = false
|
hasS = false
|
||||||
}
|
}
|
||||||
i += 3
|
i += 3
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if msgbytes[i+2] == 'c' && msgbytes[i+3] == 'o' && msgbytes[i+4] == 'd' && msgbytes[i+5] == 'e' && msgbytes[i+6] == ']' {
|
if mbytes[i+6] == ']' && mbytes[i+2] == 'c' && mbytes[i+3] == 'o' && mbytes[i+4] == 'd' && mbytes[i+5] == 'e' {
|
||||||
hasC = false
|
hasC = false
|
||||||
i += 7
|
i += 7
|
||||||
}
|
}
|
||||||
complexBbc = true
|
complexBbc = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if msgbytes[i+1] == 'c' && msgbytes[i+2] == 'o' && msgbytes[i+3] == 'd' && msgbytes[i+4] == 'e' && msgbytes[i+5] == ']' {
|
// Put the biggest index first to avoid unnecessary bounds checks
|
||||||
|
if mbytes[i+5] == ']' && mbytes[i+1] == 'c' && mbytes[i+2] == 'o' && mbytes[i+3] == 'd' && mbytes[i+4] == 'e' {
|
||||||
hasC = true
|
hasC = true
|
||||||
i += 6
|
i += 6
|
||||||
}
|
}
|
||||||
complexBbc = true
|
complexBbc = true
|
||||||
}
|
}
|
||||||
} else if !hasC {
|
} else if !hasC {
|
||||||
if msgbytes[i+1] == 'b' && !hasB {
|
ch := mbytes[i+1]
|
||||||
msgbytes[i] = '<'
|
if ch == 'b' && !hasB {
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i] = '<'
|
||||||
|
mbytes[i+2] = '>'
|
||||||
hasB = true
|
hasB = true
|
||||||
} else if msgbytes[i+1] == 'i' && !hasI {
|
} else if ch == 'i' && !hasI {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasI = true
|
hasI = true
|
||||||
} else if msgbytes[i+1] == 'u' && !hasU {
|
} else if ch == 'u' && !hasU {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasU = true
|
hasU = true
|
||||||
} else if msgbytes[i+1] == 's' && !hasS {
|
} else if ch == 's' && !hasS {
|
||||||
msgbytes[i] = '<'
|
mbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
mbytes[i+2] = '>'
|
||||||
hasS = true
|
hasS = true
|
||||||
}
|
}
|
||||||
i += 2
|
i += 2
|
||||||
|
@ -285,46 +291,46 @@ func BbcodeFullParse(msg string) string {
|
||||||
closeBold := []byte("</b>")
|
closeBold := []byte("</b>")
|
||||||
closeStrike := []byte("</s>")
|
closeStrike := []byte("</s>")
|
||||||
if hasI {
|
if hasI {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeItalic...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeItalic...)
|
||||||
}
|
}
|
||||||
if hasU {
|
if hasU {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeUnder...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeUnder...)
|
||||||
}
|
}
|
||||||
if hasB {
|
if hasB {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeBold...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeBold...)
|
||||||
}
|
}
|
||||||
if hasS {
|
if hasS {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), closeStrike...)
|
mbytes = append(bytes.TrimSpace(mbytes), closeStrike...)
|
||||||
}
|
}
|
||||||
msgbytes = append(msgbytes, c.SpaceGap...)
|
mbytes = append(mbytes, c.SpaceGap...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if complexBbc {
|
if complexBbc {
|
||||||
i := 0
|
i := 0
|
||||||
var start, lastTag int
|
var start, lastTag int
|
||||||
var outbytes []byte
|
var outbytes []byte
|
||||||
for ; i < len(msgbytes); i++ {
|
for ; i < len(mbytes); i++ {
|
||||||
if msgbytes[i] == '[' {
|
if mbytes[i] == '[' {
|
||||||
if msgbytes[i+1] == 'u' {
|
if mbytes[i+1] == 'u' {
|
||||||
if msgbytes[i+2] == 'r' && msgbytes[i+3] == 'l' && msgbytes[i+4] == ']' {
|
if mbytes[i+4] == ']' && mbytes[i+2] == 'r' && mbytes[i+3] == 'l' {
|
||||||
i, start, lastTag, outbytes = bbcodeParseURL(i, start, lastTag, msgbytes, outbytes)
|
i, start, lastTag, outbytes = bbcodeParseURL(i, start, lastTag, mbytes, outbytes)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else if msgbytes[i+1] == 'r' {
|
} else if mbytes[i+1] == 'r' {
|
||||||
if bytes.Equal(msgbytes[i+2:i+6], []byte("and]")) {
|
if bytes.Equal(mbytes[i+2:i+6], []byte("and]")) {
|
||||||
i, start, lastTag, outbytes = bbcodeParseRand(i, start, lastTag, msgbytes, outbytes)
|
i, start, lastTag, outbytes = bbcodeParseRand(i, start, lastTag, mbytes, outbytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lastTag != i {
|
if lastTag != i {
|
||||||
outbytes = append(outbytes, msgbytes[lastTag:]...)
|
outbytes = append(outbytes, mbytes[lastTag:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(outbytes) != 0 {
|
if len(outbytes) != 0 {
|
||||||
msg = string(outbytes[0 : len(outbytes)-10])
|
msg = string(outbytes[0 : len(outbytes)-10])
|
||||||
} else {
|
} else {
|
||||||
msg = string(msgbytes[0 : len(msgbytes)-10])
|
msg = string(mbytes[0 : len(mbytes)-10])
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Optimise these
|
// TODO: Optimise these
|
||||||
|
@ -335,27 +341,27 @@ func BbcodeFullParse(msg string) string {
|
||||||
msg = bbcodeSpoiler.ReplaceAllString(msg, "<spoiler>$1</spoiler>")
|
msg = bbcodeSpoiler.ReplaceAllString(msg, "<spoiler>$1</spoiler>")
|
||||||
msg = bbcodeH1.ReplaceAllString(msg, "<h2>$1</h2>")
|
msg = bbcodeH1.ReplaceAllString(msg, "<h2>$1</h2>")
|
||||||
} else {
|
} else {
|
||||||
msg = string(msgbytes[0 : len(msgbytes)-10])
|
msg = string(mbytes[0 : len(mbytes)-10])
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Strip the containing [url] so the media parser can work it's magic instead? Or do we want to allow something like [url=]label[/url] here?
|
// TODO: Strip the containing [url] so the media parser can work it's magic instead? Or do we want to allow something like [url=]label[/url] here?
|
||||||
func bbcodeParseURL(i int, start int, lastTag int, msgbytes []byte, outbytes []byte) (int, int, int, []byte) {
|
func bbcodeParseURL(i int, start int, lastTag int, mbytes []byte, outbytes []byte) (int, int, int, []byte) {
|
||||||
start = i + 5
|
start = i + 5
|
||||||
outbytes = append(outbytes, msgbytes[lastTag:i]...)
|
outbytes = append(outbytes, mbytes[lastTag:i]...)
|
||||||
i = start
|
i = start
|
||||||
i += c.PartialURLStringLen2(string(msgbytes[start:]))
|
i += c.PartialURLStringLen2(string(mbytes[start:]))
|
||||||
if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) {
|
if !bytes.Equal(mbytes[i:i+6], []byte("[/url]")) {
|
||||||
outbytes = append(outbytes, c.InvalidURL...)
|
outbytes = append(outbytes, c.InvalidURL...)
|
||||||
return i, start, lastTag, outbytes
|
return i, start, lastTag, outbytes
|
||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, c.URLOpen...)
|
outbytes = append(outbytes, c.URLOpen...)
|
||||||
outbytes = append(outbytes, msgbytes[start:i]...)
|
outbytes = append(outbytes, mbytes[start:i]...)
|
||||||
outbytes = append(outbytes, c.URLOpen2...)
|
outbytes = append(outbytes, c.URLOpen2...)
|
||||||
outbytes = append(outbytes, msgbytes[start:i]...)
|
outbytes = append(outbytes, mbytes[start:i]...)
|
||||||
outbytes = append(outbytes, c.URLClose...)
|
outbytes = append(outbytes, c.URLClose...)
|
||||||
i += 6
|
i += 6
|
||||||
lastTag = i
|
lastTag = i
|
||||||
|
|
|
@ -167,7 +167,14 @@ func TestParser(t *testing.T) {
|
||||||
l.Add("// t", "// t")
|
l.Add("// t", "// t")
|
||||||
l.Add("http:// t", "<red>[Invalid URL]</red> t")
|
l.Add("http:// t", "<red>[Invalid URL]</red> t")
|
||||||
|
|
||||||
|
l.Add("h", "h")
|
||||||
|
l.Add("ht", "ht")
|
||||||
|
l.Add("htt", "htt")
|
||||||
|
l.Add("http", "http")
|
||||||
l.Add("http:", "http:")
|
l.Add("http:", "http:")
|
||||||
|
//t l.Add("http:/", "http:/")
|
||||||
|
//t l.Add("http:/d", "http:/d")
|
||||||
|
l.Add("http:d", "http:d")
|
||||||
l.Add("https:", "https:")
|
l.Add("https:", "https:")
|
||||||
l.Add("ftp:", "ftp:")
|
l.Add("ftp:", "ftp:")
|
||||||
l.Add("git:", "git:")
|
l.Add("git:", "git:")
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
addInitHook("end_init", () => {
|
addInitHook("end_init", () => {
|
||||||
$("#dash_username input").click(function(){
|
$("#dash_username input").click(()=>{
|
||||||
$("#dash_username button").show();
|
$("#dash_username button").show();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
let clickHandle = function(event){
|
let clickHandle = function(ev){
|
||||||
console.log("in clickHandle")
|
console.log("in clickHandle")
|
||||||
event.preventDefault();
|
ev.preventDefault();
|
||||||
let eparent = $(this).closest(".editable_parent");
|
let ep = $(this).closest(".editable_parent");
|
||||||
eparent.find(".hide_on_block_edit").addClass("edit_opened");
|
ep.find(".hide_on_block_edit").addClass("edit_opened");
|
||||||
eparent.find(".show_on_block_edit").addClass("edit_opened");
|
ep.find(".show_on_block_edit").addClass("edit_opened");
|
||||||
eparent.addClass("in_edit");
|
ep.addClass("in_edit");
|
||||||
|
|
||||||
eparent.find(".widget_save").click(() => {
|
ep.find(".widget_save").click(() => {
|
||||||
eparent.find(".hide_on_block_edit").removeClass("edit_opened");
|
ep.find(".hide_on_block_edit").removeClass("edit_opened");
|
||||||
eparent.find(".show_on_block_edit").removeClass("edit_opened");
|
ep.find(".show_on_block_edit").removeClass("edit_opened");
|
||||||
eparent.removeClass("in_edit");
|
ep.removeClass("in_edit");
|
||||||
});
|
});
|
||||||
|
|
||||||
eparent.find(".widget_delete").click(function(event) {
|
ep.find(".widget_delete").click(function(ev) {
|
||||||
event.preventDefault();
|
ev.preventDefault();
|
||||||
eparent.remove();
|
ep.remove();
|
||||||
let formData = new URLSearchParams();
|
let formData = new URLSearchParams();
|
||||||
formData.append("s",me.User.S);
|
formData.append("s",me.User.S);
|
||||||
let req = new XMLHttpRequest();
|
let req = new XMLHttpRequest();
|
||||||
|
@ -29,15 +29,14 @@ $(document).ready(() => {
|
||||||
|
|
||||||
$(".widget_item a").click(clickHandle);
|
$(".widget_item a").click(clickHandle);
|
||||||
|
|
||||||
let changeHandle = function(event){
|
let changeHandle = function(ev){
|
||||||
let wtype = this.options[this.selectedIndex].value;
|
let wtype = this.options[this.selectedIndex].value;
|
||||||
let typeBlock = this.closest(".widget_edit").querySelector(".wtypes");
|
let typeBlock = this.closest(".widget_edit").querySelector(".wtypes");
|
||||||
typeBlock.className = "wtypes wtype_"+wtype;
|
typeBlock.className = "wtypes wtype_"+wtype;
|
||||||
};
|
};
|
||||||
|
|
||||||
$(".wtype_sel").change(changeHandle);
|
$(".wtype_sel").change(changeHandle);
|
||||||
|
|
||||||
$(".widget_new a").click(function(event){
|
$(".widget_new a").click(function(ev){
|
||||||
console.log("clicked widget_new a")
|
console.log("clicked widget_new a")
|
||||||
let widgetList = this.closest(".panel_widgets");
|
let widgetList = this.closest(".panel_widgets");
|
||||||
let widgetNew = this.closest(".widget_new");
|
let widgetNew = this.closest(".widget_new");
|
||||||
|
@ -51,10 +50,10 @@ $(document).ready(() => {
|
||||||
$(".wtype_sel").change(changeHandle);
|
$(".wtype_sel").change(changeHandle);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".widget_save").click(function(event){
|
$(".widget_save").click(function(ev){
|
||||||
console.log("in .widget_save")
|
console.log("in .widget_save")
|
||||||
event.preventDefault();
|
ev.preventDefault();
|
||||||
event.stopPropagation();
|
ev.stopPropagation();
|
||||||
let pform = this.closest("form");
|
let pform = this.closest("form");
|
||||||
let data = new URLSearchParams();
|
let data = new URLSearchParams();
|
||||||
for (const pair of new FormData(pform)) data.append(pair[0], pair[1]);
|
for (const pair of new FormData(pform)) data.append(pair[0], pair[1]);
|
||||||
|
|
|
@ -99,19 +99,19 @@ func (build *Accumulator) Tx(handler func(*TransactionBuilder) error) {
|
||||||
build.RecordError(tx.Commit())
|
build.RecordError(tx.Commit())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleSelect(table string, columns string, where string, orderby string, limit string) *sql.Stmt {
|
func (build *Accumulator) SimpleSelect(table, columns, where, orderby, limit string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleSelect("", table, columns, where, orderby, limit))
|
return build.prepare(build.adapter.SimpleSelect("", table, columns, where, orderby, limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleCount(table string, where string, limit string) *sql.Stmt {
|
func (build *Accumulator) SimpleCount(table, where, limit string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleCount("", table, where, limit))
|
return build.prepare(build.adapter.SimpleCount("", table, where, limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleLeftJoin(table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) *sql.Stmt {
|
func (build *Accumulator) SimpleLeftJoin(table1, table2, columns, joiners, where, orderby, limit string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleLeftJoin("", table1, table2, columns, joiners, where, orderby, limit))
|
return build.prepare(build.adapter.SimpleLeftJoin("", table1, table2, columns, joiners, where, orderby, limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleInnerJoin(table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) *sql.Stmt {
|
func (build *Accumulator) SimpleInnerJoin(table1, table2, columns, joiners, where, orderby, limit string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleInnerJoin("", table1, table2, columns, joiners, where, orderby, limit))
|
return build.prepare(build.adapter.SimpleInnerJoin("", table1, table2, columns, joiners, where, orderby, limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ func (build *Accumulator) CreateTable(table string, charset string, collation st
|
||||||
return build.prepare(build.adapter.CreateTable("", table, charset, collation, columns, keys))
|
return build.prepare(build.adapter.CreateTable("", table, charset, collation, columns, keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleInsert(table string, columns string, fields string) *sql.Stmt {
|
func (build *Accumulator) SimpleInsert(table, columns, fields string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleInsert("", table, columns, fields))
|
return build.prepare(build.adapter.SimpleInsert("", table, columns, fields))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,15 +135,16 @@ func (build *Accumulator) SimpleInsertInnerJoin(ins DBInsert, sel DBJoin) *sql.S
|
||||||
return build.prepare(build.adapter.SimpleInsertInnerJoin("", ins, sel))
|
return build.prepare(build.adapter.SimpleInsertInnerJoin("", ins, sel))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleUpdate(table string, set string, where string) *sql.Stmt {
|
func (build *Accumulator) SimpleUpdate(table, set, where string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleUpdate(qUpdate(table, set, where)))
|
return build.prepare(build.adapter.SimpleUpdate(qUpdate(table, set, where)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleUpdateSelect(table string, set string, where string) *sql.Stmt {
|
func (build *Accumulator) SimpleUpdateSelect(table, set, table2, cols, where, orderby, limit string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleUpdateSelect(qUpdate(table, set, where)))
|
pre := qUpdate(table, set, "").WhereQ(build.GetAdapter().Builder().Select().Table(table2).Columns(cols).Where(where).Orderby(orderby).Limit(limit))
|
||||||
|
return build.prepare(build.adapter.SimpleUpdateSelect(pre))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (build *Accumulator) SimpleDelete(table string, where string) *sql.Stmt {
|
func (build *Accumulator) SimpleDelete(table, where string) *sql.Stmt {
|
||||||
return build.prepare(build.adapter.SimpleDelete("", table, where))
|
return build.prepare(build.adapter.SimpleDelete("", table, where))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (a *MssqlAdapter) DbVersion() string {
|
||||||
return "SELECT CONCAT(SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition'))"
|
return "SELECT CONCAT(SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition'))"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MssqlAdapter) DropTable(name string, table string) (string, error) {
|
func (a *MssqlAdapter) DropTable(name, table 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")
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ func (a *MssqlAdapter) AddColumn(name string, table string, column DBTableColumn
|
||||||
|
|
||||||
// TODO: Implement this
|
// TODO: Implement this
|
||||||
// TODO: Test to make sure everything works here
|
// TODO: Test to make sure everything works here
|
||||||
func (a *MssqlAdapter) AddIndex(name string, table string, iname string, colname string) (string, error) {
|
func (a *MssqlAdapter) AddIndex(name, table, iname, 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")
|
||||||
}
|
}
|
||||||
|
@ -194,27 +194,26 @@ func (a *MssqlAdapter) AddForeignKey(name string, table string, column string, f
|
||||||
return "", errors.New("not implemented")
|
return "", errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MssqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
|
func (a *MssqlAdapter) SimpleInsert(name, table, cols, 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
q := "INSERT INTO [" + table + "] ("
|
q := "INSERT INTO [" + table + "] ("
|
||||||
if columns == "" {
|
if cols == "" {
|
||||||
q += ") VALUES ()"
|
q += ") VALUES ()"
|
||||||
a.pushStatement(name, "insert", q)
|
a.pushStatement(name, "insert", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range processColumns(columns) {
|
for _, col := range processColumns(cols) {
|
||||||
if column.Type == "function" {
|
if col.Type == TokenFunc {
|
||||||
q += column.Left + ","
|
q += col.Left + ","
|
||||||
} else {
|
} else {
|
||||||
q += "[" + column.Left + "],"
|
q += "[" + col.Left + "],"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove the trailing comma
|
|
||||||
q = q[0 : len(q)-1]
|
q = q[0 : len(q)-1]
|
||||||
|
|
||||||
q += ") VALUES ("
|
q += ") VALUES ("
|
||||||
|
@ -314,17 +313,17 @@ func (a *MssqlAdapter) SimpleUpsert(name string, table string, columns string, f
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
q += " ?"
|
q += " ?"
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -337,14 +336,14 @@ func (a *MssqlAdapter) SimpleUpsert(name string, table string, columns string, f
|
||||||
var fieldList string
|
var fieldList string
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for columnID, column := range processColumns(columns) {
|
for columnID, col := range processColumns(columns) {
|
||||||
fieldList += "f" + strconv.Itoa(columnID) + ","
|
fieldList += "f" + strconv.Itoa(columnID) + ","
|
||||||
if column.Type == "function" {
|
if col.Type == TokenFunc {
|
||||||
matched += column.Left + " = f" + strconv.Itoa(columnID) + ","
|
matched += col.Left + " = f" + strconv.Itoa(columnID) + ","
|
||||||
notMatched += column.Left + ","
|
notMatched += col.Left + ","
|
||||||
} else {
|
} else {
|
||||||
matched += "[" + column.Left + "] = f" + strconv.Itoa(columnID) + ","
|
matched += "[" + col.Left + "] = f" + strconv.Itoa(columnID) + ","
|
||||||
notMatched += "[" + column.Left + "],"
|
notMatched += "[" + col.Left + "],"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,17 +375,17 @@ func (a *MssqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
|
||||||
q += "[" + item.Column + "]="
|
q += "[" + item.Column + "]="
|
||||||
for _, token := range item.Expr {
|
for _, token := range item.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
q += " ?"
|
q += " ?"
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -394,7 +393,6 @@ func (a *MssqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
|
||||||
}
|
}
|
||||||
q += ","
|
q += ","
|
||||||
}
|
}
|
||||||
// Remove the trailing comma
|
|
||||||
q = q[0 : len(q)-1]
|
q = q[0 : len(q)-1]
|
||||||
|
|
||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
|
@ -403,15 +401,15 @@ func (a *MssqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
|
||||||
for _, loc := range processWhere(up.where) {
|
for _, loc := range processWhere(up.where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -443,17 +441,17 @@ func (a *MssqlAdapter) SimpleDelete(name string, table string, where string) (st
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
q += " ?"
|
q += " ?"
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -492,7 +490,7 @@ func (a *MssqlAdapter) SimpleSelect(name string, table string, columns string, w
|
||||||
if len(orderby) == 0 && limit != "" {
|
if len(orderby) == 0 && limit != "" {
|
||||||
return "", errors.New("Orderby needs to be set to use limit on Mssql")
|
return "", errors.New("Orderby needs to be set to use limit on Mssql")
|
||||||
}
|
}
|
||||||
substituteCount := 0
|
subCount := 0
|
||||||
q := ""
|
q := ""
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
|
@ -508,19 +506,19 @@ func (a *MssqlAdapter) SimpleSelect(name string, table string, columns string, w
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " ?" + strconv.Itoa(substituteCount)
|
q += " ?" + strconv.Itoa(subCount)
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
// MSSQL seems to convert the formats? so we'll compare it with a regular date. Do this with the other methods too?
|
// MSSQL seems to convert the formats? so we'll compare it with a regular date. Do this with the other methods too?
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETDATE()"
|
token.Contents = "GETDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -546,8 +544,8 @@ func (a *MssqlAdapter) SimpleSelect(name string, table string, columns string, w
|
||||||
log.Printf("limiter: %+v\n", limiter)
|
log.Printf("limiter: %+v\n", limiter)
|
||||||
if limiter.Offset != "" {
|
if limiter.Offset != "" {
|
||||||
if limiter.Offset == "?" {
|
if limiter.Offset == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " OFFSET ?" + strconv.Itoa(substituteCount) + " ROWS"
|
q += " OFFSET ?" + strconv.Itoa(subCount) + " ROWS"
|
||||||
} else {
|
} else {
|
||||||
q += " OFFSET " + limiter.Offset + " ROWS"
|
q += " OFFSET " + limiter.Offset + " ROWS"
|
||||||
}
|
}
|
||||||
|
@ -556,8 +554,8 @@ func (a *MssqlAdapter) SimpleSelect(name string, table string, columns string, w
|
||||||
// ! Does this work without an offset?
|
// ! Does this work without an offset?
|
||||||
if limiter.MaxCount != "" {
|
if limiter.MaxCount != "" {
|
||||||
if limiter.MaxCount == "?" {
|
if limiter.MaxCount == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
limiter.MaxCount = "?" + strconv.Itoa(substituteCount)
|
limiter.MaxCount = "?" + strconv.Itoa(subCount)
|
||||||
}
|
}
|
||||||
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
||||||
}
|
}
|
||||||
|
@ -594,22 +592,22 @@ func (a *MssqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string,
|
||||||
if len(orderby) == 0 && limit != "" {
|
if len(orderby) == 0 && limit != "" {
|
||||||
return "", errors.New("Orderby needs to be set to use limit on Mssql")
|
return "", errors.New("Orderby needs to be set to use limit on Mssql")
|
||||||
}
|
}
|
||||||
substituteCount := 0
|
subCount := 0
|
||||||
q := ""
|
q := ""
|
||||||
|
|
||||||
for _, column := range processColumns(columns) {
|
for _, col := range processColumns(columns) {
|
||||||
var source, alias string
|
var source, alias string
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
if column.Table != "" {
|
if col.Table != "" {
|
||||||
source = "[" + column.Table + "].[" + column.Left + "]"
|
source = "[" + col.Table + "].[" + col.Left + "]"
|
||||||
} else if column.Type == "function" {
|
} else if col.Type == TokenFunc {
|
||||||
source = column.Left
|
source = col.Left
|
||||||
} else {
|
} else {
|
||||||
source = "[" + column.Left + "]"
|
source = "[" + col.Left + "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
if column.Alias != "" {
|
if col.Alias != "" {
|
||||||
alias = " AS '" + column.Alias + "'"
|
alias = " AS '" + col.Alias + "'"
|
||||||
}
|
}
|
||||||
q += source + alias + ","
|
q += source + alias + ","
|
||||||
}
|
}
|
||||||
|
@ -629,23 +627,23 @@ func (a *MssqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string,
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " ?" + strconv.Itoa(substituteCount)
|
q += " ?" + strconv.Itoa(subCount)
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
q += " [" + halves[0] + "].[" + halves[1] + "]"
|
q += " [" + halves[0] + "].[" + halves[1] + "]"
|
||||||
} else {
|
} else {
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
}
|
}
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -676,8 +674,8 @@ func (a *MssqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string,
|
||||||
limiter := processLimit(limit)
|
limiter := processLimit(limit)
|
||||||
if limiter.Offset != "" {
|
if limiter.Offset != "" {
|
||||||
if limiter.Offset == "?" {
|
if limiter.Offset == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " OFFSET ?" + strconv.Itoa(substituteCount) + " ROWS"
|
q += " OFFSET ?" + strconv.Itoa(subCount) + " ROWS"
|
||||||
} else {
|
} else {
|
||||||
q += " OFFSET " + limiter.Offset + " ROWS"
|
q += " OFFSET " + limiter.Offset + " ROWS"
|
||||||
}
|
}
|
||||||
|
@ -686,8 +684,8 @@ func (a *MssqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string,
|
||||||
// ! Does this work without an offset?
|
// ! Does this work without an offset?
|
||||||
if limiter.MaxCount != "" {
|
if limiter.MaxCount != "" {
|
||||||
if limiter.MaxCount == "?" {
|
if limiter.MaxCount == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
limiter.MaxCount = "?" + strconv.Itoa(substituteCount)
|
limiter.MaxCount = "?" + strconv.Itoa(subCount)
|
||||||
}
|
}
|
||||||
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
||||||
}
|
}
|
||||||
|
@ -719,22 +717,22 @@ func (a *MssqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string
|
||||||
if len(orderby) == 0 && limit != "" {
|
if len(orderby) == 0 && limit != "" {
|
||||||
return "", errors.New("Orderby needs to be set to use limit on Mssql")
|
return "", errors.New("Orderby needs to be set to use limit on Mssql")
|
||||||
}
|
}
|
||||||
substituteCount := 0
|
subCount := 0
|
||||||
q := ""
|
q := ""
|
||||||
|
|
||||||
for _, column := range processColumns(columns) {
|
for _, col := range processColumns(columns) {
|
||||||
var source, alias string
|
var source, alias string
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
if column.Table != "" {
|
if col.Table != "" {
|
||||||
source = "[" + column.Table + "].[" + column.Left + "]"
|
source = "[" + col.Table + "].[" + col.Left + "]"
|
||||||
} else if column.Type == "function" {
|
} else if col.Type == TokenFunc {
|
||||||
source = column.Left
|
source = col.Left
|
||||||
} else {
|
} else {
|
||||||
source = "[" + column.Left + "]"
|
source = "[" + col.Left + "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
if column.Alias != "" {
|
if col.Alias != "" {
|
||||||
alias = " AS '" + column.Alias + "'"
|
alias = " AS '" + col.Alias + "'"
|
||||||
}
|
}
|
||||||
q += source + alias + ","
|
q += source + alias + ","
|
||||||
}
|
}
|
||||||
|
@ -754,23 +752,23 @@ func (a *MssqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " ?" + strconv.Itoa(substituteCount)
|
q += " ?" + strconv.Itoa(subCount)
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
q += " [" + halves[0] + "].[" + halves[1] + "]"
|
q += " [" + halves[0] + "].[" + halves[1] + "]"
|
||||||
} else {
|
} else {
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
}
|
}
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -802,8 +800,8 @@ func (a *MssqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string
|
||||||
limiter := processLimit(limit)
|
limiter := processLimit(limit)
|
||||||
if limiter.Offset != "" {
|
if limiter.Offset != "" {
|
||||||
if limiter.Offset == "?" {
|
if limiter.Offset == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " OFFSET ?" + strconv.Itoa(substituteCount) + " ROWS"
|
q += " OFFSET ?" + strconv.Itoa(subCount) + " ROWS"
|
||||||
} else {
|
} else {
|
||||||
q += " OFFSET " + limiter.Offset + " ROWS"
|
q += " OFFSET " + limiter.Offset + " ROWS"
|
||||||
}
|
}
|
||||||
|
@ -812,8 +810,8 @@ func (a *MssqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string
|
||||||
// ! Does this work without an offset?
|
// ! Does this work without an offset?
|
||||||
if limiter.MaxCount != "" {
|
if limiter.MaxCount != "" {
|
||||||
if limiter.MaxCount == "?" {
|
if limiter.MaxCount == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
limiter.MaxCount = "?" + strconv.Itoa(substituteCount)
|
limiter.MaxCount = "?" + strconv.Itoa(subCount)
|
||||||
}
|
}
|
||||||
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
||||||
}
|
}
|
||||||
|
@ -839,28 +837,28 @@ func (a *MssqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelec
|
||||||
q := "INSERT INTO [" + ins.Table + "] ("
|
q := "INSERT INTO [" + ins.Table + "] ("
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range processColumns(ins.Columns) {
|
for _, col := range processColumns(ins.Columns) {
|
||||||
if column.Type == "function" {
|
if col.Type == TokenFunc {
|
||||||
q += column.Left + ","
|
q += col.Left + ","
|
||||||
} else {
|
} else {
|
||||||
q += "[" + column.Left + "],"
|
q += "[" + col.Left + "],"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q = q[0:len(q)-1] + ") SELECT "
|
q = q[0:len(q)-1] + ") SELECT "
|
||||||
|
|
||||||
/* Select */
|
/* Select */
|
||||||
substituteCount := 0
|
subCount := 0
|
||||||
|
|
||||||
for _, column := range processColumns(sel.Columns) {
|
for _, col := range processColumns(sel.Columns) {
|
||||||
var source, alias string
|
var source, alias string
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
if column.Type == "function" || column.Type == "substitute" {
|
if col.Type == TokenFunc || col.Type == TokenSub {
|
||||||
source = column.Left
|
source = col.Left
|
||||||
} else {
|
} else {
|
||||||
source = "[" + column.Left + "]"
|
source = "[" + col.Left + "]"
|
||||||
}
|
}
|
||||||
if column.Alias != "" {
|
if col.Alias != "" {
|
||||||
alias = " AS [" + column.Alias + "]"
|
alias = " AS [" + col.Alias + "]"
|
||||||
}
|
}
|
||||||
q += " " + source + alias + ","
|
q += " " + source + alias + ","
|
||||||
}
|
}
|
||||||
|
@ -872,18 +870,18 @@ func (a *MssqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelec
|
||||||
for _, loc := range processWhere(sel.Where) {
|
for _, loc := range processWhere(sel.Where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " ?" + strconv.Itoa(substituteCount)
|
q += " ?" + strconv.Itoa(subCount)
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -913,8 +911,8 @@ func (a *MssqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelec
|
||||||
limiter := processLimit(sel.Limit)
|
limiter := processLimit(sel.Limit)
|
||||||
if limiter.Offset != "" {
|
if limiter.Offset != "" {
|
||||||
if limiter.Offset == "?" {
|
if limiter.Offset == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " OFFSET ?" + strconv.Itoa(substituteCount) + " ROWS"
|
q += " OFFSET ?" + strconv.Itoa(subCount) + " ROWS"
|
||||||
} else {
|
} else {
|
||||||
q += " OFFSET " + limiter.Offset + " ROWS"
|
q += " OFFSET " + limiter.Offset + " ROWS"
|
||||||
}
|
}
|
||||||
|
@ -923,8 +921,8 @@ func (a *MssqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelec
|
||||||
// ! Does this work without an offset?
|
// ! Does this work without an offset?
|
||||||
if limiter.MaxCount != "" {
|
if limiter.MaxCount != "" {
|
||||||
if limiter.MaxCount == "?" {
|
if limiter.MaxCount == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
limiter.MaxCount = "?" + strconv.Itoa(substituteCount)
|
limiter.MaxCount = "?" + strconv.Itoa(subCount)
|
||||||
}
|
}
|
||||||
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
||||||
}
|
}
|
||||||
|
@ -950,30 +948,30 @@ func (a *MssqlAdapter) simpleJoin(name string, ins DBInsert, sel DBJoin, joinTyp
|
||||||
q := "INSERT INTO [" + ins.Table + "] ("
|
q := "INSERT INTO [" + ins.Table + "] ("
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range processColumns(ins.Columns) {
|
for _, col := range processColumns(ins.Columns) {
|
||||||
if column.Type == "function" {
|
if col.Type == TokenFunc {
|
||||||
q += column.Left + ","
|
q += col.Left + ","
|
||||||
} else {
|
} else {
|
||||||
q += "[" + column.Left + "],"
|
q += "[" + col.Left + "],"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q = q[0:len(q)-1] + ") SELECT "
|
q = q[0:len(q)-1] + ") SELECT "
|
||||||
|
|
||||||
/* Select */
|
/* Select */
|
||||||
substituteCount := 0
|
subCount := 0
|
||||||
|
|
||||||
for _, column := range processColumns(sel.Columns) {
|
for _, col := range processColumns(sel.Columns) {
|
||||||
var source, alias string
|
var source, alias string
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
if column.Table != "" {
|
if col.Table != "" {
|
||||||
source = "[" + column.Table + "].[" + column.Left + "]"
|
source = "[" + col.Table + "].[" + col.Left + "]"
|
||||||
} else if column.Type == "function" {
|
} else if col.Type == TokenFunc {
|
||||||
source = column.Left
|
source = col.Left
|
||||||
} else {
|
} else {
|
||||||
source = "[" + column.Left + "]"
|
source = "[" + col.Left + "]"
|
||||||
}
|
}
|
||||||
if column.Alias != "" {
|
if col.Alias != "" {
|
||||||
alias = " AS '" + column.Alias + "'"
|
alias = " AS '" + col.Alias + "'"
|
||||||
}
|
}
|
||||||
q += source + alias + ","
|
q += source + alias + ","
|
||||||
}
|
}
|
||||||
|
@ -993,23 +991,23 @@ func (a *MssqlAdapter) simpleJoin(name string, ins DBInsert, sel DBJoin, joinTyp
|
||||||
for _, loc := range processWhere(sel.Where) {
|
for _, loc := range processWhere(sel.Where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "substitute":
|
case TokenSub:
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " ?" + strconv.Itoa(substituteCount)
|
q += " ?" + strconv.Itoa(subCount)
|
||||||
case "function", "operator", "number", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenOr, TokenNot, TokenLike:
|
||||||
// TODO: Split the function case off to speed things up
|
// TODO: Split the function case off to speed things up
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
q += " [" + halves[0] + "].[" + halves[1] + "]"
|
q += " [" + halves[0] + "].[" + halves[1] + "]"
|
||||||
} else {
|
} else {
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
}
|
}
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -1040,8 +1038,8 @@ func (a *MssqlAdapter) simpleJoin(name string, ins DBInsert, sel DBJoin, joinTyp
|
||||||
limiter := processLimit(sel.Limit)
|
limiter := processLimit(sel.Limit)
|
||||||
if limiter.Offset != "" {
|
if limiter.Offset != "" {
|
||||||
if limiter.Offset == "?" {
|
if limiter.Offset == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
q += " OFFSET ?" + strconv.Itoa(substituteCount) + " ROWS"
|
q += " OFFSET ?" + strconv.Itoa(subCount) + " ROWS"
|
||||||
} else {
|
} else {
|
||||||
q += " OFFSET " + limiter.Offset + " ROWS"
|
q += " OFFSET " + limiter.Offset + " ROWS"
|
||||||
}
|
}
|
||||||
|
@ -1050,8 +1048,8 @@ func (a *MssqlAdapter) simpleJoin(name string, ins DBInsert, sel DBJoin, joinTyp
|
||||||
// ! Does this work without an offset?
|
// ! Does this work without an offset?
|
||||||
if limiter.MaxCount != "" {
|
if limiter.MaxCount != "" {
|
||||||
if limiter.MaxCount == "?" {
|
if limiter.MaxCount == "?" {
|
||||||
substituteCount++
|
subCount++
|
||||||
limiter.MaxCount = "?" + strconv.Itoa(substituteCount)
|
limiter.MaxCount = "?" + strconv.Itoa(subCount)
|
||||||
}
|
}
|
||||||
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
q += " FETCH NEXT " + limiter.MaxCount + " ROWS ONLY "
|
||||||
}
|
}
|
||||||
|
@ -1074,7 +1072,7 @@ func (a *MssqlAdapter) SimpleInsertInnerJoin(name string, ins DBInsert, sel DBJo
|
||||||
return a.simpleJoin(name, ins, sel, "INNER")
|
return a.simpleJoin(name, ins, sel, "INNER")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MssqlAdapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
|
func (a *MssqlAdapter) SimpleCount(name, table, where, limit 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")
|
||||||
}
|
}
|
||||||
|
@ -1086,14 +1084,14 @@ func (a *MssqlAdapter) SimpleCount(name string, table string, where string, limi
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike:
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "GETUTCDATE()"
|
token.Contents = "GETUTCDATE()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " [" + token.Contents + "]"
|
q += " [" + token.Contents + "]"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
|
|
@ -27,20 +27,20 @@ type MysqlAdapter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName gives you the name of the database adapter. In this case, it's mysql
|
// GetName gives you the name of the database adapter. In this case, it's mysql
|
||||||
func (adapter *MysqlAdapter) GetName() string {
|
func (a *MysqlAdapter) GetName() string {
|
||||||
return adapter.Name
|
return a.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) GetStmt(name string) DBStmt {
|
func (a *MysqlAdapter) GetStmt(name string) DBStmt {
|
||||||
return adapter.Buffer[name]
|
return a.Buffer[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) GetStmts() map[string]DBStmt {
|
func (a *MysqlAdapter) GetStmts() map[string]DBStmt {
|
||||||
return adapter.Buffer
|
return a.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add an option to disable unix pipes
|
// TODO: Add an option to disable unix pipes
|
||||||
func (adapter *MysqlAdapter) BuildConn(config map[string]string) (*sql.DB, error) {
|
func (a *MysqlAdapter) BuildConn(config map[string]string) (*sql.DB, error) {
|
||||||
dbCollation, ok := config["collation"]
|
dbCollation, ok := config["collation"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrNoCollation
|
return nil, ErrNoCollation
|
||||||
|
@ -78,21 +78,21 @@ func (adapter *MysqlAdapter) BuildConn(config map[string]string) (*sql.DB, error
|
||||||
return db, db.Ping()
|
return db, db.Ping()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) DbVersion() string {
|
func (a *MysqlAdapter) DbVersion() string {
|
||||||
return "SELECT VERSION()"
|
return "SELECT VERSION()"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) DropTable(name string, table string) (string, error) {
|
func (a *MysqlAdapter) DropTable(name string, table 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")
|
||||||
}
|
}
|
||||||
querystr := "DROP TABLE IF EXISTS `" + table + "`;"
|
q := "DROP TABLE IF EXISTS `" + table + "`;"
|
||||||
// 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, "drop-table", querystr)
|
a.pushStatement(name, "drop-table", q)
|
||||||
return querystr, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error) {
|
func (a *MysqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DBTableColumn, keys []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")
|
||||||
}
|
}
|
||||||
|
@ -100,49 +100,50 @@ func (adapter *MysqlAdapter) CreateTable(name string, table string, charset stri
|
||||||
return "", errors.New("You can't have a table with no columns")
|
return "", errors.New("You can't have a table with no columns")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr = "CREATE TABLE `" + table + "` ("
|
q := "CREATE TABLE `" + table + "` ("
|
||||||
for _, column := range columns {
|
for _, column := range columns {
|
||||||
column, size, end := adapter.parseColumn(column)
|
column, size, end := a.parseColumn(column)
|
||||||
querystr += "\n\t`" + column.Name + "` " + column.Type + size + end + ","
|
q += "\n\t`" + column.Name + "` " + column.Type + size + end + ","
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
querystr += "\n\t" + key.Type
|
q += "\n\t" + key.Type
|
||||||
if key.Type != "unique" {
|
if key.Type != "unique" {
|
||||||
querystr += " key"
|
q += " key"
|
||||||
}
|
}
|
||||||
if key.Type == "foreign" {
|
if key.Type == "foreign" {
|
||||||
cols := strings.Split(key.Columns, ",")
|
cols := strings.Split(key.Columns, ",")
|
||||||
querystr += "(`" + cols[0] + "`) REFERENCES `" + key.FTable + "`(`" + cols[1] + "`)"
|
q += "(`" + cols[0] + "`) REFERENCES `" + key.FTable + "`(`" + cols[1] + "`)"
|
||||||
if key.Cascade {
|
if key.Cascade {
|
||||||
querystr += " ON DELETE CASCADE"
|
q += " ON DELETE CASCADE"
|
||||||
}
|
}
|
||||||
querystr += ","
|
q += ","
|
||||||
} else {
|
} else {
|
||||||
querystr += "("
|
q += "("
|
||||||
for _, column := range strings.Split(key.Columns, ",") {
|
for _, column := range strings.Split(key.Columns, ",") {
|
||||||
querystr += "`" + column + "`,"
|
q += "`" + column + "`,"
|
||||||
}
|
}
|
||||||
querystr = querystr[0:len(querystr)-1] + "),"
|
q = q[0:len(q)-1] + "),"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
querystr = querystr[0:len(querystr)-1] + "\n)"
|
q = q[0:len(q)-1] + "\n)"
|
||||||
if charset != "" {
|
if charset != "" {
|
||||||
querystr += " CHARSET=" + charset
|
q += " CHARSET=" + charset
|
||||||
}
|
}
|
||||||
if collation != "" {
|
if collation != "" {
|
||||||
querystr += " COLLATE " + collation
|
q += " COLLATE " + collation
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, "create-table", querystr+";")
|
q += ";"
|
||||||
return querystr + ";", nil
|
a.pushStatement(name, "create-table", q)
|
||||||
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) parseColumn(column DBTableColumn) (col DBTableColumn, size string, end string) {
|
func (a *MysqlAdapter) parseColumn(column DBTableColumn) (col DBTableColumn, size string, end string) {
|
||||||
// Make it easier to support Cassandra in the future
|
// Make it easier to support Cassandra in the future
|
||||||
if column.Type == "createdAt" {
|
if column.Type == "createdAt" {
|
||||||
column.Type = "datetime"
|
column.Type = "datetime"
|
||||||
|
@ -162,7 +163,7 @@ func (adapter *MysqlAdapter) parseColumn(column DBTableColumn) (col DBTableColum
|
||||||
end = " DEFAULT "
|
end = " DEFAULT "
|
||||||
/*if column.Type == "datetime" && column.Default[len(column.Default)-1] == ')' {
|
/*if column.Type == "datetime" && column.Default[len(column.Default)-1] == ')' {
|
||||||
end += column.Default
|
end += column.Default
|
||||||
} else */if adapter.stringyType(column.Type) && column.Default != "''" {
|
} else */if a.stringyType(column.Type) && column.Default != "''" {
|
||||||
end += "'" + column.Default + "'"
|
end += "'" + column.Default + "'"
|
||||||
} else {
|
} else {
|
||||||
end += column.Default
|
end += column.Default
|
||||||
|
@ -188,20 +189,20 @@ func (a *MysqlAdapter) AddColumn(name string, table string, column DBTableColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
column, size, end := a.parseColumn(column)
|
column, size, end := a.parseColumn(column)
|
||||||
querystr := "ALTER TABLE `" + table + "` ADD COLUMN " + "`" + column.Name + "` " + column.Type + size + end
|
q := "ALTER TABLE `" + table + "` ADD COLUMN " + "`" + column.Name + "` " + column.Type + size + end
|
||||||
|
|
||||||
if key != nil {
|
if key != nil {
|
||||||
querystr += " " + key.Type
|
q += " " + key.Type
|
||||||
if key.Type != "unique" {
|
if key.Type != "unique" {
|
||||||
querystr += " key"
|
q += " key"
|
||||||
} else if key.Type == "primary" {
|
} else if key.Type == "primary" {
|
||||||
querystr += " first"
|
q += " first"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
a.pushStatement(name, "add-column", querystr)
|
a.pushStatement(name, "add-column", q)
|
||||||
return querystr, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test to make sure everything works here
|
// TODO: Test to make sure everything works here
|
||||||
|
@ -216,10 +217,10 @@ func (a *MysqlAdapter) AddIndex(name string, table string, iname string, colname
|
||||||
return "", errors.New("You need a name for the column")
|
return "", errors.New("You need a name for the column")
|
||||||
}
|
}
|
||||||
|
|
||||||
querystr := "ALTER TABLE `" + table + "` ADD INDEX " + "`i_" + iname + "` (`" + colname + "`);"
|
q := "ALTER TABLE `" + table + "` ADD INDEX " + "`i_" + 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
|
||||||
a.pushStatement(name, "add-index", querystr)
|
a.pushStatement(name, "add-index", q)
|
||||||
return querystr, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test to make sure everything works here
|
// TODO: Test to make sure everything works here
|
||||||
|
@ -228,20 +229,20 @@ func (a *MysqlAdapter) AddKey(name string, table string, column string, key DBTa
|
||||||
if table == "" {
|
if table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
var querystr string
|
var q string
|
||||||
if key.Type == "fulltext" {
|
if key.Type == "fulltext" {
|
||||||
querystr = "ALTER TABLE `" + table + "` ADD FULLTEXT(`" + column + "`)"
|
q = "ALTER TABLE `" + table + "` ADD FULLTEXT(`" + column + "`)"
|
||||||
} else {
|
} else {
|
||||||
return "", errors.New("Only fulltext is supported by AddKey right now")
|
return "", errors.New("Only fulltext is supported by AddKey right now")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
a.pushStatement(name, "add-key", querystr)
|
a.pushStatement(name, "add-key", q)
|
||||||
return querystr, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MysqlAdapter) AddForeignKey(name string, table string, column string, ftable string, fcolumn string, cascade bool) (out string, e error) {
|
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) {
|
c := func(str string, val bool) {
|
||||||
if e != nil || !val {
|
if e != nil || !val {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -255,18 +256,19 @@ func (a *MysqlAdapter) AddForeignKey(name string, table string, column string, f
|
||||||
return "", e
|
return "", e
|
||||||
}
|
}
|
||||||
|
|
||||||
querystr := "ALTER TABLE `"+table+"` ADD CONSTRAINT `fk_"+column+"` FOREIGN KEY(`"+column+"`) REFERENCES `"+ftable+"`(`"+fcolumn+"`)"
|
q := "ALTER TABLE `" + table + "` ADD CONSTRAINT `fk_" + column + "` FOREIGN KEY(`" + column + "`) REFERENCES `" + ftable + "`(`" + fcolumn + "`)"
|
||||||
if cascade {
|
if cascade {
|
||||||
querystr += " ON DELETE CASCADE"
|
q += " 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
|
// 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)
|
a.pushStatement(name, "add-foreign-key", q)
|
||||||
return querystr, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var silen1 = len("INSERT INTO ``() VALUES () ")
|
var silen1 = len("INSERT INTO ``() VALUES () ")
|
||||||
func (adapter *MysqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
|
|
||||||
|
func (a *MysqlAdapter) 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")
|
||||||
}
|
}
|
||||||
|
@ -277,7 +279,7 @@ func (adapter *MysqlAdapter) SimpleInsert(name string, table string, columns str
|
||||||
sb.WriteString(table)
|
sb.WriteString(table)
|
||||||
sb.WriteString("`(")
|
sb.WriteString("`(")
|
||||||
if columns != "" {
|
if columns != "" {
|
||||||
sb.WriteString(adapter.buildColumns(columns))
|
sb.WriteString(a.buildColumns(columns))
|
||||||
sb.WriteString(") VALUES (")
|
sb.WriteString(") VALUES (")
|
||||||
fs := processFields(fields)
|
fs := processFields(fields)
|
||||||
sb.Grow(len(fs) * 3)
|
sb.Grow(len(fs) * 3)
|
||||||
|
@ -301,27 +303,27 @@ func (adapter *MysqlAdapter) SimpleInsert(name string, table string, columns str
|
||||||
|
|
||||||
// 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
|
||||||
q := sb.String()
|
q := sb.String()
|
||||||
adapter.pushStatement(name, "insert", q)
|
a.pushStatement(name, "insert", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) buildColumns(columns string) (querystr string) {
|
func (a *MysqlAdapter) buildColumns(columns string) (q string) {
|
||||||
if columns == "" {
|
if columns == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range processColumns(columns) {
|
for _, col := range processColumns(columns) {
|
||||||
if column.Type == "function" {
|
if col.Type == TokenFunc {
|
||||||
querystr += column.Left + ","
|
q += col.Left + ","
|
||||||
} else {
|
} else {
|
||||||
querystr += "`" + column.Left + "`,"
|
q += "`" + col.Left + "`,"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return querystr[0 : len(querystr)-1]
|
return q[0 : len(q)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! DEPRECATED
|
// ! DEPRECATED
|
||||||
func (adapter *MysqlAdapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
|
func (a *MysqlAdapter) SimpleReplace(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")
|
||||||
}
|
}
|
||||||
|
@ -332,18 +334,18 @@ func (adapter *MysqlAdapter) SimpleReplace(name string, table string, columns st
|
||||||
return "", errors.New("No input data found for SimpleInsert")
|
return "", errors.New("No input data found for SimpleInsert")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr = "REPLACE INTO `" + table + "`(" + adapter.buildColumns(columns) + ") VALUES ("
|
q := "REPLACE INTO `" + table + "`(" + a.buildColumns(columns) + ") VALUES ("
|
||||||
for _, field := range processFields(fields) {
|
for _, field := range processFields(fields) {
|
||||||
querystr += field.Name + ","
|
q += field.Name + ","
|
||||||
}
|
}
|
||||||
querystr = querystr[0 : len(querystr)-1]
|
q = q[0 : len(q)-1]
|
||||||
|
|
||||||
// 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, "replace", querystr+")")
|
a.pushStatement(name, "replace", q+")")
|
||||||
return querystr + ")", nil
|
return q + ")", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error) {
|
func (a *MysqlAdapter) SimpleUpsert(name string, table string, columns string, fields string, where 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")
|
||||||
}
|
}
|
||||||
|
@ -357,23 +359,23 @@ func (adapter *MysqlAdapter) SimpleUpsert(name string, table string, columns str
|
||||||
return "", errors.New("You need a where for this upsert")
|
return "", errors.New("You need a where for this upsert")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr = "INSERT INTO `" + table + "`("
|
q := "INSERT INTO `" + table + "`("
|
||||||
var parsedFields = processFields(fields)
|
parsedFields := processFields(fields)
|
||||||
|
|
||||||
var insertColumns string
|
var insertColumns string
|
||||||
var insertValues string
|
var insertValues string
|
||||||
var setBit = ") ON DUPLICATE KEY UPDATE "
|
setBit := ") ON DUPLICATE KEY UPDATE "
|
||||||
|
|
||||||
for columnID, column := range processColumns(columns) {
|
for columnID, col := range processColumns(columns) {
|
||||||
field := parsedFields[columnID]
|
field := parsedFields[columnID]
|
||||||
if column.Type == "function" {
|
if col.Type == TokenFunc {
|
||||||
insertColumns += column.Left + ","
|
insertColumns += col.Left + ","
|
||||||
insertValues += field.Name + ","
|
insertValues += field.Name + ","
|
||||||
setBit += column.Left + " = " + field.Name + " AND "
|
setBit += col.Left + " = " + field.Name + " AND "
|
||||||
} else {
|
} else {
|
||||||
insertColumns += "`" + column.Left + "`,"
|
insertColumns += "`" + col.Left + "`,"
|
||||||
insertValues += field.Name + ","
|
insertValues += field.Name + ","
|
||||||
setBit += "`" + column.Left + "` = " + field.Name + " AND "
|
setBit += "`" + col.Left + "` = " + field.Name + " AND "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insertColumns = insertColumns[0 : len(insertColumns)-1]
|
insertColumns = insertColumns[0 : len(insertColumns)-1]
|
||||||
|
@ -381,15 +383,16 @@ func (adapter *MysqlAdapter) SimpleUpsert(name string, table string, columns str
|
||||||
insertColumns += ") VALUES (" + insertValues
|
insertColumns += ") VALUES (" + insertValues
|
||||||
setBit = setBit[0 : len(setBit)-5]
|
setBit = setBit[0 : len(setBit)-5]
|
||||||
|
|
||||||
querystr += insertColumns + setBit
|
q += insertColumns + setBit
|
||||||
|
|
||||||
// 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, "upsert", querystr)
|
a.pushStatement(name, "upsert", q)
|
||||||
return querystr, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var sulen1 = len("UPDATE `` SET ")
|
var sulen1 = len("UPDATE `` SET ")
|
||||||
func (adapter *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
|
|
||||||
|
func (a *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
|
||||||
if up.table == "" {
|
if up.table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
|
@ -414,14 +417,14 @@ func (adapter *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error)
|
||||||
sb.WriteString("`=")
|
sb.WriteString("`=")
|
||||||
for _, token := range item.Expr {
|
for _, token := range item.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr:
|
||||||
sb.WriteString(" ")
|
sb.WriteString(" ")
|
||||||
sb.WriteString(token.Contents)
|
sb.WriteString(token.Contents)
|
||||||
case "column":
|
case TokenColumn:
|
||||||
sb.WriteString(" `")
|
sb.WriteString(" `")
|
||||||
sb.WriteString(token.Contents)
|
sb.WriteString(token.Contents)
|
||||||
sb.WriteString("`")
|
sb.WriteString("`")
|
||||||
case "string":
|
case TokenString:
|
||||||
sb.WriteString(" '")
|
sb.WriteString(" '")
|
||||||
sb.WriteString(token.Contents)
|
sb.WriteString(token.Contents)
|
||||||
sb.WriteString("'")
|
sb.WriteString("'")
|
||||||
|
@ -429,7 +432,7 @@ func (adapter *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
whereStr, err := adapter.buildFlexiWhere(up.where,up.dateCutoff)
|
whereStr, err := a.buildFlexiWhere(up.where, up.dateCutoff)
|
||||||
sb.WriteString(whereStr)
|
sb.WriteString(whereStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sb.String(), err
|
return sb.String(), err
|
||||||
|
@ -437,29 +440,28 @@ func (adapter *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error)
|
||||||
|
|
||||||
// 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
|
||||||
q := sb.String()
|
q := sb.String()
|
||||||
adapter.pushStatement(up.name, "update", q)
|
a.pushStatement(up.name, "update", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleDelete(name string, table string, where string) (string, error) {
|
func (a *MysqlAdapter) SimpleDelete(name string, table string, where 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")
|
||||||
}
|
}
|
||||||
if where == "" {
|
if where == "" {
|
||||||
return "", errors.New("You need to specify what data you want to delete")
|
return "", errors.New("You need to specify what data you want to delete")
|
||||||
}
|
}
|
||||||
|
q := "DELETE FROM `" + table + "` WHERE"
|
||||||
var q = "DELETE FROM `" + table + "` WHERE"
|
|
||||||
|
|
||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot:
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " `" + token.Contents + "`"
|
q += " `" + token.Contents + "`"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
@ -470,41 +472,41 @@ func (adapter *MysqlAdapter) SimpleDelete(name string, table string, where strin
|
||||||
|
|
||||||
q = strings.TrimSpace(q[0 : len(q)-4])
|
q = strings.TrimSpace(q[0 : len(q)-4])
|
||||||
// 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, "delete", q)
|
a.pushStatement(name, "delete", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) {
|
func (a *MysqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) {
|
||||||
if b.table == "" {
|
if b.table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
if b.where == "" && b.dateCutoff == nil {
|
if b.where == "" && b.dateCutoff == nil {
|
||||||
return "", errors.New("You need to specify what data you want to delete")
|
return "", errors.New("You need to specify what data you want to delete")
|
||||||
}
|
}
|
||||||
var q = "DELETE FROM `" + b.table + "`"
|
q := "DELETE FROM `" + b.table + "`"
|
||||||
|
|
||||||
whereStr, err := adapter.buildFlexiWhere(b.where, b.dateCutoff)
|
whereStr, err := a.buildFlexiWhere(b.where, b.dateCutoff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return q, err
|
return q, err
|
||||||
}
|
}
|
||||||
q += whereStr
|
q += whereStr
|
||||||
|
|
||||||
// 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(b.name, "delete", q)
|
a.pushStatement(b.name, "delete", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't want to accidentally wipe tables, so we'll have a separate method for purging tables instead
|
// We don't want to accidentally wipe tables, so we'll have a separate method for purging tables instead
|
||||||
func (adapter *MysqlAdapter) Purge(name string, table string) (string, error) {
|
func (a *MysqlAdapter) Purge(name string, table 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")
|
||||||
}
|
}
|
||||||
q := "DELETE FROM `" + table + "`"
|
q := "DELETE FROM `" + table + "`"
|
||||||
adapter.pushStatement(name, "purge", q)
|
a.pushStatement(name, "purge", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) buildWhere(where string) (q string, err error) {
|
func (a *MysqlAdapter) buildWhere(where string) (q string, err error) {
|
||||||
if len(where) == 0 {
|
if len(where) == 0 {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -512,11 +514,11 @@ func (adapter *MysqlAdapter) buildWhere(where string) (q string, err error) {
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike:
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " `" + token.Contents + "`"
|
q += " `" + token.Contents + "`"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
return q, errors.New("This token doesn't exist o_o")
|
return q, errors.New("This token doesn't exist o_o")
|
||||||
|
@ -528,11 +530,10 @@ func (adapter *MysqlAdapter) buildWhere(where string) (q string, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The new version of buildWhere() currently only used in ComplexSelect for complex OO builder queries
|
// The new version of buildWhere() currently only used in ComplexSelect for complex OO builder queries
|
||||||
func (adapter *MysqlAdapter) buildFlexiWhere(where string, dateCutoff *dateCutoff) (q string, err error) {
|
func (a *MysqlAdapter) buildFlexiWhere(where string, dateCutoff *dateCutoff) (q string, err error) {
|
||||||
if len(where) == 0 && dateCutoff == nil {
|
if len(where) == 0 && dateCutoff == nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
q = " WHERE"
|
q = " WHERE"
|
||||||
if dateCutoff != nil {
|
if dateCutoff != nil {
|
||||||
if dateCutoff.Type == 0 {
|
if dateCutoff.Type == 0 {
|
||||||
|
@ -546,11 +547,11 @@ func (adapter *MysqlAdapter) buildFlexiWhere(where string, dateCutoff *dateCutof
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike:
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " `" + token.Contents + "`"
|
q += " `" + token.Contents + "`"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
return q, errors.New("This token doesn't exist o_o")
|
return q, errors.New("This token doesn't exist o_o")
|
||||||
|
@ -563,7 +564,7 @@ func (adapter *MysqlAdapter) buildFlexiWhere(where string, dateCutoff *dateCutof
|
||||||
return q[0 : len(q)-4], nil
|
return q[0 : len(q)-4], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) buildOrderby(orderby string) (q string) {
|
func (a *MysqlAdapter) buildOrderby(orderby string) (q string) {
|
||||||
if len(orderby) != 0 {
|
if len(orderby) != 0 {
|
||||||
q = " ORDER BY "
|
q = " ORDER BY "
|
||||||
for _, column := range processOrderby(orderby) {
|
for _, column := range processOrderby(orderby) {
|
||||||
|
@ -575,14 +576,14 @@ func (adapter *MysqlAdapter) buildOrderby(orderby string) (q string) {
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
|
func (a *MysqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit 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")
|
||||||
}
|
}
|
||||||
if len(columns) == 0 {
|
if len(columns) == 0 {
|
||||||
return "", errors.New("No columns found for SimpleSelect")
|
return "", errors.New("No columns found for SimpleSelect")
|
||||||
}
|
}
|
||||||
var q = "SELECT "
|
q := "SELECT "
|
||||||
|
|
||||||
// Slice up the user friendly strings into something easier to process
|
// Slice up the user friendly strings into something easier to process
|
||||||
for _, column := range strings.Split(strings.TrimSpace(columns), ",") {
|
for _, column := range strings.Split(strings.TrimSpace(columns), ",") {
|
||||||
|
@ -590,14 +591,14 @@ func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns str
|
||||||
}
|
}
|
||||||
q = q[0 : len(q)-1]
|
q = q[0 : len(q)-1]
|
||||||
|
|
||||||
whereStr, err := adapter.buildWhere(where)
|
whereStr, err := a.buildWhere(where)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return q, err
|
return q, err
|
||||||
}
|
}
|
||||||
q += " FROM `" + table + "`" + whereStr + adapter.buildOrderby(orderby) + adapter.buildLimit(limit)
|
q += " FROM `" + table + "`" + whereStr + a.buildOrderby(orderby) + a.buildLimit(limit)
|
||||||
|
|
||||||
q = strings.TrimSpace(q)
|
q = strings.TrimSpace(q)
|
||||||
adapter.pushStatement(name, "select", q)
|
a.pushStatement(name, "select", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,6 +612,7 @@ func (a *MysqlAdapter) ComplexSelect(preBuilder *selectPrebuilder) (out string,
|
||||||
|
|
||||||
var cslen1 = len("SELECT FROM ``")
|
var cslen1 = len("SELECT FROM ``")
|
||||||
var cslen2 = len(" WHERE `` IN(")
|
var cslen2 = len(" WHERE `` IN(")
|
||||||
|
|
||||||
func (a *MysqlAdapter) complexSelect(preBuilder *selectPrebuilder, sb *strings.Builder) error {
|
func (a *MysqlAdapter) complexSelect(preBuilder *selectPrebuilder, sb *strings.Builder) error {
|
||||||
if preBuilder.table == "" {
|
if preBuilder.table == "" {
|
||||||
return errors.New("You need a name for this table")
|
return errors.New("You need a name for this table")
|
||||||
|
@ -728,9 +730,9 @@ func (a *MysqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleUpdateSelect(up *updatePrebuilder) (string, error) {
|
func (a *MysqlAdapter) SimpleUpdateSelect(up *updatePrebuilder) (string, error) {
|
||||||
sel := up.whereSubQuery
|
sel := up.whereSubQuery
|
||||||
whereStr, err := adapter.buildWhere(sel.where)
|
whereStr, err := a.buildWhere(sel.where)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -740,11 +742,11 @@ func (adapter *MysqlAdapter) SimpleUpdateSelect(up *updatePrebuilder) (string, e
|
||||||
setter += "`" + item.Column + "`="
|
setter += "`" + item.Column + "`="
|
||||||
for _, token := range item.Expr {
|
for _, token := range item.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr:
|
||||||
setter += " " + token.Contents
|
setter += token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
setter += "`" + token.Contents + "`"
|
setter += "`" + token.Contents + "`"
|
||||||
case "string":
|
case TokenString:
|
||||||
setter += "'" + token.Contents + "'"
|
setter += "'" + token.Contents + "'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -752,65 +754,62 @@ func (adapter *MysqlAdapter) SimpleUpdateSelect(up *updatePrebuilder) (string, e
|
||||||
}
|
}
|
||||||
setter = setter[0 : len(setter)-1]
|
setter = setter[0 : len(setter)-1]
|
||||||
|
|
||||||
var querystr = "UPDATE `" + up.table + "` SET " + setter + " WHERE (SELECT" + adapter.buildJoinColumns(sel.columns) + " FROM `" + sel.table + "`" + whereStr + adapter.buildOrderby(sel.orderby) + adapter.buildLimit(sel.limit) + ")"
|
q := "UPDATE `" + up.table + "` SET " + setter + " WHERE (SELECT" + a.buildJoinColumns(sel.columns) + " FROM `" + sel.table + "`" + whereStr + a.buildOrderby(sel.orderby) + a.buildLimit(sel.limit) + ")"
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
|
||||||
adapter.pushStatement(up.name, "update", querystr)
|
|
||||||
return querystr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelect) (string, error) {
|
|
||||||
whereStr, err := adapter.buildWhere(sel.Where)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var q = "INSERT INTO `" + ins.Table + "`(" + adapter.buildColumns(ins.Columns) + ") SELECT" + adapter.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table + "`" + whereStr + adapter.buildOrderby(sel.Orderby) + adapter.buildLimit(sel.Limit)
|
|
||||||
|
|
||||||
q = strings.TrimSpace(q)
|
q = strings.TrimSpace(q)
|
||||||
adapter.pushStatement(name, "insert", q)
|
a.pushStatement(up.name, "update", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel DBJoin) (string, error) {
|
func (a *MysqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelect) (string, error) {
|
||||||
whereStr, err := adapter.buildJoinWhere(sel.Where)
|
whereStr, err := a.buildWhere(sel.Where)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
q := "INSERT INTO `" + ins.Table + "`(" + adapter.buildColumns(ins.Columns) + ") SELECT" + adapter.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON " + adapter.buildJoiners(sel.Joiners) + whereStr + adapter.buildOrderby(sel.Orderby) + adapter.buildLimit(sel.Limit)
|
q := "INSERT INTO `" + ins.Table + "`(" + a.buildColumns(ins.Columns) + ") SELECT" + a.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table + "`" + whereStr + a.buildOrderby(sel.Orderby) + a.buildLimit(sel.Limit)
|
||||||
|
|
||||||
q = strings.TrimSpace(q)
|
q = strings.TrimSpace(q)
|
||||||
adapter.pushStatement(name, "insert", q)
|
a.pushStatement(name, "insert", q)
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel DBJoin) (string, error) {
|
||||||
|
whereStr, err := a.buildJoinWhere(sel.Where)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
q := "INSERT INTO `" + ins.Table + "`(" + a.buildColumns(ins.Columns) + ") SELECT" + a.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON " + a.buildJoiners(sel.Joiners) + whereStr + a.buildOrderby(sel.Orderby) + a.buildLimit(sel.Limit)
|
||||||
|
q = strings.TrimSpace(q)
|
||||||
|
a.pushStatement(name, "insert", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this more consistent with the other build* methods?
|
// TODO: Make this more consistent with the other build* methods?
|
||||||
func (adapter *MysqlAdapter) buildJoiners(joiners string) (q string) {
|
func (a *MysqlAdapter) buildJoiners(joiners string) (q string) {
|
||||||
for _, joiner := range processJoiner(joiners) {
|
for _, j := range processJoiner(joiners) {
|
||||||
q += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
q += "`" + j.LeftTable + "`.`" + j.LeftColumn + "` " + j.Operator + " `" + j.RightTable + "`.`" + j.RightColumn + "` AND "
|
||||||
}
|
}
|
||||||
// Remove the trailing AND
|
// Remove the trailing AND
|
||||||
return q[0 : len(q)-4]
|
return q[0 : len(q)-4]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
func (adapter *MysqlAdapter) buildJoinWhere(where string) (q string, err error) {
|
func (a *MysqlAdapter) buildJoinWhere(where string) (q string, err error) {
|
||||||
if len(where) != 0 {
|
if len(where) != 0 {
|
||||||
q = " WHERE"
|
q = " WHERE"
|
||||||
for _, loc := range processWhere(where) {
|
for _, loc := range processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute", "or":
|
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike:
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
q += " `" + halves[0] + "`.`" + halves[1] + "`"
|
q += " `" + halves[0] + "`.`" + halves[1] + "`"
|
||||||
} else {
|
} else {
|
||||||
q += " `" + token.Contents + "`"
|
q += " `" + token.Contents + "`"
|
||||||
}
|
}
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
return q, errors.New("This token doesn't exist o_o")
|
return q, errors.New("This token doesn't exist o_o")
|
||||||
|
@ -823,74 +822,73 @@ func (adapter *MysqlAdapter) buildJoinWhere(where string) (q string, err error)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) buildLimit(limit string) (q string) {
|
func (a *MysqlAdapter) buildLimit(limit string) (q string) {
|
||||||
if limit != "" {
|
if limit != "" {
|
||||||
q = " LIMIT " + limit
|
q = " LIMIT " + limit
|
||||||
}
|
}
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MysqlAdapter) buildJoinColumns(columns string) (q string) {
|
func (a *MysqlAdapter) buildJoinColumns(cols string) (q string) {
|
||||||
for _, column := range processColumns(columns) {
|
for _, col := range processColumns(cols) {
|
||||||
// TODO: Move the stirng and number logic to processColumns?
|
// TODO: Move the stirng and number logic to processColumns?
|
||||||
// TODO: Error if [0] doesn't exist
|
// TODO: Error if [0] doesn't exist
|
||||||
firstChar := column.Left[0]
|
firstChar := col.Left[0]
|
||||||
if firstChar == '\'' {
|
if firstChar == '\'' {
|
||||||
column.Type = "string"
|
col.Type = TokenString
|
||||||
} else {
|
} else {
|
||||||
_, err := strconv.Atoi(string(firstChar))
|
_, err := strconv.Atoi(string(firstChar))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
column.Type = "number"
|
col.Type = TokenNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
var source = column.Left
|
source := col.Left
|
||||||
if column.Table != "" {
|
if col.Table != "" {
|
||||||
source = "`" + column.Table + "`.`" + source + "`"
|
source = "`" + col.Table + "`.`" + source + "`"
|
||||||
} else if column.Type != "function" && column.Type != "number" && column.Type != "substitute" && column.Type != "string" {
|
} else if col.Type != TokenFunc && col.Type != TokenNumber && col.Type != TokenSub && col.Type != TokenString {
|
||||||
source = "`" + source + "`"
|
source = "`" + source + "`"
|
||||||
}
|
}
|
||||||
|
|
||||||
var alias string
|
var alias string
|
||||||
if column.Alias != "" {
|
if col.Alias != "" {
|
||||||
alias = " AS `" + column.Alias + "`"
|
alias = " AS `" + col.Alias + "`"
|
||||||
}
|
}
|
||||||
q += " " + source + alias + ","
|
q += " " + source + alias + ","
|
||||||
}
|
}
|
||||||
return q[0 : len(q)-1]
|
return q[0 : len(q)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DBInsert, sel DBJoin) (string, error) {
|
func (a *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DBInsert, sel DBJoin) (string, error) {
|
||||||
whereStr, err := adapter.buildJoinWhere(sel.Where)
|
whereStr, err := a.buildJoinWhere(sel.Where)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
q := "INSERT INTO `" + ins.Table + "`(" + adapter.buildColumns(ins.Columns) + ") SELECT" + adapter.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table1 + "` INNER JOIN `" + sel.Table2 + "` ON " + adapter.buildJoiners(sel.Joiners) + whereStr + adapter.buildOrderby(sel.Orderby) + adapter.buildLimit(sel.Limit)
|
q := "INSERT INTO `" + ins.Table + "`(" + a.buildColumns(ins.Columns) + ") SELECT" + a.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table1 + "` INNER JOIN `" + sel.Table2 + "` ON " + a.buildJoiners(sel.Joiners) + whereStr + a.buildOrderby(sel.Orderby) + a.buildLimit(sel.Limit)
|
||||||
|
|
||||||
q = strings.TrimSpace(q)
|
q = strings.TrimSpace(q)
|
||||||
adapter.pushStatement(name, "insert", q)
|
a.pushStatement(name, "insert", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) SimpleCount(name string, table string, where string, limit string) (q string, err error) {
|
func (a *MysqlAdapter) SimpleCount(name string, table string, where string, limit string) (q string, err 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")
|
||||||
}
|
}
|
||||||
whereStr, err := adapter.buildWhere(where)
|
whereStr, err := a.buildWhere(where)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
q = "SELECT COUNT(*) FROM `" + table + "`" + whereStr + adapter.buildLimit(limit)
|
q = "SELECT COUNT(*) FROM `" + table + "`" + whereStr + a.buildLimit(limit)
|
||||||
q = strings.TrimSpace(q)
|
q = strings.TrimSpace(q)
|
||||||
adapter.pushStatement(name, "select", q)
|
a.pushStatement(name, "select", q)
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) Builder() *prebuilder {
|
func (a *MysqlAdapter) Builder() *prebuilder {
|
||||||
return &prebuilder{adapter}
|
return &prebuilder{a}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MysqlAdapter) Write() error {
|
func (a *MysqlAdapter) Write() error {
|
||||||
|
@ -964,7 +962,7 @@ func (a *MysqlAdapter) pushStatement(name string, stype string, querystr string)
|
||||||
a.BufferOrder = append(a.BufferOrder, name)
|
a.BufferOrder = append(a.BufferOrder, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) stringyType(ctype string) bool {
|
func (a *MysqlAdapter) stringyType(ctype string) bool {
|
||||||
ctype = strings.ToLower(ctype)
|
ctype = strings.ToLower(ctype)
|
||||||
return ctype == "varchar" || ctype == "tinytext" || ctype == "text" || ctype == "mediumtext" || ctype == "longtext" || ctype == "char" || ctype == "datetime" || ctype == "timestamp" || ctype == "time" || ctype == "date"
|
return ctype == "varchar" || ctype == "tinytext" || ctype == "text" || ctype == "mediumtext" || ctype == "longtext" || ctype == "char" || ctype == "datetime" || ctype == "timestamp" || ctype == "time" || ctype == "date"
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,23 +195,23 @@ func (a *PgsqlAdapter) SimpleInsert(name string, table string, columns string, f
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *PgsqlAdapter) buildColumns(columns string) (q string) {
|
func (a *PgsqlAdapter) buildColumns(cols string) (q string) {
|
||||||
if columns == "" {
|
if cols == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range processColumns(columns) {
|
for _, col := range processColumns(cols) {
|
||||||
if column.Type == "function" {
|
if col.Type == TokenFunc {
|
||||||
q += column.Left + ","
|
q += col.Left + ","
|
||||||
} else {
|
} else {
|
||||||
q += "\"" + column.Left + "\","
|
q += "\"" + col.Left + "\","
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return q[0 : len(q)-1]
|
return q[0 : len(q)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement this
|
// TODO: Implement this
|
||||||
func (a *PgsqlAdapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
|
func (a *PgsqlAdapter) SimpleReplace(name, table, columns, 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")
|
||||||
}
|
}
|
||||||
|
@ -252,23 +252,22 @@ func (a *PgsqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
|
||||||
q += "`" + item.Column + "`="
|
q += "`" + item.Column + "`="
|
||||||
for _, token := range item.Expr {
|
for _, token := range item.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function":
|
case TokenFunc:
|
||||||
// TODO: Write a more sophisticated function parser on the utils side.
|
// TODO: Write a more sophisticated function parser on the utils side.
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "LOCALTIMESTAMP()"
|
token.Contents = "LOCALTIMESTAMP()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "operator", "number", "substitute", "or":
|
case TokenOp, TokenNumber, TokenSub, TokenOr:
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " `" + token.Contents + "`"
|
q += " `" + token.Contents + "`"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q += ","
|
q += ","
|
||||||
}
|
}
|
||||||
// Remove the trailing comma
|
|
||||||
q = q[0 : len(q)-1]
|
q = q[0 : len(q)-1]
|
||||||
|
|
||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
|
@ -277,17 +276,17 @@ func (a *PgsqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
|
||||||
for _, loc := range processWhere(up.where) {
|
for _, loc := range processWhere(up.where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case "function":
|
case TokenFunc:
|
||||||
// TODO: Write a more sophisticated function parser on the utils side. What's the situation in regards to case sensitivity?
|
// TODO: Write a more sophisticated function parser on the utils side. What's the situation in regards to case sensitivity?
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "LOCALTIMESTAMP()"
|
token.Contents = "LOCALTIMESTAMP()"
|
||||||
}
|
}
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "operator", "number", "substitute", "or":
|
case TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike:
|
||||||
q += " " + token.Contents
|
q += " " + token.Contents
|
||||||
case "column":
|
case TokenColumn:
|
||||||
q += " `" + token.Contents + "`"
|
q += " `" + token.Contents + "`"
|
||||||
case "string":
|
case TokenString:
|
||||||
q += " '" + token.Contents + "'"
|
q += " '" + token.Contents + "'"
|
||||||
default:
|
default:
|
||||||
panic("This token doesn't exist o_o")
|
panic("This token doesn't exist o_o")
|
||||||
|
|
|
@ -57,7 +57,8 @@ type DBColumn struct {
|
||||||
Table string
|
Table string
|
||||||
Left string // Could be a function or a column, so I'm naming this Left
|
Left string // Could be a function or a column, so I'm naming this Left
|
||||||
Alias string // aka AS Blah, if it's present
|
Alias string // aka AS Blah, if it's present
|
||||||
Type string // function or column
|
//Type string // function or column
|
||||||
|
Type int
|
||||||
}
|
}
|
||||||
|
|
||||||
type DBField struct {
|
type DBField struct {
|
||||||
|
@ -82,9 +83,22 @@ type DBOrder struct {
|
||||||
Order string
|
Order string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TokenFunc = iota
|
||||||
|
TokenOp
|
||||||
|
TokenColumn
|
||||||
|
TokenNumber
|
||||||
|
TokenString
|
||||||
|
TokenSub
|
||||||
|
TokenOr
|
||||||
|
TokenNot
|
||||||
|
TokenLike
|
||||||
|
)
|
||||||
|
|
||||||
type DBToken struct {
|
type DBToken struct {
|
||||||
Contents string
|
Contents string
|
||||||
Type string // function, operator, column, number, string, substitute
|
//Type string // function, op, column, number, string, sub, not, like
|
||||||
|
Type int
|
||||||
}
|
}
|
||||||
|
|
||||||
type DBSetter struct {
|
type DBSetter struct {
|
||||||
|
|
|
@ -13,18 +13,18 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Add support for numbers and strings?
|
// TODO: Add support for numbers and strings?
|
||||||
func processColumns(colstr string) (columns []DBColumn) {
|
func processColumns(colStr string) (columns []DBColumn) {
|
||||||
if colstr == "" {
|
if colStr == "" {
|
||||||
return columns
|
return columns
|
||||||
}
|
}
|
||||||
colstr = strings.Replace(colstr, " as ", " AS ", -1)
|
colStr = strings.Replace(colStr, " as ", " AS ", -1)
|
||||||
for _, segment := range strings.Split(colstr, ",") {
|
for _, segment := range strings.Split(colStr, ",") {
|
||||||
var outcol DBColumn
|
var outCol DBColumn
|
||||||
dotHalves := strings.Split(strings.TrimSpace(segment), ".")
|
dotHalves := strings.Split(strings.TrimSpace(segment), ".")
|
||||||
|
|
||||||
var halves []string
|
var halves []string
|
||||||
if len(dotHalves) == 2 {
|
if len(dotHalves) == 2 {
|
||||||
outcol.Table = dotHalves[0]
|
outCol.Table = dotHalves[0]
|
||||||
halves = strings.Split(dotHalves[1], " AS ")
|
halves = strings.Split(dotHalves[1], " AS ")
|
||||||
} else {
|
} else {
|
||||||
halves = strings.Split(dotHalves[0], " AS ")
|
halves = strings.Split(dotHalves[0], " AS ")
|
||||||
|
@ -32,132 +32,132 @@ func processColumns(colstr string) (columns []DBColumn) {
|
||||||
|
|
||||||
halves[0] = strings.TrimSpace(halves[0])
|
halves[0] = strings.TrimSpace(halves[0])
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
outcol.Alias = strings.TrimSpace(halves[1])
|
outCol.Alias = strings.TrimSpace(halves[1])
|
||||||
}
|
}
|
||||||
if halves[0][len(halves[0])-1] == ')' {
|
if halves[0][len(halves[0])-1] == ')' {
|
||||||
outcol.Type = "function"
|
outCol.Type = TokenFunc
|
||||||
} else if halves[0] == "?" {
|
} else if halves[0] == "?" {
|
||||||
outcol.Type = "substitute"
|
outCol.Type = TokenSub
|
||||||
} else {
|
} else {
|
||||||
outcol.Type = "column"
|
outCol.Type = TokenColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
outcol.Left = halves[0]
|
outCol.Left = halves[0]
|
||||||
columns = append(columns, outcol)
|
columns = append(columns, outCol)
|
||||||
}
|
}
|
||||||
return columns
|
return columns
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Allow order by statements without a direction
|
// TODO: Allow order by statements without a direction
|
||||||
func processOrderby(orderstr string) (order []DBOrder) {
|
func processOrderby(orderStr string) (order []DBOrder) {
|
||||||
if orderstr == "" {
|
if orderStr == "" {
|
||||||
return order
|
return order
|
||||||
}
|
}
|
||||||
for _, segment := range strings.Split(orderstr, ",") {
|
for _, segment := range strings.Split(orderStr, ",") {
|
||||||
var outorder DBOrder
|
var outOrder DBOrder
|
||||||
halves := strings.Split(strings.TrimSpace(segment), " ")
|
halves := strings.Split(strings.TrimSpace(segment), " ")
|
||||||
if len(halves) != 2 {
|
if len(halves) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
outorder.Column = halves[0]
|
outOrder.Column = halves[0]
|
||||||
outorder.Order = strings.ToLower(halves[1])
|
outOrder.Order = strings.ToLower(halves[1])
|
||||||
order = append(order, outorder)
|
order = append(order, outOrder)
|
||||||
}
|
}
|
||||||
return order
|
return order
|
||||||
}
|
}
|
||||||
|
|
||||||
func processJoiner(joinstr string) (joiner []DBJoiner) {
|
func processJoiner(joinStr string) (joiner []DBJoiner) {
|
||||||
if joinstr == "" {
|
if joinStr == "" {
|
||||||
return joiner
|
return joiner
|
||||||
}
|
}
|
||||||
joinstr = strings.Replace(joinstr, " on ", " ON ", -1)
|
joinStr = strings.Replace(joinStr, " on ", " ON ", -1)
|
||||||
joinstr = strings.Replace(joinstr, " and ", " AND ", -1)
|
joinStr = strings.Replace(joinStr, " and ", " AND ", -1)
|
||||||
for _, segment := range strings.Split(joinstr, " AND ") {
|
for _, segment := range strings.Split(joinStr, " AND ") {
|
||||||
var outjoin DBJoiner
|
var outJoin DBJoiner
|
||||||
var parseOffset int
|
var parseOffset int
|
||||||
var left, right string
|
var left, right string
|
||||||
|
|
||||||
left, parseOffset = getIdentifier(segment, parseOffset)
|
left, parseOffset = getIdentifier(segment, parseOffset)
|
||||||
outjoin.Operator, parseOffset = getOperator(segment, parseOffset+1)
|
outJoin.Operator, parseOffset = getOperator(segment, parseOffset+1)
|
||||||
right, parseOffset = getIdentifier(segment, parseOffset+1)
|
right, parseOffset = getIdentifier(segment, parseOffset+1)
|
||||||
|
|
||||||
leftColumn := strings.Split(left, ".")
|
leftColumn := strings.Split(left, ".")
|
||||||
rightColumn := strings.Split(right, ".")
|
rightColumn := strings.Split(right, ".")
|
||||||
outjoin.LeftTable = strings.TrimSpace(leftColumn[0])
|
outJoin.LeftTable = strings.TrimSpace(leftColumn[0])
|
||||||
outjoin.RightTable = strings.TrimSpace(rightColumn[0])
|
outJoin.RightTable = strings.TrimSpace(rightColumn[0])
|
||||||
outjoin.LeftColumn = strings.TrimSpace(leftColumn[1])
|
outJoin.LeftColumn = strings.TrimSpace(leftColumn[1])
|
||||||
outjoin.RightColumn = strings.TrimSpace(rightColumn[1])
|
outJoin.RightColumn = strings.TrimSpace(rightColumn[1])
|
||||||
|
|
||||||
joiner = append(joiner, outjoin)
|
joiner = append(joiner, outJoin)
|
||||||
}
|
}
|
||||||
return joiner
|
return joiner
|
||||||
}
|
}
|
||||||
|
|
||||||
func (where *DBWhere) parseNumber(segment string, i int) int {
|
func (wh *DBWhere) parseNumber(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
if '0' <= char && char <= '9' {
|
if '0' <= ch && ch <= '9' {
|
||||||
buffer += string(char)
|
buffer += string(ch)
|
||||||
} else {
|
} else {
|
||||||
i--
|
i--
|
||||||
where.Expr = append(where.Expr, DBToken{buffer, "number"})
|
wh.Expr = append(wh.Expr, DBToken{buffer, TokenNumber})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (where *DBWhere) parseColumn(segment string, i int) int {
|
func (wh *DBWhere) parseColumn(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
switch {
|
switch {
|
||||||
case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '.' || char == '_':
|
case ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '.' || ch == '_':
|
||||||
buffer += string(char)
|
buffer += string(ch)
|
||||||
case char == '(':
|
case ch == '(':
|
||||||
return where.parseFunction(segment, buffer, i)
|
return wh.parseFunction(segment, buffer, i)
|
||||||
default:
|
default:
|
||||||
i--
|
i--
|
||||||
where.Expr = append(where.Expr, DBToken{buffer, "column"})
|
wh.Expr = append(wh.Expr, DBToken{buffer, TokenColumn})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (where *DBWhere) parseFunction(segment string, buffer string, i int) int {
|
func (wh *DBWhere) parseFunction(segment string, buffer string, i int) int {
|
||||||
var preI = i
|
preI := i
|
||||||
i = skipFunctionCall(segment, i-1)
|
i = skipFunctionCall(segment, i-1)
|
||||||
buffer += segment[preI:i] + string(segment[i])
|
buffer += segment[preI:i] + string(segment[i])
|
||||||
where.Expr = append(where.Expr, DBToken{buffer, "function"})
|
wh.Expr = append(wh.Expr, DBToken{buffer, TokenFunc})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (where *DBWhere) parseString(segment string, i int) int {
|
func (wh *DBWhere) parseString(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
i++
|
i++
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
if char != '\'' {
|
if ch != '\'' {
|
||||||
buffer += string(char)
|
buffer += string(ch)
|
||||||
} else {
|
} else {
|
||||||
where.Expr = append(where.Expr, DBToken{buffer, "string"})
|
wh.Expr = append(wh.Expr, DBToken{buffer, TokenString})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (where *DBWhere) parseOperator(segment string, i int) int {
|
func (wh *DBWhere) parseOperator(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
if isOpByte(char) {
|
if isOpByte(ch) {
|
||||||
buffer += string(char)
|
buffer += string(ch)
|
||||||
} else {
|
} else {
|
||||||
i--
|
i--
|
||||||
where.Expr = append(where.Expr, DBToken{buffer, "operator"})
|
wh.Expr = append(wh.Expr, DBToken{buffer, TokenOp})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,35 +175,41 @@ func normalizeOr(in string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write tests for this
|
// TODO: Write tests for this
|
||||||
func processWhere(wherestr string) (where []DBWhere) {
|
func processWhere(whereStr string) (where []DBWhere) {
|
||||||
if wherestr == "" {
|
if whereStr == "" {
|
||||||
return where
|
return where
|
||||||
}
|
}
|
||||||
wherestr = normalizeAnd(wherestr)
|
whereStr = normalizeAnd(whereStr)
|
||||||
wherestr = normalizeOr(wherestr)
|
whereStr = normalizeOr(whereStr)
|
||||||
|
|
||||||
for _, segment := range strings.Split(wherestr, " AND ") {
|
for _, seg := range strings.Split(whereStr, " AND ") {
|
||||||
var tmpWhere = &DBWhere{[]DBToken{}}
|
tmpWhere := &DBWhere{[]DBToken{}}
|
||||||
segment += ")"
|
seg += ")"
|
||||||
for i := 0; i < len(segment); i++ {
|
for i := 0; i < len(seg); i++ {
|
||||||
char := segment[i]
|
ch := seg[i]
|
||||||
switch {
|
switch {
|
||||||
case '0' <= char && char <= '9':
|
case '0' <= ch && ch <= '9':
|
||||||
i = tmpWhere.parseNumber(segment, i)
|
i = tmpWhere.parseNumber(seg, i)
|
||||||
// TODO: Sniff the third byte offset from char or it's non-existent to avoid matching uppercase strings which start with OR
|
// TODO: Sniff the third byte offset from char or it's non-existent to avoid matching uppercase strings which start with OR
|
||||||
case char == 'O' && (i+1) < len(segment) && segment[i+1] == 'R':
|
case ch == 'O' && (i+1) < len(seg) && seg[i+1] == 'R':
|
||||||
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"OR", "or"})
|
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"OR", TokenOr})
|
||||||
i += 1
|
i += 1
|
||||||
case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_':
|
case ch == 'N' && (i+2) < len(seg) && seg[i+1] == 'O' && seg[i+2] == 'T':
|
||||||
i = tmpWhere.parseColumn(segment, i)
|
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"NOT", TokenNot})
|
||||||
case char == '\'':
|
i += 2
|
||||||
i = tmpWhere.parseString(segment, i)
|
case ch == 'L' && (i+3) < len(seg) && seg[i+1] == 'I' && seg[i+2] == 'K' && seg[i+3] == 'E':
|
||||||
case char == ')' && i < (len(segment)-1):
|
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"LIKE", TokenLike})
|
||||||
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{")", "operator"})
|
i += 3
|
||||||
case isOpByte(char):
|
case ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_':
|
||||||
i = tmpWhere.parseOperator(segment, i)
|
i = tmpWhere.parseColumn(seg, i)
|
||||||
case char == '?':
|
case ch == '\'':
|
||||||
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"?", "substitute"})
|
i = tmpWhere.parseString(seg, i)
|
||||||
|
case ch == ')' && i < (len(seg)-1):
|
||||||
|
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{")", TokenOp})
|
||||||
|
case isOpByte(ch):
|
||||||
|
i = tmpWhere.parseOperator(seg, i)
|
||||||
|
case ch == '?':
|
||||||
|
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"?", TokenSub})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
where = append(where, *tmpWhere)
|
where = append(where, *tmpWhere)
|
||||||
|
@ -211,47 +217,47 @@ func processWhere(wherestr string) (where []DBWhere) {
|
||||||
return where
|
return where
|
||||||
}
|
}
|
||||||
|
|
||||||
func (setter *DBSetter) parseNumber(segment string, i int) int {
|
func (set *DBSetter) parseNumber(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
if '0' <= char && char <= '9' {
|
if '0' <= ch && ch <= '9' {
|
||||||
buffer += string(char)
|
buffer += string(ch)
|
||||||
} else {
|
} else {
|
||||||
setter.Expr = append(setter.Expr, DBToken{buffer, "number"})
|
set.Expr = append(set.Expr, DBToken{buffer, TokenNumber})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (setter *DBSetter) parseColumn(segment string, i int) int {
|
func (set *DBSetter) parseColumn(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
switch {
|
switch {
|
||||||
case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_':
|
case ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_':
|
||||||
buffer += string(char)
|
buffer += string(ch)
|
||||||
case char == '(':
|
case ch == '(':
|
||||||
return setter.parseFunction(segment, buffer, i)
|
return set.parseFunction(segment, buffer, i)
|
||||||
default:
|
default:
|
||||||
i--
|
i--
|
||||||
setter.Expr = append(setter.Expr, DBToken{buffer, "column"})
|
set.Expr = append(set.Expr, DBToken{buffer, TokenColumn})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (setter *DBSetter) parseFunction(segment string, buffer string, i int) int {
|
func (set *DBSetter) parseFunction(segment string, buffer string, i int) int {
|
||||||
var preI = i
|
preI := i
|
||||||
i = skipFunctionCall(segment, i-1)
|
i = skipFunctionCall(segment, i-1)
|
||||||
buffer += segment[preI:i] + string(segment[i])
|
buffer += segment[preI:i] + string(segment[i])
|
||||||
setter.Expr = append(setter.Expr, DBToken{buffer, "function"})
|
set.Expr = append(set.Expr, DBToken{buffer, TokenFunc})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (setter *DBSetter) parseString(segment string, i int) int {
|
func (set *DBSetter) parseString(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
i++
|
i++
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
|
@ -259,22 +265,22 @@ func (setter *DBSetter) parseString(segment string, i int) int {
|
||||||
if char != '\'' {
|
if char != '\'' {
|
||||||
buffer += string(char)
|
buffer += string(char)
|
||||||
} else {
|
} else {
|
||||||
setter.Expr = append(setter.Expr, DBToken{buffer, "string"})
|
set.Expr = append(set.Expr, DBToken{buffer, TokenString})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (setter *DBSetter) parseOperator(segment string, i int) int {
|
func (set *DBSetter) parseOperator(segment string, i int) int {
|
||||||
var buffer string
|
var buffer string
|
||||||
for ; i < len(segment); i++ {
|
for ; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
if isOpByte(char) {
|
if isOpByte(ch) {
|
||||||
buffer += string(char)
|
buffer += string(ch)
|
||||||
} else {
|
} else {
|
||||||
i--
|
i--
|
||||||
setter.Expr = append(setter.Expr, DBToken{buffer, "operator"})
|
set.Expr = append(set.Expr, DBToken{buffer, TokenOp})
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,18 +322,18 @@ func processSet(setstr string) (setter []DBSetter) {
|
||||||
segment := halves[1] + ")"
|
segment := halves[1] + ")"
|
||||||
|
|
||||||
for i := 0; i < len(segment); i++ {
|
for i := 0; i < len(segment); i++ {
|
||||||
char := segment[i]
|
ch := segment[i]
|
||||||
switch {
|
switch {
|
||||||
case '0' <= char && char <= '9':
|
case '0' <= ch && ch <= '9':
|
||||||
i = tmpSetter.parseNumber(segment, i)
|
i = tmpSetter.parseNumber(segment, i)
|
||||||
case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_':
|
case ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_':
|
||||||
i = tmpSetter.parseColumn(segment, i)
|
i = tmpSetter.parseColumn(segment, i)
|
||||||
case char == '\'':
|
case ch == '\'':
|
||||||
i = tmpSetter.parseString(segment, i)
|
i = tmpSetter.parseString(segment, i)
|
||||||
case isOpByte(char):
|
case isOpByte(ch):
|
||||||
i = tmpSetter.parseOperator(segment, i)
|
i = tmpSetter.parseOperator(segment, i)
|
||||||
case char == '?':
|
case ch == '?':
|
||||||
tmpSetter.Expr = append(tmpSetter.Expr, DBToken{"?", "substitute"})
|
tmpSetter.Expr = append(tmpSetter.Expr, DBToken{"?", TokenSub})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setter = append(setter, *tmpSetter)
|
setter = append(setter, *tmpSetter)
|
||||||
|
@ -335,86 +341,88 @@ func processSet(setstr string) (setter []DBSetter) {
|
||||||
return setter
|
return setter
|
||||||
}
|
}
|
||||||
|
|
||||||
func processLimit(limitstr string) (limiter DBLimit) {
|
func processLimit(limitStr string) (limit DBLimit) {
|
||||||
halves := strings.Split(limitstr, ",")
|
halves := strings.Split(limitStr, ",")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
limiter.Offset = halves[0]
|
limit.Offset = halves[0]
|
||||||
limiter.MaxCount = halves[1]
|
limit.MaxCount = halves[1]
|
||||||
} else {
|
} else {
|
||||||
limiter.MaxCount = halves[0]
|
limit.MaxCount = halves[0]
|
||||||
}
|
}
|
||||||
return limiter
|
return limit
|
||||||
}
|
}
|
||||||
|
|
||||||
func isOpByte(char byte) bool {
|
func isOpByte(ch byte) bool {
|
||||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/' || char == '(' || char == ')'
|
return ch == '<' || ch == '>' || ch == '=' || ch == '!' || ch == '*' || ch == '%' || ch == '+' || ch == '-' || ch == '/' || ch == '(' || ch == ')'
|
||||||
}
|
}
|
||||||
|
|
||||||
func isOpRune(char rune) bool {
|
func isOpRune(ch rune) bool {
|
||||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/' || char == '(' || char == ')'
|
return ch == '<' || ch == '>' || ch == '=' || ch == '!' || ch == '*' || ch == '%' || ch == '+' || ch == '-' || ch == '/' || ch == '(' || ch == ')'
|
||||||
}
|
}
|
||||||
|
|
||||||
func processFields(fieldstr string) (fields []DBField) {
|
func processFields(fieldStr string) (fields []DBField) {
|
||||||
if fieldstr == "" {
|
if fieldStr == "" {
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
var buffer string
|
var buffer string
|
||||||
var lastItem int
|
var lastItem int
|
||||||
fieldstr += ","
|
fieldStr += ","
|
||||||
for i := 0; i < len(fieldstr); i++ {
|
for i := 0; i < len(fieldStr); i++ {
|
||||||
if fieldstr[i] == '(' {
|
ch := fieldStr[i]
|
||||||
i = skipFunctionCall(fieldstr, i-1)
|
if ch == '(' {
|
||||||
fields = append(fields, DBField{Name: fieldstr[lastItem : i+1], Type: getIdentifierType(fieldstr[lastItem : i+1])})
|
i = skipFunctionCall(fieldStr, i-1)
|
||||||
|
fields = append(fields, DBField{Name: fieldStr[lastItem : i+1], Type: getIdentifierType(fieldStr[lastItem : i+1])})
|
||||||
buffer = ""
|
buffer = ""
|
||||||
lastItem = i + 2
|
lastItem = i + 2
|
||||||
} else if fieldstr[i] == ',' && buffer != "" {
|
} else if ch == ',' && buffer != "" {
|
||||||
fields = append(fields, DBField{Name: buffer, Type: getIdentifierType(buffer)})
|
fields = append(fields, DBField{Name: buffer, Type: getIdentifierType(buffer)})
|
||||||
buffer = ""
|
buffer = ""
|
||||||
lastItem = i + 1
|
lastItem = i + 1
|
||||||
} else if (fieldstr[i] >= 32) && fieldstr[i] != ',' && fieldstr[i] != ')' {
|
} else if (ch >= 32) && ch != ',' && ch != ')' {
|
||||||
buffer += string(fieldstr[i])
|
buffer += string(ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIdentifierType(identifier string) string {
|
func getIdentifierType(iden string) string {
|
||||||
if ('a' <= identifier[0] && identifier[0] <= 'z') || ('A' <= identifier[0] && identifier[0] <= 'Z') {
|
if ('a' <= iden[0] && iden[0] <= 'z') || ('A' <= iden[0] && iden[0] <= 'Z') {
|
||||||
if identifier[len(identifier)-1] == ')' {
|
if iden[len(iden)-1] == ')' {
|
||||||
return "function"
|
return "function"
|
||||||
}
|
}
|
||||||
return "column"
|
return "column"
|
||||||
}
|
}
|
||||||
if identifier[0] == '\'' || identifier[0] == '"' {
|
if iden[0] == '\'' || iden[0] == '"' {
|
||||||
return "string"
|
return "string"
|
||||||
}
|
}
|
||||||
return "literal"
|
return "literal"
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIdentifier(segment string, startOffset int) (out string, i int) {
|
func getIdentifier(seg string, startOffset int) (out string, i int) {
|
||||||
segment = strings.TrimSpace(segment)
|
seg = strings.TrimSpace(seg)
|
||||||
segment += " " // Avoid overflow bugs with slicing
|
seg += " " // Avoid overflow bugs with slicing
|
||||||
for i = startOffset; i < len(segment); i++ {
|
for i = startOffset; i < len(seg); i++ {
|
||||||
if segment[i] == '(' {
|
ch := seg[i]
|
||||||
i = skipFunctionCall(segment, i)
|
if ch == '(' {
|
||||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
i = skipFunctionCall(seg, i)
|
||||||
|
return strings.TrimSpace(seg[startOffset:i]), (i - 1)
|
||||||
}
|
}
|
||||||
if (segment[i] == ' ' || isOpByte(segment[i])) && i != startOffset {
|
if (ch == ' ' || isOpByte(ch)) && i != startOffset {
|
||||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
return strings.TrimSpace(seg[startOffset:i]), (i - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
return strings.TrimSpace(seg[startOffset:]), (i - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOperator(segment string, startOffset int) (out string, i int) {
|
func getOperator(seg string, startOffset int) (out string, i int) {
|
||||||
segment = strings.TrimSpace(segment)
|
seg = strings.TrimSpace(seg)
|
||||||
segment += " " // Avoid overflow bugs with slicing
|
seg += " " // Avoid overflow bugs with slicing
|
||||||
for i = startOffset; i < len(segment); i++ {
|
for i = startOffset; i < len(seg); i++ {
|
||||||
if !isOpByte(segment[i]) && i != startOffset {
|
if !isOpByte(seg[i]) && i != startOffset {
|
||||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
return strings.TrimSpace(seg[startOffset:i]), (i - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
return strings.TrimSpace(seg[startOffset:]), (i - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func skipFunctionCall(data string, index int) int {
|
func skipFunctionCall(data string, index int) int {
|
||||||
|
|
14
routes.go
14
routes.go
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
// A blank list to fill out that parameter in Page for routes which don't use it
|
// A blank list to fill out that parameter in Page for routes which don't use it
|
||||||
var tList []interface{}
|
var tList []interface{}
|
||||||
var successJSONBytes = []byte(`{"success":"1"}`)
|
var successJSONBytes = []byte(`{"success":1}`)
|
||||||
|
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
// TODO: Use the phrase system
|
// TODO: Use the phrase system
|
||||||
|
@ -115,8 +115,8 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var alert c.Alert
|
var al c.Alert
|
||||||
err = rows.Scan(&alert.ASID, &alert.ActorID, &alert.TargetUserID, &alert.Event, &alert.ElementType, &alert.ElementID, &createdAt)
|
err = rows.Scan(&al.ASID, &al.ActorID, &al.TargetUserID, &al.Event, &al.ElementType, &al.ElementID, &createdAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJS(err, w, r)
|
return c.InternalErrorJS(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -124,8 +124,8 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
|
||||||
uCreatedAt := createdAt.Unix()
|
uCreatedAt := createdAt.Unix()
|
||||||
//log.Print("uCreatedAt", uCreatedAt)
|
//log.Print("uCreatedAt", uCreatedAt)
|
||||||
//if rCreatedAt == 0 || rCreatedAt < uCreatedAt {
|
//if rCreatedAt == 0 || rCreatedAt < uCreatedAt {
|
||||||
alerts = append(alerts, alert)
|
alerts = append(alerts, al)
|
||||||
actors = append(actors, alert.ActorID)
|
actors = append(actors, al.ActorID)
|
||||||
//}
|
//}
|
||||||
if uCreatedAt > topCreatedAt {
|
if uCreatedAt > topCreatedAt {
|
||||||
topCreatedAt = uCreatedAt
|
topCreatedAt = uCreatedAt
|
||||||
|
@ -325,10 +325,10 @@ func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
||||||
func routeJSAntispam(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
func routeJSAntispam(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
h.Write([]byte(c.JSTokenBox.Load().(string)))
|
h.Write([]byte(c.JSTokenBox.Load().(string)))
|
||||||
h.Write([]byte(user.LastIP))
|
h.Write([]byte(user.GetIP()))
|
||||||
jsToken := hex.EncodeToString(h.Sum(nil))
|
jsToken := hex.EncodeToString(h.Sum(nil))
|
||||||
|
|
||||||
var innerCode = "`document.getElementByld('golden-watch').value = '" + jsToken + "';`"
|
innerCode := "`document.getElementByld('golden-watch').value = '" + jsToken + "';`"
|
||||||
io.WriteString(w, `let hihi = `+innerCode+`;
|
io.WriteString(w, `let hihi = `+innerCode+`;
|
||||||
hihi = hihi.replace('ld','Id');
|
hihi = hihi.replace('ld','Id');
|
||||||
eval(hihi);`)
|
eval(hihi);`)
|
||||||
|
|
|
@ -36,11 +36,11 @@ func AccountLoginSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.R
|
||||||
return c.LocalError("You're already logged in.", w, r, user)
|
return c.LocalError("You're already logged in.", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
username := c.SanitiseSingleLine(r.PostFormValue("username"))
|
name := c.SanitiseSingleLine(r.PostFormValue("username"))
|
||||||
uid, err, requiresExtraAuth := c.Auth.Authenticate(username, r.PostFormValue("password"))
|
uid, err, requiresExtraAuth := c.Auth.Authenticate(name, r.PostFormValue("password"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: uid is currently set to 0 as authenticate fetches the user by username and password. Get the actual uid, so we can alert the user of attempted logins? What if someone takes advantage of the response times to deduce if an account exists?
|
// TODO: uid is currently set to 0 as authenticate fetches the user by username and password. Get the actual uid, so we can alert the user of attempted logins? What if someone takes advantage of the response times to deduce if an account exists?
|
||||||
logItem := &c.LoginLogItem{UID: uid, Success: false, IP: user.LastIP}
|
logItem := &c.LoginLogItem{UID: uid, Success: false, IP: user.GetIP()}
|
||||||
_, err := logItem.Create()
|
_, err := logItem.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
|
@ -49,7 +49,7 @@ func AccountLoginSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.R
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Take 2FA into account
|
// TODO: Take 2FA into account
|
||||||
logItem := &c.LoginLogItem{UID: uid, Success: true, IP: user.LastIP}
|
logItem := &c.LoginLogItem{UID: uid, Success: true, IP: user.GetIP()}
|
||||||
_, err = logItem.Create()
|
_, err = logItem.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
|
@ -91,7 +91,7 @@ func loginSuccess(uid int, w http.ResponseWriter, r *http.Request, user *c.User)
|
||||||
if user.IsAdmin {
|
if user.IsAdmin {
|
||||||
// Is this error check redundant? We already check for the error in PreRoute for the same IP
|
// Is this error check redundant? We already check for the error in PreRoute for the same IP
|
||||||
// TODO: Should we be logging this?
|
// TODO: Should we be logging this?
|
||||||
log.Printf("#%d has logged in with IP %s", uid, user.LastIP)
|
log.Printf("#%d has logged in with IP %s", uid, user.GetIP())
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
|
@ -220,7 +220,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
|
||||||
if !c.Config.DisableJSAntispam {
|
if !c.Config.DisableJSAntispam {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
h.Write([]byte(c.JSTokenBox.Load().(string)))
|
h.Write([]byte(c.JSTokenBox.Load().(string)))
|
||||||
h.Write([]byte(user.LastIP))
|
h.Write([]byte(user.GetIP()))
|
||||||
if r.PostFormValue("golden-watch") != hex.EncodeToString(h.Sum(nil)) {
|
if r.PostFormValue("golden-watch") != hex.EncodeToString(h.Sum(nil)) {
|
||||||
regError(p.GetErrorPhrase("register_might_be_machine"), "js-antispam")
|
regError(p.GetErrorPhrase("register_might_be_machine"), "js-antispam")
|
||||||
}
|
}
|
||||||
|
@ -261,7 +261,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
regLog := c.RegLogItem{Username: name, Email: email, FailureReason: regErrReason, Success: regSuccess, IP: user.LastIP}
|
regLog := c.RegLogItem{Username: name, Email: email, FailureReason: regErrReason, Success: regSuccess, IP: user.GetIP()}
|
||||||
_, err = regLog.Create()
|
_, err = regLog.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
|
|
|
@ -42,7 +42,7 @@ func Backups(w http.ResponseWriter, r *http.Request, user c.User, backupURL stri
|
||||||
}
|
}
|
||||||
// TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side
|
// TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side
|
||||||
http.ServeFile(w, r, "./backups/"+backupURL)
|
http.ServeFile(w, r, "./backups/"+backupURL)
|
||||||
err = c.AdminLogs.Create("download", 0, "backup", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("download", 0, "backup", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ func ForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.R
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("create", fid, "forum", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("create", fid, "forum", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ func ForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfi
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("delete", fid, "forum", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("delete", fid, "forum", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ func ForumsOrderSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
}
|
}
|
||||||
c.Forums.UpdateOrder(updateMap)
|
c.Forums.UpdateOrder(updateMap)
|
||||||
|
|
||||||
err := c.AdminLogs.Create("reorder", 0, "forum", user.LastIP, user.ID)
|
err := c.AdminLogs.Create("reorder", 0, "forum", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfid
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", fid, "forum", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", fid, "forum", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ func ForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user c.User,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", fid, "forum", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", fid, "forum", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -348,7 +348,6 @@ func ForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user c.User,
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
if forum.Preset == "" {
|
if forum.Preset == "" {
|
||||||
forum.Preset = "custom"
|
forum.Preset = "custom"
|
||||||
}
|
}
|
||||||
|
@ -438,7 +437,7 @@ func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, user c
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", fid, "forum", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", fid, "forum", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,7 @@ func GroupsPromotionsCreateSubmit(w http.ResponseWriter, r *http.Request, user c
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("create", pid, "group_promotion", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("create", pid, "group_promotion", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ func GroupsPromotionsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("delete", pid, "group_promotion", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("delete", pid, "group_promotion", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -375,7 +375,6 @@ func GroupsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sgid
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
group, err := c.Groups.Get(gid)
|
group, err := c.Groups.Get(gid)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
//log.Print("aaaaa monsters")
|
//log.Print("aaaaa monsters")
|
||||||
|
@ -386,24 +385,25 @@ func GroupsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sgid
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
|
|
||||||
gname := r.FormValue("name")
|
name := r.FormValue("name")
|
||||||
if gname == "" {
|
if name == "" {
|
||||||
return c.LocalError(p.GetErrorPhrase("panel_groups_need_name"), w, r, user)
|
return c.LocalError(p.GetErrorPhrase("panel_groups_need_name"), w, r, user)
|
||||||
}
|
}
|
||||||
gtag := r.FormValue("tag")
|
tag := r.FormValue("tag")
|
||||||
rank := r.FormValue("type")
|
rank := r.FormValue("type")
|
||||||
|
|
||||||
var originalRank string
|
var originalRank string
|
||||||
// TODO: Use a switch for this
|
// TODO: Use a switch for this
|
||||||
if group.IsAdmin {
|
switch {
|
||||||
|
case group.IsAdmin:
|
||||||
originalRank = "Admin"
|
originalRank = "Admin"
|
||||||
} else if group.IsMod {
|
case group.IsMod:
|
||||||
originalRank = "Mod"
|
originalRank = "Mod"
|
||||||
} else if group.IsBanned {
|
case group.IsBanned:
|
||||||
originalRank = "Banned"
|
originalRank = "Banned"
|
||||||
} else if group.ID == 6 {
|
case group.ID == 6:
|
||||||
originalRank = "Guest"
|
originalRank = "Guest"
|
||||||
} else {
|
default:
|
||||||
originalRank = "Member"
|
originalRank = "Member"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,11 +436,11 @@ func GroupsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sgid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = group.Update(gname, gtag)
|
err = group.Update(name, tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", group.ID, "group", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", group.ID, "group", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ func GroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user c.User,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", group.ID, "group", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", group.ID, "group", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -536,7 +536,7 @@ func GroupsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.R
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("create", gid, "group", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("create", gid, "group", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ func PagesCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("create", pid, "page", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("create", pid, "page", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ func PagesEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", pid, "page", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", pid, "page", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ func PagesDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("delete", pid, "page", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("delete", pid, "page", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ func PluginsActivate(w http.ResponseWriter, r *http.Request, user c.User, uname
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError(err.Error(), w, r, user)
|
return c.LocalError(err.Error(), w, r, user)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.CreateExtra("activate", 0, "plugin", user.LastIP, user.ID, c.SanitiseSingleLine(plugin.Name))
|
err = c.AdminLogs.CreateExtra("activate", 0, "plugin", user.GetIP(), user.ID, c.SanitiseSingleLine(plugin.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ func PluginsDeactivate(w http.ResponseWriter, r *http.Request, user c.User, unam
|
||||||
if plugin.Deactivate != nil {
|
if plugin.Deactivate != nil {
|
||||||
plugin.Deactivate(plugin)
|
plugin.Deactivate(plugin)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.CreateExtra("deactivate", 0, "plugin", user.LastIP, user.ID, c.SanitiseSingleLine(plugin.Name))
|
err = c.AdminLogs.CreateExtra("deactivate", 0, "plugin", user.GetIP(), user.ID, c.SanitiseSingleLine(plugin.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ func PluginsInstall(w http.ResponseWriter, r *http.Request, user c.User, uname s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError(err.Error(), w, r, user)
|
return c.LocalError(err.Error(), w, r, user)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.CreateExtra("install", 0, "plugin", user.LastIP, user.ID, c.SanitiseSingleLine(plugin.Name))
|
err = c.AdminLogs.CreateExtra("install", 0, "plugin", user.GetIP(), user.ID, c.SanitiseSingleLine(plugin.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ func SettingEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, name
|
||||||
return rerr
|
return rerr
|
||||||
}
|
}
|
||||||
// TODO: Avoid this hack
|
// TODO: Avoid this hack
|
||||||
err := c.AdminLogs.Create(name, 0, "setting", user.LastIP, user.ID)
|
err := c.AdminLogs.Create(name, 0, "setting", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user c.User, uname
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.CreateExtra("set_default", 0, "theme", user.LastIP, user.ID, c.SanitiseSingleLine(theme.Name))
|
err = c.AdminLogs.CreateExtra("set_default", 0, "theme", user.GetIP(), user.ID, c.SanitiseSingleLine(theme.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user c.Use
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", menuItem.ID, "menu_item", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", menuItem.ID, "menu_item", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user c.U
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("create", itemID, "menu_item", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("create", itemID, "menu_item", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.U
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("delete", menuItem.ID, "menu_item", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("delete", menuItem.ID, "menu_item", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -342,7 +342,7 @@ func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user c.Us
|
||||||
}
|
}
|
||||||
menuHold.UpdateOrder(updateMap)
|
menuHold.UpdateOrder(updateMap)
|
||||||
|
|
||||||
err = c.AdminLogs.Create("suborder", menuHold.MenuID, "menu", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("suborder", menuHold.MenuID, "menu", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,7 @@ func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("edit", widget.ID, "widget", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", widget.ID, "widget", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -474,7 +474,7 @@ func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.Us
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("create", wid, "widget", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("create", wid, "widget", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.Us
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("delete", widget.ID, "widget", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("delete", widget.ID, "widget", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ func UsersEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, suid s
|
||||||
}
|
}
|
||||||
targetUser.CacheRemove()
|
targetUser.CacheRemove()
|
||||||
|
|
||||||
err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ func UsersAvatarSubmit(w http.ResponseWriter, r *http.Request, user c.User, suid
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ func UsersAvatarRemoveSubmit(w http.ResponseWriter, r *http.Request, user c.User
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("edit", targetUser.ID, "user", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func WordFiltersCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("create", wfid, "word_filter", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("create", wfid, "word_filter", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user c.User,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.CreateExtra("edit", wfid, "word_filter", user.LastIP, user.ID, string(lBytes))
|
err = c.AdminLogs.CreateExtra("edit", wfid, "word_filter", user.GetIP(), user.ID, string(lBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ func WordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
js := (r.PostFormValue("js") == "1")
|
js := r.PostFormValue("js") == "1"
|
||||||
if !user.Perms.EditSettings {
|
if !user.Perms.EditSettings {
|
||||||
return c.NoPermissionsJSQ(w, r, user, js)
|
return c.NoPermissionsJSQ(w, r, user, js)
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ func WordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return c.LocalErrorJSQ("This word filter doesn't exist", w, r, user, js)
|
return c.LocalErrorJSQ("This word filter doesn't exist", w, r, user, js)
|
||||||
}
|
}
|
||||||
err = c.AdminLogs.Create("delete", wfid, "word_filter", user.LastIP, user.ID)
|
err = c.AdminLogs.Create("delete", wfid, "word_filter", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ func PollVote(w http.ResponseWriter, r *http.Request, user c.User, sPollID strin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError("Malformed input", w, r, user)
|
return c.LocalError("Malformed input", w, r, user)
|
||||||
}
|
}
|
||||||
err = poll.CastVote(optionIndex, user.ID, user.LastIP)
|
err = poll.CastVote(optionIndex, user.ID, user.GetIP())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user c.Use
|
||||||
return c.LocalError("You can't make a blank post", w, r, user)
|
return c.LocalError("You can't make a blank post", w, r, user)
|
||||||
}
|
}
|
||||||
// TODO: Fully parse the post and store it in the parsed column
|
// TODO: Fully parse the post and store it in the parsed column
|
||||||
_, err = c.Prstore.Create(profileOwner.ID, content, user.ID, user.LastIP)
|
_, err = c.Prstore.Create(profileOwner.ID, content, user.ID, user.GetIP())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
|
|
||||||
content := c.PreparseMessage(r.PostFormValue("content"))
|
content := c.PreparseMessage(r.PostFormValue("content"))
|
||||||
// TODO: Fully parse the post and put that in the parsed column
|
// TODO: Fully parse the post and put that in the parsed column
|
||||||
rid, err := c.Rstore.Create(topic, content, user.LastIP, user.ID)
|
rid, err := c.Rstore.Create(topic, content, user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
@ -337,7 +337,7 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.ModLogs.Create("delete", reply.ParentID, "reply", user.LastIP, user.ID)
|
err = c.ModLogs.Create("delete", reply.ParentID, "reply", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
//"fmt"
|
//"fmt"
|
||||||
"golang.org/x/image/tiff"
|
|
||||||
"image"
|
"image"
|
||||||
"image/gif"
|
"image/gif"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
|
@ -21,6 +20,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/image/tiff"
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/common/counters"
|
"github.com/Azareal/Gosora/common/counters"
|
||||||
"github.com/Azareal/Gosora/common/phrases"
|
"github.com/Azareal/Gosora/common/phrases"
|
||||||
|
@ -332,7 +333,7 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
fid, err := strconv.Atoi(r.PostFormValue("topic-board"))
|
fid, err := strconv.Atoi(r.PostFormValue("board"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalError(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
return c.LocalError(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user)
|
||||||
}
|
}
|
||||||
|
@ -345,10 +346,10 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
return c.NoPermissions(w, r, user)
|
return c.NoPermissions(w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
tname := c.SanitiseSingleLine(r.PostFormValue("topic-name"))
|
tname := c.SanitiseSingleLine(r.PostFormValue("name"))
|
||||||
content := c.PreparseMessage(r.PostFormValue("topic-content"))
|
content := c.PreparseMessage(r.PostFormValue("content"))
|
||||||
// TODO: Fully parse the post and store it in the parsed column
|
// TODO: Fully parse the post and store it in the parsed column
|
||||||
tid, err := c.Topics.Create(fid, tname, content, user.ID, user.LastIP)
|
tid, err := c.Topics.Create(fid, tname, content, user.ID, user.GetIP())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err {
|
switch err {
|
||||||
case c.ErrNoRows:
|
case c.ErrNoRows:
|
||||||
|
@ -632,7 +633,7 @@ func DeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.PreError("The provided TopicID is not a valid number.", w, r)
|
return c.PreError("The provided TopicID is not a valid number.", w, r)
|
||||||
}
|
}
|
||||||
tids = append(tids, tid)
|
tids = []int{tid}
|
||||||
}
|
}
|
||||||
if len(tids) == 0 {
|
if len(tids) == 0 {
|
||||||
return c.LocalErrorJSQ("You haven't provided any IDs", w, r, user, js)
|
return c.LocalErrorJSQ("You haven't provided any IDs", w, r, user, js)
|
||||||
|
@ -663,13 +664,13 @@ func DeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.ModLogs.Create("delete", tid, "topic", user.LastIP, user.ID)
|
err = c.ModLogs.Create("delete", tid, "topic", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ? - We might need to add soft-delete before we can do an action reply for this
|
// ? - We might need to add soft-delete before we can do an action reply for this
|
||||||
/*_, err = stmts.createActionReply.Exec(tid,"delete",ipaddress,user.ID)
|
/*_, err = stmts.createActionReply.Exec(tid,"delete",ip,user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err,w,r,js)
|
return c.InternalErrorJSQ(err,w,r,js)
|
||||||
}*/
|
}*/
|
||||||
|
@ -890,11 +891,11 @@ func MoveTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfid s
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTopicAction(action string, t *c.Topic, u c.User) error {
|
func addTopicAction(action string, t *c.Topic, u c.User) error {
|
||||||
err := c.ModLogs.Create(action, t.ID, "topic", u.LastIP, u.ID)
|
err := c.ModLogs.Create(action, t.ID, "topic", u.GetIP(), u.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.CreateActionReply(action, u.LastIP, u.ID)
|
return t.CreateActionReply(action, u.GetIP(), u.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
|
|
|
@ -73,7 +73,7 @@ func BanUserSubmit(w http.ResponseWriter, r *http.Request, user c.User, suid str
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.ModLogs.Create("ban", uid, "user", user.LastIP, user.ID)
|
err = c.ModLogs.Create("ban", uid, "user", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func UnbanUser(w http.ResponseWriter, r *http.Request, user c.User, suid string)
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.ModLogs.Create("unban", uid, "user", user.LastIP, user.ID)
|
err = c.ModLogs.Create("unban", uid, "user", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ func ActivateUser(w http.ResponseWriter, r *http.Request, user c.User, suid stri
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.ModLogs.Create("activate", targetUser.ID, "user", user.LastIP, user.ID)
|
err = c.ModLogs.Create("activate", targetUser.ID, "user", user.GetIP(), user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,17 @@
|
||||||
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/?s={{.CurrentUser.Session}}" method="post"></form>
|
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/?s={{.CurrentUser.Session}}" method="post"></form>
|
||||||
<div class="formrow real_first_child">
|
<div class="formrow real_first_child">
|
||||||
<div class="formitem formlabel"><a>{{lang "create_topic_board"}}</a></div>
|
<div class="formitem formlabel"><a>{{lang "create_topic_board"}}</a></div>
|
||||||
<div class="formitem"><select form="quick_post_form" id="topic_board_input" name="topic-board">
|
<div class="formitem"><select form="quick_post_form" id="topic_board_input" name="board">
|
||||||
{{range .ItemList}}<option{{if eq .ID $.FID}} selected{{end}} value="{{.ID}}">{{.Name}}</option>{{end}}
|
{{range .ItemList}}<option{{if eq .ID $.FID}} selected{{end}} value="{{.ID}}">{{.Name}}</option>{{end}}
|
||||||
</select></div>
|
</select></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem formlabel"><a>{{lang "create_topic_name"}}</a></div>
|
<div class="formitem formlabel"><a>{{lang "create_topic_name"}}</a></div>
|
||||||
<div class="formitem"><input form="quick_post_form" name="topic-name" type="text" placeholder="{{lang "create_topic_name"}}" required /></div>
|
<div class="formitem"><input form="quick_post_form" name="name" type="text" placeholder="{{lang "create_topic_name"}}" required /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem formlabel"><a>{{lang "create_topic_content"}}</a></div>
|
<div class="formitem formlabel"><a>{{lang "create_topic_content"}}</a></div>
|
||||||
<div class="formitem"><textarea form="quick_post_form" class="large" id="topic_content" name="topic-content" placeholder="{{lang "create_topic_placeholder"}}" required></textarea></div>
|
<div class="formitem"><textarea form="quick_post_form" class="large" id="topic_content" name="content" placeholder="{{lang "create_topic_placeholder"}}" required></textarea></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<button form="quick_post_form" name="topic-button" class="formbutton">{{lang "create_topic_create_button"}}</button>
|
<button form="quick_post_form" name="topic-button" class="formbutton">{{lang "create_topic_create_button"}}</button>
|
||||||
|
|
|
@ -31,12 +31,12 @@
|
||||||
<div id="forum_topic_create_form" class="rowblock topic_create_form quick_create_form auto_hide" aria-label="{{lang "quick_topic.aria"}}">
|
<div id="forum_topic_create_form" class="rowblock topic_create_form quick_create_form auto_hide" aria-label="{{lang "quick_topic.aria"}}">
|
||||||
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/?s={{.CurrentUser.Session}}" method="post"></form>
|
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/?s={{.CurrentUser.Session}}" method="post"></form>
|
||||||
<img class="little_row_avatar" src="{{.CurrentUser.MicroAvatar}}" height=64 alt="{{lang "quick_topic.avatar_alt"}}" title="{{lang "quick_topic.avatar_tooltip"}}" />
|
<img class="little_row_avatar" src="{{.CurrentUser.MicroAvatar}}" height=64 alt="{{lang "quick_topic.avatar_alt"}}" title="{{lang "quick_topic.avatar_tooltip"}}" />
|
||||||
<input form="quick_post_form" id="topic_board_input" name="topic-board" value="{{.Forum.ID}}" type="hidden">
|
<input form="quick_post_form" id="topic_board_input" name="board" value="{{.Forum.ID}}" type="hidden">
|
||||||
<div class="main_form">
|
<div class="main_form">
|
||||||
<div class="topic_meta">
|
<div class="topic_meta">
|
||||||
<div class="formrow topic_name_row real_first_child">
|
<div class="formrow topic_name_row real_first_child">
|
||||||
<div class="formitem">
|
<div class="formitem">
|
||||||
<input form="quick_post_form" name="topic-name" placeholder="{{lang "quick_topic.whatsup"}}" required>
|
<input form="quick_post_form" name="name" placeholder="{{lang "quick_topic.whatsup"}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,12 +29,12 @@
|
||||||
<div id="forum_topic_create_form" class="rowblock topic_create_form quick_create_form auto_hide" aria-label="{{lang "quick_topic.aria"}}">
|
<div id="forum_topic_create_form" class="rowblock topic_create_form quick_create_form auto_hide" aria-label="{{lang "quick_topic.aria"}}">
|
||||||
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/?s={{.CurrentUser.Session}}" method="post"></form>
|
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/?s={{.CurrentUser.Session}}" method="post"></form>
|
||||||
<img class="little_row_avatar" src="{{.CurrentUser.MicroAvatar}}" height=64 alt="{{lang "quick_topic.avatar_alt"}}" title="{{lang "quick_topic.avatar_tooltip"}}" />
|
<img class="little_row_avatar" src="{{.CurrentUser.MicroAvatar}}" height=64 alt="{{lang "quick_topic.avatar_alt"}}" title="{{lang "quick_topic.avatar_tooltip"}}" />
|
||||||
<input form="quick_post_form" id="topic_board_input" name="topic-board" value="{{.Forum.ID}}" type="hidden">
|
<input form="quick_post_form" id="topic_board_input" name="board" value="{{.Forum.ID}}" type="hidden">
|
||||||
<div class="main_form">
|
<div class="main_form">
|
||||||
<div class="topic_meta">
|
<div class="topic_meta">
|
||||||
<div class="formrow topic_name_row real_first_child">
|
<div class="formrow topic_name_row real_first_child">
|
||||||
<div class="formitem">
|
<div class="formitem">
|
||||||
<input form="quick_post_form" name="topic-name" placeholder="{{lang "quick_topic.whatsup"}}" required>
|
<input form="quick_post_form" name="name" placeholder="{{lang "quick_topic.whatsup"}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
<div class="formitem formlabel"><a>{{lang "panel_themes_widgets_enabled"}}</a></div>
|
<div class="formitem formlabel"><a>{{lang "panel_themes_widgets_enabled"}}</a></div>
|
||||||
<div class="formitem">
|
<div class="formitem">
|
||||||
<select name="wenabled">
|
<select name="wenabled">
|
||||||
<option{{if .Enabled}} selected{{end}} value="1">{{lang "option_yes"}}</option>
|
<option{{if .Enabled}} selected{{end}} value=1>{{lang "option_yes"}}</option>
|
||||||
<option{{if not .Enabled}} selected{{end}} value="0">{{lang "option_no"}}</option>
|
<option{{if not .Enabled}} selected{{end}} value=0>{{lang "option_no"}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -59,13 +59,13 @@
|
||||||
<div class="main_form">
|
<div class="main_form">
|
||||||
<div class="topic_meta">
|
<div class="topic_meta">
|
||||||
<div class="formrow topic_board_row real_first_child">
|
<div class="formrow topic_board_row real_first_child">
|
||||||
<div class="formitem"><select form="quick_post_form" id="topic_board_input" name="topic-board">
|
<div class="formitem"><select form="quick_post_form" id="topic_board_input" name="board">
|
||||||
{{range .ForumList}}<option{{if eq .ID $.DefaultForum}} selected{{end}} value="{{.ID}}">{{.Name}}</option>{{end}}
|
{{range .ForumList}}<option{{if eq .ID $.DefaultForum}} selected{{end}} value="{{.ID}}">{{.Name}}</option>{{end}}
|
||||||
</select></div>
|
</select></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="formrow topic_name_row">
|
<div class="formrow topic_name_row">
|
||||||
<div class="formitem">
|
<div class="formitem">
|
||||||
<input form="quick_post_form" name="topic-name" placeholder="{{lang "quick_topic.whatsup"}}" required>
|
<input form="quick_post_form" name="name" placeholder="{{lang "quick_topic.whatsup"}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<input form="quick_post_form" id="has_poll_input" name="has_poll" value=0 type="hidden" />
|
<input form="quick_post_form" id="has_poll_input" name="has_poll" value=0 type="hidden" />
|
||||||
<div class="formrow topic_content_row">
|
<div class="formrow topic_content_row">
|
||||||
<div class="formitem">
|
<div class="formitem">
|
||||||
<textarea form="quick_post_form" id="input_content" name="topic-content" placeholder="{{lang "quick_topic.content_placeholder"}}" required></textarea>
|
<textarea form="quick_post_form" id="input_content" name="content" placeholder="{{lang "quick_topic.content_placeholder"}}" required></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="formrow poll_content_row auto_hide">
|
<div class="formrow poll_content_row auto_hide">
|
||||||
|
|
38
tickloop.go
38
tickloop.go
|
@ -141,10 +141,18 @@ func tickLoop(thumbChan chan bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dailies() {
|
func asmMatches() {
|
||||||
// TODO: Find a more efficient way of doing this
|
// TODO: Find a more efficient way of doing this
|
||||||
err := qgen.NewAcc().Select("activity_stream").Cols("asid").EachInt(func(asid int) error {
|
acc := qgen.NewAcc()
|
||||||
count, err := qgen.NewAcc().Count("activity_stream_matches").Where("asid = " + strconv.Itoa(asid)).Total()
|
countStmt := acc.Count("activity_stream_matches").Where("asid=?").Prepare()
|
||||||
|
if err := acc.FirstError(); err != nil {
|
||||||
|
c.LogError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := acc.Select("activity_stream").Cols("asid").EachInt(func(asid int) error {
|
||||||
|
var count int
|
||||||
|
err := countStmt.QueryRow(asid).Scan(&count)
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -157,6 +165,10 @@ func dailies() {
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
c.LogError(err)
|
c.LogError(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dailies() {
|
||||||
|
asmMatches()
|
||||||
|
|
||||||
if c.Config.LogPruneCutoff > -1 {
|
if c.Config.LogPruneCutoff > -1 {
|
||||||
f := func(tbl string) {
|
f := func(tbl string) {
|
||||||
|
@ -182,16 +194,30 @@ func dailies() {
|
||||||
f("users_replies")
|
f("users_replies")
|
||||||
|
|
||||||
// TODO: Find some way of purging the ip data in polls_votes without breaking any anti-cheat measures which might be running... maybe hash it instead?
|
// TODO: Find some way of purging the ip data in polls_votes without breaking any anti-cheat measures which might be running... maybe hash it instead?
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: lastActiveAt isn't currently set, so we can't rely on this to purge last_ips of users who haven't been on in a while
|
// TODO: lastActiveAt isn't currently set, so we can't rely on this to purge last_ips of users who haven't been on in a while
|
||||||
|
/*if c.Config.LastIPCutoff == -1 {
|
||||||
|
_, err := qgen.NewAcc().Update("users").Set("last_ip=0").Where("last_ip!=0").Exec()
|
||||||
|
if err != nil {
|
||||||
|
c.LogError(err)
|
||||||
|
}
|
||||||
|
} else */if c.Config.LastIPCutoff > 0 {
|
||||||
/*_, err = qgen.NewAcc().Update("users").Set("last_ip='0'").DateOlderThan("lastActiveAt",c.Config.PostIPCutoff,"day").Where("last_ip!='0'").Exec()
|
/*_, err = qgen.NewAcc().Update("users").Set("last_ip='0'").DateOlderThan("lastActiveAt",c.Config.PostIPCutoff,"day").Where("last_ip!='0'").Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.LogError(err)
|
c.LogError(err)
|
||||||
}*/
|
}*/
|
||||||
}
|
mon := time.Now().Month()
|
||||||
|
_, err := qgen.NewAcc().Update("users").Set("last_ip=0").Where("last_ip!=0 AND last_ip NOT LIKE '"+strconv.Itoa(int(mon))+"-%'").Exec()
|
||||||
err = c.Meta.Set("lastDaily", strconv.FormatInt(time.Now().Unix(), 10))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.LogError(err)
|
c.LogError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
err := c.Meta.Set("lastDaily", strconv.FormatInt(time.Now().Unix(), 10))
|
||||||
|
if err != nil {
|
||||||
|
c.LogError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue