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:
parent
05a8adb25e
commit
ac0dd6d2cb
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
2
mysql.go
2
mysql.go
|
@ -3,7 +3,7 @@
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Gosora MySQL Interface
|
* Gosora MySQL Interface
|
||||||
* Copyright Azareal 2016 - 2019
|
* Copyright Azareal 2016 - 2020
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -4,7 +4,7 @@ type dateCutoff struct {
|
||||||
Column string
|
Column string
|
||||||
Quantity int
|
Quantity int
|
||||||
Unit string
|
Unit string
|
||||||
Type int
|
Type int
|
||||||
}
|
}
|
||||||
|
|
||||||
type prebuilder struct {
|
type prebuilder struct {
|
||||||
|
@ -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 {
|
||||||
|
@ -70,7 +79,7 @@ type updatePrebuilder struct {
|
||||||
table string
|
table string
|
||||||
set string
|
set string
|
||||||
where string
|
where string
|
||||||
dateCutoff *dateCutoff // We might want to do this in a slightly less hacky way
|
dateCutoff *dateCutoff // We might want to do this in a slightly less hacky way
|
||||||
whereSubQuery *selectPrebuilder
|
whereSubQuery *selectPrebuilder
|
||||||
|
|
||||||
build Adapter
|
build Adapter
|
||||||
|
@ -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 {
|
||||||
|
|
|
@ -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 == "" {
|
||||||
|
|
|
@ -345,7 +345,7 @@ func (adapter *MysqlAdapter) SimpleUpsert(name string, table string, columns str
|
||||||
if where == "" {
|
if where == "" {
|
||||||
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 + "`("
|
var querystr = "INSERT INTO `" + table + "`("
|
||||||
var parsedFields = processFields(fields)
|
var parsedFields = processFields(fields)
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
return q[0 : len(q)-4], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *MysqlAdapter) buildOrderby(orderby string) (querystr string) {
|
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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
11
tickloop.go
11
tickloop.go
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue