feat(*): initial commit
build / Go-Build (push) Successful in 1m1s

This commit is contained in:
2026-06-24 00:16:21 +02:00
parent 3cf9e6f266
commit 85e4df52a5
20 changed files with 1125 additions and 3 deletions
+14
View File
@@ -3,6 +3,7 @@ package database
import (
"database/sql"
"log"
"time"
"github.com/lib/pq"
)
@@ -17,11 +18,24 @@ func OpenDB(conf pq.Config) {
}
db = sql.OpenDB(connector)
db.SetMaxOpenConns(500)
db.SetMaxIdleConns(50)
db.SetConnMaxLifetime(time.Hour)
if err := db.Ping(); err != nil {
panic(err)
}
log.Printf("Database opened to %s:%d, %s as %s!\n", conf.Host, conf.Port, conf.Database, conf.User)
if err := initStateDB(); err != nil {
panic(err)
}
if err := initVoteDB(); err != nil {
panic(err)
}
}
func CloseDB() {
+87
View File
@@ -0,0 +1,87 @@
package database
import (
"strconv"
"tomatentum.net/outfit-voting-abi26/internal"
)
const INITSTATEDB string = "CREATE TABLE IF NOT EXISTS state(key varchar(255) PRIMARY KEY, value TEXT)"
const STATEINSERT string = "INSERT INTO state(key, value) VALUES ($1, $2) ON CONFLICT (key) DO NOTHING;"
const STATESET string = "UPDATE state SET value = $1 WHERE key = $2"
const STATEGET string = "SELECT value FROM state WHERE key = $1"
const KEYVOTELOCKED string = "votinglocked"
const KEYRESULTLOCKED string = "resultlocked"
var voteLocked internal.CacheItem[bool] = internal.NewCache(func() (bool, error) {
res := db.QueryRow(STATEGET, KEYVOTELOCKED)
var valuestring string
if err := res.Scan(&valuestring); err != nil {
return false, err
}
value, err := strconv.ParseBool(valuestring)
if err != nil {
return false, err
}
return value, nil
}, 30)
var resultLocked internal.CacheItem[bool] = internal.NewCache(func() (bool, error) {
res := db.QueryRow(STATEGET, KEYRESULTLOCKED)
var valuestring string
if err := res.Scan(&valuestring); err != nil {
return false, err
}
value, err := strconv.ParseBool(valuestring)
if err != nil {
return false, err
}
return value, nil
}, 30)
func initStateDB() error {
_, err := db.Exec(INITSTATEDB)
if err != nil {
return err
}
_, err = db.Exec(STATEINSERT, KEYVOTELOCKED, "true")
_, err = db.Exec(STATEINSERT, KEYRESULTLOCKED, "true")
if err != nil {
return err
}
return nil
}
func setState(key string, value string) error {
_, err := db.Exec(STATESET, value, key)
return err
}
func GetVoteLocked() (bool, error) {
return voteLocked.Get()
}
func GetResultLocked() (bool, error) {
return resultLocked.Get()
}
func SetVoteLocked(value bool) error {
voteLocked.Invalidate()
return setState(KEYVOTELOCKED, strconv.FormatBool(value))
}
func SetResultLocked(value bool) error {
resultLocked.Invalidate()
return setState(KEYRESULTLOCKED, strconv.FormatBool(value))
}
+201
View File
@@ -0,0 +1,201 @@
package database
import (
"errors"
"fmt"
"strings"
"tomatentum.net/outfit-voting-abi26/internal/util"
)
const VALUESTEMPLATE string = "(%s, %s, %s, %d)"
const INITVOTEDB string = "CREATE TABLE IF NOT EXISTS vote(id varchar(16) PRIMARY KEY, category TEXT NOT NULL, name TEXT NOT NULL, votes int NOT NULL)"
const INSERTVOTEENTRY string = "INSERT INTO vote(id, category, name, votes) VALUES($1, $2, $3, $4)"
const BULKINSERTVOTEENTRY string = "INSERT INTO vote(id, name, votes) VALUES"
const SETVOTE string = "UPDATE vote SET votes = $1 WHERE id = $2"
const INCVOTE string = "UPDATE vote SET votes = votes + 1 WHERE id = $1"
const DELVOTEENTRY string = "DELETE FROM vote WHERE id = $1"
const BULKDELVOTEENTRY string = "DELETE FROM vote WHERE key IN (%s)"
const GETVOTES string = "SELECT * FROM vote ORDER BY votes DESC"
const GETVOTEOPTIONS string = "SELECT id, name FROM vote"
const GETVOTE string = "SELECT * FROM vote WHERE id = $1"
type VoteEntry struct {
VoteOption
Votes int
}
type VoteOption struct {
ID string
Category string
Name string
}
func initVoteDB() error {
_, err := db.Exec(INITVOTEDB)
return err
}
func InsertVoteEntry(name string, category string) (VoteEntry, error) {
id, err := util.RandString(8)
if err != nil {
return VoteEntry{}, err
}
_, err = db.Exec(INSERTVOTEENTRY, id, name, 0)
if err != nil {
return VoteEntry{}, err
}
return VoteEntry{VoteOption{id, category, name}, 0}, nil
}
func BulkInsertVoteEntry(names []string, category string) (*[]VoteEntry, error) {
stmnt := BULKINSERTVOTEENTRY
var entries []VoteEntry = make([]VoteEntry, len(names))
for i, v := range names {
id, err := util.RandString(8)
if err != nil {
return nil, err
}
stmnt = stmnt + fmt.Sprintf(VALUESTEMPLATE, id, category, v, 0)
entries = append(entries, VoteEntry{VoteOption{id, category, v}, 0})
if i < len(names)-1 {
stmnt = stmnt + ","
}
}
stmnt = stmnt + ";"
_, err := db.Exec(stmnt)
if err != nil {
return nil, err
}
return &entries, nil
}
func SetVote(id string, votes int) error {
_, err := db.Exec(SETVOTE, votes, id)
if err != nil {
return err
}
return nil
}
func IncVote(id string) error {
res, err := db.Exec(INCVOTE, id)
if err != nil {
return err
}
n, _ := res.RowsAffected()
if n < 1 {
return errors.New("id does not exist")
}
return nil
}
func DelVoteEntry(id string) error {
res, err := db.Exec(DELVOTEENTRY, id)
if err != nil {
return err
}
n, _ := res.RowsAffected()
if n < 1 {
return errors.New("id does not exist")
}
return nil
}
func BulkDelVoteEntry(ids []string) error {
placeholders := make([]string, len(ids))
for i := 0; i < len(ids); i++ {
placeholders = append(placeholders, fmt.Sprintf("$%d", i))
}
res, err := db.Exec(fmt.Sprintf(BULKDELVOTEENTRY, strings.Join(placeholders, ", ")), ids)
if err != nil {
return err
}
n, _ := res.RowsAffected()
if n < 1 {
return errors.New("id does not exist")
}
return nil
}
func GetVotes() ([]VoteEntry, error) {
res, err := db.Query(GETVOTES)
if err != nil {
return nil, err
}
defer res.Close()
var current VoteEntry
var entries []VoteEntry = []VoteEntry{}
for res.Next() {
if err := res.Err(); err != nil {
return nil, err
}
if err := res.Scan(&current.ID, &current.Category, &current.Name, &current.Votes); err != nil {
return nil, err
}
entries = append(entries, current)
}
return entries, nil
}
func GetVoteOptions() ([]VoteOption, error) {
res, err := db.Query(GETVOTEOPTIONS)
if err != nil {
return nil, err
}
defer res.Close()
var current VoteOption
var entries []VoteOption = []VoteOption{}
for res.Next() {
if err := res.Err(); err != nil {
return nil, err
}
if err := res.Scan(&current.ID, &current.Category, &current.Name); err != nil {
return nil, err
}
entries = append(entries, current)
}
return entries, nil
}
func GetVote(id string) (VoteEntry, error) {
res := db.QueryRow(GETVOTE, id)
var current VoteEntry
if err := res.Scan(&current.ID, &current.Category, &current.Name, &current.Votes); err != nil {
return VoteEntry{}, err
}
return current, nil
}