Experiment with the accumulator.

Less boilerplate.
This commit is contained in:
Azareal 2019-10-29 11:58:04 +10:00
parent eb49dde076
commit 033f4624c8
5 changed files with 116 additions and 46 deletions

View File

@ -26,12 +26,12 @@ type Poll struct {
VoteCount int
}
func (poll *Poll) CastVote(optionIndex int, uid int, ipaddress string) error {
return Polls.CastVote(optionIndex, poll.ID, uid, ipaddress) // TODO: Move the query into a pollStmts rather than having it in the store
func (p *Poll) CastVote(optionIndex int, uid int, ip string) error {
return Polls.CastVote(optionIndex, p.ID, uid, ip) // TODO: Move the query into a pollStmts rather than having it in the store
}
func (poll *Poll) Copy() Poll {
return *poll
func (p *Poll) Copy() Poll {
return *p
}
type PollOption struct {
@ -122,7 +122,7 @@ func (s *DefaultPollStore) Get(id int) (*Poll, error) {
// TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
// TODO: ID of 0 should always error?
func (s *DefaultPollStore) BulkGetMap(ids []int) (list map[int]*Poll, err error) {
var idCount = len(ids)
idCount := len(ids)
list = make(map[int]*Poll)
if idCount == 0 {
return list, nil
@ -159,21 +159,21 @@ func (s *DefaultPollStore) BulkGetMap(ids []int) (list map[int]*Poll, err error)
}
for rows.Next() {
poll := &Poll{ID: 0}
p := &Poll{ID: 0}
var optionTxt []byte
err := rows.Scan(&poll.ID, &poll.ParentID, &poll.ParentTable, &poll.Type, &optionTxt, &poll.VoteCount)
err := rows.Scan(&p.ID, &p.ParentID, &p.ParentTable, &p.Type, &optionTxt, &p.VoteCount)
if err != nil {
return list, err
}
err = json.Unmarshal(optionTxt, &poll.Options)
err = json.Unmarshal(optionTxt, &p.Options)
if err != nil {
return list, err
}
poll.QuickOptions = s.unpackOptionsMap(poll.Options)
s.cache.Set(poll)
p.QuickOptions = s.unpackOptionsMap(p.Options)
s.cache.Set(p)
list[poll.ID] = poll
list[p.ID] = p
}
// Did we miss any polls?
@ -206,22 +206,22 @@ func (s *DefaultPollStore) BulkGetMap(ids []int) (list map[int]*Poll, err error)
}
func (s *DefaultPollStore) Reload(id int) error {
poll := &Poll{ID: id}
p := &Poll{ID: id}
var optionTxt []byte
err := s.get.QueryRow(id).Scan(&poll.ParentID, &poll.ParentTable, &poll.Type, &optionTxt, &poll.VoteCount)
err := s.get.QueryRow(id).Scan(&p.ParentID, &p.ParentTable, &p.Type, &optionTxt, &p.VoteCount)
if err != nil {
s.cache.Remove(id)
return err
}
err = json.Unmarshal(optionTxt, &poll.Options)
err = json.Unmarshal(optionTxt, &p.Options)
if err != nil {
s.cache.Remove(id)
return err
}
poll.QuickOptions = s.unpackOptionsMap(poll.Options)
_ = s.cache.Set(poll)
p.QuickOptions = s.unpackOptionsMap(p.Options)
_ = s.cache.Set(p)
return nil
}
@ -258,7 +258,6 @@ func (s *DefaultPollStore) Create(parent Pollable, pollType int, pollOptions map
if err != nil {
return 0, err
}
lastID, err := res.LastInsertId()
if err != nil {
return 0, err
@ -271,7 +270,8 @@ func (s *DefaultPollStore) Create(parent Pollable, pollType int, pollOptions map
}
}
return int(lastID), parent.SetPoll(int(lastID)) // TODO: Delete the poll (and options) if SetPoll fails
id = int(lastID)
return id, parent.SetPoll(id) // TODO: Delete the poll (and options) if SetPoll fails
}
func (s *DefaultPollStore) SetCache(cache PollCache) {

View File

@ -4,6 +4,7 @@ package qgen
import (
"database/sql"
"log"
"strings"
)
var LogPrepares = true
@ -235,6 +236,10 @@ func (build *Accumulator) Select(table string) *AccSelectBuilder {
return &AccSelectBuilder{table, "", "", "", "", nil, nil, "", build}
}
func (build *Accumulator) Exists(tbl, col string) *AccSelectBuilder {
return build.Select(tbl).Columns(col).Where(col + "=?")
}
func (build *Accumulator) Insert(table string) *accInsertBuilder {
return &accInsertBuilder{table, "", "", build}
}
@ -242,3 +247,68 @@ func (build *Accumulator) Insert(table string) *accInsertBuilder {
func (build *Accumulator) Count(table string) *accCountBuilder {
return &accCountBuilder{table, "", "", nil, nil, "", build}
}
type SimpleModel struct {
delete *sql.Stmt
create *sql.Stmt
update *sql.Stmt
}
func (build *Accumulator) SimpleModel(tbl, colstr, primary string) SimpleModel {
var qlist, uplist string
for _, col := range strings.Split(colstr,",") {
qlist += "?,"
uplist += col + "=?,"
}
if len(qlist) > 0 {
qlist = qlist[0 : len(qlist)-1]
uplist = uplist[0 : len(uplist)-1]
}
where := primary + "=?"
return SimpleModel{
delete: build.Delete(tbl).Where(where).Prepare(),
create: build.Insert(tbl).Columns(colstr).Fields(qlist).Prepare(),
update: build.Update(tbl).Set(uplist).Where(where).Prepare(),
}
}
func (m SimpleModel) Delete(keyVal interface{}) error {
_, err := m.delete.Exec(keyVal)
return err
}
func (m SimpleModel) Update(args ...interface{}) error {
_, err := m.update.Exec(args...)
return err
}
func (m SimpleModel) Create(args ...interface{}) error {
_, err := m.create.Exec(args...)
return err
}
func (m SimpleModel) CreateID(args ...interface{}) (int, error) {
res, err := m.create.Exec(args...)
if err != nil {
return 0, err
}
lastID, err := res.LastInsertId()
return int(lastID), err
}
func (build *Accumulator) Model(table string) *accModelBuilder {
return &accModelBuilder{table,"",build}
}
type accModelBuilder struct {
table string
primary string
build *Accumulator
}
func (b *accModelBuilder) Primary(col string) *accModelBuilder {
b.primary = col
return b
}

View File

@ -11,29 +11,29 @@ type prebuilder struct {
adapter Adapter
}
func (build *prebuilder) Select(nlist ...string) *selectPrebuilder {
func (b *prebuilder) Select(nlist ...string) *selectPrebuilder {
name := optString(nlist, "")
return &selectPrebuilder{name, "", "", "", "", "", nil, nil, "", build.adapter}
return &selectPrebuilder{name, "", "", "", "", "", nil, nil, "", b.adapter}
}
func (build *prebuilder) Count(nlist ...string) *selectPrebuilder {
func (b *prebuilder) Count(nlist ...string) *selectPrebuilder {
name := optString(nlist, "")
return &selectPrebuilder{name, "", "COUNT(*)", "", "", "", nil, nil, "", build.adapter}
return &selectPrebuilder{name, "", "COUNT(*)", "", "", "", nil, nil, "", b.adapter}
}
func (build *prebuilder) Insert(nlist ...string) *insertPrebuilder {
func (b *prebuilder) Insert(nlist ...string) *insertPrebuilder {
name := optString(nlist, "")
return &insertPrebuilder{name, "", "", "", build.adapter}
return &insertPrebuilder{name, "", "", "", b.adapter}
}
func (build *prebuilder) Update(nlist ...string) *updatePrebuilder {
func (b *prebuilder) Update(nlist ...string) *updatePrebuilder {
name := optString(nlist, "")
return &updatePrebuilder{name, "", "", "", nil, nil, build.adapter}
return &updatePrebuilder{name, "", "", "", nil, nil, b.adapter}
}
func (build *prebuilder) Delete(nlist ...string) *deletePrebuilder {
func (b *prebuilder) Delete(nlist ...string) *deletePrebuilder {
name := optString(nlist, "")
return &deletePrebuilder{name, "", "", nil, build.adapter}
return &deletePrebuilder{name, "", "", nil, b.adapter}
}
type deletePrebuilder struct {

View File

@ -24,49 +24,49 @@ type TransactionBuilder struct {
textToStmt map[string]*transactionStmt
}
func (build *TransactionBuilder) SimpleDelete(table string, where string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleDelete("", table, where)
func (b *TransactionBuilder) SimpleDelete(table string, where string) (stmt *sql.Stmt, err error) {
res, err := b.adapter.SimpleDelete("", table, where)
if err != nil {
return stmt, err
}
return build.tx.Prepare(res)
return b.tx.Prepare(res)
}
// Quick* versions refer to it being quick to type not the performance. For performance critical transactions, you might want to use the Simple* methods or the *Tx methods on the main builder. Alternate suggestions for names are welcome :)
func (build *TransactionBuilder) QuickDelete(table string, where string) *transactionStmt {
res, err := build.adapter.SimpleDelete("", table, where)
func (b *TransactionBuilder) QuickDelete(table string, where string) *transactionStmt {
res, err := b.adapter.SimpleDelete("", table, where)
if err != nil {
return newTransactionStmt(nil, err)
}
stmt, ok := build.textToStmt[res]
stmt, ok := b.textToStmt[res]
if ok {
return stmt
}
stmt = newTransactionStmt(build.tx.Prepare(res))
build.textToStmt[res] = stmt
stmt = newTransactionStmt(b.tx.Prepare(res))
b.textToStmt[res] = stmt
return stmt
}
func (build *TransactionBuilder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleInsert("", table, columns, fields)
func (b *TransactionBuilder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) {
res, err := b.adapter.SimpleInsert("", table, columns, fields)
if err != nil {
return stmt, err
}
return build.tx.Prepare(res)
return b.tx.Prepare(res)
}
func (build *TransactionBuilder) QuickInsert(table string, where string) *transactionStmt {
res, err := build.adapter.SimpleDelete("", table, where)
func (b *TransactionBuilder) QuickInsert(table string, where string) *transactionStmt {
res, err := b.adapter.SimpleDelete("", table, where)
if err != nil {
return newTransactionStmt(nil, err)
}
stmt, ok := build.textToStmt[res]
stmt, ok := b.textToStmt[res]
if ok {
return stmt
}
stmt = newTransactionStmt(build.tx.Prepare(res))
build.textToStmt[res] = stmt
stmt = newTransactionStmt(b.tx.Prepare(res))
b.textToStmt[res] = stmt
return stmt
}

View File

@ -399,7 +399,7 @@ func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user c.User,
elemStr = elemStr[:len(elemStr)-1]
}
w.Write([]byte(`{"success":"1","elems":{` + elemStr + `}}`))
w.Write([]byte(`{"success":1,"elems":{` + elemStr + `}}`))
return nil
}