|
@@ -12,6 +12,14 @@ import (
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
|
)
|
|
|
|
|
|
+//
|
|
|
+// Tables:
|
|
|
+//
|
|
|
+// settings(username, setting, value)
|
|
|
+// scores(username, when, date, hand, won, run, score)
|
|
|
+// monthly(month, username, days, hands_won, bestrun, score)
|
|
|
+//
|
|
|
+
|
|
|
// Make sure the go-sqlite3 is here. Keep the db related things together.
|
|
|
|
|
|
type DBData struct {
|
|
@@ -41,33 +49,37 @@ const LOCK_SETTING = "LOCK"
|
|
|
const LOCK_CLEAR = "0"
|
|
|
|
|
|
func (db *DBData) Create() {
|
|
|
- _, err := db.DB.Exec(
|
|
|
- "CREATE TABLE IF NOT EXISTS settings(username TEXT, setting TEXT, value TEXT, PRIMARY KEY(username, setting));")
|
|
|
- if err != nil {
|
|
|
- log.Panicln(err)
|
|
|
- }
|
|
|
- _, err = db.DB.Exec(
|
|
|
- "CREATE TABLE IF NOT EXISTS scores ( username TEXT, `when` INTEGER, date INTEGER, hand INTEGER, won INTEGER, score INTEGER, PRIMARY KEY(username, date, hand));")
|
|
|
- if err != nil {
|
|
|
- log.Panicln(err)
|
|
|
- }
|
|
|
- _, err = db.DB.Exec(
|
|
|
- "CREATE TABLE IF NOT EXISTS monthly ( month INTEGER, username TEXT, days INTEGER, hands_won INTEGER, score INTEGER, PRIMARY KEY(month, username) );")
|
|
|
- if err != nil {
|
|
|
- log.Panicln(err)
|
|
|
+ var SQLLines []string = []string{
|
|
|
+ "CREATE TABLE IF NOT EXISTS settings( " +
|
|
|
+ "username TEXT, setting TEXT, value TEXT, " +
|
|
|
+ "PRIMARY KEY(username, setting));",
|
|
|
+ "CREATE TABLE IF NOT EXISTS scores( " +
|
|
|
+ "username TEXT, `when` INTEGER, date INTEGER, " +
|
|
|
+ "hand INTEGER, won INTEGER, run INTEGER, " +
|
|
|
+ " score INTEGER, " +
|
|
|
+ "PRIMARY KEY(username, date, hand));",
|
|
|
+ "CREATE TABLE IF NOT EXISTS monthly( " +
|
|
|
+ "month INTEGER, username TEXT, days INTEGER, " +
|
|
|
+ "hands_won INTEGER, bestrun INTEGER, " +
|
|
|
+ "score INTEGER, " +
|
|
|
+ "PRIMARY KEY(month, username) );",
|
|
|
+ }
|
|
|
+ for _, sql := range SQLLines {
|
|
|
+ _, err := db.DB.Exec(sql)
|
|
|
+ if err != nil {
|
|
|
+ log.Panicln("DBData.Create:", err)
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
// Make sure our settings LOCK value exists
|
|
|
db.DB.Exec(
|
|
|
- "INSERT INTO settings(username, setting, value) VALUES(?,?,?);",
|
|
|
+ "INSERT INTO settings(username, setting, value) "+
|
|
|
+ "VALUES(?,?,?);",
|
|
|
LOCK_USERNAME, LOCK_SETTING, LOCK_CLEAR)
|
|
|
// An error here is OK. It means the setting already exists.
|
|
|
- /*
|
|
|
- if err != nil {
|
|
|
- log.Printf("LOCK %#v\n", err)
|
|
|
- }
|
|
|
- */
|
|
|
}
|
|
|
|
|
|
+// Lock the database (for Monthly maint)
|
|
|
func (db *DBData) Lock(timeout int) bool {
|
|
|
var now time.Time = time.Now()
|
|
|
var value string = fmt.Sprintf("%d,%d", os.Getpid(), now.Unix())
|
|
@@ -120,7 +132,7 @@ RetryLock:
|
|
|
}
|
|
|
|
|
|
time.Sleep(time.Duration(50) * time.Millisecond)
|
|
|
- howOld = time.Until(now) // now.Sub(time.Now())
|
|
|
+ howOld = time.Until(now)
|
|
|
if int(-howOld.Seconds()) > timeout {
|
|
|
return false
|
|
|
}
|
|
@@ -173,9 +185,9 @@ func (db *DBData) SetSetting(setting string, value string) {
|
|
|
// log.Printf("SetSetting %s %s = %s\n", db.User, setting, value)
|
|
|
}
|
|
|
|
|
|
-func (db *DBData) SaveScore(when int64, date int64, hand int, won int, score int) {
|
|
|
- _, err := db.DB.Exec("INSERT INTO scores(username, `when`, date, hand, won, score) VALUES(?,?,?,?,?,?);",
|
|
|
- db.User, when, date, hand, won, score)
|
|
|
+func (db *DBData) SaveScore(when DBDate, date DBDate, hand int, won int, run int, score int) {
|
|
|
+ _, err := db.DB.Exec("INSERT INTO scores(username, `when`, date, hand, won, run, score) VALUES(?,?,?,?,?,?,?);",
|
|
|
+ db.User, int(when), int(date), hand, won, run, score)
|
|
|
if err != nil {
|
|
|
log.Println("SaveScore", err)
|
|
|
// When we play a hand we've already played:
|
|
@@ -183,9 +195,9 @@ func (db *DBData) SaveScore(when int64, date int64, hand int, won int, score int
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (db *DBData) HandsPlayedOnDay(day int64) int {
|
|
|
+func (db *DBData) HandsPlayedOnDay(day DBDate) int {
|
|
|
row := db.DB.QueryRow("SELECT COUNT(*) FROM scores WHERE username=? AND date=?;",
|
|
|
- db.User, day)
|
|
|
+ db.User, int(day))
|
|
|
var value int
|
|
|
err := row.Scan(&value)
|
|
|
if err != nil {
|
|
@@ -197,8 +209,8 @@ func (db *DBData) HandsPlayedOnDay(day int64) int {
|
|
|
/*
|
|
|
WhenPlayed = GetPlayed (as far as I can tell...)
|
|
|
*/
|
|
|
-func (db *DBData) WhenPlayed() map[int64]int {
|
|
|
- var result map[int64]int = make(map[int64]int)
|
|
|
+func (db *DBData) WhenPlayed() map[DBDate]int {
|
|
|
+ var result map[DBDate]int = make(map[DBDate]int)
|
|
|
|
|
|
rows, err := db.DB.Query("SELECT date, COUNT(hand) FROM scores WHERE username=? GROUP BY date;",
|
|
|
db.User)
|
|
@@ -209,7 +221,7 @@ func (db *DBData) WhenPlayed() map[int64]int {
|
|
|
defer rows.Close()
|
|
|
|
|
|
for rows.Next() {
|
|
|
- var date int64
|
|
|
+ var date DBDate
|
|
|
var hands int
|
|
|
|
|
|
if err := rows.Scan(&date, &hands); err != nil {
|
|
@@ -228,17 +240,18 @@ func (db *DBData) WhenPlayed() map[int64]int {
|
|
|
}
|
|
|
|
|
|
type MonthUser struct {
|
|
|
- Date int64
|
|
|
+ Date DBDate
|
|
|
Username string
|
|
|
}
|
|
|
|
|
|
type MonthStats struct {
|
|
|
Days int
|
|
|
Hands_Won int
|
|
|
+ Run int
|
|
|
Score int
|
|
|
}
|
|
|
|
|
|
-func (db *DBData) ExpireScores(month_first_unix int64) {
|
|
|
+func (db *DBData) ExpireScores(month_first DBDate) {
|
|
|
// step 1: acquire lock
|
|
|
|
|
|
l := db.Lock(5)
|
|
@@ -251,8 +264,10 @@ func (db *DBData) ExpireScores(month_first_unix int64) {
|
|
|
defer db.Unlock()
|
|
|
|
|
|
var Monthly map[MonthUser]MonthStats = make(map[MonthUser]MonthStats)
|
|
|
- rows, err := db.DB.Query("SELECT date, username, SUM(score), SUM(won) FROM scores WHERE date < ? GROUP BY date, username ORDER BY date, SUM(score) DESC;",
|
|
|
- month_first_unix)
|
|
|
+ rows, err := db.DB.Query("SELECT date, username, SUM(score), SUM(won), MAX(run) "+
|
|
|
+ "FROM scores WHERE date < ? "+
|
|
|
+ "GROUP BY date, username ORDER BY date, SUM(score) DESC;",
|
|
|
+ month_first)
|
|
|
if err != nil {
|
|
|
log.Println("ExpireScores", err)
|
|
|
return
|
|
@@ -263,25 +278,31 @@ func (db *DBData) ExpireScores(month_first_unix int64) {
|
|
|
var mu MonthUser
|
|
|
var score int
|
|
|
var won int
|
|
|
+ var run int
|
|
|
|
|
|
- if err := rows.Scan(&mu.Date, &mu.Username, &score, &won); err != nil {
|
|
|
+ if err := rows.Scan(&mu.Date, &mu.Username, &score, &won, &run); err != nil {
|
|
|
log.Println("ExpireScores Scan", err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- FirstOfMonthDateUnix(&mu.Date)
|
|
|
+ mu.Date.First()
|
|
|
+ // FirstOfMonthDateUnix(&mu.Date)
|
|
|
|
|
|
if mumap, found := Monthly[mu]; found {
|
|
|
// entry found
|
|
|
mumap.Days++
|
|
|
mumap.Score += score
|
|
|
mumap.Hands_Won += won
|
|
|
+ if run > mumap.Run {
|
|
|
+ mumap.Run = run
|
|
|
+ }
|
|
|
Monthly[mu] = mumap
|
|
|
} else {
|
|
|
// new entry
|
|
|
var ms MonthStats = MonthStats{Days: 1,
|
|
|
Score: score,
|
|
|
Hands_Won: won,
|
|
|
+ Run: run,
|
|
|
}
|
|
|
Monthly[mu] = ms
|
|
|
}
|
|
@@ -303,11 +324,12 @@ func (db *DBData) ExpireScores(month_first_unix int64) {
|
|
|
|
|
|
tx.Exec(
|
|
|
"DELETE FROM scores WHERE date < ?;",
|
|
|
- month_first_unix)
|
|
|
+ month_first)
|
|
|
|
|
|
for mu, ms := range Monthly {
|
|
|
- _, err := tx.Exec("INSERT INTO monthly(month, username, days, hands_won, score) VALUES(?,?,?,?,?);",
|
|
|
- mu.Date, mu.Username, ms.Days, ms.Hands_Won, ms.Score)
|
|
|
+ _, err := tx.Exec("INSERT INTO monthly(month, username, days, hands_won, bestrun, score) "+
|
|
|
+ "VALUES(?,?,?,?,?,?);",
|
|
|
+ mu.Date, mu.Username, ms.Days, ms.Hands_Won, ms.Run, ms.Score)
|
|
|
if err != nil {
|
|
|
log.Println("ExpireScores Insert", err)
|
|
|
tx.Rollback()
|
|
@@ -333,7 +355,8 @@ type ScoresDetails struct {
|
|
|
|
|
|
func (db *DBData) GetScoresOnDay(date int64) []ScoresDetails {
|
|
|
var result []ScoresDetails
|
|
|
- rows, err := db.DB.Query("SELECT username, date, hand, won, score FROM SCORES WHERE date=? ORDER BY username, hand;",
|
|
|
+ rows, err := db.DB.Query("SELECT username, date, hand, won, score FROM SCORES "+
|
|
|
+ "WHERE date=? ORDER BY username, hand;",
|
|
|
date)
|
|
|
if err != nil {
|
|
|
log.Println("GetScoresOnDay", date, err)
|
|
@@ -367,7 +390,8 @@ type ScoresData struct {
|
|
|
func (db *DBData) GetScores(limit int) []ScoresData {
|
|
|
var result []ScoresData
|
|
|
|
|
|
- rows, err := db.DB.Query("SELECT date, username, SUM(score), SUM(won) FROM SCORES GROUP BY date, username ORDER BY SUM(score) DESC LIMIT ?;",
|
|
|
+ rows, err := db.DB.Query("SELECT date, username, SUM(score), SUM(won) "+
|
|
|
+ "FROM SCORES GROUP BY date, username ORDER BY SUM(score) DESC LIMIT ?;",
|
|
|
limit)
|
|
|
if err != nil {
|
|
|
log.Println("GetScores", err)
|
|
@@ -396,13 +420,15 @@ type MonthlyData struct {
|
|
|
User string
|
|
|
Days int
|
|
|
Hands_Won int
|
|
|
+ Best_Run int
|
|
|
Score int
|
|
|
}
|
|
|
|
|
|
func (db *DBData) GetMonthlyScores(limit int) []MonthlyData {
|
|
|
var result []MonthlyData
|
|
|
|
|
|
- rows, err := db.DB.Query("SELECT month, username, days, hands_won, score FROM monthly ORDER BY score DESC LIMIT ?;",
|
|
|
+ rows, err := db.DB.Query("SELECT month, username, days, hands_won, bestrun, score "+
|
|
|
+ "FROM monthly ORDER BY score DESC LIMIT ?;",
|
|
|
limit)
|
|
|
if err != nil {
|
|
|
log.Println("GetMonthlyScores", err)
|
|
@@ -413,7 +439,7 @@ func (db *DBData) GetMonthlyScores(limit int) []MonthlyData {
|
|
|
for rows.Next() {
|
|
|
var md MonthlyData
|
|
|
|
|
|
- if err := rows.Scan(&md.Date, &md.User, &md.Days, &md.Hands_Won, &md.Score); err != nil {
|
|
|
+ if err := rows.Scan(&md.Date, &md.User, &md.Days, &md.Hands_Won, &md.Best_Run, &md.Score); err != nil {
|
|
|
log.Println("GetMonthlyScores Scan", err)
|
|
|
return result
|
|
|
}
|