mirror of
https://github.com/gofiber/storage.git
synced 2025-10-05 08:37:10 +08:00
✏ refactor storage
This commit is contained in:
@@ -26,9 +26,7 @@ store := memcache.New()
|
|||||||
|
|
||||||
// Initialize custom config
|
// Initialize custom config
|
||||||
store := memcache.New(memcache.Config{
|
store := memcache.New(memcache.Config{
|
||||||
Servers: "localhost:11211",
|
Servers: "localhost:11211",
|
||||||
Timeout: 100 * time.Millisecond,
|
|
||||||
MaxIdleConns: 10,
|
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -40,19 +38,6 @@ type Config struct {
|
|||||||
//
|
//
|
||||||
// Optional. Default is "127.0.0.1:11211"
|
// Optional. Default is "127.0.0.1:11211"
|
||||||
Servers string
|
Servers string
|
||||||
|
|
||||||
// The socket read/write timeout.
|
|
||||||
//
|
|
||||||
// Optional. Default is 100 * time.Millisecond
|
|
||||||
Timeout time.Duration
|
|
||||||
|
|
||||||
// The maximum number of idle connections that will be maintained per address.
|
|
||||||
//
|
|
||||||
// Consider your expected traffic rates and latency carefully. This should
|
|
||||||
// be set to a number higher than your peak parallel requests.
|
|
||||||
//
|
|
||||||
// Optional. Default is 2
|
|
||||||
MaxIdleConns int
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -60,7 +45,5 @@ type Config struct {
|
|||||||
```go
|
```go
|
||||||
var ConfigDefault = Config{
|
var ConfigDefault = Config{
|
||||||
Servers: "localhost:11211",
|
Servers: "localhost:11211",
|
||||||
Timeout: 100 * time.Millisecond,
|
|
||||||
MaxIdleConns: 2,
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@@ -13,7 +13,7 @@ type Config struct {
|
|||||||
// The socket read/write timeout.
|
// The socket read/write timeout.
|
||||||
//
|
//
|
||||||
// Optional. Default is 100 * time.Millisecond
|
// Optional. Default is 100 * time.Millisecond
|
||||||
Timeout time.Duration
|
timeout time.Duration
|
||||||
|
|
||||||
// The maximum number of idle connections that will be maintained per address.
|
// The maximum number of idle connections that will be maintained per address.
|
||||||
//
|
//
|
||||||
@@ -21,14 +21,14 @@ type Config struct {
|
|||||||
// be set to a number higher than your peak parallel requests.
|
// be set to a number higher than your peak parallel requests.
|
||||||
//
|
//
|
||||||
// Optional. Default is 2
|
// Optional. Default is 2
|
||||||
MaxIdleConns int
|
maxIdleConns int
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigDefault is the default config
|
// ConfigDefault is the default config
|
||||||
var ConfigDefault = Config{
|
var ConfigDefault = Config{
|
||||||
Servers: "localhost:11211",
|
Servers: "localhost:11211",
|
||||||
Timeout: 100 * time.Millisecond,
|
timeout: 100 * time.Millisecond,
|
||||||
MaxIdleConns: 2,
|
maxIdleConns: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to set default values
|
// Helper function to set default values
|
||||||
@@ -45,12 +45,12 @@ func configDefault(config ...Config) Config {
|
|||||||
if len(cfg.Servers) < 1 {
|
if len(cfg.Servers) < 1 {
|
||||||
cfg.Servers = ConfigDefault.Servers
|
cfg.Servers = ConfigDefault.Servers
|
||||||
}
|
}
|
||||||
if int(cfg.Timeout) == 0 {
|
// if int(cfg.Timeout) == 0 {
|
||||||
cfg.Timeout = ConfigDefault.Timeout
|
// cfg.Timeout = ConfigDefault.Timeout
|
||||||
}
|
// }
|
||||||
if cfg.MaxIdleConns == 0 {
|
// if cfg.MaxIdleConns == 0 {
|
||||||
cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
// cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
||||||
}
|
// }
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package memcache
|
package memcache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -15,6 +16,9 @@ type Storage struct {
|
|||||||
items *sync.Pool
|
items *sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common storage errors
|
||||||
|
var ErrNotExist = errors.New("key does not exist")
|
||||||
|
|
||||||
// New creates a new storage
|
// New creates a new storage
|
||||||
func New(config ...Config) *Storage {
|
func New(config ...Config) *Storage {
|
||||||
// Set default config
|
// Set default config
|
||||||
@@ -27,8 +31,8 @@ func New(config ...Config) *Storage {
|
|||||||
db := mc.New(serverList...)
|
db := mc.New(serverList...)
|
||||||
|
|
||||||
// Set options
|
// Set options
|
||||||
db.Timeout = cfg.Timeout
|
db.Timeout = cfg.timeout
|
||||||
db.MaxIdleConns = cfg.MaxIdleConns
|
db.MaxIdleConns = cfg.maxIdleConns
|
||||||
|
|
||||||
// Ping database to ensure a connection has been made
|
// Ping database to ensure a connection has been made
|
||||||
if err := db.Ping(); err != nil {
|
if err := db.Ping(); err != nil {
|
||||||
|
@@ -1,3 +1,105 @@
|
|||||||
// +build memcache
|
// +build memcache
|
||||||
|
|
||||||
package memcache
|
package memcache
|
||||||
|
|
||||||
|
func Test_Redis_Set(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, val, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
exp = 500 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, exp)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get_Expired(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get_NotExist(t *testing.T) {
|
||||||
|
var store = testStore
|
||||||
|
|
||||||
|
result, err := store.Get("notexist")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Delete(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Delete(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Clear(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set("john1", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Set("john2", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Clear()
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get("john1")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
|
result, err = store.Get("john2")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package memory
|
package memory
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -12,6 +13,9 @@ type Storage struct {
|
|||||||
gcInterval time.Duration
|
gcInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common storage errors
|
||||||
|
var ErrNotExist = errors.New("key does not exist")
|
||||||
|
|
||||||
type entry struct {
|
type entry struct {
|
||||||
data []byte
|
data []byte
|
||||||
expiry int64
|
expiry int64
|
||||||
|
@@ -9,181 +9,104 @@ import (
|
|||||||
"github.com/gofiber/utils"
|
"github.com/gofiber/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Memory_Config(t *testing.T) {
|
func Test_Redis_Set(t *testing.T) {
|
||||||
t.Parallel()
|
var (
|
||||||
|
store = testStore
|
||||||
store := New(Config{})
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
utils.AssertEqual(t, ConfigDefault.GCInterval, store.gcInterval)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Memory_Set(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
store := New()
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
err := store.Set(id, value, 0)
|
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, entry{value, 0}, store.db[id])
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Memory_SetExpiry(t *testing.T) {
|
func Test_Redis_Get(t *testing.T) {
|
||||||
t.Parallel()
|
var (
|
||||||
|
store = testStore
|
||||||
store := New()
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
id := "hello"
|
)
|
||||||
value := []byte("Hi there!")
|
|
||||||
expiry := time.Second * 10
|
|
||||||
|
|
||||||
err := store.Set(id, value, expiry)
|
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
now := time.Now().Unix()
|
result, err := store.Get(key)
|
||||||
fromStore, found := store.db[id]
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, true, found)
|
utils.AssertEqual(t, val, result)
|
||||||
|
|
||||||
delta := fromStore.expiry - now
|
|
||||||
upperBound := int64(expiry.Seconds())
|
|
||||||
lowerBound := upperBound - 2
|
|
||||||
|
|
||||||
if !(delta <= upperBound && delta > lowerBound) {
|
|
||||||
t.Fatalf("Test_SetExpiry: expiry delta out of bounds (is %d, must be %d<x<=%d)", delta, lowerBound, upperBound)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Memory_GC(t *testing.T) {
|
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||||
t.Parallel()
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
exp = 500 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
store := &Storage{
|
err := store.Set(key, val, exp)
|
||||||
db: make(map[string]entry),
|
|
||||||
gcInterval: time.Millisecond * 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
expireAt := time.Now().Add(-time.Second).Unix()
|
|
||||||
|
|
||||||
store.db[id] = entry{value, expireAt}
|
|
||||||
|
|
||||||
go store.gc()
|
|
||||||
|
|
||||||
// The purpose of the long delay is to ensure the GC has time to run and delete the value
|
|
||||||
time.Sleep(time.Millisecond * 15)
|
|
||||||
|
|
||||||
store.mux.RLock()
|
|
||||||
_, found := store.db[id]
|
|
||||||
utils.AssertEqual(t, false, found)
|
|
||||||
store.mux.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Memory_Get(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
store := New()
|
|
||||||
|
|
||||||
t.Run("exist", func(t *testing.T) {
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.db[id] = entry{value, 0}
|
|
||||||
|
|
||||||
returnedValue, err := store.Get(id)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
|
||||||
utils.AssertEqual(t, value, returnedValue)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("expired", func(t *testing.T) {
|
|
||||||
expired := "expired"
|
|
||||||
store.db[expired] = entry{[]byte{}, time.Now().Add(-time.Second).Unix()}
|
|
||||||
|
|
||||||
returnedValue, err := store.Get(expired)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
|
||||||
utils.AssertEqual(t, true, returnedValue == nil)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("non-exist", func(t *testing.T) {
|
|
||||||
returnedValue, err := store.Get("non-exist")
|
|
||||||
utils.AssertEqual(t, nil, err)
|
|
||||||
utils.AssertEqual(t, true, returnedValue == nil)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Memory_Delete(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
store := New()
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.db[id] = entry{value, 0}
|
|
||||||
|
|
||||||
err := store.Delete(id)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
_, found := store.db[id]
|
time.Sleep(1 * time.Second)
|
||||||
utils.AssertEqual(t, false, found)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Memory_Clear(t *testing.T) {
|
func Test_Redis_Get_Expired(t *testing.T) {
|
||||||
t.Parallel()
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
)
|
||||||
|
|
||||||
store := New()
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
id := "hello"
|
func Test_Redis_Get_NotExist(t *testing.T) {
|
||||||
value := []byte("Hi there!")
|
var store = testStore
|
||||||
|
|
||||||
store.db[id] = entry{value, 0}
|
result, err := store.Get("notexist")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
err := store.Clear()
|
func Test_Redis_Delete(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, make(map[string]entry), store.db)
|
|
||||||
|
|
||||||
|
err = store.Delete(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_Memory_Set(b *testing.B) {
|
func Test_Redis_Clear(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
store := New()
|
err := store.Set("john1", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
id := "hello"
|
err = store.Set("john2", val, 0)
|
||||||
value := []byte("Hi there!")
|
utils.AssertEqual(t, nil, err)
|
||||||
expiry := time.Duration(0)
|
|
||||||
|
|
||||||
b.ReportAllocs()
|
err = store.Clear()
|
||||||
b.ResetTimer()
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
result, err := store.Get("john1")
|
||||||
for pb.Next() {
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
_ = store.Set(id, value, expiry)
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
|
||||||
})
|
result, err = store.Get("john2")
|
||||||
}
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
func Benchmark_Memory_Get(b *testing.B) {
|
|
||||||
|
|
||||||
store := New()
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.db[id] = entry{value, 0}
|
|
||||||
|
|
||||||
b.ReportAllocs()
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
|
||||||
for pb.Next() {
|
|
||||||
_, _ = store.Get(id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package mongodb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -18,6 +19,9 @@ type Storage struct {
|
|||||||
items *sync.Pool
|
items *sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common storage errors
|
||||||
|
var ErrNotExist = errors.New("key does not exist")
|
||||||
|
|
||||||
type item struct {
|
type item struct {
|
||||||
ObjectID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
|
ObjectID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
|
||||||
Key string `json:"key" bson:"key"`
|
Key string `json:"key" bson:"key"`
|
||||||
|
@@ -3,12 +3,11 @@
|
|||||||
package mongodb
|
package mongodb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"github.com/gofiber/utils"
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -27,141 +26,104 @@ func getConfig() Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(arr []string, item string) bool {
|
func Test_Redis_Set(t *testing.T) {
|
||||||
for _, i := range arr {
|
var (
|
||||||
if i == item {
|
store = testStore
|
||||||
return true
|
key = "john"
|
||||||
}
|
val = []byte("doe")
|
||||||
}
|
)
|
||||||
return false
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MongoDB_Set_Get(t *testing.T) {
|
func Test_Redis_Get(t *testing.T) {
|
||||||
if uri == "" {
|
var (
|
||||||
t.Skip()
|
store = testStore
|
||||||
}
|
key = "john"
|
||||||
store := New(getConfig())
|
val = []byte("doe")
|
||||||
defer func() {
|
)
|
||||||
_ = store.db.Client().Disconnect(context.TODO())
|
|
||||||
}()
|
|
||||||
|
|
||||||
key := "example_key"
|
err := store.Set(key, val, 0)
|
||||||
value := []byte("123")
|
|
||||||
|
|
||||||
err := store.Set(key, value, 0)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
getVal, getErr := store.Get(key)
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, nil, getErr)
|
utils.AssertEqual(t, val, result)
|
||||||
utils.AssertEqual(t, value, getVal, "correctly set and get value")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MongoDB_Get_Invalid(t *testing.T) {
|
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||||
if uri == "" {
|
var (
|
||||||
t.Skip()
|
store = testStore
|
||||||
}
|
key = "john"
|
||||||
store := New(getConfig())
|
val = []byte("doe")
|
||||||
defer func() {
|
exp = 500 * time.Millisecond
|
||||||
_ = store.db.Client().Disconnect(context.TODO())
|
)
|
||||||
}()
|
|
||||||
|
|
||||||
key := "random_invalid_key"
|
err := store.Set(key, val, exp)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
getVal, getErr := store.Get(key)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
utils.AssertEqual(t, true, getErr != nil)
|
|
||||||
utils.AssertEqual(t, true, getVal == nil, "get nil if key not found")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MongoDB_Set_Replace(t *testing.T) {
|
func Test_Redis_Get_Expired(t *testing.T) {
|
||||||
if uri == "" {
|
var (
|
||||||
t.Skip()
|
store = testStore
|
||||||
}
|
key = "john"
|
||||||
store := New(getConfig())
|
)
|
||||||
defer func() {
|
|
||||||
_ = store.db.Client().Disconnect(context.TODO())
|
|
||||||
}()
|
|
||||||
|
|
||||||
key := "replace_key"
|
result, err := store.Get(key)
|
||||||
value1 := []byte("value1")
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
value2 := []byte("value2")
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
setErr1 := store.Set(key, value1, 0)
|
|
||||||
setErr2 := store.Set(key, value2, 0)
|
|
||||||
val, getErr := store.Get(key)
|
|
||||||
|
|
||||||
utils.AssertEqual(t, true, setErr1 == nil)
|
|
||||||
utils.AssertEqual(t, true, setErr2 == nil)
|
|
||||||
utils.AssertEqual(t, true, getErr == nil)
|
|
||||||
|
|
||||||
utils.AssertEqual(t, value2, val, "replace value if key exists")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MongoDB_SetExpiry(t *testing.T) {
|
func Test_Redis_Get_NotExist(t *testing.T) {
|
||||||
if uri == "" {
|
var store = testStore
|
||||||
t.Skip()
|
|
||||||
}
|
|
||||||
store := New(getConfig())
|
|
||||||
defer func() {
|
|
||||||
_ = store.db.Client().Disconnect(context.TODO())
|
|
||||||
}()
|
|
||||||
|
|
||||||
key := "example_key_2"
|
result, err := store.Get("notexist")
|
||||||
value := []byte("123")
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
setErr := store.Set(key, value, 1*time.Nanosecond)
|
|
||||||
utils.AssertEqual(t, true, setErr == nil)
|
|
||||||
|
|
||||||
val, getErr := store.Get(key)
|
|
||||||
utils.AssertEqual(t, true, getErr == nil)
|
|
||||||
utils.AssertEqual(t, true, val == nil, "get nil if key is expire")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MongoDB_Delete(t *testing.T) {
|
func Test_Redis_Delete(t *testing.T) {
|
||||||
if uri == "" {
|
var (
|
||||||
t.Skip()
|
store = testStore
|
||||||
}
|
key = "john"
|
||||||
store := New(getConfig())
|
val = []byte("doe")
|
||||||
defer func() {
|
)
|
||||||
_ = store.db.Client().Disconnect(context.TODO())
|
|
||||||
}()
|
|
||||||
|
|
||||||
key := "example_key_3"
|
err := store.Set(key, val, 0)
|
||||||
value := []byte("123")
|
|
||||||
|
|
||||||
err := store.Set(key, value, 0)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
err = store.Delete(key)
|
err = store.Delete(key)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
getVal, getErr := store.Get(key)
|
result, err := store.Get(key)
|
||||||
utils.AssertEqual(t, true, getErr != nil)
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
utils.AssertEqual(t, true, getVal == nil, "correctly delete value")
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MongoDB_Clear(t *testing.T) {
|
func Test_Redis_Clear(t *testing.T) {
|
||||||
if uri == "" {
|
var (
|
||||||
t.Skip()
|
store = testStore
|
||||||
}
|
val = []byte("doe")
|
||||||
store := New(getConfig())
|
)
|
||||||
defer func() {
|
|
||||||
_ = store.db.Client().Disconnect(context.TODO())
|
|
||||||
}()
|
|
||||||
|
|
||||||
key := "example_key_4"
|
|
||||||
value := []byte("123")
|
|
||||||
|
|
||||||
err := store.Set(key, value, 10)
|
|
||||||
names, _ := store.db.ListCollectionNames(context.TODO(), bson.D{})
|
|
||||||
|
|
||||||
|
err := store.Set("john1", val, 0)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, true, contains(names, colName), "has collection")
|
|
||||||
|
|
||||||
cErr := store.Clear()
|
err = store.Set("john2", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
names2, _ := store.db.ListCollectionNames(context.TODO(), bson.D{})
|
err = store.Clear()
|
||||||
utils.AssertEqual(t, nil, cErr)
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, false, contains(names2, colName), "do not have collection")
|
|
||||||
|
result, err := store.Get("john1")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
|
result, err = store.Get("john2")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
@@ -1,34 +1,56 @@
|
|||||||
# MySQL
|
# MySQL
|
||||||
|
|
||||||
A MySQL storage driver using `database/sql` and [`go-sql-driver/mysql`](https://github.com/go-sql-driver/mysql).
|
A MySQL storage driver using `database/sql` and [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql).
|
||||||
|
|
||||||
### Creation
|
### Table of Contents
|
||||||
|
- [Signatures](#signatures)
|
||||||
To create a new instance of the MySQL store, is is reccomended that you provide a database name, a table name, a username and a password. The database must exist beforehand, but the table will be created if it does not exist.
|
- [Examples](#examples)
|
||||||
|
- [Config](#config)
|
||||||
|
- [Default Config](#default-config)
|
||||||
|
|
||||||
|
### Signatures
|
||||||
```go
|
```go
|
||||||
// import "github.com/gomodule/redigo/redis"
|
func New(config ...Config) Storage
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
Import the storage package.
|
||||||
|
```go
|
||||||
|
import "github.com/gofiber/storage/mysql"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use the following possibilities to create a storage:
|
||||||
|
```go
|
||||||
|
// Initialize default config
|
||||||
|
store := mysql.New()
|
||||||
|
|
||||||
|
// Initialize custom config
|
||||||
store := mysql.New(mysql.Config{
|
store := mysql.New(mysql.Config{
|
||||||
DatabaseName: "myDb",
|
GCInterval: 10 * time.Second,
|
||||||
TableName: "thisStore",
|
Address: "127.0.0.1:3306",
|
||||||
Username: "user",
|
TableName: "fiber",
|
||||||
Password: "yourPasswordHere",
|
DatabaseName: "fiber",
|
||||||
|
DropTable: false,
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
By default the store will connect to a database on `127.0.0.1:3306`. If you are using multiple MySQL stores in your application, it is strongly advised that you use different table names for each, to avoid data being overwritten or otherwise damaged.
|
### Config
|
||||||
|
```go
|
||||||
|
type Config struct {
|
||||||
|
// Time before deleting expired keys
|
||||||
|
//
|
||||||
|
// Default is 10 * time.Second
|
||||||
|
GCInterval time.Duration
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
A full list of configuration options and their defaults can be found [in `config.go`](/config.go).
|
### Default Config
|
||||||
|
```go
|
||||||
### Running tests/benchmarks
|
var ConfigDefault = Config{
|
||||||
|
GCInterval: 10 * time.Second,
|
||||||
Tests and benchmarks for this package require a running MySQL server, and assume you have one at `127.0.0.1:3306`. The following environment variables can be used to configure the tests:
|
Address: "127.0.0.1:3306",
|
||||||
|
TableName: "fiber",
|
||||||
| Name | Corresponding `Config` option |
|
DatabaseName: "fiber",
|
||||||
| ---------------- | ----------------------------- |
|
DropTable: false,
|
||||||
| `MYSQL_ADDRESS` | `Address` |
|
}
|
||||||
| `MYSQL_USERNAME` | `Username` |
|
```
|
||||||
| `MYSQL_PASSWORD` | `Password` |
|
|
||||||
| `MYSQL_DATABASE` | `DatabaseName` |
|
|
||||||
|
|
||||||
If a given environment variable is not set, the default value is used.
|
|
||||||
|
@@ -48,7 +48,7 @@ type Config struct {
|
|||||||
// If n < 0, no idle connections are retained.
|
// If n < 0, no idle connections are retained.
|
||||||
//
|
//
|
||||||
// The default is 100.
|
// The default is 100.
|
||||||
MaxIdleConns int
|
maxIdleConns int
|
||||||
|
|
||||||
// The maximum number of open connections to the database.
|
// The maximum number of open connections to the database.
|
||||||
//
|
//
|
||||||
@@ -59,7 +59,7 @@ type Config struct {
|
|||||||
// If n < 0, then there is no limit on the number of open connections.
|
// If n < 0, then there is no limit on the number of open connections.
|
||||||
//
|
//
|
||||||
// The default is 100.
|
// The default is 100.
|
||||||
MaxOpenConns int
|
maxOpenConns int
|
||||||
|
|
||||||
// The maximum amount of time a connection may be reused.
|
// The maximum amount of time a connection may be reused.
|
||||||
//
|
//
|
||||||
@@ -68,7 +68,7 @@ type Config struct {
|
|||||||
// If d < 0, connections are reused forever.
|
// If d < 0, connections are reused forever.
|
||||||
//
|
//
|
||||||
// The default is 1 * time.Second
|
// The default is 1 * time.Second
|
||||||
ConnMaxLifetime time.Duration
|
connMaxLifetime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigDefault is the default config
|
// ConfigDefault is the default config
|
||||||
@@ -78,9 +78,9 @@ var ConfigDefault = Config{
|
|||||||
TableName: "fiber",
|
TableName: "fiber",
|
||||||
DatabaseName: "fiber",
|
DatabaseName: "fiber",
|
||||||
DropTable: false,
|
DropTable: false,
|
||||||
MaxOpenConns: 100,
|
maxOpenConns: 100,
|
||||||
MaxIdleConns: 100,
|
maxIdleConns: 100,
|
||||||
ConnMaxLifetime: 1 * time.Second,
|
connMaxLifetime: 1 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to set default values
|
// Helper function to set default values
|
||||||
@@ -112,15 +112,15 @@ func configDefault(config ...Config) Config {
|
|||||||
if cfg.DatabaseName == "" {
|
if cfg.DatabaseName == "" {
|
||||||
cfg.DatabaseName = ConfigDefault.DatabaseName
|
cfg.DatabaseName = ConfigDefault.DatabaseName
|
||||||
}
|
}
|
||||||
if cfg.MaxOpenConns == 0 {
|
// if cfg.MaxOpenConns == 0 {
|
||||||
cfg.MaxOpenConns = ConfigDefault.MaxOpenConns
|
// cfg.MaxOpenConns = ConfigDefault.MaxOpenConns
|
||||||
}
|
// }
|
||||||
if cfg.MaxIdleConns == 0 {
|
// if cfg.MaxIdleConns == 0 {
|
||||||
cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
// cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
||||||
}
|
// }
|
||||||
if int(cfg.ConnMaxLifetime) == 0 {
|
// if int(cfg.ConnMaxLifetime) == 0 {
|
||||||
cfg.ConnMaxLifetime = ConfigDefault.ConnMaxLifetime
|
// cfg.ConnMaxLifetime = ConfigDefault.ConnMaxLifetime
|
||||||
}
|
// }
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ package mysql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -21,6 +22,9 @@ type Storage struct {
|
|||||||
sqlGC string
|
sqlGC string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common storage errors
|
||||||
|
var ErrNotExist = errors.New("key does not exist")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dropQuery = "DROP TABLE IF EXISTS %s;"
|
dropQuery = "DROP TABLE IF EXISTS %s;"
|
||||||
initQuery = []string{
|
initQuery = []string{
|
||||||
@@ -41,9 +45,9 @@ func New(config ...Config) *Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set options
|
// Set options
|
||||||
db.SetMaxOpenConns(cfg.MaxOpenConns)
|
db.SetMaxOpenConns(cfg.maxOpenConns)
|
||||||
db.SetMaxIdleConns(cfg.MaxIdleConns)
|
db.SetMaxIdleConns(cfg.maxIdleConns)
|
||||||
db.SetConnMaxLifetime(cfg.ConnMaxLifetime)
|
db.SetConnMaxLifetime(cfg.connMaxLifetime)
|
||||||
|
|
||||||
// Ping database to ensure a connection has been made
|
// Ping database to ensure a connection has been made
|
||||||
if err := db.Ping(); err != nil {
|
if err := db.Ping(); err != nil {
|
||||||
|
@@ -29,159 +29,104 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MySQL_Set(t *testing.T) {
|
func Test_Redis_Set(t *testing.T) {
|
||||||
|
|
||||||
store := New(storeConfig)
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.Set(id, value, 0)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
returnedValue []byte
|
store = testStore
|
||||||
exp int64
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
)
|
)
|
||||||
|
|
||||||
store.db.QueryRow(store.sqlSelect, id).Scan(&returnedValue, &exp)
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, returnedValue, value)
|
|
||||||
utils.AssertEqual(t, exp, int64(0))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MySQL_SetExpiry(t *testing.T) {
|
func Test_Redis_Get(t *testing.T) {
|
||||||
|
|
||||||
store := New(storeConfig)
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
expiry := time.Second * 10
|
|
||||||
|
|
||||||
store.Set(id, value, expiry)
|
|
||||||
|
|
||||||
now := time.Now().Unix()
|
|
||||||
var (
|
var (
|
||||||
returnedValue []byte
|
store = testStore
|
||||||
exp int64
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
)
|
)
|
||||||
store.db.QueryRow(store.sqlSelect, id).Scan(&returnedValue, &exp)
|
|
||||||
|
|
||||||
delta := exp - now
|
err := store.Set(key, val, 0)
|
||||||
upperBound := int64(expiry.Seconds())
|
|
||||||
lowerBound := upperBound - 2
|
|
||||||
|
|
||||||
if !(delta <= upperBound && delta > lowerBound) {
|
|
||||||
t.Fatalf("Test_SetExpiry: expiry delta out of bounds (is %d, must be %d<x<=%d)", delta, lowerBound, upperBound)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_MySQL_Get(t *testing.T) {
|
|
||||||
|
|
||||||
store := New(storeConfig)
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.db.Exec(store.sqlInsert, id, utils.UnsafeString(value), 0)
|
|
||||||
|
|
||||||
returnedValue, err := store.Get(id)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
|
||||||
utils.AssertEqual(t, value, returnedValue)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_MySQL_Get_NoRows(t *testing.T) {
|
|
||||||
|
|
||||||
store := New(storeConfig)
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
|
|
||||||
returnedValue, err := store.Get(id)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
|
||||||
utils.AssertEqual(t, 0, len(returnedValue))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_MySQL_Get_Expired(t *testing.T) {
|
|
||||||
|
|
||||||
store := New(storeConfig)
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.db.Exec(store.sqlInsert, id, utils.UnsafeString(value), time.Now().Add(time.Minute*-1).Unix())
|
|
||||||
|
|
||||||
returnedValue, err := store.Get(id)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
|
||||||
utils.AssertEqual(t, 0, len(returnedValue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_MySQL_Delete(t *testing.T) {
|
|
||||||
|
|
||||||
store := New(storeConfig)
|
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.db.Exec(store.sqlInsert, id, utils.UnsafeString(value), 0)
|
|
||||||
|
|
||||||
err := store.Delete(id)
|
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
row := store.db.QueryRow(store.sqlSelect, id)
|
result, err := store.Get(key)
|
||||||
err = row.Scan()
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, noRows, err.Error())
|
utils.AssertEqual(t, val, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_MySQL_Clear(t *testing.T) {
|
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
exp = 500 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
store := New(storeConfig)
|
err := store.Set(key, val, exp)
|
||||||
|
|
||||||
id := "hello"
|
|
||||||
value := []byte("Hi there!")
|
|
||||||
|
|
||||||
store.db.Exec(store.sqlInsert, id, utils.UnsafeString(value), 0)
|
|
||||||
|
|
||||||
err := store.Clear()
|
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
row := store.db.QueryRow(store.sqlSelect, id)
|
time.Sleep(1 * time.Second)
|
||||||
err = row.Scan()
|
|
||||||
utils.AssertEqual(t, noRows, err.Error())
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_MySQL_Set(b *testing.B) {
|
func Test_Redis_Get_Expired(t *testing.T) {
|
||||||
store := New(storeConfig)
|
var (
|
||||||
|
store = testStore
|
||||||
key := "aaaa"
|
key = "john"
|
||||||
val := []byte("This is a value")
|
)
|
||||||
|
|
||||||
expiry := time.Second * 60
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
store.Set(key, val, expiry)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_MySQL_Get(b *testing.B) {
|
func Test_Redis_Get_NotExist(t *testing.T) {
|
||||||
store := New(storeConfig)
|
var store = testStore
|
||||||
|
|
||||||
key := "aaaa"
|
|
||||||
val := []byte("This is a value")
|
|
||||||
|
|
||||||
store.Set(key, val, 0)
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
store.Get(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
result, err := store.Get("notexist")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Delete(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Delete(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Clear(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set("john1", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Set("john2", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Clear()
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get("john1")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
|
result, err = store.Get("john2")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
@@ -32,10 +32,6 @@ store := postgres.New(postgres.Config{
|
|||||||
Database: "fiber",
|
Database: "fiber",
|
||||||
TableName: "fiber",
|
TableName: "fiber",
|
||||||
DropTable: false,
|
DropTable: false,
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
MaxOpenConns: 100,
|
|
||||||
MaxIdleConns: 100,
|
|
||||||
ConnMaxLifetime: 1 * time.Second,
|
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -82,38 +78,6 @@ type Config struct {
|
|||||||
//
|
//
|
||||||
// Optional. Default is false
|
// Optional. Default is false
|
||||||
DropTable bool
|
DropTable bool
|
||||||
|
|
||||||
// Maximum wait for connection, in seconds. Zero or
|
|
||||||
// n < 0 means wait indefinitely.
|
|
||||||
Timeout time.Duration
|
|
||||||
|
|
||||||
// The maximum number of connections in the idle connection pool.
|
|
||||||
//
|
|
||||||
// If MaxOpenConns is greater than 0 but less than the new MaxIdleConns,
|
|
||||||
// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.
|
|
||||||
//
|
|
||||||
// If n <= 0, no idle connections are retained.
|
|
||||||
//
|
|
||||||
// The default max idle connections is currently 2. This may change in
|
|
||||||
// a future release.
|
|
||||||
MaxIdleConns int
|
|
||||||
|
|
||||||
// The maximum number of open connections to the database.
|
|
||||||
//
|
|
||||||
// If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than
|
|
||||||
// MaxIdleConns, then MaxIdleConns will be reduced to match the new
|
|
||||||
// MaxOpenConns limit.
|
|
||||||
//
|
|
||||||
// If n <= 0, then there is no limit on the number of open connections.
|
|
||||||
// The default is 0 (unlimited).
|
|
||||||
MaxOpenConns int
|
|
||||||
|
|
||||||
// The maximum amount of time a connection may be reused.
|
|
||||||
//
|
|
||||||
// Expired connections may be closed lazily before reuse.
|
|
||||||
//
|
|
||||||
// If d <= 0, connections are reused forever.
|
|
||||||
ConnMaxLifetime time.Duration
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -126,9 +90,5 @@ var ConfigDefault = Config{
|
|||||||
Database: "fiber",
|
Database: "fiber",
|
||||||
TableName: "fiber",
|
TableName: "fiber",
|
||||||
DropTable: false,
|
DropTable: false,
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
MaxOpenConns: 100,
|
|
||||||
MaxIdleConns: 100,
|
|
||||||
ConnMaxLifetime: 1 * time.Second,
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@@ -46,7 +46,7 @@ type Config struct {
|
|||||||
|
|
||||||
// Maximum wait for connection, in seconds. Zero or
|
// Maximum wait for connection, in seconds. Zero or
|
||||||
// n < 0 means wait indefinitely.
|
// n < 0 means wait indefinitely.
|
||||||
Timeout time.Duration
|
timeout time.Duration
|
||||||
|
|
||||||
// The maximum number of connections in the idle connection pool.
|
// The maximum number of connections in the idle connection pool.
|
||||||
//
|
//
|
||||||
@@ -57,7 +57,7 @@ type Config struct {
|
|||||||
//
|
//
|
||||||
// The default max idle connections is currently 2. This may change in
|
// The default max idle connections is currently 2. This may change in
|
||||||
// a future release.
|
// a future release.
|
||||||
MaxIdleConns int
|
maxIdleConns int
|
||||||
|
|
||||||
// The maximum number of open connections to the database.
|
// The maximum number of open connections to the database.
|
||||||
//
|
//
|
||||||
@@ -67,14 +67,14 @@ type Config struct {
|
|||||||
//
|
//
|
||||||
// If n <= 0, then there is no limit on the number of open connections.
|
// If n <= 0, then there is no limit on the number of open connections.
|
||||||
// The default is 0 (unlimited).
|
// The default is 0 (unlimited).
|
||||||
MaxOpenConns int
|
maxOpenConns int
|
||||||
|
|
||||||
// The maximum amount of time a connection may be reused.
|
// The maximum amount of time a connection may be reused.
|
||||||
//
|
//
|
||||||
// Expired connections may be closed lazily before reuse.
|
// Expired connections may be closed lazily before reuse.
|
||||||
//
|
//
|
||||||
// If d <= 0, connections are reused forever.
|
// If d <= 0, connections are reused forever.
|
||||||
ConnMaxLifetime time.Duration
|
connMaxLifetime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigDefault is the default config
|
// ConfigDefault is the default config
|
||||||
@@ -85,10 +85,10 @@ var ConfigDefault = Config{
|
|||||||
Database: "fiber",
|
Database: "fiber",
|
||||||
TableName: "fiber",
|
TableName: "fiber",
|
||||||
DropTable: false,
|
DropTable: false,
|
||||||
Timeout: 30 * time.Second,
|
timeout: 30 * time.Second,
|
||||||
MaxOpenConns: 100,
|
maxOpenConns: 100,
|
||||||
MaxIdleConns: 100,
|
maxIdleConns: 100,
|
||||||
ConnMaxLifetime: 1 * time.Second,
|
connMaxLifetime: 1 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to set default values
|
// Helper function to set default values
|
||||||
@@ -120,17 +120,17 @@ func configDefault(config ...Config) Config {
|
|||||||
if cfg.TableName == "" {
|
if cfg.TableName == "" {
|
||||||
cfg.TableName = ConfigDefault.TableName
|
cfg.TableName = ConfigDefault.TableName
|
||||||
}
|
}
|
||||||
if int(cfg.Timeout) == 0 {
|
// if int(cfg.Timeout) == 0 {
|
||||||
cfg.Timeout = ConfigDefault.Timeout
|
// cfg.Timeout = ConfigDefault.Timeout
|
||||||
}
|
// }
|
||||||
if cfg.MaxOpenConns == 0 {
|
// if cfg.MaxOpenConns == 0 {
|
||||||
cfg.MaxOpenConns = ConfigDefault.MaxOpenConns
|
// cfg.MaxOpenConns = ConfigDefault.MaxOpenConns
|
||||||
}
|
// }
|
||||||
if cfg.MaxIdleConns == 0 {
|
// if cfg.MaxIdleConns == 0 {
|
||||||
cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
// cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
||||||
}
|
// }
|
||||||
if int(cfg.ConnMaxLifetime) == 0 {
|
// if int(cfg.ConnMaxLifetime) == 0 {
|
||||||
cfg.ConnMaxLifetime = ConfigDefault.ConnMaxLifetime
|
// cfg.ConnMaxLifetime = ConfigDefault.ConnMaxLifetime
|
||||||
}
|
// }
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,9 @@ type Storage struct {
|
|||||||
sqlGC string
|
sqlGC string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common storage errors
|
||||||
|
var ErrNotExist = errors.New("key does not exist")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dropQuery = `DROP TABLE IF EXISTS %s;`
|
dropQuery = `DROP TABLE IF EXISTS %s;`
|
||||||
initQuery = []string{
|
initQuery = []string{
|
||||||
@@ -47,7 +50,7 @@ func New(config ...Config) *Storage {
|
|||||||
url.QueryEscape(cfg.Host),
|
url.QueryEscape(cfg.Host),
|
||||||
cfg.Port,
|
cfg.Port,
|
||||||
url.QueryEscape(cfg.Database),
|
url.QueryEscape(cfg.Database),
|
||||||
int64(cfg.Timeout.Seconds()))
|
int64(cfg.timeout.Seconds()))
|
||||||
|
|
||||||
// Create db
|
// Create db
|
||||||
db, err := sql.Open("postgres", dsn)
|
db, err := sql.Open("postgres", dsn)
|
||||||
@@ -56,9 +59,9 @@ func New(config ...Config) *Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set database options
|
// Set database options
|
||||||
db.SetMaxOpenConns(cfg.MaxOpenConns)
|
db.SetMaxOpenConns(cfg.maxOpenConns)
|
||||||
db.SetMaxIdleConns(cfg.MaxIdleConns)
|
db.SetMaxIdleConns(cfg.maxIdleConns)
|
||||||
db.SetConnMaxLifetime(cfg.ConnMaxLifetime)
|
db.SetConnMaxLifetime(cfg.connMaxLifetime)
|
||||||
|
|
||||||
// Ping database
|
// Ping database
|
||||||
if err := db.Ping(); err != nil {
|
if err := db.Ping(); err != nil {
|
||||||
|
@@ -1,3 +1,118 @@
|
|||||||
// +build postgres
|
// +build postgres
|
||||||
|
|
||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
|
var testStore *Storage
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
testConfig := ConfigDefault
|
||||||
|
testConfig.Addr = "127.0.0.1:5432"
|
||||||
|
|
||||||
|
if v := os.Getenv("POSTGRES_ADDR"); v != "" {
|
||||||
|
testConfig.Addr = v
|
||||||
|
}
|
||||||
|
|
||||||
|
testStore = New(testConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Set(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, val, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
exp = 500 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, exp)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get_Expired(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get_NotExist(t *testing.T) {
|
||||||
|
var store = testStore
|
||||||
|
|
||||||
|
result, err := store.Get("notexist")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Delete(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Delete(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Clear(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set("john1", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Set("john2", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Clear()
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get("john1")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
|
result, err = store.Get("john2")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package redis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
@@ -12,6 +13,9 @@ type Storage struct {
|
|||||||
db *redis.Client
|
db *redis.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common storage errors
|
||||||
|
var ErrNotExist = errors.New("key does not exist")
|
||||||
|
|
||||||
// New creates a new redis storage
|
// New creates a new redis storage
|
||||||
func New(config ...Config) *Storage {
|
func New(config ...Config) *Storage {
|
||||||
// Set default config
|
// Set default config
|
||||||
@@ -55,13 +59,10 @@ func New(config ...Config) *Storage {
|
|||||||
// Get value by key
|
// Get value by key
|
||||||
func (s *Storage) Get(key string) ([]byte, error) {
|
func (s *Storage) Get(key string) ([]byte, error) {
|
||||||
val, err := s.db.Get(context.Background(), key).Bytes()
|
val, err := s.db.Get(context.Background(), key).Bytes()
|
||||||
if err != nil {
|
if err == redis.Nil {
|
||||||
if err != redis.Nil {
|
return nil, ErrNotExist
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
return val, nil
|
return val, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set key with value
|
// Set key with value
|
||||||
|
@@ -41,13 +41,12 @@ func Test_Redis_Get(t *testing.T) {
|
|||||||
val = []byte("doe")
|
val = []byte("doe")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
result, err := store.Get(key)
|
result, err := store.Get(key)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, val, result)
|
utils.AssertEqual(t, val, result)
|
||||||
|
|
||||||
result, err = store.Get("doe")
|
|
||||||
utils.AssertEqual(t, nil, err)
|
|
||||||
utils.AssertEqual(t, true, len(result) == 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Redis_Set_Expiration(t *testing.T) {
|
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||||
@@ -72,7 +71,15 @@ func Test_Redis_Get_Expired(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
result, err := store.Get(key)
|
result, err := store.Get(key)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get_NotExist(t *testing.T) {
|
||||||
|
var store = testStore
|
||||||
|
|
||||||
|
result, err := store.Get("notexist")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
utils.AssertEqual(t, true, len(result) == 0)
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +97,7 @@ func Test_Redis_Delete(t *testing.T) {
|
|||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
result, err := store.Get(key)
|
result, err := store.Get(key)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
utils.AssertEqual(t, true, len(result) == 0)
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,10 +117,10 @@ func Test_Redis_Clear(t *testing.T) {
|
|||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
result, err := store.Get("john1")
|
result, err := store.Get("john1")
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
utils.AssertEqual(t, true, len(result) == 0)
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
result, err = store.Get("john2")
|
result, err = store.Get("john2")
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
utils.AssertEqual(t, true, len(result) == 0)
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
@@ -30,9 +30,6 @@ store := sqlite3.New(sqlite3.Config{
|
|||||||
Database: "./fiber.sqlite3",
|
Database: "./fiber.sqlite3",
|
||||||
TableName: "fiber",
|
TableName: "fiber",
|
||||||
DropTable: false,
|
DropTable: false,
|
||||||
MaxOpenConns: 100,
|
|
||||||
MaxIdleConns: 100,
|
|
||||||
ConnMaxLifetime: 1 * time.Second,
|
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -56,36 +53,6 @@ type Config struct {
|
|||||||
|
|
||||||
// When set to true, this will Drop any existing table with the same name
|
// When set to true, this will Drop any existing table with the same name
|
||||||
DropTable bool
|
DropTable bool
|
||||||
|
|
||||||
// The maximum number of connections in the idle connection pool.
|
|
||||||
//
|
|
||||||
// If MaxOpenConns is greater than 0 but less than the new MaxIdleConns,
|
|
||||||
// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.
|
|
||||||
//
|
|
||||||
// If n < 0, no idle connections are retained.
|
|
||||||
//
|
|
||||||
// The default is 100.
|
|
||||||
MaxIdleConns int
|
|
||||||
|
|
||||||
// The maximum number of open connections to the database.
|
|
||||||
//
|
|
||||||
// If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than
|
|
||||||
// MaxIdleConns, then MaxIdleConns will be reduced to match the new
|
|
||||||
// MaxOpenConns limit.
|
|
||||||
//
|
|
||||||
// If n < 0, then there is no limit on the number of open connections.
|
|
||||||
//
|
|
||||||
// The default is 100.
|
|
||||||
MaxOpenConns int
|
|
||||||
|
|
||||||
// The maximum amount of time a connection may be reused.
|
|
||||||
//
|
|
||||||
// Expired connections may be closed lazily before reuse.
|
|
||||||
//
|
|
||||||
// If d < 0, connections are reused forever.
|
|
||||||
//
|
|
||||||
// The default is 1 * time.Second
|
|
||||||
ConnMaxLifetime time.Duration
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -96,8 +63,5 @@ var ConfigDefault = Config{
|
|||||||
Database: "./fiber.sqlite3",
|
Database: "./fiber.sqlite3",
|
||||||
TableName: "fiber",
|
TableName: "fiber",
|
||||||
DropTable: false,
|
DropTable: false,
|
||||||
MaxOpenConns: 100,
|
|
||||||
MaxIdleConns: 100,
|
|
||||||
ConnMaxLifetime: 1 * time.Second,
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@@ -30,7 +30,7 @@ type Config struct {
|
|||||||
// If n < 0, no idle connections are retained.
|
// If n < 0, no idle connections are retained.
|
||||||
//
|
//
|
||||||
// The default is 100.
|
// The default is 100.
|
||||||
MaxIdleConns int
|
maxIdleConns int
|
||||||
|
|
||||||
// The maximum number of open connections to the database.
|
// The maximum number of open connections to the database.
|
||||||
//
|
//
|
||||||
@@ -41,7 +41,7 @@ type Config struct {
|
|||||||
// If n < 0, then there is no limit on the number of open connections.
|
// If n < 0, then there is no limit on the number of open connections.
|
||||||
//
|
//
|
||||||
// The default is 100.
|
// The default is 100.
|
||||||
MaxOpenConns int
|
maxOpenConns int
|
||||||
|
|
||||||
// The maximum amount of time a connection may be reused.
|
// The maximum amount of time a connection may be reused.
|
||||||
//
|
//
|
||||||
@@ -50,7 +50,7 @@ type Config struct {
|
|||||||
// If d < 0, connections are reused forever.
|
// If d < 0, connections are reused forever.
|
||||||
//
|
//
|
||||||
// The default is 1 * time.Second
|
// The default is 1 * time.Second
|
||||||
ConnMaxLifetime time.Duration
|
connMaxLifetime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigDefault is the default config
|
// ConfigDefault is the default config
|
||||||
@@ -59,9 +59,9 @@ var ConfigDefault = Config{
|
|||||||
Database: "./fiber.sqlite3",
|
Database: "./fiber.sqlite3",
|
||||||
TableName: "fiber",
|
TableName: "fiber",
|
||||||
DropTable: false,
|
DropTable: false,
|
||||||
MaxOpenConns: 100,
|
maxOpenConns: 100,
|
||||||
MaxIdleConns: 100,
|
maxIdleConns: 100,
|
||||||
ConnMaxLifetime: 1 * time.Second,
|
connMaxLifetime: 1 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to set default values
|
// Helper function to set default values
|
||||||
@@ -84,14 +84,14 @@ func configDefault(config ...Config) Config {
|
|||||||
if cfg.TableName == "" {
|
if cfg.TableName == "" {
|
||||||
cfg.TableName = ConfigDefault.TableName
|
cfg.TableName = ConfigDefault.TableName
|
||||||
}
|
}
|
||||||
if cfg.MaxOpenConns == 0 {
|
// if cfg.MaxOpenConns == 0 {
|
||||||
cfg.MaxOpenConns = ConfigDefault.MaxOpenConns
|
// cfg.MaxOpenConns = ConfigDefault.MaxOpenConns
|
||||||
}
|
// }
|
||||||
if cfg.MaxIdleConns == 0 {
|
// if cfg.MaxIdleConns == 0 {
|
||||||
cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
// cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
||||||
}
|
// }
|
||||||
if int(cfg.ConnMaxLifetime) == 0 {
|
// if int(cfg.ConnMaxLifetime) == 0 {
|
||||||
cfg.ConnMaxLifetime = ConfigDefault.ConnMaxLifetime
|
// cfg.ConnMaxLifetime = ConfigDefault.ConnMaxLifetime
|
||||||
}
|
// }
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package sqlite3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -22,6 +23,9 @@ type Storage struct {
|
|||||||
sqlGC string
|
sqlGC string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common storage errors
|
||||||
|
var ErrNotExist = errors.New("key does not exist")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dropQuery = `DROP TABLE IF EXISTS %s;`
|
dropQuery = `DROP TABLE IF EXISTS %s;`
|
||||||
initQuery = []string{
|
initQuery = []string{
|
||||||
@@ -46,9 +50,9 @@ func New(config ...Config) *Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set database options
|
// Set database options
|
||||||
db.SetMaxOpenConns(cfg.MaxOpenConns)
|
db.SetMaxOpenConns(cfg.maxOpenConns)
|
||||||
db.SetMaxIdleConns(cfg.MaxIdleConns)
|
db.SetMaxIdleConns(cfg.maxIdleConns)
|
||||||
db.SetConnMaxLifetime(cfg.ConnMaxLifetime)
|
db.SetConnMaxLifetime(cfg.connMaxLifetime)
|
||||||
|
|
||||||
// Ping database
|
// Ping database
|
||||||
if err := db.Ping(); err != nil {
|
if err := db.Ping(); err != nil {
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
// +build sqlite3
|
||||||
|
|
||||||
package sqlite3
|
package sqlite3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -8,31 +10,113 @@ import (
|
|||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_New(t *testing.T) {
|
var testStore *Storage
|
||||||
New()
|
|
||||||
|
func init() {
|
||||||
|
testConfig := ConfigDefault
|
||||||
|
testConfig.Database = ":memory:"
|
||||||
|
|
||||||
|
testStore = New(testConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Sqlite_Get_Set(t *testing.T) {
|
func Test_Redis_Set(t *testing.T) {
|
||||||
s := New(Config{
|
var (
|
||||||
Database: ":memory:",
|
store = testStore
|
||||||
})
|
key = "john"
|
||||||
err := s.Set("fiber-10k-stars?", []byte("yes!"), time.Duration(time.Hour*1))
|
val = []byte("doe")
|
||||||
utils.AssertEqual(t, nil, err)
|
)
|
||||||
|
|
||||||
b, err := s.Get("fiber-10k-stars?")
|
err := store.Set(key, val, 0)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, []byte("yes!"), b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Sqlite_Expiration(t *testing.T) {
|
func Test_Redis_Get(t *testing.T) {
|
||||||
s := New(Config{
|
var (
|
||||||
Database: ":memory:",
|
store = testStore
|
||||||
})
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
err := s.Set("fiber-20k-stars?", []byte("yes!"), time.Duration(time.Nanosecond/2))
|
err := store.Set(key, val, 0)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
b, err := s.Get("fiber-220k-stars?")
|
result, err := store.Get(key)
|
||||||
utils.AssertEqual(t, nil, err)
|
utils.AssertEqual(t, nil, err)
|
||||||
utils.AssertEqual(t, true, b == nil)
|
utils.AssertEqual(t, val, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
exp = 500 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, exp)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get_Expired(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Get_NotExist(t *testing.T) {
|
||||||
|
var store = testStore
|
||||||
|
|
||||||
|
result, err := store.Get("notexist")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Delete(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Delete(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get(key)
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Redis_Clear(t *testing.T) {
|
||||||
|
var (
|
||||||
|
store = testStore
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := store.Set("john1", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Set("john2", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = store.Clear()
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := store.Get("john1")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
|
result, err = store.Get("john2")
|
||||||
|
utils.AssertEqual(t, ErrNotExist, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user