The login and registration logs are pruned after a year now.

Add filter exclusions for the user agents analytics pane.
Shorten some of the variable names in qgen.

Add ComplexDelete to the query adapter.
Add DateCutoff and DateOlderThan to accDeleteBuilder.
This commit is contained in:
Azareal 2019-06-05 14:57:10 +10:00
parent 05a8adb25e
commit ac0dd6d2cb
12 changed files with 382 additions and 283 deletions

View File

@ -91,6 +91,7 @@ type config struct {
PrimaryServer bool PrimaryServer bool
ServerCount int ServerCount int
PostIPCutoff int PostIPCutoff int
LogPruneCutoff int
DisableLiveTopicList bool DisableLiveTopicList bool
DisableJSAntispam bool DisableJSAntispam bool
@ -204,6 +205,9 @@ func ProcessConfig() (err error) {
if Config.PostIPCutoff == 0 { if Config.PostIPCutoff == 0 {
Config.PostIPCutoff = 180 // Default cutoff Config.PostIPCutoff = 180 // Default cutoff
} }
if Config.LogPruneCutoff == 0 {
Config.LogPruneCutoff = 365 // Default cutoff
}
// ? Find a way of making these unlimited if zero? It might rule out some optimisations, waste memory, and break layouts // ? Find a way of making these unlimited if zero? It might rule out some optimisations, waste memory, and break layouts
if Config.MaxTopicTitleLength == 0 { if Config.MaxTopicTitleLength == 0 {

View File

@ -86,6 +86,8 @@ ServerCount - The number of instances you're running. This setting is currently
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 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
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
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
DisableJSAntispam - This switch lets you disable the JS anti-spam feature. It may be useful if you primarily get users who for one reason or another have decided to disable JavaScript. Default: false DisableJSAntispam - This switch lets you disable the JS anti-spam feature. It may be useful if you primarily get users who for one reason or another have decided to disable JavaScript. Default: false

View File

@ -3,7 +3,7 @@
/* /*
* *
* Gosora MySQL Interface * Gosora MySQL Interface
* Copyright Azareal 2016 - 2019 * Copyright Azareal 2016 - 2020
* *
*/ */
package main package main

View File

@ -8,26 +8,47 @@ import (
type accDeleteBuilder struct { type accDeleteBuilder struct {
table string table string
where string where string
dateCutoff *dateCutoff // We might want to do this in a slightly less hacky way
build *Accumulator build *Accumulator
} }
func (builder *accDeleteBuilder) Where(where string) *accDeleteBuilder { func (b *accDeleteBuilder) Where(where string) *accDeleteBuilder {
if builder.where != "" { if b.where != "" {
builder.where += " AND " b.where += " AND "
} }
builder.where += where b.where += where
return builder return b
} }
func (builder *accDeleteBuilder) Prepare() *sql.Stmt { func (b *accDeleteBuilder) DateCutoff(column string, quantity int, unit string) *accDeleteBuilder {
return builder.build.SimpleDelete(builder.table, builder.where) b.dateCutoff = &dateCutoff{column, quantity, unit, 0}
return b
} }
func (builder *accDeleteBuilder) Run(args ...interface{}) (int, error) { func (b *accDeleteBuilder) DateOlderThan(column string, quantity int, unit string) *accDeleteBuilder {
stmt := builder.Prepare() b.dateCutoff = &dateCutoff{column, quantity, unit, 1}
return b
}
/*func (b *accDeleteBuilder) Prepare() *sql.Stmt {
return b.build.SimpleDelete(b.table, b.where)
}*/
// TODO: Fix this nasty hack
func (b *accDeleteBuilder) Prepare() *sql.Stmt {
// TODO: Phase out the procedural API and use the adapter's OO API? The OO API might need a bit more work before we do that and it needs to be rolled out to MSSQL.
if b.dateCutoff != nil {
dBuilder := b.build.GetAdapter().Builder().Delete().FromAcc(b)
return b.build.prepare(b.build.GetAdapter().ComplexDelete(dBuilder))
}
return b.build.SimpleDelete(b.table, b.where)
}
func (b *accDeleteBuilder) Run(args ...interface{}) (int, error) {
stmt := b.Prepare()
if stmt == nil { if stmt == nil {
return 0, builder.build.FirstError() return 0, b.build.FirstError()
} }
res, err := stmt.Exec(args...) res, err := stmt.Exec(args...)
@ -57,26 +78,26 @@ func (u *accUpdateBuilder) Where(where string) *accUpdateBuilder {
return u return u
} }
func (u *accUpdateBuilder) DateCutoff(column string, quantity int, unit string) *accUpdateBuilder { func (b *accUpdateBuilder) DateCutoff(column string, quantity int, unit string) *accUpdateBuilder {
u.up.dateCutoff = &dateCutoff{column, quantity, unit, 0} b.up.dateCutoff = &dateCutoff{column, quantity, unit, 0}
return u return b
} }
func (u *accUpdateBuilder) DateOlderThan(column string, quantity int, unit string) *accUpdateBuilder { func (b *accUpdateBuilder) DateOlderThan(column string, quantity int, unit string) *accUpdateBuilder {
u.up.dateCutoff = &dateCutoff{column, quantity, unit, 1} b.up.dateCutoff = &dateCutoff{column, quantity, unit, 1}
return u return b
} }
func (u *accUpdateBuilder) WhereQ(sel *selectPrebuilder) *accUpdateBuilder { func (b *accUpdateBuilder) WhereQ(sel *selectPrebuilder) *accUpdateBuilder {
u.up.whereSubQuery = sel b.up.whereSubQuery = sel
return u return b
} }
func (u *accUpdateBuilder) Prepare() *sql.Stmt { func (b *accUpdateBuilder) Prepare() *sql.Stmt {
if u.up.whereSubQuery != nil { if b.up.whereSubQuery != nil {
return u.build.prepare(u.build.adapter.SimpleUpdateSelect(u.up)) return b.build.prepare(b.build.adapter.SimpleUpdateSelect(b.up))
} }
return u.build.prepare(u.build.adapter.SimpleUpdate(u.up)) return b.build.prepare(b.build.adapter.SimpleUpdate(b.up))
} }
func (u *accUpdateBuilder) Exec(args ...interface{}) (res sql.Result, err error) { func (u *accUpdateBuilder) Exec(args ...interface{}) (res sql.Result, err error) {
@ -100,28 +121,28 @@ type AccSelectBuilder struct {
build *Accumulator build *Accumulator
} }
func (builder *AccSelectBuilder) Columns(columns string) *AccSelectBuilder { func (b *AccSelectBuilder) Columns(columns string) *AccSelectBuilder {
builder.columns = columns b.columns = columns
return builder return b
} }
func (builder *AccSelectBuilder) Cols(columns string) *AccSelectBuilder { func (b *AccSelectBuilder) Cols(columns string) *AccSelectBuilder {
builder.columns = columns b.columns = columns
return builder return b
} }
func (builder *AccSelectBuilder) Where(where string) *AccSelectBuilder { func (b *AccSelectBuilder) Where(where string) *AccSelectBuilder {
if builder.where != "" { if b.where != "" {
builder.where += " AND " b.where += " AND "
} }
builder.where += where b.where += where
return builder return b
} }
// TODO: Don't implement the SQL at the accumulator level but the adapter level // TODO: Don't implement the SQL at the accumulator level but the adapter level
func (selectItem *AccSelectBuilder) In(column string, inList []int) *AccSelectBuilder { func (b *AccSelectBuilder) In(column string, inList []int) *AccSelectBuilder {
if len(inList) == 0 { if len(inList) == 0 {
return selectItem return b
} }
var where = column + " IN(" var where = column + " IN("
@ -129,59 +150,59 @@ func (selectItem *AccSelectBuilder) In(column string, inList []int) *AccSelectBu
where += strconv.Itoa(item) + "," where += strconv.Itoa(item) + ","
} }
where = where[:len(where)-1] + ")" where = where[:len(where)-1] + ")"
if selectItem.where != "" { if b.where != "" {
where += " AND " + selectItem.where where += " AND " + b.where
} }
selectItem.where = where b.where = where
return selectItem return b
} }
func (selectItem *AccSelectBuilder) InQ(column string, subBuilder *AccSelectBuilder) *AccSelectBuilder { func (b *AccSelectBuilder) InQ(column string, subBuilder *AccSelectBuilder) *AccSelectBuilder {
selectItem.inChain = subBuilder b.inChain = subBuilder
selectItem.inColumn = column b.inColumn = column
return selectItem return b
} }
func (builder *AccSelectBuilder) DateCutoff(column string, quantity int, unit string) *AccSelectBuilder { func (b *AccSelectBuilder) DateCutoff(column string, quantity int, unit string) *AccSelectBuilder {
builder.dateCutoff = &dateCutoff{column, quantity, unit, 0} b.dateCutoff = &dateCutoff{column, quantity, unit, 0}
return builder return b
} }
func (builder *AccSelectBuilder) Orderby(orderby string) *AccSelectBuilder { func (b *AccSelectBuilder) Orderby(orderby string) *AccSelectBuilder {
builder.orderby = orderby b.orderby = orderby
return builder return b
} }
func (builder *AccSelectBuilder) Limit(limit string) *AccSelectBuilder { func (b *AccSelectBuilder) Limit(limit string) *AccSelectBuilder {
builder.limit = limit b.limit = limit
return builder return b
} }
func (builder *AccSelectBuilder) Prepare() *sql.Stmt { func (b *AccSelectBuilder) Prepare() *sql.Stmt {
// TODO: Phase out the procedural API and use the adapter's OO API? The OO API might need a bit more work before we do that and it needs to be rolled out to MSSQL. // TODO: Phase out the procedural API and use the adapter's OO API? The OO API might need a bit more work before we do that and it needs to be rolled out to MSSQL.
if builder.dateCutoff != nil || builder.inChain != nil { if b.dateCutoff != nil || b.inChain != nil {
selectBuilder := builder.build.GetAdapter().Builder().Select().FromAcc(builder) selectBuilder := b.build.GetAdapter().Builder().Select().FromAcc(b)
return builder.build.prepare(builder.build.GetAdapter().ComplexSelect(selectBuilder)) return b.build.prepare(b.build.GetAdapter().ComplexSelect(selectBuilder))
} }
return builder.build.SimpleSelect(builder.table, builder.columns, builder.where, builder.orderby, builder.limit) return b.build.SimpleSelect(b.table, b.columns, b.where, b.orderby, b.limit)
} }
func (builder *AccSelectBuilder) query() (string, error) { func (b *AccSelectBuilder) query() (string, error) {
// TODO: Phase out the procedural API and use the adapter's OO API? The OO API might need a bit more work before we do that and it needs to be rolled out to MSSQL. // TODO: Phase out the procedural API and use the adapter's OO API? The OO API might need a bit more work before we do that and it needs to be rolled out to MSSQL.
if builder.dateCutoff != nil || builder.inChain != nil { if b.dateCutoff != nil || b.inChain != nil {
selectBuilder := builder.build.GetAdapter().Builder().Select().FromAcc(builder) selectBuilder := b.build.GetAdapter().Builder().Select().FromAcc(b)
return builder.build.GetAdapter().ComplexSelect(selectBuilder) return b.build.GetAdapter().ComplexSelect(selectBuilder)
} }
return builder.build.adapter.SimpleSelect("", builder.table, builder.columns, builder.where, builder.orderby, builder.limit) return b.build.adapter.SimpleSelect("", b.table, b.columns, b.where, b.orderby, b.limit)
} }
func (builder *AccSelectBuilder) Query(args ...interface{}) (*sql.Rows, error) { func (b *AccSelectBuilder) Query(args ...interface{}) (*sql.Rows, error) {
stmt := builder.Prepare() stmt := b.Prepare()
if stmt != nil { if stmt != nil {
return stmt.Query(args...) return stmt.Query(args...)
} }
return nil, builder.build.FirstError() return nil, b.build.FirstError()
} }
type AccRowWrap struct { type AccRowWrap struct {
@ -197,21 +218,21 @@ func (wrap *AccRowWrap) Scan(dest ...interface{}) error {
} }
// TODO: Test to make sure the errors are passed up properly // TODO: Test to make sure the errors are passed up properly
func (builder *AccSelectBuilder) QueryRow(args ...interface{}) *AccRowWrap { func (b *AccSelectBuilder) QueryRow(args ...interface{}) *AccRowWrap {
stmt := builder.Prepare() stmt := b.Prepare()
if stmt != nil { if stmt != nil {
return &AccRowWrap{stmt.QueryRow(args...), nil} return &AccRowWrap{stmt.QueryRow(args...), nil}
} }
return &AccRowWrap{nil, builder.build.FirstError()} return &AccRowWrap{nil, b.build.FirstError()}
} }
// Experimental, reduces lines // Experimental, reduces lines
func (builder *AccSelectBuilder) Each(handle func(*sql.Rows) error) error { func (b *AccSelectBuilder) Each(handle func(*sql.Rows) error) error {
query, err := builder.query() query, err := b.query()
if err != nil { if err != nil {
return err return err
} }
rows, err := builder.build.query(query) rows, err := b.build.query(query)
if err != nil { if err != nil {
return err return err
} }
@ -225,12 +246,12 @@ func (builder *AccSelectBuilder) Each(handle func(*sql.Rows) error) error {
} }
return rows.Err() return rows.Err()
} }
func (builder *AccSelectBuilder) EachInt(handle func(int) error) error { func (b *AccSelectBuilder) EachInt(handle func(int) error) error {
query, err := builder.query() query, err := b.query()
if err != nil { if err != nil {
return err return err
} }
rows, err := builder.build.query(query) rows, err := b.build.query(query)
if err != nil { if err != nil {
return err return err
} }
@ -258,34 +279,34 @@ type accInsertBuilder struct {
build *Accumulator build *Accumulator
} }
func (insert *accInsertBuilder) Columns(columns string) *accInsertBuilder { func (b *accInsertBuilder) Columns(columns string) *accInsertBuilder {
insert.columns = columns b.columns = columns
return insert return b
} }
func (insert *accInsertBuilder) Fields(fields string) *accInsertBuilder { func (b *accInsertBuilder) Fields(fields string) *accInsertBuilder {
insert.fields = fields b.fields = fields
return insert return b
} }
func (insert *accInsertBuilder) Prepare() *sql.Stmt { func (b *accInsertBuilder) Prepare() *sql.Stmt {
return insert.build.SimpleInsert(insert.table, insert.columns, insert.fields) return b.build.SimpleInsert(b.table, b.columns, b.fields)
} }
func (builder *accInsertBuilder) Exec(args ...interface{}) (res sql.Result, err error) { func (b *accInsertBuilder) Exec(args ...interface{}) (res sql.Result, err error) {
query, err := builder.build.adapter.SimpleInsert("", builder.table, builder.columns, builder.fields) query, err := b.build.adapter.SimpleInsert("", b.table, b.columns, b.fields)
if err != nil { if err != nil {
return res, err return res, err
} }
return builder.build.exec(query, args...) return b.build.exec(query, args...)
} }
func (builder *accInsertBuilder) Run(args ...interface{}) (int, error) { func (b *accInsertBuilder) Run(args ...interface{}) (int, error) {
query, err := builder.build.adapter.SimpleInsert("", builder.table, builder.columns, builder.fields) query, err := b.build.adapter.SimpleInsert("", b.table, b.columns, b.fields)
if err != nil { if err != nil {
return 0, err return 0, err
} }
res, err := builder.build.exec(query, args...) res, err := b.build.exec(query, args...)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -224,7 +224,7 @@ func (build *Accumulator) PurgeTx(tx *sql.Tx, table string) (stmt *sql.Stmt) {
} }
func (build *Accumulator) Delete(table string) *accDeleteBuilder { func (build *Accumulator) Delete(table string) *accDeleteBuilder {
return &accDeleteBuilder{table, "", build} return &accDeleteBuilder{table, "", nil, build}
} }
func (build *Accumulator) Update(table string) *accUpdateBuilder { func (build *Accumulator) Update(table string) *accUpdateBuilder {

View File

@ -33,36 +33,45 @@ func (build *prebuilder) Update(nlist ...string) *updatePrebuilder {
func (build *prebuilder) Delete(nlist ...string) *deletePrebuilder { func (build *prebuilder) Delete(nlist ...string) *deletePrebuilder {
name := optString(nlist, "") name := optString(nlist, "")
return &deletePrebuilder{name, "", "", build.adapter} return &deletePrebuilder{name, "", "", nil, build.adapter}
} }
type deletePrebuilder struct { type deletePrebuilder struct {
name string name string
table string table string
where string where string
dateCutoff *dateCutoff
build Adapter build Adapter
} }
func (delete *deletePrebuilder) Table(table string) *deletePrebuilder { func (b *deletePrebuilder) Table(table string) *deletePrebuilder {
delete.table = table b.table = table
return delete return b
} }
func (delete *deletePrebuilder) Where(where string) *deletePrebuilder { func (b *deletePrebuilder) Where(where string) *deletePrebuilder {
if delete.where != "" { if b.where != "" {
delete.where += " AND " b.where += " AND "
} }
delete.where += where b.where += where
return delete return b
} }
func (delete *deletePrebuilder) Text() (string, error) { // TODO: We probably want to avoid the double allocation of two builders somehow
return delete.build.SimpleDelete(delete.name, delete.table, delete.where) func (b *deletePrebuilder) FromAcc(acc *accDeleteBuilder) *deletePrebuilder {
b.table = acc.table
b.where = acc.where
b.dateCutoff = acc.dateCutoff
return b
} }
func (delete *deletePrebuilder) Parse() { func (b *deletePrebuilder) Text() (string, error) {
delete.build.SimpleDelete(delete.name, delete.table, delete.where) return b.build.SimpleDelete(b.name, b.table, b.where)
}
func (b *deletePrebuilder) Parse() {
b.build.SimpleDelete(b.name, b.table, b.where)
} }
type updatePrebuilder struct { type updatePrebuilder struct {
@ -80,35 +89,35 @@ func qUpdate(table string, set string, where string) *updatePrebuilder {
return &updatePrebuilder{table: table, set: set, where: where} return &updatePrebuilder{table: table, set: set, where: where}
} }
func (update *updatePrebuilder) Table(table string) *updatePrebuilder { func (b *updatePrebuilder) Table(table string) *updatePrebuilder {
update.table = table b.table = table
return update return b
} }
func (update *updatePrebuilder) Set(set string) *updatePrebuilder { func (b *updatePrebuilder) Set(set string) *updatePrebuilder {
update.set = set b.set = set
return update return b
} }
func (update *updatePrebuilder) Where(where string) *updatePrebuilder { func (b *updatePrebuilder) Where(where string) *updatePrebuilder {
if update.where != "" { if b.where != "" {
update.where += " AND " b.where += " AND "
} }
update.where += where b.where += where
return update return b
} }
func (update *updatePrebuilder) WhereQ(sel *selectPrebuilder) *updatePrebuilder { func (b *updatePrebuilder) WhereQ(sel *selectPrebuilder) *updatePrebuilder {
update.whereSubQuery = sel b.whereSubQuery = sel
return update return b
} }
func (update *updatePrebuilder) Text() (string, error) { func (b *updatePrebuilder) Text() (string, error) {
return update.build.SimpleUpdate(update) return b.build.SimpleUpdate(b)
} }
func (update *updatePrebuilder) Parse() { func (b *updatePrebuilder) Parse() {
update.build.SimpleUpdate(update) b.build.SimpleUpdate(b)
} }
type selectPrebuilder struct { type selectPrebuilder struct {
@ -125,22 +134,22 @@ type selectPrebuilder struct {
build Adapter build Adapter
} }
func (selectItem *selectPrebuilder) Table(table string) *selectPrebuilder { func (b *selectPrebuilder) Table(table string) *selectPrebuilder {
selectItem.table = table b.table = table
return selectItem return b
} }
func (selectItem *selectPrebuilder) Columns(columns string) *selectPrebuilder { func (b *selectPrebuilder) Columns(columns string) *selectPrebuilder {
selectItem.columns = columns b.columns = columns
return selectItem return b
} }
func (selectItem *selectPrebuilder) Where(where string) *selectPrebuilder { func (b *selectPrebuilder) Where(where string) *selectPrebuilder {
if selectItem.where != "" { if b.where != "" {
selectItem.where += " AND " b.where += " AND "
} }
selectItem.where += where b.where += where
return selectItem return b
} }
func (b *selectPrebuilder) InQ(subBuilder *selectPrebuilder) *selectPrebuilder { func (b *selectPrebuilder) InQ(subBuilder *selectPrebuilder) *selectPrebuilder {
@ -190,13 +199,13 @@ func (b *selectPrebuilder) FromCountAcc(acc *accCountBuilder) *selectPrebuilder
} }
// TODO: Add support for dateCutoff // TODO: Add support for dateCutoff
func (selectItem *selectPrebuilder) Text() (string, error) { func (b *selectPrebuilder) Text() (string, error) {
return selectItem.build.SimpleSelect(selectItem.name, selectItem.table, selectItem.columns, selectItem.where, selectItem.orderby, selectItem.limit) return b.build.SimpleSelect(b.name, b.table, b.columns, b.where, b.orderby, b.limit)
} }
// TODO: Add support for dateCutoff // TODO: Add support for dateCutoff
func (selectItem *selectPrebuilder) Parse() { func (b *selectPrebuilder) Parse() {
selectItem.build.SimpleSelect(selectItem.name, selectItem.table, selectItem.columns, selectItem.where, selectItem.orderby, selectItem.limit) b.build.SimpleSelect(b.name, b.table, b.columns, b.where, b.orderby, b.limit)
} }
type insertPrebuilder struct { type insertPrebuilder struct {
@ -208,27 +217,27 @@ type insertPrebuilder struct {
build Adapter build Adapter
} }
func (insert *insertPrebuilder) Table(table string) *insertPrebuilder { func (b *insertPrebuilder) Table(table string) *insertPrebuilder {
insert.table = table b.table = table
return insert return b
} }
func (insert *insertPrebuilder) Columns(columns string) *insertPrebuilder { func (b *insertPrebuilder) Columns(columns string) *insertPrebuilder {
insert.columns = columns b.columns = columns
return insert return b
} }
func (insert *insertPrebuilder) Fields(fields string) *insertPrebuilder { func (b *insertPrebuilder) Fields(fields string) *insertPrebuilder {
insert.fields = fields b.fields = fields
return insert return b
} }
func (insert *insertPrebuilder) Text() (string, error) { func (b *insertPrebuilder) Text() (string, error) {
return insert.build.SimpleInsert(insert.name, insert.table, insert.columns, insert.fields) return b.build.SimpleInsert(b.name, b.table, b.columns, b.fields)
} }
func (insert *insertPrebuilder) Parse() { func (b *insertPrebuilder) Parse() {
insert.build.SimpleInsert(insert.name, insert.table, insert.columns, insert.fields) b.build.SimpleInsert(b.name, b.table, b.columns, b.fields)
} }
/*type countPrebuilder struct { /*type countPrebuilder struct {
@ -240,30 +249,30 @@ func (insert *insertPrebuilder) Parse() {
build Adapter build Adapter
} }
func (count *countPrebuilder) Table(table string) *countPrebuilder { func (b *countPrebuilder) Table(table string) *countPrebuilder {
count.table = table b.table = table
return count return b
} }
func (count *countPrebuilder) Where(where string) *countPrebuilder { func b *countPrebuilder) Where(where string) *countPrebuilder {
if count.where != "" { if b.where != "" {
count.where += " AND " b.where += " AND "
} }
count.where += where b.where += where
return count return b
} }
func (count *countPrebuilder) Limit(limit string) *countPrebuilder { func (b *countPrebuilder) Limit(limit string) *countPrebuilder {
count.limit = limit b.limit = limit
return count return b
} }
func (count *countPrebuilder) Text() (string, error) { func (b *countPrebuilder) Text() (string, error) {
return count.build.SimpleCount(count.name, count.table, count.where, count.limit) return b.build.SimpleCount(b.name, b.table, b.where, b.limit)
} }
func (count *countPrebuilder) Parse() { func (b *countPrebuilder) Parse() {
count.build.SimpleCount(count.name, count.table, count.where, count.limit) b.build.SimpleCount(b.name, b.table, b.where, b.limit)
}*/ }*/
func optString(nlist []string, defaultStr string) string { func optString(nlist []string, defaultStr string) string {

View File

@ -428,7 +428,7 @@ func (adapter *MssqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error)
return querystr, nil return querystr, nil
} }
func (adapter *MssqlAdapter) SimpleUpdateSelect(up *updatePrebuilder) (string, error) { func (adapter *MssqlAdapter) SimpleUpdateSelect(b *updatePrebuilder) (string, error) {
return "", errors.New("not implemented") return "", errors.New("not implemented")
} }
@ -470,6 +470,10 @@ func (adapter *MssqlAdapter) SimpleDelete(name string, table string, where strin
return querystr, nil return querystr, nil
} }
func (adapter *MssqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) {
return "", errors.New("not implemented")
}
// 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 *MssqlAdapter) Purge(name string, table string) (string, error) { func (adapter *MssqlAdapter) Purge(name string, table string) (string, error) {
if table == "" { if table == "" {

View File

@ -385,32 +385,32 @@ func (adapter *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error)
return "", errors.New("You need to set data in this update statement") return "", errors.New("You need to set data in this update statement")
} }
var querystr = "UPDATE `" + up.table + "` SET " var q = "UPDATE `" + up.table + "` SET "
for _, item := range processSet(up.set) { for _, item := range processSet(up.set) {
querystr += "`" + item.Column + "` =" q += "`" + 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 "function", "operator", "number", "substitute", "or":
querystr += " " + token.Contents q += " " + token.Contents
case "column": case "column":
querystr += " `" + token.Contents + "`" q += " `" + token.Contents + "`"
case "string": case "string":
querystr += " '" + token.Contents + "'" q += " '" + token.Contents + "'"
} }
} }
querystr += "," q += ","
} }
querystr = querystr[0 : len(querystr)-1] q = q[0 : len(q)-1]
whereStr, err := adapter.buildFlexiWhere(up.where,up.dateCutoff) whereStr, err := adapter.buildFlexiWhere(up.where,up.dateCutoff)
if err != nil { if err != nil {
return querystr, err return q, err
} }
querystr += 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(up.name, "update", querystr) adapter.pushStatement(up.name, "update", q)
return querystr, nil return q, nil
} }
func (adapter *MysqlAdapter) SimpleDelete(name string, table string, where string) (string, error) { func (adapter *MysqlAdapter) SimpleDelete(name string, table string, where string) (string, error) {
@ -421,29 +421,49 @@ func (adapter *MysqlAdapter) SimpleDelete(name string, table string, where strin
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 querystr = "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 "function", "operator", "number", "substitute", "or":
querystr += " " + token.Contents q += " " + token.Contents
case "column": case "column":
querystr += " `" + token.Contents + "`" q += " `" + token.Contents + "`"
case "string": case "string":
querystr += " '" + token.Contents + "'" q += " '" + token.Contents + "'"
default: default:
panic("This token doesn't exist o_o") panic("This token doesn't exist o_o")
} }
} }
querystr += " AND" q += " AND"
} }
querystr = strings.TrimSpace(querystr[0 : len(querystr)-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", querystr) adapter.pushStatement(name, "delete", q)
return querystr, nil return q, nil
}
func (adapter *MysqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) {
if b.table == "" {
return "", errors.New("You need a name for this table")
}
if b.where == "" && b.dateCutoff == nil {
return "", errors.New("You need to specify what data you want to delete")
}
var q = "DELETE FROM `" + b.table + "`"
whereStr, err := adapter.buildFlexiWhere(b.where, b.dateCutoff)
if err != nil {
return q, err
}
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
adapter.pushStatement(b.name, "delete", q)
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
@ -451,76 +471,80 @@ func (adapter *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")
} }
adapter.pushStatement(name, "purge", "DELETE FROM `"+table+"`") q := "DELETE FROM `"+table+"`"
return "DELETE FROM `" + table + "`", nil adapter.pushStatement(name, "purge", q)
return q, nil
} }
func (adapter *MysqlAdapter) buildWhere(where string) (querystr string, err error) { func (adapter *MysqlAdapter) buildWhere(where string) (q string, err error) {
if len(where) == 0 { if len(where) == 0 {
return "", nil return "", nil
} }
querystr = " 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 "function", "operator", "number", "substitute", "or":
querystr += " " + token.Contents q += " " + token.Contents
case "column": case "column":
querystr += " `" + token.Contents + "`" q += " `" + token.Contents + "`"
case "string": case "string":
querystr += " '" + token.Contents + "'" q += " '" + token.Contents + "'"
default: default:
return querystr, errors.New("This token doesn't exist o_o") return q, errors.New("This token doesn't exist o_o")
} }
} }
querystr += " AND" q += " AND"
} }
return querystr[0 : len(querystr)-4], nil return q[0 : len(q)-4], nil
} }
// 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) (querystr string, err error) { func (adapter *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
} }
querystr = " WHERE"
q = " WHERE"
if dateCutoff != nil { if dateCutoff != nil {
if dateCutoff.Type == 0 { if dateCutoff.Type == 0 {
querystr += " " + dateCutoff.Column + " BETWEEN (UTC_TIMESTAMP() - interval " + strconv.Itoa(dateCutoff.Quantity) + " " + dateCutoff.Unit + ") AND UTC_TIMESTAMP() AND" q += " " + dateCutoff.Column + " BETWEEN (UTC_TIMESTAMP() - interval " + strconv.Itoa(dateCutoff.Quantity) + " " + dateCutoff.Unit + ") AND UTC_TIMESTAMP() AND"
} else { } else {
querystr += " " + dateCutoff.Column + " < UTC_TIMESTAMP() - interval " + strconv.Itoa(dateCutoff.Quantity) + " " + dateCutoff.Unit + " AND" q += " " + dateCutoff.Column + " < UTC_TIMESTAMP() - interval " + strconv.Itoa(dateCutoff.Quantity) + " " + dateCutoff.Unit + " AND"
} }
} }
if len(where) != 0 { if len(where) != 0 {
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 "function", "operator", "number", "substitute", "or":
querystr += " " + token.Contents q += " " + token.Contents
case "column": case "column":
querystr += " `" + token.Contents + "`" q += " `" + token.Contents + "`"
case "string": case "string":
querystr += " '" + token.Contents + "'" q += " '" + token.Contents + "'"
default: default:
return querystr, errors.New("This token doesn't exist o_o") return q, errors.New("This token doesn't exist o_o")
} }
} }
querystr += " AND" q += " AND"
} }
} }
return querystr[0 : len(querystr)-4], nil
}
func (adapter *MysqlAdapter) buildOrderby(orderby string) (querystr string) { return q[0 : len(q)-4], nil
}
func (adapter *MysqlAdapter) buildOrderby(orderby string) (q string) {
if len(orderby) != 0 { if len(orderby) != 0 {
querystr = " ORDER BY " q = " ORDER BY "
for _, column := range processOrderby(orderby) { for _, column := range processOrderby(orderby) {
// TODO: We might want to escape this column // TODO: We might want to escape this column
querystr += "`" + strings.Replace(column.Column, ".", "`.`", -1) + "` " + strings.ToUpper(column.Order) + "," q += "`" + strings.Replace(column.Column, ".", "`.`", -1) + "` " + strings.ToUpper(column.Order) + ","
} }
querystr = querystr[0 : len(querystr)-1] q = q[0 : len(q)-1]
} }
return querystr return q
} }
func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) { func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
@ -530,25 +554,23 @@ func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns str
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 "
var querystr = "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), ",") {
querystr += "`" + strings.TrimSpace(column) + "`," q += "`" + strings.TrimSpace(column) + "`,"
} }
querystr = querystr[0 : len(querystr)-1] q = q[0 : len(q)-1]
whereStr, err := adapter.buildWhere(where) whereStr, err := adapter.buildWhere(where)
if err != nil { if err != nil {
return querystr, err return q, err
} }
q += " FROM `" + table + "`" + whereStr + adapter.buildOrderby(orderby) + adapter.buildLimit(limit)
querystr += " FROM `" + table + "`" + whereStr + adapter.buildOrderby(orderby) + adapter.buildLimit(limit) q = strings.TrimSpace(q)
adapter.pushStatement(name, "select", q)
querystr = strings.TrimSpace(querystr) return q, nil
adapter.pushStatement(name, "select", querystr)
return querystr, nil
} }
func (adapter *MysqlAdapter) ComplexSelect(preBuilder *selectPrebuilder) (out string, err error) { func (adapter *MysqlAdapter) ComplexSelect(preBuilder *selectPrebuilder) (out string, err error) {
@ -558,35 +580,28 @@ func (adapter *MysqlAdapter) ComplexSelect(preBuilder *selectPrebuilder) (out st
if len(preBuilder.columns) == 0 { if len(preBuilder.columns) == 0 {
return "", errors.New("No columns found for ComplexSelect") return "", errors.New("No columns found for ComplexSelect")
} }
var q = "SELECT " + adapter.buildJoinColumns(preBuilder.columns)
var querystr = "SELECT " + adapter.buildJoinColumns(preBuilder.columns)
// Slice up the user friendly strings into something easier to process
/*for _, column := range strings.Split(strings.TrimSpace(preBuilder.columns), ",") {
querystr += "`" + strings.TrimSpace(column) + "`,"
}
querystr = querystr[0 : len(querystr)-1]*/
var whereStr string var whereStr string
// TODO: Let callers have a Where() and a InQ() // TODO: Let callers have a Where() and a InQ()
if preBuilder.inChain != nil { if preBuilder.inChain != nil {
whereStr, err = adapter.ComplexSelect(preBuilder.inChain) whereStr, err = adapter.ComplexSelect(preBuilder.inChain)
if err != nil { if err != nil {
return querystr, err return q, err
} }
whereStr = " WHERE `" + preBuilder.inColumn + "` IN(" + whereStr + ")" whereStr = " WHERE `" + preBuilder.inColumn + "` IN(" + whereStr + ")"
} else { } else {
whereStr, err = adapter.buildFlexiWhere(preBuilder.where, preBuilder.dateCutoff) whereStr, err = adapter.buildFlexiWhere(preBuilder.where, preBuilder.dateCutoff)
if err != nil { if err != nil {
return querystr, err return q, err
} }
} }
querystr += " FROM `" + preBuilder.table + "`" + whereStr + adapter.buildOrderby(preBuilder.orderby) + adapter.buildLimit(preBuilder.limit) q += " FROM `" + preBuilder.table + "`" + whereStr + adapter.buildOrderby(preBuilder.orderby) + adapter.buildLimit(preBuilder.limit)
querystr = strings.TrimSpace(querystr) q = strings.TrimSpace(q)
adapter.pushStatement(preBuilder.name, "select", querystr) adapter.pushStatement(preBuilder.name, "select", q)
return querystr, nil return q, nil
} }
func (adapter *MysqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) { func (adapter *MysqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
@ -678,11 +693,11 @@ func (adapter *MysqlAdapter) SimpleInsertSelect(name string, ins DBInsert, sel D
return "", err return "", err
} }
var querystr = "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) 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)
querystr = strings.TrimSpace(querystr) q = strings.TrimSpace(q)
adapter.pushStatement(name, "insert", querystr) adapter.pushStatement(name, "insert", q)
return querystr, nil return q, nil
} }
func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel DBJoin) (string, error) { func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel DBJoin) (string, error) {
@ -691,59 +706,59 @@ func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DBInsert, sel
return "", err return "", err
} }
var querystr = "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) var 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)
querystr = strings.TrimSpace(querystr) q = strings.TrimSpace(q)
adapter.pushStatement(name, "insert", querystr) adapter.pushStatement(name, "insert", q)
return querystr, 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) (querystr string) { func (adapter *MysqlAdapter) buildJoiners(joiners string) (q string) {
for _, joiner := range processJoiner(joiners) { for _, joiner := range processJoiner(joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND " q += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
} }
// Remove the trailing AND // Remove the trailing AND
return querystr[0 : len(querystr)-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) (querystr string, err error) { func (adapter *MysqlAdapter) buildJoinWhere(where string) (q string, err error) {
if len(where) != 0 { if len(where) != 0 {
querystr = " 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 "function", "operator", "number", "substitute", "or":
querystr += " " + token.Contents q += " " + token.Contents
case "column": case "column":
halves := strings.Split(token.Contents, ".") halves := strings.Split(token.Contents, ".")
if len(halves) == 2 { if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`" q += " `" + halves[0] + "`.`" + halves[1] + "`"
} else { } else {
querystr += " `" + token.Contents + "`" q += " `" + token.Contents + "`"
} }
case "string": case "string":
querystr += " '" + token.Contents + "'" q += " '" + token.Contents + "'"
default: default:
return querystr, errors.New("This token doesn't exist o_o") return q, errors.New("This token doesn't exist o_o")
} }
} }
querystr += " AND" q += " AND"
} }
querystr = querystr[0 : len(querystr)-4] q = q[0 : len(q)-4]
} }
return querystr, nil return q, nil
} }
func (adapter *MysqlAdapter) buildLimit(limit string) (querystr string) { func (adapter *MysqlAdapter) buildLimit(limit string) (q string) {
if limit != "" { if limit != "" {
querystr = " LIMIT " + limit q = " LIMIT " + limit
} }
return querystr return q
} }
func (adapter *MysqlAdapter) buildJoinColumns(columns string) (querystr string) { func (adapter *MysqlAdapter) buildJoinColumns(columns string) (q string) {
for _, column := range processColumns(columns) { for _, column := range processColumns(columns) {
// 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
@ -769,9 +784,9 @@ func (adapter *MysqlAdapter) buildJoinColumns(columns string) (querystr string)
if column.Alias != "" { if column.Alias != "" {
alias = " AS `" + column.Alias + "`" alias = " AS `" + column.Alias + "`"
} }
querystr += " " + source + alias + "," q += " " + source + alias + ","
} }
return querystr[0 : len(querystr)-1] return q[0 : len(q)-1]
} }
func (adapter *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DBInsert, sel DBJoin) (string, error) { func (adapter *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DBInsert, sel DBJoin) (string, error) {
@ -780,27 +795,26 @@ func (adapter *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DBInsert, se
return "", err return "", err
} }
var querystr = "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) var 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)
querystr = strings.TrimSpace(querystr) q = strings.TrimSpace(q)
adapter.pushStatement(name, "insert", querystr) adapter.pushStatement(name, "insert", q)
return querystr, nil return q, nil
} }
func (adapter *MysqlAdapter) SimpleCount(name string, table string, where string, limit string) (querystr string, err error) { func (adapter *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 := adapter.buildWhere(where)
if err != nil { if err != nil {
return "", err return "", err
} }
querystr = "SELECT COUNT(*) AS `count` FROM `" + table + "`" + whereStr + adapter.buildLimit(limit) q = "SELECT COUNT(*) AS `count` FROM `" + table + "`" + whereStr + adapter.buildLimit(limit)
querystr = strings.TrimSpace(querystr) q = strings.TrimSpace(q)
adapter.pushStatement(name, "select", querystr) adapter.pushStatement(name, "select", q)
return querystr, nil return q, nil
} }
func (adapter *MysqlAdapter) Builder() *prebuilder { func (adapter *MysqlAdapter) Builder() *prebuilder {

View File

@ -319,6 +319,17 @@ func (adapter *PgsqlAdapter) SimpleDelete(name string, table string, where strin
return "", nil return "", nil
} }
// TODO: Implement this
func (adapter *PgsqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) {
if b.table == "" {
return "", errors.New("You need a name for this table")
}
if b.where == "" {
return "", errors.New("You need to specify what data you want to delete")
}
return "", nil
}
// TODO: Implement this // TODO: Implement this
// 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 *PgsqlAdapter) Purge(name string, table string) (string, error) { func (adapter *PgsqlAdapter) Purge(name string, table string) (string, error) {

View File

@ -117,11 +117,12 @@ type Adapter interface {
AddKey(name string, table string, column string, key DBTableKey) (string, error) AddKey(name string, table string, column string, key DBTableKey) (string, error)
AddForeignKey(name string, table string, column string, ftable string, fcolumn string, cascade bool) (out string, e error) AddForeignKey(name string, table string, column string, ftable string, fcolumn string, cascade bool) (out string, e error)
SimpleInsert(name string, table string, columns string, fields string) (string, error) SimpleInsert(name string, table string, columns string, fields string) (string, error)
SimpleUpdate(up *updatePrebuilder) (string, error) SimpleUpdate(b *updatePrebuilder) (string, error)
SimpleUpdateSelect(up *updatePrebuilder) (string, error) // ! Experimental SimpleUpdateSelect(b *updatePrebuilder) (string, error) // ! Experimental
SimpleDelete(name string, table string, where string) (string, error) SimpleDelete(name string, table string, where string) (string, error)
Purge(name string, table string) (string, error) Purge(name string, table string) (string, error)
SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error)
ComplexDelete(b *deletePrebuilder) (string, error)
SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error)
SimpleInnerJoin(string, string, string, string, string, string, string, string) (string, error) SimpleInnerJoin(string, string, string, string, string, string, string, string) (string, error)
SimpleInsertSelect(string, DBInsert, DBSelect) (string, error) SimpleInsertSelect(string, DBInsert, DBSelect) (string, error)

View File

@ -899,19 +899,35 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
} }
ovList := analyticsVMapToOVList(vMap) ovList := analyticsVMapToOVList(vMap)
ex := strings.Split(r.FormValue("ex"), ",")
var inEx = func(name string) bool {
for _, e := range ex {
if e == name {
return true
}
}
return false
}
var vList [][]int64 var vList [][]int64
var legendList []string var legendList []string
var i int var i int
for _, ovitem := range ovList { for _, ovitem := range ovList {
if inEx(ovitem.name) {
continue
}
lName, ok := phrases.GetUserAgentPhrase(ovitem.name)
if !ok {
lName = ovitem.name
}
if inEx(lName) {
continue
}
var viewList []int64 var viewList []int64
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, ovitem.viewMap[value]) viewList = append(viewList, ovitem.viewMap[value])
} }
vList = append(vList, viewList) vList = append(vList, viewList)
lName, ok := phrases.GetUserAgentPhrase(ovitem.name)
if !ok {
lName = ovitem.name
}
legendList = append(legendList, lName) legendList = append(legendList, lName)
if i >= 6 { if i >= 6 {
break break
@ -924,10 +940,16 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
// TODO: Sort this slice // TODO: Sort this slice
var agentItems []c.PanelAnalyticsAgentsItem var agentItems []c.PanelAnalyticsAgentsItem
for agent, count := range agentMap { for agent, count := range agentMap {
if inEx(agent) {
continue
}
aAgent, ok := phrases.GetUserAgentPhrase(agent) aAgent, ok := phrases.GetUserAgentPhrase(agent)
if !ok { if !ok {
aAgent = agent aAgent = agent
} }
if inEx(aAgent) {
continue
}
agentItems = append(agentItems, c.PanelAnalyticsAgentsItem{ agentItems = append(agentItems, c.PanelAnalyticsAgentsItem{
Agent: agent, Agent: agent,
FriendlyAgent: aAgent, FriendlyAgent: aAgent,

View File

@ -164,6 +164,17 @@ func dailies() {
c.LogError(err) c.LogError(err)
} }
if c.Config.LogPruneCutoff > -1 {
_, err := qgen.NewAcc().Delete("login_logs").DateOlderThan("doneAt",c.Config.LogPruneCutoff,"day").Run()
if err != nil {
c.LogError(err)
}
_, err = qgen.NewAcc().Delete("registration_logs").DateOlderThan("doneAt",c.Config.LogPruneCutoff,"day").Run()
if err != nil {
c.LogError(err)
}
}
if c.Config.PostIPCutoff > -1 { if c.Config.PostIPCutoff > -1 {
// TODO: Use unixtime to remove this MySQLesque logic? // TODO: Use unixtime to remove this MySQLesque logic?
_, err := qgen.NewAcc().Update("topics").Set("ipaddress = '0'").DateOlderThan("createdAt",c.Config.PostIPCutoff,"day").Where("ipaddress != '0'").Exec() _, err := qgen.NewAcc().Update("topics").Set("ipaddress = '0'").DateOlderThan("createdAt",c.Config.PostIPCutoff,"day").Where("ipaddress != '0'").Exec()