mirror of
https://github.com/gofiber/storage.git
synced 2025-10-05 08:37:10 +08:00
🎄 xmas present
This commit is contained in:
16
.github/workflows/test-mongodb.yml
vendored
16
.github/workflows/test-mongodb.yml
vendored
@@ -1,23 +1,13 @@
|
||||
on: [push, pull_request]
|
||||
name: Test MongoDB
|
||||
|
||||
name: MongoDB test
|
||||
jobs:
|
||||
# Label of the container job
|
||||
mongodb-tests:
|
||||
# Containers must run in Linux based operating systems
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Service containers to run with `container-job`
|
||||
services:
|
||||
# Label used to access the service container
|
||||
mongo:
|
||||
# Docker Hub image
|
||||
image: mongo:4.4
|
||||
image: mongo:latest
|
||||
ports:
|
||||
- 27017:27017
|
||||
env:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: password
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.14.x, 1.15.x]
|
||||
@@ -30,5 +20,3 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: go test ./mongodb -tags=mongodb -v -race
|
||||
env:
|
||||
MONGO_URI: "mongodb://root:password@127.0.0.1:27017"
|
||||
|
20
.github/workflows/test-mysql.yml
vendored
20
.github/workflows/test-mysql.yml
vendored
@@ -1,26 +1,13 @@
|
||||
on: [push, pull_request]
|
||||
name: MySQL test
|
||||
|
||||
jobs:
|
||||
# Label of the container job
|
||||
mysql-tests:
|
||||
# Containers must run in Linux based operating systems
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Service containers to run with `container-job`
|
||||
services:
|
||||
# Label used to access the service container
|
||||
mysql:
|
||||
# Docker Hub image
|
||||
image: mysql:8
|
||||
env:
|
||||
MYSQL_USER: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_ROOT_PASSWORD: rootpassword
|
||||
MYSQL_DATABASE: fiber
|
||||
image: mysql:latest
|
||||
ports:
|
||||
- 3306:3306
|
||||
# Set health checks to wait until MySQL has started
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping"
|
||||
--health-interval 10s
|
||||
@@ -38,8 +25,3 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: go test ./mysql -tags=mysql -v -race
|
||||
env:
|
||||
MYSQL_ADDRESS: "127.0.0.1:3306"
|
||||
MYSQL_USERNAME: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_DATABASE: fiber
|
||||
|
2
.github/workflows/test-redis.yml
vendored
2
.github/workflows/test-redis.yml
vendored
@@ -20,5 +20,3 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: go test ./redis -tags=redis -v -race
|
||||
env:
|
||||
REDIS_ADDR: "127.0.0.1:6379"
|
||||
|
18
.github/workflows/test-sqlite3.yml
vendored
Normal file
18
.github/workflows/test-sqlite3.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
on: [push, pull_request]
|
||||
name: SQLite3 test
|
||||
jobs:
|
||||
Build:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.14.x, 1.15.x]
|
||||
platform: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: go test ./sqlite3 -tags=sqlite3 -v -race
|
8
go.mod
8
go.mod
@@ -3,11 +3,17 @@ module github.com/gofiber/storage
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go v1.35.21 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
|
||||
github.com/go-redis/redis/v8 v8.3.3
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gofiber/utils v0.1.0
|
||||
github.com/golang/snappy v0.0.2 // indirect
|
||||
github.com/klauspost/compress v1.11.2 // indirect
|
||||
github.com/lib/pq v1.8.0
|
||||
github.com/mattn/go-sqlite3 v1.14.4
|
||||
go.mongodb.org/mongo-driver v1.4.2
|
||||
go.mongodb.org/mongo-driver v1.4.3
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
)
|
||||
|
14
go.sum
14
go.sum
@@ -1,6 +1,8 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk=
|
||||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
||||
github.com/aws/aws-sdk-go v1.35.21 h1:6cMeHzcca+0uweOpUonDYv4DsPp9Qa9PTMYxH+VqDkY=
|
||||
github.com/aws/aws-sdk-go v1.35.21/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
@@ -56,6 +58,8 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
|
||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@@ -72,6 +76,8 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR
|
||||
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
|
||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
|
||||
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@@ -125,6 +131,8 @@ github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwX
|
||||
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
go.mongodb.org/mongo-driver v1.4.2 h1:WlnEglfTg/PfPq4WXs2Vkl/5ICC6hoG8+r+LraPmGk4=
|
||||
go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.mongodb.org/mongo-driver v1.4.3 h1:moga+uhicpVshTyaqY9L23E6QqwcHRUv1sqyOsoyOO8=
|
||||
go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
|
||||
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -133,6 +141,8 @@ golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaE
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -146,6 +156,8 @@ golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -165,6 +177,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
|
@@ -7,9 +7,14 @@ type Config struct {
|
||||
// Server list divided by ,
|
||||
// i.e. server1:11211, server2:11212
|
||||
//
|
||||
// Optional. Default is "localhost:11211"
|
||||
// Optional. Default is "127.0.0.1:11211"
|
||||
Servers string
|
||||
|
||||
// Clear any existing keys in existing Table
|
||||
//
|
||||
// Optional. Default is false
|
||||
Clear bool
|
||||
|
||||
// The socket read/write timeout.
|
||||
//
|
||||
// Optional. Default is 100 * time.Millisecond
|
||||
@@ -26,7 +31,7 @@ type Config struct {
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Servers: "localhost:11211",
|
||||
Servers: "127.0.0.1:11211",
|
||||
timeout: 100 * time.Millisecond,
|
||||
maxIdleConns: 2,
|
||||
}
|
||||
@@ -45,12 +50,6 @@ func configDefault(config ...Config) Config {
|
||||
if len(cfg.Servers) < 1 {
|
||||
cfg.Servers = ConfigDefault.Servers
|
||||
}
|
||||
// if int(cfg.Timeout) == 0 {
|
||||
// cfg.Timeout = ConfigDefault.Timeout
|
||||
// }
|
||||
// if cfg.MaxIdleConns == 0 {
|
||||
// cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
|
||||
// }
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
@@ -39,6 +39,12 @@ func New(config ...Config) *Storage {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if cfg.Clear {
|
||||
if err := db.DeleteAll(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create storage
|
||||
store := &Storage{
|
||||
db: db,
|
||||
|
@@ -2,104 +2,106 @@
|
||||
|
||||
package memcache
|
||||
|
||||
func Test_Redis_Set(t *testing.T) {
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/utils"
|
||||
)
|
||||
|
||||
var testStore = New()
|
||||
|
||||
func Test_Memcache_Set(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
}
|
||||
|
||||
func Test_Redis_Get(t *testing.T) {
|
||||
func Test_Memcache_Get(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, val, result)
|
||||
}
|
||||
|
||||
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||
func Test_Memcache_Set_Expiration(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
exp = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
err := store.Set(key, val, exp)
|
||||
err := testStore.Set(key, val, exp)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
}
|
||||
|
||||
func Test_Redis_Get_Expired(t *testing.T) {
|
||||
func Test_Memcache_Get_Expired(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.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
|
||||
func Test_Memcache_Get_NotExist(t *testing.T) {
|
||||
|
||||
result, err := store.Get("notexist")
|
||||
result, err := testStore.Get("notexist")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Delete(t *testing.T) {
|
||||
func Test_Memcache_Delete(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Delete(key)
|
||||
err = testStore.Delete(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Clear(t *testing.T) {
|
||||
func Test_Memcache_Clear(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set("john1", val, 0)
|
||||
err := testStore.Set("john1", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Set("john2", val, 0)
|
||||
err = testStore.Set("john2", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Clear()
|
||||
err = testStore.Clear()
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get("john1")
|
||||
result, err := testStore.Get("john1")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
|
||||
result, err = store.Get("john2")
|
||||
result, err = testStore.Get("john2")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
@@ -9,104 +9,100 @@ import (
|
||||
"github.com/gofiber/utils"
|
||||
)
|
||||
|
||||
func Test_Redis_Set(t *testing.T) {
|
||||
var testStore = New()
|
||||
|
||||
func Test_Memory_Set(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
}
|
||||
|
||||
func Test_Redis_Get(t *testing.T) {
|
||||
func Test_Memory_Get(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, val, result)
|
||||
}
|
||||
|
||||
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||
func Test_Memory_Set_Expiration(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
exp = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
err := store.Set(key, val, exp)
|
||||
err := testStore.Set(key, val, exp)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
}
|
||||
|
||||
func Test_Redis_Get_Expired(t *testing.T) {
|
||||
func Test_Memory_Get_Expired(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.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
|
||||
func Test_Memory_Get_NotExist(t *testing.T) {
|
||||
|
||||
result, err := store.Get("notexist")
|
||||
|
||||
result, err := testStore.Get("notexist")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Delete(t *testing.T) {
|
||||
func Test_Memory_Delete(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Delete(key)
|
||||
err = testStore.Delete(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Clear(t *testing.T) {
|
||||
func Test_Memory_Clear(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set("john1", val, 0)
|
||||
err := testStore.Set("john1", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Set("john2", val, 0)
|
||||
err = testStore.Set("john2", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Clear()
|
||||
err = testStore.Clear()
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get("john1")
|
||||
result, err := testStore.Get("john1")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
|
||||
result, err = store.Get("john2")
|
||||
result, err = testStore.Get("john2")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
@@ -1,60 +1,60 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/bsoncodec"
|
||||
"go.mongodb.org/mongo-driver/event"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/mongo/readconcern"
|
||||
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||
"go.mongodb.org/mongo-driver/mongo/writeconcern"
|
||||
)
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
//https://docs.mongodb.com/manual/reference/connection-string/
|
||||
URI string
|
||||
// Host name where the DB is hosted
|
||||
//
|
||||
// Optional. Default is "127.0.0.1"
|
||||
Host string
|
||||
|
||||
// Port where the DB is listening on
|
||||
//
|
||||
// Optional. Default is 27017
|
||||
Port int
|
||||
|
||||
// Server username
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Username string
|
||||
|
||||
// Server password
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Password string
|
||||
|
||||
// Database name
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
Database string
|
||||
|
||||
// Collection name
|
||||
//
|
||||
// Optional. Default is "fiber_storage"
|
||||
Collection string
|
||||
|
||||
// https://pkg.go.dev/go.mongodb.org/mongo-driver@v1.4.2/mongo/options#ClientOptions
|
||||
AppName string
|
||||
Auth options.Credential
|
||||
AutoEncryptionOptions *options.AutoEncryptionOptions
|
||||
ConnectTimeout time.Duration
|
||||
Compressors []string
|
||||
Dialer options.ContextDialer
|
||||
Direct bool
|
||||
DisableOCSPEndpointCheck bool
|
||||
HeartbeatInterval time.Duration
|
||||
Hosts []string
|
||||
LocalThreshold time.Duration
|
||||
MaxConnIdleTime time.Duration
|
||||
MaxPoolSize uint64
|
||||
MinPoolSize uint64
|
||||
PoolMonitor *event.PoolMonitor
|
||||
Monitor *event.CommandMonitor
|
||||
ReadConcern *readconcern.ReadConcern
|
||||
ReadPreference *readpref.ReadPref
|
||||
Registry *bsoncodec.Registry
|
||||
ReplicaSet string
|
||||
RetryReads bool
|
||||
RetryWrites bool
|
||||
ServerSelectionTimeout time.Duration
|
||||
SocketTimeout time.Duration
|
||||
TLSConfig *tls.Config
|
||||
WriteConcern *writeconcern.WriteConcern
|
||||
ZlibLevel int
|
||||
ZstdLevel int
|
||||
// Clear any existing keys in existing Table
|
||||
//
|
||||
// Optional. Default is false
|
||||
Clear bool
|
||||
|
||||
// Time before deleting expired keys
|
||||
//
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
URI: "mongodb://127.0.0.1:27017",
|
||||
Host: "127.0.0.1",
|
||||
Port: 27017,
|
||||
Database: "fiber",
|
||||
Collection: "fiber",
|
||||
Collection: "fiber_storage",
|
||||
Clear: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
@@ -68,8 +68,11 @@ func configDefault(config ...Config) Config {
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.URI == "" {
|
||||
cfg.URI = ConfigDefault.URI
|
||||
if cfg.Host == "" {
|
||||
cfg.Host = ConfigDefault.Host
|
||||
}
|
||||
if cfg.Port <= 0 {
|
||||
cfg.Port = ConfigDefault.Port
|
||||
}
|
||||
if cfg.Database == "" {
|
||||
cfg.Database = ConfigDefault.Database
|
||||
|
@@ -3,6 +3,7 @@ package mongodb
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -34,44 +35,24 @@ func New(config ...Config) *Storage {
|
||||
// Set default config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Set mongo options
|
||||
opt := options.Client()
|
||||
opt.SetAppName(cfg.AppName)
|
||||
opt.SetAuth(cfg.Auth)
|
||||
opt.SetAutoEncryptionOptions(cfg.AutoEncryptionOptions)
|
||||
opt.SetConnectTimeout(cfg.ConnectTimeout)
|
||||
opt.SetCompressors(cfg.Compressors)
|
||||
opt.SetDialer(cfg.Dialer)
|
||||
opt.SetDirect(cfg.Direct)
|
||||
opt.SetDisableOCSPEndpointCheck(cfg.DisableOCSPEndpointCheck)
|
||||
opt.SetHosts(cfg.Hosts)
|
||||
opt.SetLocalThreshold(cfg.LocalThreshold)
|
||||
opt.SetMaxConnIdleTime(cfg.MaxConnIdleTime)
|
||||
opt.SetMaxPoolSize(cfg.MaxPoolSize)
|
||||
opt.SetMinPoolSize(cfg.MinPoolSize)
|
||||
opt.SetPoolMonitor(cfg.PoolMonitor)
|
||||
opt.SetMonitor(cfg.Monitor)
|
||||
opt.SetReadConcern(cfg.ReadConcern)
|
||||
opt.SetReadPreference(cfg.ReadPreference)
|
||||
opt.SetRegistry(cfg.Registry)
|
||||
opt.SetReplicaSet(cfg.ReplicaSet)
|
||||
opt.SetRetryReads(cfg.RetryReads)
|
||||
opt.SetRetryWrites(cfg.RetryWrites)
|
||||
opt.SetServerSelectionTimeout(cfg.ServerSelectionTimeout)
|
||||
opt.SetSocketTimeout(cfg.SocketTimeout)
|
||||
opt.SetTLSConfig(cfg.TLSConfig)
|
||||
opt.SetWriteConcern(cfg.WriteConcern)
|
||||
opt.SetZlibLevel(cfg.ZlibLevel)
|
||||
opt.SetZstdLevel(cfg.ZstdLevel)
|
||||
|
||||
// default time.Duration is not nil
|
||||
// will cause panic: non-positive interval for NewTicker
|
||||
if cfg.HeartbeatInterval > 0 {
|
||||
opt.SetHeartbeatInterval(cfg.HeartbeatInterval)
|
||||
// Create data source name
|
||||
var dsn string = "mongodb://"
|
||||
if cfg.Username != "" {
|
||||
dsn += url.QueryEscape(cfg.Username)
|
||||
}
|
||||
if cfg.Password != "" {
|
||||
dsn += ":" + cfg.Password
|
||||
}
|
||||
if cfg.Username != "" || cfg.Password != "" {
|
||||
dsn += "@"
|
||||
}
|
||||
|
||||
// Set mongo options
|
||||
opt := options.Client()
|
||||
opt.ApplyURI(dsn)
|
||||
|
||||
// Create mongo client
|
||||
client, err := mongo.NewClient(opt.ApplyURI(cfg.URI))
|
||||
client, err := mongo.NewClient(opt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@@ -3,127 +3,107 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
dbName = "fiberStorage"
|
||||
colName = "fiberStorage"
|
||||
)
|
||||
var testStore = New(Config{
|
||||
Clear: true,
|
||||
})
|
||||
|
||||
var uri = os.Getenv("MONGO_URI")
|
||||
|
||||
func getConfig() Config {
|
||||
|
||||
return Config{
|
||||
URI: uri,
|
||||
Database: dbName,
|
||||
Collection: colName,
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Redis_Set(t *testing.T) {
|
||||
func Test_MongoDB_Set(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
}
|
||||
|
||||
func Test_Redis_Get(t *testing.T) {
|
||||
func Test_MongoDB_Get(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, val, result)
|
||||
}
|
||||
|
||||
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||
func Test_MongoDB_Set_Expiration(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
exp = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
err := store.Set(key, val, exp)
|
||||
err := testStore.Set(key, val, exp)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
}
|
||||
|
||||
func Test_Redis_Get_Expired(t *testing.T) {
|
||||
func Test_MongoDB_Get_Expired(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.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
|
||||
func Test_MongoDB_Get_NotExist(t *testing.T) {
|
||||
|
||||
result, err := store.Get("notexist")
|
||||
result, err := testStore.Get("notexist")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Delete(t *testing.T) {
|
||||
func Test_MongoDB_Delete(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Delete(key)
|
||||
err = testStore.Delete(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Clear(t *testing.T) {
|
||||
func Test_MongoDB_Clear(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set("john1", val, 0)
|
||||
err := testStore.Set("john1", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Set("john2", val, 0)
|
||||
err = testStore.Set("john2", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Clear()
|
||||
err = testStore.Clear()
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get("john1")
|
||||
result, err := testStore.Get("john1")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
|
||||
result, err = store.Get("john2")
|
||||
result, err = testStore.Get("john2")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
@@ -26,20 +26,50 @@ store := mysql.New()
|
||||
|
||||
// Initialize custom config
|
||||
store := mysql.New(mysql.Config{
|
||||
Server: "127.0.0.1:3306",
|
||||
Database: "fiber",
|
||||
Table: "fiber",
|
||||
Drop: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
Address: "127.0.0.1:3306",
|
||||
TableName: "fiber",
|
||||
DatabaseName: "fiber",
|
||||
DropTable: false,
|
||||
})
|
||||
```
|
||||
|
||||
### Config
|
||||
```go
|
||||
type Config struct {
|
||||
// Server address in <host>:<port> format
|
||||
//
|
||||
// Optional. Default is "127.0.0.1:3306"
|
||||
Server string
|
||||
|
||||
// Server username
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Username string
|
||||
|
||||
// Server password
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Password string
|
||||
|
||||
// Database name
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
Database string
|
||||
|
||||
// Table name
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
Table string
|
||||
|
||||
// Drop any existing table with the same Table name
|
||||
//
|
||||
// Optional. Default is false
|
||||
Drop bool
|
||||
|
||||
// Time before deleting expired keys
|
||||
//
|
||||
// Default is 10 * time.Second
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
}
|
||||
```
|
||||
@@ -47,10 +77,10 @@ type Config struct {
|
||||
### Default Config
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Server: "127.0.0.1:3306",
|
||||
Database: "fiber",
|
||||
Table: "fiber",
|
||||
Drop: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
Address: "127.0.0.1:3306",
|
||||
TableName: "fiber",
|
||||
DatabaseName: "fiber",
|
||||
DropTable: false,
|
||||
}
|
||||
```
|
||||
|
124
mysql/config.go
124
mysql/config.go
@@ -7,82 +7,72 @@ import (
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
// Time before deleting expired keys
|
||||
// Host name where the DB is hosted
|
||||
//
|
||||
// Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
// Optional. Default is "127.0.0.1"
|
||||
Host string
|
||||
|
||||
// MySQL server address. Must include port.
|
||||
// Port where the DB is listening on
|
||||
//
|
||||
// Default is "127.0.0.1:3306"
|
||||
Address string
|
||||
// Optional. Default is 3306
|
||||
Port int
|
||||
|
||||
// MySQL server username
|
||||
// Server username
|
||||
//
|
||||
// Default is ""
|
||||
// Optional. Default is ""
|
||||
Username string
|
||||
|
||||
// MySQL server password
|
||||
// Server password
|
||||
//
|
||||
// Default is ""
|
||||
// Optional. Default is ""
|
||||
Password string
|
||||
|
||||
// MySQL database name
|
||||
// Database name
|
||||
//
|
||||
// Default is "fiber"
|
||||
DatabaseName string
|
||||
// Optional. Default is "fiber"
|
||||
Database string
|
||||
|
||||
// DB table name
|
||||
// Table name
|
||||
//
|
||||
// Default is "fiber"
|
||||
TableName string
|
||||
// Optional. Default is "fiber_storage"
|
||||
Table string
|
||||
|
||||
// When set to true, this will Drop any existing table with the same name
|
||||
DropTable bool
|
||||
// Clear any existing keys in existing Table
|
||||
//
|
||||
// Optional. Default is false
|
||||
Clear bool
|
||||
|
||||
// The maximum number of connections in the idle connection pool.
|
||||
// Time before deleting expired keys
|
||||
//
|
||||
// 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.
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
|
||||
////////////////////////////////////
|
||||
// Adaptor related config options //
|
||||
////////////////////////////////////
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 3306,
|
||||
Database: "fiber",
|
||||
Table: "fiber_storage",
|
||||
Clear: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
Address: "127.0.0.1:3306",
|
||||
TableName: "fiber",
|
||||
DatabaseName: "fiber",
|
||||
DropTable: false,
|
||||
maxOpenConns: 100,
|
||||
maxIdleConns: 100,
|
||||
connMaxLifetime: 1 * time.Second,
|
||||
}
|
||||
|
||||
func (c Config) dsn() string {
|
||||
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.Username, c.Password, c.Host, c.Port, c.Database)
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
@@ -94,36 +84,20 @@ func configDefault(config ...Config) Config {
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.Host == "" {
|
||||
cfg.Host = ConfigDefault.Host
|
||||
}
|
||||
if cfg.Port <= 0 {
|
||||
cfg.Port = ConfigDefault.Port
|
||||
}
|
||||
if cfg.Database == "" {
|
||||
cfg.Database = ConfigDefault.Database
|
||||
}
|
||||
if cfg.Table == "" {
|
||||
cfg.Table = ConfigDefault.Table
|
||||
}
|
||||
if int(cfg.GCInterval) == 0 {
|
||||
cfg.GCInterval = ConfigDefault.GCInterval
|
||||
}
|
||||
if cfg.Address == "" {
|
||||
cfg.Address = ConfigDefault.Address
|
||||
}
|
||||
if cfg.Username == "" {
|
||||
cfg.Username = ConfigDefault.Username
|
||||
}
|
||||
if cfg.Password == "" {
|
||||
cfg.Password = ConfigDefault.Password
|
||||
}
|
||||
if cfg.TableName == "" {
|
||||
cfg.TableName = ConfigDefault.TableName
|
||||
}
|
||||
if cfg.DatabaseName == "" {
|
||||
cfg.DatabaseName = ConfigDefault.DatabaseName
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
func (c Config) makeDSN() string {
|
||||
return fmt.Sprintf("%s:%s@tcp(%s)/%s", c.Username, c.Password, c.Address, c.DatabaseName)
|
||||
}
|
||||
|
@@ -29,7 +29,6 @@ var (
|
||||
dropQuery = "DROP TABLE IF EXISTS %s;"
|
||||
initQuery = []string{
|
||||
"CREATE TABLE IF NOT EXISTS %s ( `id` VARCHAR(64) NOT NULL DEFAULT '' , `data` TEXT NOT NULL , `exp` BIGINT NOT NULL DEFAULT '0' , PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;",
|
||||
// "CREATE INDEX IF NOT EXISTS exp ON %s (exp);", // This was causing syntax errors with MySQL in Docker, and it works without it sooo..... I guess remove it?
|
||||
}
|
||||
)
|
||||
|
||||
@@ -39,7 +38,7 @@ func New(config ...Config) *Storage {
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Create db
|
||||
db, err := sql.Open("mysql", cfg.makeDSN())
|
||||
db, err := sql.Open("mysql", cfg.dsn())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -54,22 +53,20 @@ func New(config ...Config) *Storage {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Drop table if set to true
|
||||
if cfg.DropTable {
|
||||
query := fmt.Sprintf(dropQuery, cfg.TableName)
|
||||
// Drop table if Clear set to true
|
||||
if cfg.Clear {
|
||||
query := fmt.Sprintf(dropQuery, cfg.Table)
|
||||
if _, err = db.Exec(query); err != nil {
|
||||
_ = db.Close()
|
||||
fmt.Println(query)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Init database queries
|
||||
for _, query := range initQuery {
|
||||
query = fmt.Sprintf(query, cfg.TableName)
|
||||
query = fmt.Sprintf(query, cfg.Table)
|
||||
if _, err := db.Exec(query); err != nil {
|
||||
_ = db.Close()
|
||||
fmt.Println(query)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -78,11 +75,11 @@ func New(config ...Config) *Storage {
|
||||
store := &Storage{
|
||||
gcInterval: cfg.GCInterval,
|
||||
db: db,
|
||||
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE id=?;`, cfg.TableName),
|
||||
sqlInsert: fmt.Sprintf("INSERT INTO %s (id, data, exp) VALUES (?,?,?)", cfg.TableName),
|
||||
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE id=?", cfg.TableName),
|
||||
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.TableName),
|
||||
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.TableName),
|
||||
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE id=?;`, cfg.Table),
|
||||
sqlInsert: fmt.Sprintf("INSERT INTO %s (id, data, exp) VALUES (?,?,?)", cfg.Table),
|
||||
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE id=?", cfg.Table),
|
||||
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.Table),
|
||||
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.Table),
|
||||
}
|
||||
|
||||
// Start garbage collector
|
||||
|
@@ -10,123 +10,105 @@ import (
|
||||
"github.com/gofiber/utils"
|
||||
)
|
||||
|
||||
var storeConfig = Config{
|
||||
DropTable: true,
|
||||
}
|
||||
var testStore = New(Config{
|
||||
Database: os.Getenv("MYSQL_DATABASE"),
|
||||
Username: os.Getenv("MYSQL_USERNAME"),
|
||||
Password: os.Getenv("MYSQL_PASSWORD"),
|
||||
Clear: true,
|
||||
})
|
||||
|
||||
func init() {
|
||||
if v := os.Getenv("MYSQL_ADDRESS"); v != "" {
|
||||
storeConfig.Address = v
|
||||
}
|
||||
if v := os.Getenv("MYSQL_USERNAME"); v != "" {
|
||||
storeConfig.Username = v
|
||||
}
|
||||
if v := os.Getenv("MYSQL_PASSWORD"); v != "" {
|
||||
storeConfig.Password = v
|
||||
}
|
||||
if v := os.Getenv("MYSQL_DATABASE"); v != "" {
|
||||
storeConfig.DatabaseName = v
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Redis_Set(t *testing.T) {
|
||||
func Test_MYSQL_Set(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
}
|
||||
|
||||
func Test_Redis_Get(t *testing.T) {
|
||||
func Test_MYSQL_Get(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, val, result)
|
||||
}
|
||||
|
||||
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||
func Test_MYSQL_Set_Expiration(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
exp = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
err := store.Set(key, val, exp)
|
||||
err := testStore.Set(key, val, exp)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
}
|
||||
|
||||
func Test_Redis_Get_Expired(t *testing.T) {
|
||||
func Test_MYSQL_Get_Expired(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.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
|
||||
func Test_MYSQL_Get_NotExist(t *testing.T) {
|
||||
|
||||
result, err := store.Get("notexist")
|
||||
|
||||
result, err := testStore.Get("notexist")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Delete(t *testing.T) {
|
||||
func Test_MYSQL_Delete(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Delete(key)
|
||||
err = testStore.Delete(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Clear(t *testing.T) {
|
||||
func Test_MYSQL_Clear(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set("john1", val, 0)
|
||||
err := testStore.Set("john1", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Set("john2", val, 0)
|
||||
err = testStore.Set("john2", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Clear()
|
||||
err = testStore.Clear()
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get("john1")
|
||||
result, err := testStore.Get("john1")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
|
||||
result, err = store.Get("john2")
|
||||
result, err = testStore.Get("john2")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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{}
|
||||
|
@@ -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")
|
||||
)
|
||||
|
||||
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")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
@@ -41,24 +41,22 @@ 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
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
)
|
||||
|
||||
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")
|
||||
)
|
||||
|
||||
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()
|
||||
|
132
redis/config.go
132
redis/config.go
@@ -1,111 +1,52 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
// Config defines the config for redis storage.
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
// Custom options
|
||||
// Host name where the DB is hosted
|
||||
//
|
||||
// Optional. Default is "127.0.0.1"
|
||||
Host string
|
||||
|
||||
// https://pkg.go.dev/github.com/go-redis/redis/v8#Options
|
||||
// Port where the DB is listening on
|
||||
//
|
||||
// Optional. Default is 3306
|
||||
Port int
|
||||
|
||||
// The network type, either tcp or unix.
|
||||
// Default is tcp.
|
||||
Network string
|
||||
|
||||
// host:port address.
|
||||
Addr string
|
||||
|
||||
// Dialer creates new network connection and has priority over
|
||||
// Network and Addr options.
|
||||
Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
|
||||
// Hook that is called when new connection is established.
|
||||
OnConnect func(ctx context.Context, cn *redis.Conn) error
|
||||
|
||||
// Use the specified Username to authenticate the current connection
|
||||
// with one of the connections defined in the ACL list when connecting
|
||||
// to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
|
||||
// Server username
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Username string
|
||||
// Optional password. Must match the password specified in the
|
||||
// requirepass server configuration option (if connecting to a Redis 5.0 instance, or lower),
|
||||
// or the User Password when connecting to a Redis 6.0 instance, or greater,
|
||||
// that is using the Redis ACL system.
|
||||
|
||||
// Server password
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Password string
|
||||
|
||||
// Database to be selected after connecting to the server.
|
||||
DB int
|
||||
//
|
||||
// Optional. Default is 0
|
||||
Database int
|
||||
|
||||
// Maximum number of retries before giving up.
|
||||
// Default is 3 retries.
|
||||
MaxRetries int
|
||||
// Clear any existing keys in existing Collection
|
||||
//
|
||||
// Optional. Default is false
|
||||
Clear bool
|
||||
|
||||
// Minimum backoff between each retry.
|
||||
// Default is 8 milliseconds; -1 disables backoff.
|
||||
MinRetryBackoff time.Duration
|
||||
////////////////////////////////////
|
||||
// Adaptor related config options //
|
||||
////////////////////////////////////
|
||||
|
||||
// Maximum backoff between each retry.
|
||||
// Default is 512 milliseconds; -1 disables backoff.
|
||||
MaxRetryBackoff time.Duration
|
||||
|
||||
// Dial timeout for establishing new connections.
|
||||
// Default is 5 seconds.
|
||||
DialTimeout time.Duration
|
||||
|
||||
// Timeout for socket reads. If reached, commands will fail
|
||||
// with a timeout instead of blocking. Use value -1 for no timeout and 0 for default.
|
||||
// Default is 3 seconds.
|
||||
ReadTimeout time.Duration
|
||||
|
||||
// Timeout for socket writes. If reached, commands will fail
|
||||
// with a timeout instead of blocking.
|
||||
// Default is ReadTimeout.
|
||||
WriteTimeout time.Duration
|
||||
|
||||
// Maximum number of socket connections.
|
||||
// Default is 10 connections per every CPU as reported by runtime.NumCPU.
|
||||
PoolSize int
|
||||
|
||||
// Minimum number of idle connections which is useful when establishing
|
||||
// new connection is slow.
|
||||
MinIdleConns int
|
||||
|
||||
// Connection age at which client retires (closes) the connection.
|
||||
// Default is to not close aged connections.
|
||||
MaxConnAge time.Duration
|
||||
|
||||
// Amount of time client waits for connection if all connections
|
||||
// are busy before returning an error.
|
||||
// Default is ReadTimeout + 1 second.
|
||||
PoolTimeout time.Duration
|
||||
|
||||
// Amount of time after which client closes idle connections.
|
||||
// Should be less than server's timeout.
|
||||
// Default is 5 minutes. -1 disables idle timeout check.
|
||||
IdleTimeout time.Duration
|
||||
|
||||
// Frequency of idle checks made by idle connections reaper.
|
||||
// Default is 1 minute. -1 disables idle connections reaper,
|
||||
// but idle connections are still discarded by the client
|
||||
// if IdleTimeout is set.
|
||||
IdleCheckFrequency time.Duration
|
||||
|
||||
// TLS Config to use. When set TLS will be negotiated.
|
||||
TLSConfig *tls.Config
|
||||
|
||||
// Limiter interface used to implemented circuit breaker or rate limiter.
|
||||
Limiter redis.Limiter
|
||||
// https://pkg.go.dev/github.com/go-redis/redis/v8#Options
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Addr: "127.0.0.1:6379",
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Username: "",
|
||||
Password: "",
|
||||
Database: 0,
|
||||
Clear: false,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
@@ -119,8 +60,11 @@ func configDefault(config ...Config) Config {
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.Addr == "" {
|
||||
cfg.Addr = ConfigDefault.Addr
|
||||
if cfg.Host == "" {
|
||||
cfg.Host = ConfigDefault.Host
|
||||
}
|
||||
if cfg.Port <= 0 {
|
||||
cfg.Port = ConfigDefault.Port
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package redis
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
@@ -23,33 +24,24 @@ func New(config ...Config) *Storage {
|
||||
|
||||
// Create new redis client
|
||||
db := redis.NewClient(&redis.Options{
|
||||
Network: cfg.Network,
|
||||
Addr: cfg.Addr,
|
||||
Dialer: cfg.Dialer,
|
||||
OnConnect: cfg.OnConnect,
|
||||
Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
|
||||
DB: cfg.Database,
|
||||
Username: cfg.Username,
|
||||
Password: cfg.Password,
|
||||
DB: cfg.DB,
|
||||
MaxRetries: cfg.MaxRetries,
|
||||
MinRetryBackoff: cfg.MinRetryBackoff,
|
||||
MaxRetryBackoff: cfg.MaxRetryBackoff,
|
||||
DialTimeout: cfg.DialTimeout,
|
||||
ReadTimeout: cfg.ReadTimeout,
|
||||
WriteTimeout: cfg.WriteTimeout,
|
||||
PoolSize: cfg.PoolSize,
|
||||
MinIdleConns: cfg.MinIdleConns,
|
||||
MaxConnAge: cfg.MaxConnAge,
|
||||
PoolTimeout: cfg.PoolTimeout,
|
||||
IdleTimeout: cfg.IdleTimeout,
|
||||
IdleCheckFrequency: cfg.IdleCheckFrequency,
|
||||
TLSConfig: cfg.TLSConfig,
|
||||
Limiter: cfg.Limiter,
|
||||
})
|
||||
|
||||
// Test connection
|
||||
if err := db.Ping(context.Background()).Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Empty collection if Clear is true
|
||||
if cfg.Clear {
|
||||
if err := db.FlushDB(context.Background()).Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create new store
|
||||
return &Storage{
|
||||
db: db,
|
||||
|
@@ -3,61 +3,48 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/utils"
|
||||
)
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
func init() {
|
||||
testConfig := ConfigDefault
|
||||
testConfig.Addr = "127.0.0.1:6379"
|
||||
|
||||
if v := os.Getenv("REDIS_ADDR"); v != "" {
|
||||
testConfig.Addr = v
|
||||
}
|
||||
|
||||
testStore = New(testConfig)
|
||||
}
|
||||
var testStore = New(Config{
|
||||
Clear: true,
|
||||
})
|
||||
|
||||
func Test_Redis_Set(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := store.Set(key, val, 0)
|
||||
err := testStore.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)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.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)
|
||||
err := testStore.Set(key, val, exp)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
@@ -66,61 +53,56 @@ func Test_Redis_Set_Expiration(t *testing.T) {
|
||||
|
||||
func Test_Redis_Get_Expired(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.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")
|
||||
result, err := testStore.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)
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Delete(key)
|
||||
err = testStore.Delete(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get(key)
|
||||
result, err := testStore.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)
|
||||
err := testStore.Set("john1", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Set("john2", val, 0)
|
||||
err = testStore.Set("john2", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
err = store.Clear()
|
||||
err = testStore.Clear()
|
||||
utils.AssertEqual(t, nil, err)
|
||||
|
||||
result, err := store.Get("john1")
|
||||
result, err := testStore.Get("john1")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
|
||||
result, err = store.Get("john2")
|
||||
result, err = testStore.Get("john2")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
@@ -4,61 +4,44 @@ import "time"
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
// Time before deleting expired keys
|
||||
// Database name
|
||||
//
|
||||
// Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
|
||||
// DB file path
|
||||
//
|
||||
// Default is "./fiber.sqlite3"
|
||||
// Optional. Default is "fiber"
|
||||
Database string
|
||||
|
||||
// DB table name
|
||||
// Table name
|
||||
//
|
||||
// Default is "fiber"
|
||||
TableName string
|
||||
// Optional. Default is "fiber_storage"
|
||||
Table string
|
||||
|
||||
// When set to true, this will Drop any existing table with the same name
|
||||
DropTable bool
|
||||
// Clear any existing keys in existing Table
|
||||
//
|
||||
// Optional. Default is false
|
||||
Clear bool
|
||||
|
||||
// The maximum number of connections in the idle connection pool.
|
||||
// Time before deleting expired keys
|
||||
//
|
||||
// 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.
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
|
||||
////////////////////////////////////
|
||||
// Adaptor related config options //
|
||||
////////////////////////////////////
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
GCInterval: 10 * time.Second,
|
||||
// General config options
|
||||
Database: "./fiber.sqlite3",
|
||||
TableName: "fiber",
|
||||
DropTable: false,
|
||||
Table: "fiber_storage",
|
||||
Clear: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
|
||||
// Adaptor related config options
|
||||
maxOpenConns: 100,
|
||||
maxIdleConns: 100,
|
||||
connMaxLifetime: 1 * time.Second,
|
||||
@@ -75,23 +58,14 @@ func configDefault(config ...Config) Config {
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if int(cfg.GCInterval) == 0 {
|
||||
cfg.GCInterval = ConfigDefault.GCInterval
|
||||
}
|
||||
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 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
|
||||
}
|
||||
|
@@ -60,8 +60,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)
|
||||
}
|
||||
@@ -69,9 +69,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)
|
||||
}
|
||||
}
|
||||
@@ -80,11 +80,11 @@ func New(config ...Config) *Storage {
|
||||
store := &Storage{
|
||||
db: db,
|
||||
gcInterval: cfg.GCInterval,
|
||||
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE key=?;`, cfg.TableName),
|
||||
sqlInsert: fmt.Sprintf("INSERT INTO %s (key, data, exp) VALUES (?,?,?)", cfg.TableName),
|
||||
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE key=?", cfg.TableName),
|
||||
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.TableName),
|
||||
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.TableName),
|
||||
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE key=?;`, cfg.Table),
|
||||
sqlInsert: fmt.Sprintf("INSERT INTO %s (key, data, exp) VALUES (?,?,?)", cfg.Table),
|
||||
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE key=?", cfg.Table),
|
||||
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.Table),
|
||||
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.Table),
|
||||
}
|
||||
|
||||
// Start garbage collector
|
||||
|
@@ -10,16 +10,11 @@ import (
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var testStore *Storage
|
||||
var testStore = New(Config{
|
||||
Clear: true,
|
||||
})
|
||||
|
||||
func init() {
|
||||
testConfig := ConfigDefault
|
||||
testConfig.Database = ":memory:"
|
||||
|
||||
testStore = New(testConfig)
|
||||
}
|
||||
|
||||
func Test_Redis_Set(t *testing.T) {
|
||||
func Test_SQLite3_Set(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
@@ -30,7 +25,7 @@ func Test_Redis_Set(t *testing.T) {
|
||||
utils.AssertEqual(t, nil, err)
|
||||
}
|
||||
|
||||
func Test_Redis_Get(t *testing.T) {
|
||||
func Test_SQLite3_Get(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
@@ -45,7 +40,7 @@ func Test_Redis_Get(t *testing.T) {
|
||||
utils.AssertEqual(t, val, result)
|
||||
}
|
||||
|
||||
func Test_Redis_Set_Expiration(t *testing.T) {
|
||||
func Test_SQLite3_Set_Expiration(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
@@ -60,7 +55,7 @@ func Test_Redis_Set_Expiration(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func Test_Redis_Get_Expired(t *testing.T) {
|
||||
func Test_SQLite3_Get_Expired(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
@@ -71,15 +66,15 @@ 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_SQLite3_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_SQLite3_Delete(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
key = "john"
|
||||
@@ -97,7 +92,7 @@ func Test_Redis_Delete(t *testing.T) {
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
}
|
||||
|
||||
func Test_Redis_Clear(t *testing.T) {
|
||||
func Test_SQLite3_Clear(t *testing.T) {
|
||||
var (
|
||||
store = testStore
|
||||
val = []byte("doe")
|
||||
|
Reference in New Issue
Block a user