diff --git a/common/poll_store.go b/common/poll_store.go index 263a2f01..8e02d08a 100644 --- a/common/poll_store.go +++ b/common/poll_store.go @@ -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 @@ -270,8 +269,9 @@ func (s *DefaultPollStore) Create(parent Pollable, pollType int, pollOptions map return 0, err } } - - 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) { diff --git a/query_gen/accumulator.go b/query_gen/accumulator.go index 9d2999c3..cbe9a976 100644 --- a/query_gen/accumulator.go +++ b/query_gen/accumulator.go @@ -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 +} \ No newline at end of file diff --git a/query_gen/micro_builders.go b/query_gen/micro_builders.go index 48a96908..55f9b07d 100644 --- a/query_gen/micro_builders.go +++ b/query_gen/micro_builders.go @@ -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 { diff --git a/query_gen/transaction.go b/query_gen/transaction.go index 2f6a7bec..a0e80ece 100644 --- a/query_gen/transaction.go +++ b/query_gen/transaction.go @@ -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 } diff --git a/routes/reply.go b/routes/reply.go index 71b349b1..ab5e471d 100644 --- a/routes/reply.go +++ b/routes/reply.go @@ -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 }