Browse Source

Add postgres db support

master
NGnius 4 years ago
parent
commit
0ff6ba3db0
3 changed files with 100 additions and 35 deletions
  1. +4
    -1
      go.mod
  2. +75
    -13
      sql_service.go
  3. +21
    -21
      sql_structs.go

+ 4
- 1
go.mod View File

@@ -2,4 +2,7 @@ module git.exmods.org/NGnius/leadercraft-s

go 1.13

require github.com/mattn/go-sqlite3 v2.0.3+incompatible
require (
github.com/lib/pq v1.3.0
github.com/mattn/go-sqlite3 v2.0.3+incompatible
)

+ 75
- 13
sql_service.go View File

@@ -7,7 +7,8 @@ import (
"fmt"
"time"

_ "github.com/mattn/go-sqlite3"
_ "github.com/lib/pq" // postgres
_ "github.com/mattn/go-sqlite3" // sqlite
)

const (
@@ -22,11 +23,72 @@ var (
buildTables bool
populateTables bool
// internal variables
db *sql.DB
db *sql.DB
queryType int
queryStrings [][]string
)

func sqlInit() error {
var dbOpenErr error
if sqlServer == "postgres" {
queryType = 1
} else { // sqlite3
queryType = 0
}
queryStrings = [][]string{
[]string{ // sqlite
"SELECT * FROM Boards WHERE name=? LIMIT 1;",
"SELECT * FROM Players WHERE name=? LIMTI 1;",
"INSERT INTO Entries(score, player, board, time) VALUES (?, ?, ?, ?);",
"INSERT INTO Keys(token, player, time) VALUES (?, ?, ?);",
"SELECT * FROM Keys WHERE token=? AND player=? AND time=?",
"SELECT * FROM Keys WHERE token=? LIMIT 1;",
"SELECT * FROM Keys WHERE player=? LIMIT 1;",
"SELECT * FROM Boards WHERE id=?",
"INSERT OR REPLACE INTO Boards(id, name, description) VALUES (?, ?, ?);",
"SELECT * FROM Entries WHERE board=?",
"SELECT * FROM Entries WHERE board=? and rank >= ? and rank <= ? ORDER BY rank ASC;",
"SELECT * FROM Players WHERE id=? LIMIT 1;",
"INSERT OR REPLACE INTO Players(id, name) VALUES (?, ?);",
"SELECT * FROM Entries WHERE player=?",
"SELECT * FROM Entries WHERE player=? ORDER BY time DESC LIMIT ?;",
"SELECT * FROM Entries WHERE id=? LIMIT 1;",
"INSERT OR REPLACE INTO Entries(id, rank, score, player, board, time, metadata) VALUES (?, ?, ?, ?, ?, ?, ?);",
"SELECT * FROM Keys WHERE id=? LIMIT 1;",
"INSERT OR REPLACE INTO Keys(id, token, player, time, metadata) VALUES (?, ?, ?, ?, ?);",
"CREATE TABLE IF NOT EXISTS Players (id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
"CREATE TABLE IF NOT EXISTS Boards (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL);",
"CREATE TABLE IF NOT EXISTS Entries (id INTEGER PRIMARY KEY, rank INTEGER NOT NULL DEFAULT -1, score INTEGER NOT NULL, player INTEGER NOT NULL, board INTEGER NOT NULL, time INTEGER NOT NULL, metadata BLOB NOT NULL DEFAULT x'FF', FOREIGN KEY(player) REFERENCES Players(id), FOREIGN KEY(board) REFERENCES Boards(id));",
"CREATE TABLE IF NOT EXISTS Keys (id INTEGER PRIMARY KEY, token TEXT NOT NULL, player INTEGER NOT NULL, time INTEGER NOT NULL, metadata BLOB NOT NULL DEFAULT x'FF', FOREIGN KEY(player) REFERENCES Players(id));",
},
[]string{ // postgres
"SELECT * FROM Boards WHERE name=$1 LIMIT 1;",
"SELECT * FROM Players WHERE name=$1 LIMTI 1;",
"INSERT INTO Entries(score, player, board, time) VALUES ($1, $2, $3, $4);",
"INSERT INTO Keys(token, player, time) VALUES ($1, $2, $3);",
"SELECT * FROM Keys WHERE token=$1 AND player=$2 AND time=$3",
"SELECT * FROM Keys WHERE token=$1 LIMIT 1;",
"SELECT * FROM Keys WHERE player=$1 LIMIT 1;",
"SELECT * FROM Boards WHERE id=$1",
"INSERT INTO Boards(id, name, description) VALUES ($1, $2, $3) ON CONFLICT(id) DO UPDATE SET name=$2, description=$3;",
"SELECT * FROM Entries WHERE board=$1",
"SELECT * FROM Entries WHERE board=$1 and rank >= $2 and rank <= $3 ORDER BY rank ASC;",
"SELECT * FROM Players WHERE id=$1 LIMIT 1;",
"INSERT INTO Players(id, name) VALUES ($1, $2) ON CONFLICT(id) DO UPDATE SET name=$2;",
"SELECT * FROM Entries WHERE player=$1",
"SELECT * FROM Entries WHERE player=$1 ORDER BY time DESC LIMIT $2;",
"SELECT * FROM Entries WHERE id=$1 LIMIT 1;",
"INSERT INTO Entries(id, rank, score, player, board, time, metadata) VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT(id) DO UPDATE SET rank=$2, score=$3, player=$4, board=$5, time=$6, metadata=$7;",
"SELECT * FROM Keys WHERE id=$1 LIMIT 1;",
"INSERT INTO Keys(id, token, player, time, metadata) VALUES ($1, $2, $3, $4, $5) ON CONFLICT(id) DO UPDATE SET token=$2, player=$3, time=$4, metadata=$5;",
"CREATE TABLE IF NOT EXISTS Players (id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
"CREATE TABLE IF NOT EXISTS Boards (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL);",
"CREATE TABLE IF NOT EXISTS Entries (id INTEGER PRIMARY KEY, rank INTEGER NOT NULL DEFAULT -1, score INTEGER NOT NULL, player INTEGER NOT NULL, board INTEGER NOT NULL, time INTEGER NOT NULL, metadata BYTEA NOT NULL DEFAULT E'\\\\xFF', FOREIGN KEY(player) REFERENCES Players(id), FOREIGN KEY(board) REFERENCES Boards(id));",
"CREATE TABLE IF NOT EXISTS Keys (id INTEGER PRIMARY KEY, token TEXT NOT NULL, player INTEGER NOT NULL, time INTEGER NOT NULL, metadata BYTEA NOT NULL DEFAULT E'\\\\xFF', FOREIGN KEY(player) REFERENCES Players(id));",
},
}
fmt.Printf("SQL Server %s is query type %d\n", sqlServer, queryType)
fmt.Println(len(queryStrings[queryType]))
db, dbOpenErr = sql.Open(sqlServer, sqlConnection)
if dbOpenErr != nil {
return dbOpenErr
@@ -55,17 +117,17 @@ func sqlClose() error {

func boardByName(name string) (*Board, error) {
b := &Board{}
return b, db.QueryRow("SELECT * FROM Boards WHERE name=? LIMIT 1;", name).Scan(b.Intake()...)
return b, db.QueryRow(queryStrings[queryType][0], name).Scan(b.Intake()...)
}

func playerByName(name string) (*Player, error) {
p := &Player{}
return p, db.QueryRow("SELECT * FROM Players WHERE name=? LIMTI 1;", name).Scan(p.Intake()...)
return p, db.QueryRow(queryStrings[queryType][1], name).Scan(p.Intake()...)
}

func newEntrySql(score, player, board int64) error {
tx, _ := db.Begin()
stmt, _ := tx.Prepare("INSERT INTO Entries(score, player, board, time) VALUES (?, ?, ?, ?);")
stmt, _ := tx.Prepare(queryStrings[queryType][2])
_, err := stmt.Exec(score, player, board, time.Now().Unix())
if err != nil {
tx.Rollback()
@@ -78,14 +140,14 @@ func newEntrySql(score, player, board int64) error {
func newKeySql(player int64) (*Key, error) {
tx, _ := db.Begin()
newKey := &Key{Token: "new", Player: player, Time: time.Now().Unix()}
stmt, _ := tx.Prepare("INSERT INTO Keys(token, player, time) VALUES (?, ?, ?);")
stmt, _ := tx.Prepare(queryStrings[queryType][3])
_, err := stmt.Exec(newKey.Token, newKey.Player, newKey.Time)
if err != nil {
tx.Rollback()
return nil, err
}
tx.Commit()
db.QueryRow("SELECT * FROM Keys WHERE token=? AND player=? AND time=?", newKey.Token, newKey.Player, newKey.Time).Scan(newKey.Intake()...)
db.QueryRow(queryStrings[queryType][4], newKey.Token, newKey.Player, newKey.Time).Scan(newKey.Intake()...)
tokenErr := newKey.GenerateToken()
if tokenErr != nil {
return nil, tokenErr
@@ -96,12 +158,12 @@ func newKeySql(player int64) (*Key, error) {

func keyByToken(token string) (*Key, error) {
k := &Key{}
return k, db.QueryRow("SELECT * FROM Keys WHERE token=? LIMIT 1;", token).Scan(k.Intake()...)
return k, db.QueryRow(queryStrings[queryType][5], token).Scan(k.Intake()...)
}

func keyByPlayer(player int64) (*Key, error) {
k := &Key{}
return k, db.QueryRow("SELECT * FROM Keys WHERE player=? LIMIT 1;", player).Scan(k.Intake()...)
return k, db.QueryRow(queryStrings[queryType][6], player).Scan(k.Intake()...)
}

// internal operations
@@ -114,10 +176,10 @@ func sqlBuildTables() {
//transaction.Exec("CREATE TABLE IF NOT EXISTS Test (Sometext VARCHAR, Somenumber);")
//transaction.Exec("INSERT INTO Test (Sometext, Somenumber) VALUES (?,?);", "Hello sqlite", 123)
// build real tables
transaction.Exec("CREATE TABLE IF NOT EXISTS Players (id INTEGER PRIMARY KEY, name TEXT NOT NULL);")
transaction.Exec("CREATE TABLE IF NOT EXISTS Boards (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL);")
transaction.Exec("CREATE TABLE IF NOT EXISTS Entries (id INTEGER PRIMARY KEY, rank INTEGER NOT NULL DEFAULT -1, score INTEGER NOT NULL, player INTEGER NOT NULL, board INTEGER NOT NULL, time INTEGER NOT NULL, metadata BLOB NOT NULL DEFAULT x'FF', FOREIGN KEY(player) REFERENCES Players(id), FOREIGN KEY(board) REFERENCES Boards(id));")
transaction.Exec("CREATE TABLE IF NOT EXISTS Keys (id INTEGER PRIMARY KEY, token TEXT NOT NULL, player INTEGER NOT NULL, time INTEGER NOT NULL, metadata BLOB NOT NULL DEFAULT x'FF', FOREIGN KEY(player) REFERENCES Players(id));")
transaction.Exec(queryStrings[queryType][19])
transaction.Exec(queryStrings[queryType][20])
transaction.Exec(queryStrings[queryType][21])
transaction.Exec(queryStrings[queryType][22])
transaction.Commit()
}



+ 21
- 21
sql_structs.go View File

@@ -3,12 +3,12 @@
package main

import (
"encoding/json"
"strconv"
"crypto/sha512"
"crypto/rand"
"crypto/sha512"
"encoding/binary"
"encoding/json"
"math/big"
"strconv"
// test
//"fmt"
)
@@ -45,12 +45,12 @@ func LoadBoard(id int64) *Board {
}

func (b *Board) Load() error {
return db.QueryRow("SELECT * FROM Boards WHERE id=?", b.ID).Scan(b.Intake()...)
return db.QueryRow(queryStrings[queryType][7], b.ID).Scan(b.Intake()...)
}

func (b *Board) Commit() error {
tx, _ := db.Begin()
statement, _ := tx.Prepare("INSERT OR REPLACE INTO Boards(id, name, description) VALUES (?, ?, ?);")
statement, _ := tx.Prepare(queryStrings[queryType][8])
_, err := statement.Exec(b.Output()...)
if err != nil {
tx.Rollback()
@@ -61,7 +61,7 @@ func (b *Board) Commit() error {

func (b *Board) Entries() ([]*Entry, error) {
var entries []*Entry
rows, err := db.Query("SELECT * FROM Entries WHERE board=?", b.ID)
rows, err := db.Query(queryStrings[queryType][9], b.ID)
if err != nil {
return entries, err
}
@@ -79,7 +79,7 @@ func (b *Board) Entries() ([]*Entry, error) {

func (b *Board) SomeEntries(start, end int64) ([]*Entry, error) {
var entries []*Entry
rows, err := db.Query("SELECT * FROM Entries WHERE board=? and rank >= ? and rank <= ? ORDER BY rank ASC;", b.ID, start, end)
rows, err := db.Query(queryStrings[queryType][10], b.ID, start, end)
if err != nil {
return entries, err
}
@@ -147,12 +147,12 @@ func LoadPlayer(id int64) *Player {
}

func (p *Player) Load() error {
return db.QueryRow("SELECT * FROM Players WHERE id=? LIMIT 1;", p.ID).Scan(p.Intake()...)
return db.QueryRow(queryStrings[queryType][11], p.ID).Scan(p.Intake()...)
}

func (p *Player) Commit() error {
tx, _ := db.Begin()
statement, _ := tx.Prepare("INSERT OR REPLACE INTO Players(id, name) VALUES (?, ?);")
statement, _ := tx.Prepare(queryStrings[queryType][12])
_, err := statement.Exec(p.Output()...)
if err != nil {
tx.Rollback()
@@ -163,7 +163,7 @@ func (p *Player) Commit() error {

func (p *Player) Entries() ([]*Entry, error) {
var entries []*Entry
rows, err := db.Query("SELECT * FROM Entries WHERE player=?", p.ID)
rows, err := db.Query(queryStrings[queryType][13], p.ID)
if err != nil {
return entries, err
}
@@ -181,7 +181,7 @@ func (p *Player) Entries() ([]*Entry, error) {

func (p *Player) SomeEntries(limit int64) ([]*Entry, error) {
var entries []*Entry
rows, err := db.Query("SELECT * FROM Entries WHERE player=? ORDER BY time DESC LIMIT ?;", p.ID, limit)
rows, err := db.Query(queryStrings[queryType][14], p.ID, limit)
if err != nil {
return entries, err
}
@@ -254,12 +254,12 @@ func LoadEntry(id int64) *Entry {
}

func (e *Entry) Load() error {
return db.QueryRow("SELECT * FROM Entries WHERE id=? LIMIT 1;", e.ID).Scan(e.Intake()...)
return db.QueryRow(queryStrings[queryType][15], e.ID).Scan(e.Intake()...)
}

func (e *Entry) Commit() error {
tx, _ := db.Begin()
statement, _ := tx.Prepare("INSERT OR REPLACE INTO Entries(id, rank, score, player, board, time, metadata) VALUES (?, ?, ?, ?, ?, ?, ?);")
statement, _ := tx.Prepare(queryStrings[queryType][16])
_, err := statement.Exec(e.Output()...)
if err != nil {
tx.Rollback()
@@ -316,10 +316,10 @@ func (e *Entry) Output() []interface{} {
}

type Key struct {
ID int64
Token string
Player int64
Time int64 // Created time (seconds since Unix epoch)
ID int64
Token string
Player int64
Time int64 // Created time (seconds since Unix epoch)
Metadata []byte
}

@@ -333,13 +333,13 @@ func LoadKey(id int64) *Key {
}

func (k *Key) Load() error {
return db.QueryRow("SELECT * FROM Keys WHERE id=? LIMIT 1;", k.ID).Scan(k.Intake()...)
return db.QueryRow(queryStrings[queryType][17], k.ID).Scan(k.Intake()...)
}

func (k *Key) Commit() error {
tx, _ := db.Begin()
statement, _ := tx.Prepare("INSERT OR REPLACE INTO Keys(id, token, player, time, metadata) VALUES (?, ?, ?, ?, ?);")
_, err := statement.Exec(k.Output()...)
statement, _ := tx.Prepare(queryStrings[queryType][18])
_, err := statement.Exec(k.Output()...)
if err != nil {
tx.Rollback()
return err
@@ -375,7 +375,7 @@ func (k *Key) GenerateToken() error {
buf_int64 := make([]byte, 8) // 8 bytes = 64 bits
input := []byte{}
if randomizeTokens {
max := big.NewInt(2^16-1)
max := big.NewInt(2 ^ 16 - 1)
for i := 0; i < 512; i++ {
// generate randomness
num, _ := rand.Int(rand.Reader, max)