Optimise template generator.

Optimise mysql adapter.
Add TokenScope to mysql adapter.
Add SimpleBulkInsert() to installer.
Optimise panel.Plugins() route.
This commit is contained in:
Azareal 2021-04-30 08:33:02 +10:00
parent 39ace845b7
commit 78fbbcda21
62 changed files with 469 additions and 290 deletions

View File

@ -78,6 +78,8 @@ type CTemplateSet struct {
logger *log.Logger logger *log.Logger
loggerf *os.File loggerf *os.File
lang string lang string
fsb strings.Builder
} }
func NewCTemplateSet(in string, logDir ...string) *CTemplateSet { func NewCTemplateSet(in string, logDir ...string) *CTemplateSet {
@ -446,20 +448,6 @@ func (c *CTemplateSet) compile(name, content, expects string, expectsInt interfa
importList += "import \"" + item + "\"\n" importList += "import \"" + item + "\"\n"
} }
} }
//var varString string
var vssb strings.Builder
vssb.Grow(10 + 3)
for _, varItem := range c.varList {
//varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n"
vssb.WriteString("var ")
vssb.WriteString(varItem.Name)
vssb.WriteRune(' ')
vssb.WriteString(varItem.Type)
vssb.WriteString(" = ")
vssb.WriteString(varItem.Destination)
vssb.WriteString("\n")
}
varString := vssb.String()
var fout string var fout string
if c.buildTags != "" { if c.buildTags != "" {
@ -537,19 +525,27 @@ func (c *CTemplateSet) compile(name, content, expects string, expectsInt interfa
fout += "}\n\n" fout += "}\n\n"
} }
c.fsb.Reset()
c.fsb.WriteString("// nolint\nfunc Tmpl_")
c.fsb.WriteString(fname)
if c.lang == "normal" { if c.lang == "normal" {
fout += "// nolint\nfunc Tmpl_" + fname + "(tmpl_i interface{}, w io.Writer) error {\n" /*fout += "// nolint\nfunc Tmpl_" + fname + "(tmpl_i interface{}, w io.Writer) error {\n"
fout += `tmpl_` + fname + `_vars, ok := tmpl_i.(` + expects + `) fout += `tmpl_` + fname + `_vars, ok := tmpl_i.(` + expects + `)
if !ok { if !ok {
return errors.New("invalid page struct value") return errors.New("invalid page struct value")
} }
` `*/
/*fout += `tmpl_vars, ok := tmpl_i.(` + expects + `) c.fsb.WriteString("(tmpl_i interface{}, w io.Writer) error {\n")
c.fsb.WriteString(`tmpl_`)
c.fsb.WriteString(fname)
c.fsb.WriteString(`_vars, ok := tmpl_i.(`)
c.fsb.WriteString(expects)
c.fsb.WriteString(`)
if !ok { if !ok {
return errors.New("invalid page struct value") return errors.New("invalid page struct value")
} }
`*/ var iw http.ResponseWriter
fout += `var iw http.ResponseWriter
if gzw, ok := w.(c.GzipResponseWriter); ok { if gzw, ok := w.(c.GzipResponseWriter); ok {
iw = gzw.ResponseWriter iw = gzw.ResponseWriter
w = gzw.Writer w = gzw.Writer
@ -557,19 +553,41 @@ if !ok {
_ = iw _ = iw
var tmp []byte var tmp []byte
_ = tmp _ = tmp
` `)
} else { } else {
fout += "// nolint\nfunc Tmpl_" + fname + "(tmpl_" + fname + "_vars interface{}, w io.Writer) error {\n" //fout += "// nolint\nfunc Tmpl_" + fname + "(tmpl_" + fname + "_vars interface{}, w io.Writer) error {\n"
c.fsb.WriteString("(tmpl_")
c.fsb.WriteString(fname)
c.fsb.WriteString("_vars interface{}, w io.Writer) error {\n")
//fout += "// nolint\nfunc Tmpl_" + fname + "(tmpl_vars interface{}, w io.Writer) error {\n" //fout += "// nolint\nfunc Tmpl_" + fname + "(tmpl_vars interface{}, w io.Writer) error {\n"
} }
//var fsb strings.Builder
if len(c.langIndexToName) > 0 { if len(c.langIndexToName) > 0 {
fout += "//var plist = phrases.GetTmplPhrasesBytes(" + fname + "_tmpl_phrase_id)\n" //fout += "//var plist = phrases.GetTmplPhrasesBytes(" + fname + "_tmpl_phrase_id)\n"
c.fsb.WriteString("//var plist = phrases.GetTmplPhrasesBytes(")
c.fsb.WriteString(fname)
c.fsb.WriteString("_tmpl_phrase_id)\n")
//fout += "if len(plist) > 0 {\n_ = plist[len(plist)-1]\n}\n" //fout += "if len(plist) > 0 {\n_ = plist[len(plist)-1]\n}\n"
//fout += "var plist = " + fname + "_phrase_arr\n" //fout += "var plist = " + fname + "_phrase_arr\n"
} }
var fsb strings.Builder
fsb.WriteString(varString) //var varString string
//var vssb strings.Builder
c.fsb.Grow(10 + 3)
for _, varItem := range c.varList {
//varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n"
c.fsb.WriteString("var ")
c.fsb.WriteString(varItem.Name)
c.fsb.WriteRune(' ')
c.fsb.WriteString(varItem.Type)
c.fsb.WriteString(" = ")
c.fsb.WriteString(varItem.Destination)
c.fsb.WriteString("\n")
}
//c.fsb.WriteString(varString)
//fout += varString //fout += varString
skipped := make(map[string]*SkipBlock) // map[templateName]*SkipBlock{map[atIndexAndAfter]skipThisMuch,lastCount} skipped := make(map[string]*SkipBlock) // map[templateName]*SkipBlock{map[atIndexAndAfter]skipThisMuch,lastCount}
@ -577,7 +595,7 @@ if !ok {
out := "w.Write(" + tmplName + "_frags[" + strconv.Itoa(index) + "]" + ")\n" out := "w.Write(" + tmplName + "_frags[" + strconv.Itoa(index) + "]" + ")\n"
c.detail("writing ", out) c.detail("writing ", out)
//fout += out //fout += out
fsb.WriteString(out) c.fsb.WriteString(out)
} }
for fid := 0; len(outBuf) > fid; fid++ { for fid := 0; len(outBuf) > fid; fid++ {
@ -613,31 +631,31 @@ if !ok {
writeTextFrame(fr.TemplateName, fr.Extra.(int)-skip) writeTextFrame(fr.TemplateName, fr.Extra.(int)-skip)
case fr.Type == "varsub" || fr.Type == "cvarsub": case fr.Type == "varsub" || fr.Type == "cvarsub":
//fout += "w.Write(" + fr.Body + ")\n" //fout += "w.Write(" + fr.Body + ")\n"
fsb.WriteString("w.Write(") c.fsb.WriteString("w.Write(")
fsb.WriteString(fr.Body) c.fsb.WriteString(fr.Body)
fsb.WriteString(")\n") c.fsb.WriteString(")\n")
case fr.Type == "lang": case fr.Type == "lang":
//fout += "w.Write(plist[" + strconv.Itoa(fr.Extra.(int)) + "])\n" //fout += "w.Write(plist[" + strconv.Itoa(fr.Extra.(int)) + "])\n"
fsb.WriteString("w.Write(") c.fsb.WriteString("w.Write(")
fsb.WriteString(fname) c.fsb.WriteString(fname)
if len(c.langIndexToName) == 1 { if len(c.langIndexToName) == 1 {
//fout += "w.Write(" + fname + "_phrase)\n" //fout += "w.Write(" + fname + "_phrase)\n"
fsb.WriteString("_phrase)\n") c.fsb.WriteString("_phrase)\n")
} else { } else {
//fout += "w.Write(" + fname + "_phrase_arr[" + strconv.Itoa(fr.Extra.(int)) + "])\n" //fout += "w.Write(" + fname + "_phrase_arr[" + strconv.Itoa(fr.Extra.(int)) + "])\n"
fsb.WriteString("_phrase_arr[") c.fsb.WriteString("_phrase_arr[")
fsb.WriteString(strconv.Itoa(fr.Extra.(int))) c.fsb.WriteString(strconv.Itoa(fr.Extra.(int)))
fsb.WriteString("])\n") c.fsb.WriteString("])\n")
} }
//case fr.Type == "identifier": //case fr.Type == "identifier":
default: default:
//fout += fr.Body //fout += fr.Body
fsb.WriteString(fr.Body) c.fsb.WriteString(fr.Body)
} }
} }
//fout += "return nil\n}\n" //fout += "return nil\n}\n"
fsb.WriteString("return nil\n}\n") c.fsb.WriteString("return nil\n}\n")
fout += fsb.String() fout += c.fsb.String()
writeFrag := func(tmplName string, index int, body string) { writeFrag := func(tmplName string, index int, body string) {
//c.detail("writing ", fragmentPrefix) //c.detail("writing ", fragmentPrefix)
@ -2163,8 +2181,7 @@ func (c *CTemplateSet) afterTemplateV2(con CContext, startIndex int /*, typ int*
c.dumpCall("afterTemplateV2", con, startIndex) c.dumpCall("afterTemplateV2", con, startIndex)
defer c.retCall("afterTemplateV2") defer c.retCall("afterTemplateV2")
loopDepth := 0 loopDepth, ifNilDepth := 0, 0
ifNilDepth := 0
var outBuf = *con.OutBuf var outBuf = *con.OutBuf
varcounts := make(map[string]int) varcounts := make(map[string]int)
loopStart := startIndex loopStart := startIndex
@ -2228,8 +2245,7 @@ OLoop:
} }
// Exclude varsubs within loops for now // Exclude varsubs within loops for now
loopDepth = 0 loopDepth, ifNilDepth = 0, 0
ifNilDepth = 0
OOLoop: OOLoop:
for i := loopStart; i < len(outBuf); i++ { for i := loopStart; i < len(outBuf); i++ {
item := outBuf[i] item := outBuf[i]

View File

@ -31,16 +31,16 @@ type installer struct {
} }
func (i *installer) SetAdapter(name string) error { func (i *installer) SetAdapter(name string) error {
adap, err := GetAdapter(name) a, err := GetAdapter(name)
if err != nil { if err != nil {
return err return err
} }
i.SetAdapterInstance(adap) i.SetAdapterInstance(a)
return nil return nil
} }
func (i *installer) SetAdapterInstance(adap Adapter) { func (i *installer) SetAdapterInstance(a Adapter) {
i.adapter = adap i.adapter = a
i.instructions = []DBInstallInstruction{} i.instructions = []DBInstallInstruction{}
} }
@ -48,13 +48,13 @@ func (i *installer) AddPlugins(plugins ...QueryPlugin) {
i.plugins = append(i.plugins, plugins...) i.plugins = append(i.plugins, plugins...)
} }
func (i *installer) CreateTable(table, charset, collation string, columns []DBTableColumn, keys []DBTableKey) error { func (i *installer) CreateTable(table, charset, collation string, cols []DBTableColumn, keys []DBTableKey) error {
tableStruct := &DBInstallTable{table, charset, collation, columns, keys} tableStruct := &DBInstallTable{table, charset, collation, cols, keys}
err := i.RunHook("CreateTableStart", tableStruct) err := i.RunHook("CreateTableStart", tableStruct)
if err != nil { if err != nil {
return err return err
} }
res, err := i.adapter.CreateTable("", table, charset, collation, columns, keys) res, err := i.adapter.CreateTable("", table, charset, collation, cols, keys)
if err != nil { if err != nil {
return err return err
} }
@ -68,16 +68,16 @@ func (i *installer) CreateTable(table, charset, collation string, columns []DBTa
} }
// TODO: Let plugins manipulate the parameters like in CreateTable // TODO: Let plugins manipulate the parameters like in CreateTable
func (i *installer) AddIndex(table, iname, colname string) error { func (i *installer) AddIndex(table, iname, colName string) error {
err := i.RunHook("AddIndexStart", table, iname, colname) err := i.RunHook("AddIndexStart", table, iname, colName)
if err != nil { if err != nil {
return err return err
} }
res, err := i.adapter.AddIndex("", table, iname, colname) res, err := i.adapter.AddIndex("", table, iname, colName)
if err != nil { if err != nil {
return err return err
} }
err = i.RunHook("AddIndexAfter", table, iname, colname) err = i.RunHook("AddIndexAfter", table, iname, colName)
if err != nil { if err != nil {
return err return err
} }
@ -85,16 +85,16 @@ func (i *installer) AddIndex(table, iname, colname string) error {
return nil return nil
} }
func (i *installer) AddKey(table, column string, key DBTableKey) error { func (i *installer) AddKey(table, col string, key DBTableKey) error {
err := i.RunHook("AddKeyStart", table, column, key) err := i.RunHook("AddKeyStart", table, col, key)
if err != nil { if err != nil {
return err return err
} }
res, err := i.adapter.AddKey("", table, column, key) res, err := i.adapter.AddKey("", table, col, key)
if err != nil { if err != nil {
return err return err
} }
err = i.RunHook("AddKeyAfter", table, column, key) err = i.RunHook("AddKeyAfter", table, col, key)
if err != nil { if err != nil {
return err return err
} }
@ -120,9 +120,26 @@ func (i *installer) SimpleInsert(table, columns, fields string) error {
return nil return nil
} }
func (i *installer) SimpleBulkInsert(table, cols string, fieldSet []string) error {
err := i.RunHook("SimpleBulkInsertStart", table, cols, fieldSet)
if err != nil {
return err
}
res, err := i.adapter.SimpleBulkInsert("", table, cols, fieldSet)
if err != nil {
return err
}
err = i.RunHook("SimpleBulkInsertAfter", table, cols, fieldSet, res)
if err != nil {
return err
}
i.instructions = append(i.instructions, DBInstallInstruction{table, res, "bulk-insert"})
return nil
}
func (i *installer) RunHook(name string, args ...interface{}) error { func (i *installer) RunHook(name string, args ...interface{}) error {
for _, plugin := range i.plugins { for _, pl := range i.plugins {
err := plugin.Hook(name, args...) err := pl.Hook(name, args...)
if err != nil { if err != nil {
return err return err
} }

View File

@ -94,57 +94,109 @@ func (a *MysqlAdapter) DropTable(name, table string) (string, error) {
return q, nil return q, nil
} }
func (a *MysqlAdapter) CreateTable(name, table, charset, collation string, columns []DBTableColumn, keys []DBTableKey) (string, error) { func (a *MysqlAdapter) CreateTable(name, table, charset, collation string, cols []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")
} }
if len(columns) == 0 { if len(cols) == 0 {
return "", errors.New("You can't have a table with no columns") return "", errors.New("You can't have a table with no columns")
} }
q := "CREATE TABLE `" + table + "` (" var qsb strings.Builder
for _, column := range columns { //q := "CREATE TABLE `" + table + "`("
column, size, end := a.parseColumn(column) w := func(s string) {
q += "\n\t`" + column.Name + "` " + column.Type + size + end + "," qsb.WriteString(s)
}
w("CREATE TABLE `")
w(table)
w("`(")
for i, col := range cols {
if i != 0 {
w(",\n\t`")
} else {
w("\n\t`")
}
col, size, end := a.parseColumn(col)
//q += "\n\t`" + col.Name + "` " + col.Type + size + end + ","
w(col.Name)
w("` ")
w(col.Type)
w(size)
w(end)
} }
if len(keys) > 0 { if len(keys) > 0 {
for _, key := range keys { /*if len(cols) > 0 {
q += "\n\t" + key.Type w(",")
if key.Type != "unique" { }*/
q += " key" for _, k := range keys {
} /*if ii != 0 {
if key.Type == "foreign" { w(",\n\t")
cols := strings.Split(key.Columns, ",")
q += "(`" + cols[0] + "`) REFERENCES `" + key.FTable + "`(`" + cols[1] + "`)"
if key.Cascade {
q += " ON DELETE CASCADE"
}
q += ","
} else { } else {
q += "(" w("\n\t")
for i, column := range strings.Split(key.Columns, ",") { }*/
w(",\n\t")
//q += "\n\t" + key.Type
w(k.Type)
if k.Type != "unique" {
//q += " key"
w(" key")
}
if k.Type == "foreign" {
cols := strings.Split(k.Columns, ",")
//q += "(`" + cols[0] + "`) REFERENCES `" + k.FTable + "`(`" + cols[1] + "`)"
w("(`")
w(cols[0])
w("`) REFERENCES `")
w(k.FTable)
w("`(`")
w(cols[1])
w("`)")
if k.Cascade {
//q += " ON DELETE CASCADE"
w(" ON DELETE CASCADE")
}
//q += ","
} else {
//q += "("
w("(")
for i, col := range strings.Split(k.Columns, ",") {
/*if i != 0 {
q += ",`" + col + "`"
} else {
q += "`" + col + "`"
}*/
if i != 0 { if i != 0 {
q += ",`" + column + "`" w(",`")
} else { } else {
q += "`" + column + "`" w("`")
} }
w(col)
w("`")
} }
q += ")," //q += "),"
w(")")
} }
} }
} }
q = q[0:len(q)-1] + "\n)" //q = q[0:len(q)-1] + "\n)"
w("\n)")
if charset != "" { if charset != "" {
q += " CHARSET=" + charset //q += " CHARSET=" + charset
w(" CHARSET=")
w(charset)
} }
if collation != "" { if collation != "" {
q += " COLLATE " + collation //q += " COLLATE " + collation
w(" COLLATE ")
w(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
q += ";" //q += ";"
w(";")
q := qsb.String()
a.pushStatement(name, "create-table", q) a.pushStatement(name, "create-table", q)
return q, nil return q, nil
} }
@ -312,7 +364,7 @@ func (a *MysqlAdapter) RemoveIndex(name, table, iname string) (string, error) {
return q, nil return q, nil
} }
func (a *MysqlAdapter) AddForeignKey(name, table, column, ftable, fcolumn string, cascade bool) (out string, e error) { func (a *MysqlAdapter) AddForeignKey(name, table, col, ftable, fcolumn string, cascade bool) (out string, e error) {
c := func(str string, val bool) { c := func(str string, val bool) {
if e != nil || !val { if e != nil || !val {
return return
@ -320,14 +372,14 @@ func (a *MysqlAdapter) AddForeignKey(name, table, column, ftable, fcolumn string
e = errors.New("You need a " + str + " for this table") e = errors.New("You need a " + str + " for this table")
} }
c("name", table == "") c("name", table == "")
c("column", column == "") c("col", col == "")
c("ftable", ftable == "") c("ftable", ftable == "")
c("fcolumn", fcolumn == "") c("fcolumn", fcolumn == "")
if e != nil { if e != nil {
return "", e return "", e
} }
q := "ALTER TABLE `" + table + "` ADD CONSTRAINT `fk_" + column + "` FOREIGN KEY(`" + column + "`) REFERENCES `" + ftable + "`(`" + fcolumn + "`)" q := "ALTER TABLE `" + table + "` ADD CONSTRAINT `fk_" + col + "` FOREIGN KEY(`" + col + "`) REFERENCES `" + ftable + "`(`" + fcolumn + "`)"
if cascade { if cascade {
q += " ON DELETE CASCADE" q += " ON DELETE CASCADE"
} }
@ -339,7 +391,7 @@ func (a *MysqlAdapter) AddForeignKey(name, table, column, ftable, fcolumn string
const silen1 = len("INSERT INTO``()VALUES() ") const silen1 = len("INSERT INTO``()VALUES() ")
func (a *MysqlAdapter) SimpleInsert(name, table, columns, fields string) (string, error) { func (a *MysqlAdapter) 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")
} }
@ -356,9 +408,9 @@ func (a *MysqlAdapter) SimpleInsert(name, table, columns, fields string) (string
sb.Grow(silen1 + len(table)) sb.Grow(silen1 + len(table))
sb.WriteString("INSERT INTO`") sb.WriteString("INSERT INTO`")
sb.WriteString(table) sb.WriteString(table)
if columns != "" { if cols != "" {
sb.WriteString("`(") sb.WriteString("`(")
sb.WriteString(a.buildColumns(columns)) sb.WriteString(a.buildColumns(cols))
sb.WriteString(")VALUES(") sb.WriteString(")VALUES(")
fs := processFields(fields) fs := processFields(fields)
sb.Grow(len(fs) * 3) sb.Grow(len(fs) * 3)
@ -391,7 +443,7 @@ func (a *MysqlAdapter) SimpleInsert(name, table, columns, fields string) (string
return q, nil return q, nil
} }
func (a *MysqlAdapter) SimpleBulkInsert(name, table, columns string, fieldSet []string) (string, error) { func (a *MysqlAdapter) SimpleBulkInsert(name, table, cols string, fieldSet []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")
} }
@ -407,9 +459,9 @@ func (a *MysqlAdapter) SimpleBulkInsert(name, table, columns string, fieldSet []
sb.Grow(silen1 + len(table)) sb.Grow(silen1 + len(table))
sb.WriteString("INSERT INTO`") sb.WriteString("INSERT INTO`")
sb.WriteString(table) sb.WriteString(table)
if columns != "" { if cols != "" {
sb.WriteString("`(") sb.WriteString("`(")
sb.WriteString(a.buildColumns(columns)) sb.WriteString(a.buildColumns(cols))
sb.WriteString(")VALUES(") sb.WriteString(")VALUES(")
for oi, fields := range fieldSet { for oi, fields := range fieldSet {
if oi != 0 { if oi != 0 {
@ -423,10 +475,18 @@ func (a *MysqlAdapter) SimpleBulkInsert(name, table, columns string, fieldSet []
} }
nameLen := len(field.Name) nameLen := len(field.Name)
if field.Name[0] == '"' && field.Name[nameLen-1] == '"' && nameLen >= 3 { if field.Name[0] == '"' && field.Name[nameLen-1] == '"' && nameLen >= 3 {
field.Name = "'" + field.Name[1:nameLen-1] + "'" //field.Name = "'" + field.Name[1:nameLen-1] + "'"
sb.WriteString("'")
sb.WriteString(field.Name[1 : nameLen-1])
sb.WriteString("'")
continue
} }
if field.Name[0] == '\'' && field.Name[nameLen-1] == '\'' && nameLen >= 3 { if field.Name[0] == '\'' && field.Name[nameLen-1] == '\'' && nameLen >= 3 {
field.Name = "'" + strings.Replace(field.Name[1:nameLen-1], "'", "''", -1) + "'" //field.Name = "'" + strings.Replace(field.Name[1:nameLen-1], "'", "''", -1) + "'"
sb.WriteString("'")
sb.WriteString(strings.Replace(field.Name[1:nameLen-1], "'", "''", -1))
sb.WriteString("'")
continue
} }
sb.WriteString(field.Name) sb.WriteString(field.Name)
} }
@ -443,34 +503,62 @@ func (a *MysqlAdapter) SimpleBulkInsert(name, table, columns string, fieldSet []
return q, nil return q, nil
} }
func (a *MysqlAdapter) buildColumns(columns string) (q string) { func (a *MysqlAdapter) buildColumns(cols string) 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 _, col := range processColumns(columns) { var cb strings.Builder
pcols := processColumns(cols)
var n int
for i, col := range pcols {
if i != 0 {
n += 1
}
if col.Type == TokenFunc { if col.Type == TokenFunc {
q += col.Left + "," n += len(col.Left)
} else { } else {
q += "`" + col.Left + "`," n += len(col.Left) + 2
} }
} }
return q[0 : len(q)-1] cb.Grow(n)
for i, col := range pcols {
if col.Type == TokenFunc {
if i != 0 {
cb.WriteString(",")
}
//q += col.Left + ","
cb.WriteString(col.Left)
} else {
//q += "`" + col.Left + "`,"
if i != 0 {
cb.WriteString(",`")
} else {
cb.WriteString("`")
}
cb.WriteString(col.Left)
cb.WriteString("`")
}
}
return cb.String()
} }
// ! DEPRECATED // ! DEPRECATED
func (a *MysqlAdapter) SimpleReplace(name, table, columns, fields string) (string, error) { func (a *MysqlAdapter) SimpleReplace(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")
} }
if len(columns) == 0 { if len(cols) == 0 {
return "", errors.New("No columns found for SimpleInsert") return "", errors.New("No columns found for SimpleInsert")
} }
if len(fields) == 0 { if len(fields) == 0 {
return "", errors.New("No input data found for SimpleInsert") return "", errors.New("No input data found for SimpleInsert")
} }
q := "REPLACE INTO `" + table + "`(" + a.buildColumns(columns) + ") VALUES (" q := "REPLACE INTO `" + table + "`(" + a.buildColumns(cols) + ") VALUES ("
for _, field := range processFields(fields) { for _, field := range processFields(fields) {
q += field.Name + "," q += field.Name + ","
} }
@ -575,9 +663,9 @@ func (a *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) {
} }
} }
err := a.buildFlexiWhereSb(sb, up.where, up.dateCutoff) e := a.buildFlexiWhereSb(sb, up.where, up.dateCutoff)
if err != nil { if e != nil {
return sb.String(), err return sb.String(), e
} }
// 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
@ -662,9 +750,9 @@ func (a *MysqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) {
sb.WriteString(b.table) sb.WriteString(b.table)
sb.WriteRune('`') sb.WriteRune('`')
err := a.buildFlexiWhereSb(sb, b.where, b.dateCutoff) e := a.buildFlexiWhereSb(sb, b.where, b.dateCutoff)
if err != nil { if e != nil {
return sb.String(), err return sb.String(), e
} }
q := sb.String() q := sb.String()
queryStrPool.Put(sb) queryStrPool.Put(sb)
@ -748,7 +836,6 @@ func (a *MysqlAdapter) buildFlexiWhere(where string, dateCutoff *dateCutoff) (q
sb.WriteString(dateCutoff.Unit) sb.WriteString(dateCutoff.Unit)
} }
} }
if dateCutoff != nil && len(where) != 0 { if dateCutoff != nil && len(where) != 0 {
sb.WriteString(" AND") sb.WriteString(" AND")
} }
@ -809,7 +896,6 @@ func (a *MysqlAdapter) buildFlexiWhereSb(sb *strings.Builder, where string, date
sb.WriteString(dateCutoff.Unit) sb.WriteString(dateCutoff.Unit)
} }
} }
if dateCutoff != nil && len(where) != 0 { if dateCutoff != nil && len(where) != 0 {
sb.WriteString(" AND") sb.WriteString(" AND")
} }
@ -927,7 +1013,7 @@ func (a *MysqlAdapter) SimpleSelect(name, table, cols, where, orderby, limit str
return q, nil return q, nil
} }
func (a *MysqlAdapter) ComplexSelect(preBuilder *selectPrebuilder) (out string, err error) { func (a *MysqlAdapter) ComplexSelect(preBuilder *selectPrebuilder) (out string, e error) {
var sb *strings.Builder var sb *strings.Builder
ii := queryStrPool.Get() ii := queryStrPool.Get()
if ii == nil { if ii == nil {
@ -936,11 +1022,11 @@ func (a *MysqlAdapter) ComplexSelect(preBuilder *selectPrebuilder) (out string,
sb = ii.(*strings.Builder) sb = ii.(*strings.Builder)
sb.Reset() sb.Reset()
} }
err = a.complexSelect(preBuilder, sb) e = a.complexSelect(preBuilder, sb)
out = sb.String() out = sb.String()
queryStrPool.Put(sb) queryStrPool.Put(sb)
a.pushStatement(preBuilder.name, "select", out) a.pushStatement(preBuilder.name, "select", out)
return out, err return out, e
} }
const cslen1 = len("SELECT FROM ``") const cslen1 = len("SELECT FROM ``")
@ -968,15 +1054,15 @@ func (a *MysqlAdapter) complexSelect(preBuilder *selectPrebuilder, sb *strings.B
sb.WriteString("WHERE`") sb.WriteString("WHERE`")
sb.WriteString(preBuilder.inColumn) sb.WriteString(preBuilder.inColumn)
sb.WriteString("`IN(") sb.WriteString("`IN(")
err := a.complexSelect(preBuilder.inChain, sb) e := a.complexSelect(preBuilder.inChain, sb)
if err != nil { if e != nil {
return err return e
} }
sb.WriteRune(')') sb.WriteRune(')')
} else { } else {
err := a.buildFlexiWhereSb(sb, preBuilder.where, preBuilder.dateCutoff) e := a.buildFlexiWhereSb(sb, preBuilder.where, preBuilder.dateCutoff)
if err != nil { if e != nil {
return err return e
} }
} }
@ -1092,9 +1178,9 @@ func (a *MysqlAdapter) SimpleUpdateSelect(up *updatePrebuilder) (string, error)
func (a *MysqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelect) (string, error) { func (a *MysqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelect) (string, error) {
sb := &strings.Builder{} sb := &strings.Builder{}
err := a.buildWhere(sel.Where, sb) e := a.buildWhere(sel.Where, sb)
if err != nil { if e != nil {
return "", err return "", e
} }
q := "INSERT INTO `" + ins.Table + "`(" + a.buildColumns(ins.Columns) + ") SELECT" + a.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table + "`" + sb.String() + a.buildOrderby(sel.Orderby) + a.buildLimit(sel.Limit) q := "INSERT INTO `" + ins.Table + "`(" + a.buildColumns(ins.Columns) + ") SELECT" + a.buildJoinColumns(sel.Columns) + " FROM `" + sel.Table + "`" + sb.String() + a.buildOrderby(sel.Orderby) + a.buildLimit(sel.Limit)
@ -1104,9 +1190,9 @@ func (a *MysqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel DBSelec
} }
func (a *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel DBJoin) (string, error) { func (a *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel DBJoin) (string, error) {
whereStr, err := a.buildJoinWhere(sel.Where) whereStr, e := a.buildJoinWhere(sel.Where)
if err != nil { if e != nil {
return "", err return "", e
} }
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 := "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)
@ -1117,38 +1203,65 @@ func (a *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel DBJoi
// TODO: Make this more consistent with the other build* methods? // TODO: Make this more consistent with the other build* methods?
func (a *MysqlAdapter) buildJoiners(joiners string) (q string) { func (a *MysqlAdapter) buildJoiners(joiners string) (q string) {
for _, j := range processJoiner(joiners) { var qb strings.Builder
q += "`" + j.LeftTable + "`.`" + j.LeftColumn + "` " + j.Operator + " `" + j.RightTable + "`.`" + j.RightColumn + "` AND " for i, j := range processJoiner(joiners) {
//q += "`" + j.LeftTable + "`.`" + j.LeftColumn + "` " + j.Operator + " `" + j.RightTable + "`.`" + j.RightColumn + "` AND "
if i != 0 {
qb.WriteString("AND`")
} else {
qb.WriteString("`")
} }
// Remove the trailing AND qb.WriteString(j.LeftTable)
return q[0 : len(q)-4] qb.WriteString("`.`")
qb.WriteString(j.LeftColumn)
qb.WriteString("` ")
qb.WriteString(j.Operator)
qb.WriteString(" `")
qb.WriteString(j.RightTable)
qb.WriteString("`.`")
qb.WriteString(j.RightColumn)
qb.WriteString("`")
}
return qb.String()
} }
// Add support for BETWEEN x.x // Add support for BETWEEN x.x
func (a *MysqlAdapter) buildJoinWhere(where string) (q string, err error) { func (a *MysqlAdapter) buildJoinWhere(where string) (q string, e error) {
if len(where) != 0 { if len(where) != 0 {
q = " WHERE" var qsb strings.Builder
for _, loc := range processWhere(where) { ws := processWhere(where)
qsb.Grow(6 + (len(ws) * 5))
qsb.WriteString(" WHERE")
for i, loc := range ws {
if i != 0 {
qsb.WriteString(" AND")
}
for _, token := range loc.Expr { for _, token := range loc.Expr {
switch token.Type { switch token.Type {
case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike: case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot, TokenLike:
q += " " + token.Contents qsb.WriteRune(' ')
qsb.WriteString(token.Contents)
case TokenColumn: case TokenColumn:
qsb.WriteString(" `")
halves := strings.Split(token.Contents, ".") halves := strings.Split(token.Contents, ".")
if len(halves) == 2 { if len(halves) == 2 {
q += " `" + halves[0] + "`.`" + halves[1] + "`" qsb.WriteString(halves[0])
qsb.WriteString("`.`")
qsb.WriteString(halves[1])
} else { } else {
q += " `" + token.Contents + "`" qsb.WriteString(token.Contents)
} }
qsb.WriteRune('`')
case TokenString: case TokenString:
q += " '" + token.Contents + "'" qsb.WriteString(" '")
qsb.WriteString(token.Contents)
qsb.WriteRune('\'')
default: default:
return q, errors.New("This token doesn't exist o_o") return qsb.String(), errors.New("This token doesn't exist o_o")
} }
} }
q += " AND"
} }
q = q[0 : len(q)-4] return qsb.String(), nil
} }
return q, nil return q, nil
} }
@ -1175,8 +1288,8 @@ func (a *MysqlAdapter) buildJoinColumns(cols string) (q string) {
if firstChar == '\'' { if firstChar == '\'' {
col.Type = TokenString col.Type = TokenString
} else { } else {
_, err := strconv.Atoi(string(firstChar)) _, e := strconv.Atoi(string(firstChar))
if err == nil { if e == nil {
col.Type = TokenNumber col.Type = TokenNumber
} }
} }
@ -1185,7 +1298,7 @@ func (a *MysqlAdapter) buildJoinColumns(cols string) (q string) {
source := col.Left source := col.Left
if col.Table != "" { if col.Table != "" {
source = "`" + col.Table + "`.`" + source + "`" source = "`" + col.Table + "`.`" + source + "`"
} else if col.Type != TokenFunc && col.Type != TokenNumber && col.Type != TokenSub && col.Type != TokenString { } else if col.Type != TokenScope && col.Type != TokenFunc && col.Type != TokenNumber && col.Type != TokenSub && col.Type != TokenString {
source = "`" + source + "`" source = "`" + source + "`"
} }
@ -1212,7 +1325,7 @@ func (a *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DBInsert, sel DBJo
const sclen1 = len("SELECT COUNT(*) FROM``") const sclen1 = len("SELECT COUNT(*) FROM``")
func (a *MysqlAdapter) SimpleCount(name, table, where, limit string) (q string, err error) { func (a *MysqlAdapter) SimpleCount(name, table, where, limit string) (q string, e 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")
} }
@ -1228,9 +1341,8 @@ func (a *MysqlAdapter) SimpleCount(name, table, where, limit string) (q string,
sb.WriteString("SELECT COUNT(*) FROM`") sb.WriteString("SELECT COUNT(*) FROM`")
sb.WriteString(table) sb.WriteString(table)
sb.WriteRune('`') sb.WriteRune('`')
err = a.buildWhere(where, sb) if e = a.buildWhere(where, sb); e != nil {
if err != nil { return "", e
return "", err
} }
a.buildLimitSb(sb, limit) a.buildLimitSb(sb, limit)
@ -1255,21 +1367,21 @@ func (a *MysqlAdapter) Write() error {
if stmt.Type == "upsert" { if stmt.Type == "upsert" {
stmts += "\t" + name + " *qgen.MySQLUpsertCallback\n" stmts += "\t" + name + " *qgen.MySQLUpsertCallback\n"
body += ` body += `
common.DebugLog("Preparing ` + name + ` statement.") dl("Preparing ` + name + ` statement.")
stmts.` + name + `, err = qgen.PrepareMySQLUpsertCallback(db,"` + stmt.Contents + `") stmts.` + name + `, e = qgen.PrepareMySQLUpsertCallback(db,"` + stmt.Contents + `")
if err != nil { if e != nil {
log.Print("Error in ` + name + ` statement.") l("Error in ` + name + ` statement.")
return err return e
} }
` `
} else if stmt.Type != "create-table" { } else if stmt.Type != "create-table" {
stmts += "\t" + name + " *sql.Stmt\n" stmts += "\t" + name + " *sql.Stmt\n"
body += ` body += `
common.DebugLog("Preparing ` + name + ` statement.") dl("Preparing ` + name + ` statement.")
stmts.` + name + `, err = db.Prepare("` + stmt.Contents + `") stmts.` + name + `, e = db.Prepare("` + stmt.Contents + `")
if err != nil { if e != nil {
log.Print("Error in ` + name + ` statement.") l("Error in ` + name + ` statement.")
return err return e
} }
` `
} }
@ -1282,10 +1394,12 @@ func (a *MysqlAdapter) Write() error {
package main package main
import "log" import(
import "database/sql" "log"
import "github.com/Azareal/Gosora/common" "database/sql"
//import "github.com/Azareal/Gosora/query_gen" c "github.com/Azareal/Gosora/common"
//"github.com/Azareal/Gosora/query_gen"
)
// nolint // nolint
type Stmts struct { type Stmts struct {
@ -1298,8 +1412,11 @@ type Stmts struct {
} }
// nolint // nolint
func _gen_mysql() (err error) { func _gen_mysql() (e error) {
common.DebugLog("Building the generated statements") dl := c.DebugLog
dl("Building the generated statements")
l := log.Print
_ = l
` + body + ` ` + body + `
return nil return nil
} }

View File

@ -103,6 +103,7 @@ const (
TokenOr TokenOr
TokenNot TokenNot
TokenLike TokenLike
TokenScope
) )
type DBToken struct { type DBToken struct {

View File

@ -10,6 +10,7 @@ package qgen
import ( import (
"os" "os"
"strings" "strings"
//"fmt"
) )
// TODO: Add support for numbers and strings? // TODO: Add support for numbers and strings?
@ -34,11 +35,17 @@ func processColumns(colStr string) (columns []DBColumn) {
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] == ')' { //fmt.Printf("halves: %+v\n", halves)
//fmt.Printf("halves[0]: %+v\n", halves[0])
switch {
case halves[0][0] == '(':
outCol.Type = TokenScope
outCol.Table = ""
case halves[0][len(halves[0])-1] == ')':
outCol.Type = TokenFunc outCol.Type = TokenFunc
} else if halves[0] == "?" { case halves[0] == "?":
outCol.Type = TokenSub outCol.Type = TokenSub
} else { default:
outCol.Type = TokenColumn outCol.Type = TokenColumn
} }
@ -144,7 +151,7 @@ func (wh *DBWhere) parseColumn(seg string, i int) int {
return i return i
} }
func (wh *DBWhere) parseFunction(seg string, buffer string, i int) int { func (wh *DBWhere) parseFunction(seg, buffer string, i int) int {
preI := i preI := i
i = skipFunctionCall(seg, i-1) i = skipFunctionCall(seg, i-1)
buffer += seg[preI:i] + string(seg[i]) buffer += seg[preI:i] + string(seg[i])
@ -299,7 +306,7 @@ func (set *DBSetter) parseColumn(seg string, i int) int {
return i return i
} }
func (set *DBSetter) parseFunction(segment string, buffer string, i int) int { func (set *DBSetter) parseFunction(segment, buffer string, i int) int {
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])

View File

@ -265,9 +265,9 @@ func startDirSizeTask() {
dstMuGuess = 0 dstMuGuess = 0
dstMu.Unlock() dstMu.Unlock()
}() }()
dDirSize, err := c.DirSize(".") dDirSize, e := c.DirSize(".")
if err != nil { if e != nil {
c.LogWarning(err) c.LogWarning(e)
} }
cachedDirSize.Store(dirSize{dDirSize, time.Now()}) cachedDirSize.Store(dirSize{dDirSize, time.Now()})
}() }()

View File

@ -9,7 +9,7 @@ import (
) )
func Plugins(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { func Plugins(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
basePage, ferr := buildBasePage(w, r, u, "plugins", "plugins") bp, ferr := buildBasePage(w, r, u, "plugins", "plugins")
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
@ -17,12 +17,13 @@ func Plugins(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
return c.NoPermissions(w, r, u) return c.NoPermissions(w, r, u)
} }
var plList []interface{} plList, i := make([]interface{}, len(c.Plugins)), 0
for _, pl := range c.Plugins { for _, pl := range c.Plugins {
plList = append(plList, pl) plList[i] = pl
i++
} }
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_plugins", c.PanelPage{basePage, plList, nil}}) return renderTemplate("panel", w, r, bp.Header, c.Panel{bp, "", "", "panel_plugins", c.PanelPage{bp, plList, nil}})
} }
// TODO: Abstract more of the plugin activation / installation / deactivation logic, so we can test all that more reliably and easily // TODO: Abstract more of the plugin activation / installation / deactivation logic, so we can test all that more reliably and easily

View File

@ -0,0 +1,10 @@
CREATE TABLE [forums_actions] (
[faid] int not null IDENTITY,
[fid] int not null,
[runOnTopicCreation] bit DEFAULT 0 not null,
[runDaysAfterTopicCreation] int DEFAULT 0 not null,
[runDaysAfterTopicLastReply] int DEFAULT 0 not null,
[action] nvarchar (50) not null,
[extra] nvarchar (200) DEFAULT '' not null,
primary key([faid])
);

View File

@ -0,0 +1,10 @@
CREATE TABLE "forums_actions" (
`faid` serial not null,
`fid` int not null,
`runOnTopicCreation` boolean DEFAULT 0 not null,
`runDaysAfterTopicCreation` int DEFAULT 0 not null,
`runDaysAfterTopicLastReply` int DEFAULT 0 not null,
`action` varchar (50) not null,
`extra` varchar (200) DEFAULT '' not null,
primary key(`faid`)
);