Add Exec() to accDeleteBuilder.

Add DateOlderThanQ() to accCountBuilder.
Add Stmt() to accCountBuilder.
Add AccExec interface.
Optimise AccSelectBuilder.In() with a string builder.
Use Count() in DefaultActivityStream.Count()
Reduce boilerplate and duplication.
This commit is contained in:
Azareal 2021-04-27 20:35:10 +10:00
parent aa02f9fc48
commit 01a19ede79
2 changed files with 80 additions and 61 deletions

View File

@ -106,12 +106,7 @@ func (s *DefaultActivityStream) AidsByParamsExtra(event string, elementID int, e
return aids, rows.Err() return aids, rows.Err()
} }
// TODO: Write a test for this
// Count returns the total number of activity stream items // Count returns the total number of activity stream items
func (s *DefaultActivityStream) Count() (count int) { func (s *DefaultActivityStream) Count() (count int) {
e := s.count.QueryRow().Scan(&count) return Count(s.count)
if e != nil {
LogError(e)
}
return count
} }

View File

@ -2,6 +2,8 @@ package qgen
import ( import (
"database/sql" "database/sql"
"strings"
//"fmt" //"fmt"
"strconv" "strconv"
) )
@ -51,17 +53,21 @@ func (b *accDeleteBuilder) Prepare() *sql.Stmt {
return b.build.SimpleDelete(b.table, b.where) return b.build.SimpleDelete(b.table, b.where)
} }
func (b *accDeleteBuilder) Run(args ...interface{}) (int, error) { func (b *accDeleteBuilder) Exec(args ...interface{}) (res sql.Result, e error) {
stmt := b.Prepare() stmt := b.Prepare()
if stmt == nil { if stmt == nil {
return 0, b.build.FirstError() return res, b.build.FirstError()
} }
res, err := stmt.Exec(args...) return stmt.Exec(args...)
if err != nil { }
return 0, err
func (b *accDeleteBuilder) Run(args ...interface{}) (int, error) {
res, e := b.Exec(args...)
if e != nil {
return 0, e
} }
lastID, err := res.LastInsertId() lastID, e := res.LastInsertId()
return int(lastID), err return int(lastID), e
} }
type accUpdateBuilder struct { type accUpdateBuilder struct {
@ -116,9 +122,9 @@ func (b *accUpdateBuilder) Stmt() *sql.Stmt {
} }
func (b *accUpdateBuilder) Exec(args ...interface{}) (res sql.Result, err error) { func (b *accUpdateBuilder) Exec(args ...interface{}) (res sql.Result, err error) {
q, err := b.build.adapter.SimpleUpdate(b.up) q, e := b.build.adapter.SimpleUpdate(b.up)
if err != nil { if err != nil {
return res, err return res, e
} }
//fmt.Println("q:", q) //fmt.Println("q:", q)
return b.build.exec(q, args...) return b.build.exec(q, args...)
@ -128,6 +134,10 @@ type AccBuilder interface {
Prepare() *sql.Stmt Prepare() *sql.Stmt
} }
type AccExec interface {
Exec(args ...interface{}) (res sql.Result, err error)
}
type AccSelectBuilder struct { type AccSelectBuilder struct {
table string table string
columns string columns string
@ -165,17 +175,24 @@ func (b *AccSelectBuilder) In(col string, inList []int) *AccSelectBuilder {
return b return b
} }
// TODO: Optimise this var wsb strings.Builder
where := col + " IN(" wsb.Grow(len(col) + 5 + 1 + len(b.where) + (len(inList) * 2))
for _, it := range inList { wsb.WriteString(col)
where += strconv.Itoa(it) + "," wsb.WriteString(" IN(")
for i, it := range inList {
if i != 0 {
wsb.WriteRune(',')
}
wsb.WriteString(strconv.Itoa(it))
} }
where = where[:len(where)-1] + ")"
if b.where != "" { if b.where != "" {
where += " AND " + b.where wsb.WriteString(") AND ")
wsb.WriteString(b.where)
} else {
wsb.WriteRune(')')
} }
b.where = where b.where = wsb.String()
return b return b
} }
@ -368,25 +385,21 @@ func (b *accInsertBuilder) Prepare() *sql.Stmt {
return b.build.SimpleInsert(b.table, b.columns, b.fields) return b.build.SimpleInsert(b.table, b.columns, b.fields)
} }
func (b *accInsertBuilder) Exec(args ...interface{}) (res sql.Result, err error) { func (b *accInsertBuilder) Exec(args ...interface{}) (res sql.Result, e error) {
query, err := b.build.adapter.SimpleInsert("", b.table, b.columns, b.fields) q, e := b.build.adapter.SimpleInsert("", b.table, b.columns, b.fields)
if err != nil { if e != nil {
return res, err return res, e
} }
return b.build.exec(query, args...) return b.build.exec(q, args...)
} }
func (b *accInsertBuilder) Run(args ...interface{}) (int, error) { func (b *accInsertBuilder) Run(args ...interface{}) (int, error) {
query, err := b.build.adapter.SimpleInsert("", b.table, b.columns, b.fields) res, e := b.Exec(args...)
if err != nil { if e != nil {
return 0, err return 0, e
} }
res, err := b.build.exec(query, args...) lastID, e := res.LastInsertId()
if err != nil { return int(lastID), e
return 0, err
}
lastID, err := res.LastInsertId()
return int(lastID), err
} }
type accBulkInsertBuilder struct { type accBulkInsertBuilder struct {
@ -412,24 +425,20 @@ func (b *accBulkInsertBuilder) Prepare() *sql.Stmt {
} }
func (b *accBulkInsertBuilder) Exec(args ...interface{}) (res sql.Result, err error) { func (b *accBulkInsertBuilder) Exec(args ...interface{}) (res sql.Result, err error) {
query, err := b.build.adapter.SimpleBulkInsert("", b.table, b.columns, b.fieldSet) q, e := b.build.adapter.SimpleBulkInsert("", b.table, b.columns, b.fieldSet)
if err != nil { if e != nil {
return res, err return res, e
} }
return b.build.exec(query, args...) return b.build.exec(q, args...)
} }
func (b *accBulkInsertBuilder) Run(args ...interface{}) (int, error) { func (b *accBulkInsertBuilder) Run(args ...interface{}) (int, error) {
query, err := b.build.adapter.SimpleBulkInsert("", b.table, b.columns, b.fieldSet) res, e := b.Exec(args...)
if err != nil { if e != nil {
return 0, err return 0, e
} }
res, err := b.build.exec(query, args...) lastID, e := res.LastInsertId()
if err != nil { return int(lastID), e
return 0, err
}
lastID, err := res.LastInsertId()
return int(lastID), err
} }
type accCountBuilder struct { type accCountBuilder struct {
@ -456,8 +465,13 @@ func (b *accCountBuilder) Limit(limit string) *accCountBuilder {
return b return b
} }
func (b *accCountBuilder) DateCutoff(column string, quantity int, unit string) *accCountBuilder { func (b *accCountBuilder) DateCutoff(col string, quantity int, unit string) *accCountBuilder {
b.dateCutoff = &dateCutoff{column, quantity, unit, 0} b.dateCutoff = &dateCutoff{col, quantity, unit, 0}
return b
}
func (b *accCountBuilder) DateOlderThanQ(col, unit string) *accCountBuilder {
b.dateCutoff = &dateCutoff{col, 0, unit, 11}
return b return b
} }
@ -471,23 +485,33 @@ func (b *accCountBuilder) Prepare() *sql.Stmt {
} }
return b.build.SimpleCount(b.table, b.where, b.limit) return b.build.SimpleCount(b.table, b.where, b.limit)
} }
// TODO: Fix this nasty hack
func (b *accCountBuilder) Total() (total int, err error) { func (b *accCountBuilder) Stmt() *sql.Stmt {
stmt := b.Prepare() // 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 stmt == nil { if b.dateCutoff != nil || b.inChain != nil {
return 0, b.build.FirstError() selBuilder := b.build.GetAdapter().Builder().Count().FromCountAcc(b)
selBuilder.columns = "COUNT(*)"
return b.build.prepare(b.build.GetAdapter().ComplexSelect(selBuilder))
} }
err = stmt.QueryRow().Scan(&total) return b.build.SimpleCount(b.table, b.where, b.limit)
return total, err
} }
func (b *accCountBuilder) TotalP(params ...interface{}) (total int, err error) { func (b *accCountBuilder) Total() (total int, e error) {
stmt := b.Prepare() stmt := b.Prepare()
if stmt == nil { if stmt == nil {
return 0, b.build.FirstError() return 0, b.build.FirstError()
} }
err = stmt.QueryRow(params).Scan(&total) e = stmt.QueryRow().Scan(&total)
return total, err return total, e
}
func (b *accCountBuilder) TotalP(params ...interface{}) (total int, e error) {
stmt := b.Prepare()
if stmt == nil {
return 0, b.build.FirstError()
}
e = stmt.QueryRow(params).Scan(&total)
return total, e
} }
// TODO: Add a Sum builder for summing viewchunks up into one number for the dashboard? // TODO: Add a Sum builder for summing viewchunks up into one number for the dashboard?