🎄 xmas present

This commit is contained in:
Fenny
2020-11-05 04:17:05 +01:00
parent a6058cffb3
commit b4a848ca29
26 changed files with 585 additions and 750 deletions

View File

@@ -4,45 +4,49 @@ import "time"
// Config defines the config for storage.
type Config struct {
// Time before deleting expired keys
//
// Default is 10 * time.Second
GCInterval time.Duration
// DB host
// Host name where the DB is hosted
//
// Optional. Default is "127.0.0.1"
Host string
// DB port
// Port where the DB is listening on
//
// Optional. Default is "5432"
Port int64
// Optional. Default is 5432
Port int
// DB user name
// Server username
//
// Optional. Default is ""
Username string
// DB user password
// Server password
//
// Optional. Default is ""
Password string
// DB name
// Database name
//
// Optional. Default is "fiber"
Database string
// DB table name
// Table name
//
// Optional. Default is "fiber"
TableName string
// Optional. Default is "fiber_storage"
Table string
// Drop any existing table with the same name
// Clear any existing keys in existing Table
//
// Optional. Default is false
DropTable bool
Clear bool
// Time before deleting expired keys
//
// Optional. Default is 10 * time.Second
GCInterval time.Duration
////////////////////////////////////
// Adaptor related config options //
////////////////////////////////////
// Maximum wait for connection, in seconds. Zero or
// n < 0 means wait indefinitely.
@@ -79,13 +83,12 @@ type Config struct {
// ConfigDefault is the default config
var ConfigDefault = Config{
GCInterval: 10 * time.Second,
Host: "127.0.0.1",
Port: 5432,
Database: "fiber",
TableName: "fiber",
DropTable: false,
timeout: 30 * time.Second,
Table: "fiber_storage",
Clear: false,
GCInterval: 10 * time.Second,
maxOpenConns: 100,
maxIdleConns: 100,
connMaxLifetime: 1 * time.Second,
@@ -102,35 +105,20 @@ func configDefault(config ...Config) Config {
cfg := config[0]
// Set default values
if int(cfg.GCInterval) == 0 {
cfg.GCInterval = ConfigDefault.GCInterval
}
if cfg.Host == "" {
cfg.Host = ConfigDefault.Host
}
if cfg.Port == 0 {
if cfg.Port <= 0 {
cfg.Port = ConfigDefault.Port
}
if cfg.Host == "" {
cfg.Host = ConfigDefault.Host
}
if cfg.Database == "" {
cfg.Database = ConfigDefault.Database
}
if cfg.TableName == "" {
cfg.TableName = ConfigDefault.TableName
if cfg.Table == "" {
cfg.Table = ConfigDefault.Table
}
if int(cfg.GCInterval) == 0 {
cfg.GCInterval = ConfigDefault.GCInterval
}
// if int(cfg.Timeout) == 0 {
// cfg.Timeout = ConfigDefault.Timeout
// }
// if cfg.MaxOpenConns == 0 {
// cfg.MaxOpenConns = ConfigDefault.MaxOpenConns
// }
// if cfg.MaxIdleConns == 0 {
// cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
// }
// if int(cfg.ConnMaxLifetime) == 0 {
// cfg.ConnMaxLifetime = ConfigDefault.ConnMaxLifetime
// }
return cfg
}

View File

@@ -44,13 +44,22 @@ func New(config ...Config) *Storage {
cfg := configDefault(config...)
// Create data source name
dsn := fmt.Sprintf("postgresql://%s:%s@%s:%d/%s?connect_timeout=%d&sslmode=disable",
url.QueryEscape(cfg.Username),
cfg.Password,
url.QueryEscape(cfg.Host),
cfg.Port,
var dsn string = "postgresql://"
if cfg.Username != "" {
dsn += url.QueryEscape(cfg.Username)
}
if cfg.Password != "" {
dsn += ":" + cfg.Password
}
if cfg.Username != "" || cfg.Password != "" {
dsn += "@"
}
dsn += fmt.Sprintf("%s:%d", url.QueryEscape(cfg.Host), cfg.Port)
dsn += "/" + url.QueryEscape(cfg.Database)
dsn += fmt.Sprintf("/%s?connect_timeout=%d&sslmode=disable",
url.QueryEscape(cfg.Database),
int64(cfg.timeout.Seconds()))
int64(cfg.timeout.Seconds()),
)
// Create db
db, err := sql.Open("postgres", dsn)
@@ -69,8 +78,8 @@ func New(config ...Config) *Storage {
}
// Drop table if set to true
if cfg.DropTable {
if _, err = db.Exec(fmt.Sprintf(dropQuery, cfg.TableName)); err != nil {
if cfg.Clear {
if _, err = db.Exec(fmt.Sprintf(dropQuery, cfg.Table)); err != nil {
_ = db.Close()
panic(err)
}
@@ -78,9 +87,9 @@ func New(config ...Config) *Storage {
// Init database queries
for _, query := range initQuery {
if _, err := db.Exec(fmt.Sprintf(query, cfg.TableName)); err != nil {
if _, err := db.Exec(fmt.Sprintf(query, cfg.Table)); err != nil {
_ = db.Close()
fmt.Println(fmt.Sprintf(query, cfg.TableName))
fmt.Println(fmt.Sprintf(query, cfg.Table))
panic(err)
}
}
@@ -89,11 +98,11 @@ func New(config ...Config) *Storage {
store := &Storage{
db: db,
gcInterval: cfg.GCInterval,
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE key=$1;`, cfg.TableName),
sqlInsert: fmt.Sprintf("INSERT INTO %s (key, data, exp) VALUES ($1, $2, $3)", cfg.TableName),
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE key=$1", cfg.TableName),
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.TableName),
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= $1", cfg.TableName),
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE key=$1;`, cfg.Table),
sqlInsert: fmt.Sprintf("INSERT INTO %s (key, data, exp) VALUES ($1, $2, $3)", cfg.Table),
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE key=$1", cfg.Table),
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.Table),
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= $1", cfg.Table),
}
// Start garbage collector
@@ -107,7 +116,6 @@ var noRows = errors.New("sql: no rows in result set")
// Get value by key
func (s *Storage) Get(key string) ([]byte, error) {
row := s.db.QueryRow(s.sqlSelect, key)
// Add db response to data
var (
data = []byte{}

View File

@@ -2,38 +2,38 @@
package postgres
var testStore *Storage
import (
"os"
"testing"
"time"
func init() {
testConfig := ConfigDefault
testConfig.Addr = "127.0.0.1:5432"
"github.com/gofiber/utils"
)
if v := os.Getenv("POSTGRES_ADDR"); v != "" {
testConfig.Addr = v
}
var testStore = New(Config{
Database: os.Getenv("POSTGRES_DATABASE"),
Username: os.Getenv("POSTGRES_USERNAME"),
Password: os.Getenv("POSTGRES_PASSWORD"),
Clear: true,
})
testStore = New(testConfig)
}
func Test_Redis_Set(t *testing.T) {
func Test_Postgres_Set(t *testing.T) {
var (
store = testStore
key = "john"
val = []byte("doe")
key = "john"
val = []byte("doe")
)
err := store.Set(key, val, 0)
err := testStore.(key, val, 0)
utils.AssertEqual(t, nil, err)
}
func Test_Redis_Get(t *testing.T) {
func Test_Postgres_Get(t *testing.T) {
var (
store = testStore
key = "john"
val = []byte("doe")
key = "john"
val = []byte("doe")
)
err := store.Set(key, val, 0)
err := testStore.(key, val, 0)
utils.AssertEqual(t, nil, err)
result, err := store.Get(key)
@@ -41,25 +41,23 @@ func Test_Redis_Get(t *testing.T) {
utils.AssertEqual(t, val, result)
}
func Test_Redis_Set_Expiration(t *testing.T) {
func Test_Postgres_Set_Expiration(t *testing.T) {
var (
store = testStore
key = "john"
val = []byte("doe")
exp = 500 * time.Millisecond
key = "john"
val = []byte("doe")
exp = 500 * time.Millisecond
)
err := store.Set(key, val, exp)
err := testStore.(key, val, exp)
utils.AssertEqual(t, nil, err)
time.Sleep(1 * time.Second)
}
func Test_Redis_Get_Expired(t *testing.T) {
func Test_Postgres_Get_Expired(t *testing.T) {
var (
store = testStore
key = "john"
key = "john"
)
result, err := store.Get(key)
@@ -67,22 +65,21 @@ func Test_Redis_Get_Expired(t *testing.T) {
utils.AssertEqual(t, true, len(result) == 0)
}
func Test_Redis_Get_NotExist(t *testing.T) {
var store = testStore
func Test_Postgres_Get_NotExist(t *testing.T) {
result, err := store.Get("notexist")
utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0)
}
func Test_Redis_Delete(t *testing.T) {
func Test_Postgres_Delete(t *testing.T) {
var (
store = testStore
key = "john"
val = []byte("doe")
key = "john"
val = []byte("doe")
)
err := store.Set(key, val, 0)
err := testStore.(key, val, 0)
utils.AssertEqual(t, nil, err)
err = store.Delete(key)
@@ -93,16 +90,15 @@ func Test_Redis_Delete(t *testing.T) {
utils.AssertEqual(t, true, len(result) == 0)
}
func Test_Redis_Clear(t *testing.T) {
func Test_Postgres_Clear(t *testing.T) {
var (
store = testStore
val = []byte("doe")
val = []byte("doe")
)
err := store.Set("john1", val, 0)
err := testStore.("john1", val, 0)
utils.AssertEqual(t, nil, err)
err = store.Set("john2", val, 0)
err = testStore.("john2", val, 0)
utils.AssertEqual(t, nil, err)
err = store.Clear()