🎄 xmas present

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

View File

@@ -1,23 +1,13 @@
on: [push, pull_request] on: [push, pull_request]
name: Test MongoDB name: MongoDB test
jobs: jobs:
# Label of the container job
mongodb-tests: mongodb-tests:
# Containers must run in Linux based operating systems
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Service containers to run with `container-job`
services: services:
# Label used to access the service container
mongo: mongo:
# Docker Hub image image: mongo:latest
image: mongo:4.4
ports: ports:
- 27017:27017 - 27017:27017
env:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: password
strategy: strategy:
matrix: matrix:
go-version: [1.14.x, 1.15.x] go-version: [1.14.x, 1.15.x]
@@ -30,5 +20,3 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Run Test - name: Run Test
run: go test ./mongodb -tags=mongodb -v -race run: go test ./mongodb -tags=mongodb -v -race
env:
MONGO_URI: "mongodb://root:password@127.0.0.1:27017"

View File

@@ -1,26 +1,13 @@
on: [push, pull_request] on: [push, pull_request]
name: MySQL test name: MySQL test
jobs: jobs:
# Label of the container job
mysql-tests: mysql-tests:
# Containers must run in Linux based operating systems
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Service containers to run with `container-job`
services: services:
# Label used to access the service container
mysql: mysql:
# Docker Hub image image: mysql:latest
image: mysql:8
env:
MYSQL_USER: username
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: fiber
ports: ports:
- 3306:3306 - 3306:3306
# Set health checks to wait until MySQL has started
options: >- options: >-
--health-cmd "mysqladmin ping" --health-cmd "mysqladmin ping"
--health-interval 10s --health-interval 10s
@@ -38,8 +25,3 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Run Test - name: Run Test
run: go test ./mysql -tags=mysql -v -race 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

View File

@@ -20,5 +20,3 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Run Test - name: Run Test
run: go test ./redis -tags=redis -v -race 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
View 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
View File

@@ -3,11 +3,17 @@ module github.com/gofiber/storage
go 1.14 go 1.14
require ( require (
github.com/aws/aws-sdk-go v1.35.21 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
github.com/go-redis/redis/v8 v8.3.3 github.com/go-redis/redis/v8 v8.3.3
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.5.0
github.com/gofiber/utils v0.1.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/lib/pq v1.8.0
github.com/mattn/go-sqlite3 v1.14.4 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
View File

@@ -1,6 +1,8 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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 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.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 h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= 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= 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/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= 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.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.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.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/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 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 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.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/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= 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= 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 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.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 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY= 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= 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-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 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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-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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/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-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 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-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-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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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.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 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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-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-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=

View File

@@ -7,9 +7,14 @@ type Config struct {
// Server list divided by , // Server list divided by ,
// i.e. server1:11211, server2:11212 // i.e. server1:11211, server2:11212
// //
// Optional. Default is "localhost:11211" // Optional. Default is "127.0.0.1:11211"
Servers string Servers string
// Clear any existing keys in existing Table
//
// Optional. Default is false
Clear bool
// The socket read/write timeout. // The socket read/write timeout.
// //
// Optional. Default is 100 * time.Millisecond // Optional. Default is 100 * time.Millisecond
@@ -26,7 +31,7 @@ type Config struct {
// ConfigDefault is the default config // ConfigDefault is the default config
var ConfigDefault = Config{ var ConfigDefault = Config{
Servers: "localhost:11211", Servers: "127.0.0.1:11211",
timeout: 100 * time.Millisecond, timeout: 100 * time.Millisecond,
maxIdleConns: 2, maxIdleConns: 2,
} }
@@ -45,12 +50,6 @@ 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 {
// cfg.Timeout = ConfigDefault.Timeout
// }
// if cfg.MaxIdleConns == 0 {
// cfg.MaxIdleConns = ConfigDefault.MaxIdleConns
// }
return cfg return cfg
} }

View File

@@ -39,6 +39,12 @@ func New(config ...Config) *Storage {
panic(err) panic(err)
} }
if cfg.Clear {
if err := db.DeleteAll(); err != nil {
panic(err)
}
}
// Create storage // Create storage
store := &Storage{ store := &Storage{
db: db, db: db,

View File

@@ -2,104 +2,106 @@
package memcache 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 ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
} }
func Test_Redis_Get(t *testing.T) { func Test_Memcache_Get(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, val, result) utils.AssertEqual(t, val, result)
} }
func Test_Redis_Set_Expiration(t *testing.T) { func Test_Memcache_Set_Expiration(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
exp = 500 * time.Millisecond exp = 500 * time.Millisecond
) )
err := store.Set(key, val, exp) err := testStore.Set(key, val, exp)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
func Test_Redis_Get_Expired(t *testing.T) { func Test_Memcache_Get_Expired(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
) )
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Get_NotExist(t *testing.T) { func Test_Memcache_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, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Delete(t *testing.T) { func Test_Memcache_Delete(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Delete(key) err = testStore.Delete(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Clear(t *testing.T) { func Test_Memcache_Clear(t *testing.T) {
var ( var (
store = testStore
val = []byte("doe") val = []byte("doe")
) )
err := store.Set("john1", val, 0) err := testStore.Set("john1", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Set("john2", val, 0) err = testStore.Set("john2", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Clear() err = testStore.Clear()
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get("john1") result, err := testStore.Get("john1")
utils.AssertEqual(t, ErrNotExist, 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 = testStore.Get("john2")
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }

View File

@@ -9,104 +9,100 @@ import (
"github.com/gofiber/utils" "github.com/gofiber/utils"
) )
func Test_Redis_Set(t *testing.T) { var testStore = New()
func Test_Memory_Set(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
} }
func Test_Redis_Get(t *testing.T) { func Test_Memory_Get(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, val, result) utils.AssertEqual(t, val, result)
} }
func Test_Redis_Set_Expiration(t *testing.T) { func Test_Memory_Set_Expiration(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
exp = 500 * time.Millisecond exp = 500 * time.Millisecond
) )
err := store.Set(key, val, exp) err := testStore.Set(key, val, exp)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
func Test_Redis_Get_Expired(t *testing.T) { func Test_Memory_Get_Expired(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
) )
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Get_NotExist(t *testing.T) { func Test_Memory_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, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Delete(t *testing.T) { func Test_Memory_Delete(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Delete(key) err = testStore.Delete(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Clear(t *testing.T) { func Test_Memory_Clear(t *testing.T) {
var ( var (
store = testStore
val = []byte("doe") val = []byte("doe")
) )
err := store.Set("john1", val, 0) err := testStore.Set("john1", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Set("john2", val, 0) err = testStore.Set("john2", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Clear() err = testStore.Clear()
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get("john1") result, err := testStore.Get("john1")
utils.AssertEqual(t, ErrNotExist, 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 = testStore.Get("john2")
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }

View File

@@ -1,60 +1,60 @@
package mongodb package mongodb
import ( import (
"crypto/tls"
"time" "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. // Config defines the config for storage.
type Config struct { type Config struct {
//https://docs.mongodb.com/manual/reference/connection-string/ // Host name where the DB is hosted
URI string //
// 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 Database string
// Collection name
//
// Optional. Default is "fiber_storage"
Collection string Collection string
// https://pkg.go.dev/go.mongodb.org/mongo-driver@v1.4.2/mongo/options#ClientOptions // Clear any existing keys in existing Table
AppName string //
Auth options.Credential // Optional. Default is false
AutoEncryptionOptions *options.AutoEncryptionOptions Clear bool
ConnectTimeout time.Duration
Compressors []string // Time before deleting expired keys
Dialer options.ContextDialer //
Direct bool // Optional. Default is 10 * time.Second
DisableOCSPEndpointCheck bool GCInterval time.Duration
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
} }
// ConfigDefault is the default config // ConfigDefault is the default config
var ConfigDefault = Config{ var ConfigDefault = Config{
URI: "mongodb://127.0.0.1:27017", Host: "127.0.0.1",
Port: 27017,
Database: "fiber", Database: "fiber",
Collection: "fiber", Collection: "fiber_storage",
Clear: false,
GCInterval: 10 * time.Second,
} }
// Helper function to set default values // Helper function to set default values
@@ -68,8 +68,11 @@ func configDefault(config ...Config) Config {
cfg := config[0] cfg := config[0]
// Set default values // Set default values
if cfg.URI == "" { if cfg.Host == "" {
cfg.URI = ConfigDefault.URI cfg.Host = ConfigDefault.Host
}
if cfg.Port <= 0 {
cfg.Port = ConfigDefault.Port
} }
if cfg.Database == "" { if cfg.Database == "" {
cfg.Database = ConfigDefault.Database cfg.Database = ConfigDefault.Database

View File

@@ -3,6 +3,7 @@ package mongodb
import ( import (
"context" "context"
"errors" "errors"
"net/url"
"sync" "sync"
"time" "time"
@@ -34,44 +35,24 @@ func New(config ...Config) *Storage {
// Set default config // Set default config
cfg := configDefault(config...) cfg := configDefault(config...)
// Set mongo options // Create data source name
opt := options.Client() var dsn string = "mongodb://"
opt.SetAppName(cfg.AppName) if cfg.Username != "" {
opt.SetAuth(cfg.Auth) dsn += url.QueryEscape(cfg.Username)
opt.SetAutoEncryptionOptions(cfg.AutoEncryptionOptions) }
opt.SetConnectTimeout(cfg.ConnectTimeout) if cfg.Password != "" {
opt.SetCompressors(cfg.Compressors) dsn += ":" + cfg.Password
opt.SetDialer(cfg.Dialer) }
opt.SetDirect(cfg.Direct) if cfg.Username != "" || cfg.Password != "" {
opt.SetDisableOCSPEndpointCheck(cfg.DisableOCSPEndpointCheck) dsn += "@"
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)
} }
// Set mongo options
opt := options.Client()
opt.ApplyURI(dsn)
// Create mongo client // Create mongo client
client, err := mongo.NewClient(opt.ApplyURI(cfg.URI)) client, err := mongo.NewClient(opt)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -3,127 +3,107 @@
package mongodb package mongodb
import ( import (
"os"
"testing" "testing"
"time" "time"
"github.com/gofiber/utils" "github.com/gofiber/utils"
) )
const ( var testStore = New(Config{
dbName = "fiberStorage" Clear: true,
colName = "fiberStorage" })
)
var uri = os.Getenv("MONGO_URI") func Test_MongoDB_Set(t *testing.T) {
func getConfig() Config {
return Config{
URI: uri,
Database: dbName,
Collection: colName,
}
}
func Test_Redis_Set(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
} }
func Test_Redis_Get(t *testing.T) { func Test_MongoDB_Get(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, val, result) utils.AssertEqual(t, val, result)
} }
func Test_Redis_Set_Expiration(t *testing.T) { func Test_MongoDB_Set_Expiration(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
exp = 500 * time.Millisecond exp = 500 * time.Millisecond
) )
err := store.Set(key, val, exp) err := testStore.Set(key, val, exp)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
func Test_Redis_Get_Expired(t *testing.T) { func Test_MongoDB_Get_Expired(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
) )
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Get_NotExist(t *testing.T) { func Test_MongoDB_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, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Delete(t *testing.T) { func Test_MongoDB_Delete(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Delete(key) err = testStore.Delete(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Clear(t *testing.T) { func Test_MongoDB_Clear(t *testing.T) {
var ( var (
store = testStore
val = []byte("doe") val = []byte("doe")
) )
err := store.Set("john1", val, 0) err := testStore.Set("john1", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Set("john2", val, 0) err = testStore.Set("john2", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Clear() err = testStore.Clear()
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get("john1") result, err := testStore.Get("john1")
utils.AssertEqual(t, ErrNotExist, 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 = testStore.Get("john2")
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }

View File

@@ -26,20 +26,50 @@ store := mysql.New()
// Initialize custom config // Initialize custom config
store := mysql.New(mysql.Config{ store := mysql.New(mysql.Config{
Server: "127.0.0.1:3306",
Database: "fiber",
Table: "fiber",
Drop: false,
GCInterval: 10 * time.Second, GCInterval: 10 * time.Second,
Address: "127.0.0.1:3306",
TableName: "fiber",
DatabaseName: "fiber",
DropTable: false,
}) })
``` ```
### Config ### Config
```go ```go
type Config struct { 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 // Time before deleting expired keys
// //
// Default is 10 * time.Second // Optional. Default is 10 * time.Second
GCInterval time.Duration GCInterval time.Duration
} }
``` ```
@@ -47,10 +77,10 @@ type Config struct {
### Default Config ### Default Config
```go ```go
var ConfigDefault = Config{ var ConfigDefault = Config{
Server: "127.0.0.1:3306",
Database: "fiber",
Table: "fiber",
Drop: false,
GCInterval: 10 * time.Second, GCInterval: 10 * time.Second,
Address: "127.0.0.1:3306",
TableName: "fiber",
DatabaseName: "fiber",
DropTable: false,
} }
``` ```

View File

@@ -7,82 +7,72 @@ import (
// Config defines the config for storage. // Config defines the config for storage.
type Config struct { type Config struct {
// Time before deleting expired keys // Host name where the DB is hosted
// //
// Default is 10 * time.Second // Optional. Default is "127.0.0.1"
GCInterval time.Duration Host string
// MySQL server address. Must include port. // Port where the DB is listening on
// //
// Default is "127.0.0.1:3306" // Optional. Default is 3306
Address string Port int
// MySQL server username // Server username
// //
// Default is "" // Optional. Default is ""
Username string Username string
// MySQL server password // Server password
// //
// Default is "" // Optional. Default is ""
Password string Password string
// MySQL database name // Database name
// //
// Default is "fiber" // Optional. Default is "fiber"
DatabaseName string Database string
// DB table name // Table name
// //
// Default is "fiber" // Optional. Default is "fiber_storage"
TableName string Table string
// When set to true, this will Drop any existing table with the same name // Clear any existing keys in existing Table
DropTable bool //
// 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, // Optional. Default is 10 * time.Second
// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit. GCInterval time.Duration
//
// If n < 0, no idle connections are retained. ////////////////////////////////////
// // Adaptor related config options //
// The default is 100. ////////////////////////////////////
maxIdleConns int 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 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 connMaxLifetime time.Duration
} }
// ConfigDefault is the default config // ConfigDefault is the default config
var ConfigDefault = Config{ var ConfigDefault = Config{
Host: "127.0.0.1",
Port: 3306,
Database: "fiber",
Table: "fiber_storage",
Clear: false,
GCInterval: 10 * time.Second, GCInterval: 10 * time.Second,
Address: "127.0.0.1:3306",
TableName: "fiber",
DatabaseName: "fiber",
DropTable: false,
maxOpenConns: 100, maxOpenConns: 100,
maxIdleConns: 100, maxIdleConns: 100,
connMaxLifetime: 1 * time.Second, 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 // Helper function to set default values
func configDefault(config ...Config) Config { func configDefault(config ...Config) Config {
// Return default config if nothing provided // Return default config if nothing provided
@@ -94,36 +84,20 @@ func configDefault(config ...Config) Config {
cfg := config[0] cfg := config[0]
// Set default values // 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 { if int(cfg.GCInterval) == 0 {
cfg.GCInterval = ConfigDefault.GCInterval 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 return cfg
} }
func (c Config) makeDSN() string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s", c.Username, c.Password, c.Address, c.DatabaseName)
}

View File

@@ -29,7 +29,6 @@ var (
dropQuery = "DROP TABLE IF EXISTS %s;" dropQuery = "DROP TABLE IF EXISTS %s;"
initQuery = []string{ 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 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...) cfg := configDefault(config...)
// Create db // Create db
db, err := sql.Open("mysql", cfg.makeDSN()) db, err := sql.Open("mysql", cfg.dsn())
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -54,22 +53,20 @@ func New(config ...Config) *Storage {
panic(err) panic(err)
} }
// Drop table if set to true // Drop table if Clear set to true
if cfg.DropTable { if cfg.Clear {
query := fmt.Sprintf(dropQuery, cfg.TableName) query := fmt.Sprintf(dropQuery, cfg.Table)
if _, err = db.Exec(query); err != nil { if _, err = db.Exec(query); err != nil {
_ = db.Close() _ = db.Close()
fmt.Println(query)
panic(err) panic(err)
} }
} }
// Init database queries // Init database queries
for _, query := range initQuery { for _, query := range initQuery {
query = fmt.Sprintf(query, cfg.TableName) query = fmt.Sprintf(query, cfg.Table)
if _, err := db.Exec(query); err != nil { if _, err := db.Exec(query); err != nil {
_ = db.Close() _ = db.Close()
fmt.Println(query)
panic(err) panic(err)
} }
} }
@@ -78,11 +75,11 @@ func New(config ...Config) *Storage {
store := &Storage{ store := &Storage{
gcInterval: cfg.GCInterval, gcInterval: cfg.GCInterval,
db: db, db: db,
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE id=?;`, 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.TableName), sqlInsert: fmt.Sprintf("INSERT INTO %s (id, data, exp) VALUES (?,?,?)", cfg.Table),
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE id=?", cfg.TableName), sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE id=?", cfg.Table),
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.TableName), sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.Table),
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.TableName), sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.Table),
} }
// Start garbage collector // Start garbage collector

View File

@@ -10,123 +10,105 @@ import (
"github.com/gofiber/utils" "github.com/gofiber/utils"
) )
var storeConfig = Config{ var testStore = New(Config{
DropTable: true, Database: os.Getenv("MYSQL_DATABASE"),
} Username: os.Getenv("MYSQL_USERNAME"),
Password: os.Getenv("MYSQL_PASSWORD"),
Clear: true,
})
func init() { func Test_MYSQL_Set(t *testing.T) {
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) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
} }
func Test_Redis_Get(t *testing.T) { func Test_MYSQL_Get(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, val, result) utils.AssertEqual(t, val, result)
} }
func Test_Redis_Set_Expiration(t *testing.T) { func Test_MYSQL_Set_Expiration(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
exp = 500 * time.Millisecond exp = 500 * time.Millisecond
) )
err := store.Set(key, val, exp) err := testStore.Set(key, val, exp)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
func Test_Redis_Get_Expired(t *testing.T) { func Test_MYSQL_Get_Expired(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
) )
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Get_NotExist(t *testing.T) { func Test_MYSQL_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, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Delete(t *testing.T) { func Test_MYSQL_Delete(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Delete(key) err = testStore.Delete(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Clear(t *testing.T) { func Test_MYSQL_Clear(t *testing.T) {
var ( var (
store = testStore
val = []byte("doe") val = []byte("doe")
) )
err := store.Set("john1", val, 0) err := testStore.Set("john1", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Set("john2", val, 0) err = testStore.Set("john2", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Clear() err = testStore.Clear()
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get("john1") result, err := testStore.Get("john1")
utils.AssertEqual(t, ErrNotExist, 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 = testStore.Get("john2")
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }

View File

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

View File

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

View File

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

View File

@@ -1,111 +1,52 @@
package redis package redis
import ( // Config defines the config for storage.
"context"
"crypto/tls"
"net"
"time"
"github.com/go-redis/redis/v8"
)
// Config defines the config for redis storage.
type Config struct { 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. // Server username
// Default is tcp. //
Network string // Optional. Default is ""
// 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.
Username string 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), // Server password
// or the User Password when connecting to a Redis 6.0 instance, or greater, //
// that is using the Redis ACL system. // Optional. Default is ""
Password string Password string
// Database to be selected after connecting to the server. // Database to be selected after connecting to the server.
DB int //
// Optional. Default is 0
Database int
// Maximum number of retries before giving up. // Clear any existing keys in existing Collection
// Default is 3 retries. //
MaxRetries int // Optional. Default is false
Clear bool
// Minimum backoff between each retry. ////////////////////////////////////
// Default is 8 milliseconds; -1 disables backoff. // Adaptor related config options //
MinRetryBackoff time.Duration ////////////////////////////////////
// Maximum backoff between each retry. // https://pkg.go.dev/github.com/go-redis/redis/v8#Options
// 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
} }
// ConfigDefault is the default config // ConfigDefault is the default config
var ConfigDefault = 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 // Helper function to set default values
@@ -119,8 +60,11 @@ func configDefault(config ...Config) Config {
cfg := config[0] cfg := config[0]
// Set default values // Set default values
if cfg.Addr == "" { if cfg.Host == "" {
cfg.Addr = ConfigDefault.Addr cfg.Host = ConfigDefault.Host
}
if cfg.Port <= 0 {
cfg.Port = ConfigDefault.Port
} }
return cfg return cfg
} }

View File

@@ -3,6 +3,7 @@ package redis
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"time" "time"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
@@ -23,33 +24,24 @@ func New(config ...Config) *Storage {
// Create new redis client // Create new redis client
db := redis.NewClient(&redis.Options{ db := redis.NewClient(&redis.Options{
Network: cfg.Network, Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
Addr: cfg.Addr, DB: cfg.Database,
Dialer: cfg.Dialer,
OnConnect: cfg.OnConnect,
Username: cfg.Username, Username: cfg.Username,
Password: cfg.Password, 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 // Test connection
if err := db.Ping(context.Background()).Err(); err != nil { if err := db.Ping(context.Background()).Err(); err != nil {
panic(err) 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 // Create new store
return &Storage{ return &Storage{
db: db, db: db,

View File

@@ -3,61 +3,48 @@
package redis package redis
import ( import (
"os"
"testing" "testing"
"time" "time"
"github.com/gofiber/utils" "github.com/gofiber/utils"
) )
var testStore *Storage var testStore = New(Config{
Clear: true,
func init() { })
testConfig := ConfigDefault
testConfig.Addr = "127.0.0.1:6379"
if v := os.Getenv("REDIS_ADDR"); v != "" {
testConfig.Addr = v
}
testStore = New(testConfig)
}
func Test_Redis_Set(t *testing.T) { func Test_Redis_Set(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
} }
func Test_Redis_Get(t *testing.T) { func Test_Redis_Get(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, val, result) utils.AssertEqual(t, val, result)
} }
func Test_Redis_Set_Expiration(t *testing.T) { func Test_Redis_Set_Expiration(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
exp = 500 * time.Millisecond exp = 500 * time.Millisecond
) )
err := store.Set(key, val, exp) err := testStore.Set(key, val, exp)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
time.Sleep(1 * time.Second) 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) { func Test_Redis_Get_Expired(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
) )
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Get_NotExist(t *testing.T) { func Test_Redis_Get_NotExist(t *testing.T) {
var store = testStore result, err := testStore.Get("notexist")
result, err := store.Get("notexist")
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Delete(t *testing.T) { func Test_Redis_Delete(t *testing.T) {
var ( var (
store = testStore
key = "john" key = "john"
val = []byte("doe") val = []byte("doe")
) )
err := store.Set(key, val, 0) err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Delete(key) err = testStore.Delete(key)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get(key) result, err := testStore.Get(key)
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Clear(t *testing.T) { func Test_Redis_Clear(t *testing.T) {
var ( var (
store = testStore
val = []byte("doe") val = []byte("doe")
) )
err := store.Set("john1", val, 0) err := testStore.Set("john1", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Set("john2", val, 0) err = testStore.Set("john2", val, 0)
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
err = store.Clear() err = testStore.Clear()
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
result, err := store.Get("john1") result, err := testStore.Get("john1")
utils.AssertEqual(t, ErrNotExist, 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 = testStore.Get("john2")
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }

View File

@@ -4,61 +4,44 @@ import "time"
// Config defines the config for storage. // Config defines the config for storage.
type Config struct { type Config struct {
// Time before deleting expired keys // Database name
// //
// Default is 10 * time.Second // Optional. Default is "fiber"
GCInterval time.Duration
// DB file path
//
// Default is "./fiber.sqlite3"
Database string Database string
// DB table name // Table name
// //
// Default is "fiber" // Optional. Default is "fiber_storage"
TableName string Table string
// When set to true, this will Drop any existing table with the same name // Clear any existing keys in existing Table
DropTable bool //
// 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, // Optional. Default is 10 * time.Second
// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit. GCInterval time.Duration
//
// If n < 0, no idle connections are retained. ////////////////////////////////////
// // Adaptor related config options //
// The default is 100. ////////////////////////////////////
maxIdleConns int 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 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 connMaxLifetime time.Duration
} }
// ConfigDefault is the default config // ConfigDefault is the default config
var ConfigDefault = Config{ var ConfigDefault = Config{
GCInterval: 10 * time.Second, // General config options
Database: "./fiber.sqlite3", Database: "./fiber.sqlite3",
TableName: "fiber", Table: "fiber_storage",
DropTable: false, Clear: false,
GCInterval: 10 * time.Second,
// Adaptor related config options
maxOpenConns: 100, maxOpenConns: 100,
maxIdleConns: 100, maxIdleConns: 100,
connMaxLifetime: 1 * time.Second, connMaxLifetime: 1 * time.Second,
@@ -75,23 +58,14 @@ func configDefault(config ...Config) Config {
cfg := config[0] cfg := config[0]
// Set default values // Set default values
if int(cfg.GCInterval) == 0 {
cfg.GCInterval = ConfigDefault.GCInterval
}
if cfg.Database == "" { if cfg.Database == "" {
cfg.Database = ConfigDefault.Database cfg.Database = ConfigDefault.Database
} }
if cfg.TableName == "" { if cfg.Table == "" {
cfg.TableName = ConfigDefault.TableName 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 return cfg
} }

View File

@@ -60,8 +60,8 @@ func New(config ...Config) *Storage {
} }
// Drop table if set to true // Drop table if set to true
if cfg.DropTable { if cfg.Clear {
if _, err = db.Exec(fmt.Sprintf(dropQuery, cfg.TableName)); err != nil { if _, err = db.Exec(fmt.Sprintf(dropQuery, cfg.Table)); err != nil {
_ = db.Close() _ = db.Close()
panic(err) panic(err)
} }
@@ -69,9 +69,9 @@ func New(config ...Config) *Storage {
// Init database queries // Init database queries
for _, query := range initQuery { 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() _ = db.Close()
fmt.Println(fmt.Sprintf(query, cfg.TableName)) fmt.Println(fmt.Sprintf(query, cfg.Table))
panic(err) panic(err)
} }
} }
@@ -80,11 +80,11 @@ func New(config ...Config) *Storage {
store := &Storage{ store := &Storage{
db: db, db: db,
gcInterval: cfg.GCInterval, gcInterval: cfg.GCInterval,
sqlSelect: fmt.Sprintf(`SELECT data, exp FROM %s WHERE key=?;`, 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.TableName), sqlInsert: fmt.Sprintf("INSERT INTO %s (key, data, exp) VALUES (?,?,?)", cfg.Table),
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE key=?", cfg.TableName), sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE key=?", cfg.Table),
sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.TableName), sqlClear: fmt.Sprintf("DELETE FROM %s;", cfg.Table),
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.TableName), sqlGC: fmt.Sprintf("DELETE FROM %s WHERE exp <= ?", cfg.Table),
} }
// Start garbage collector // Start garbage collector

View File

@@ -10,16 +10,11 @@ import (
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
var testStore *Storage var testStore = New(Config{
Clear: true,
})
func init() { func Test_SQLite3_Set(t *testing.T) {
testConfig := ConfigDefault
testConfig.Database = ":memory:"
testStore = New(testConfig)
}
func Test_Redis_Set(t *testing.T) {
var ( var (
store = testStore store = testStore
key = "john" key = "john"
@@ -30,7 +25,7 @@ func Test_Redis_Set(t *testing.T) {
utils.AssertEqual(t, nil, err) utils.AssertEqual(t, nil, err)
} }
func Test_Redis_Get(t *testing.T) { func Test_SQLite3_Get(t *testing.T) {
var ( var (
store = testStore store = testStore
key = "john" key = "john"
@@ -45,7 +40,7 @@ func Test_Redis_Get(t *testing.T) {
utils.AssertEqual(t, val, result) utils.AssertEqual(t, val, result)
} }
func Test_Redis_Set_Expiration(t *testing.T) { func Test_SQLite3_Set_Expiration(t *testing.T) {
var ( var (
store = testStore store = testStore
key = "john" 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 ( var (
store = testStore store = testStore
key = "john" key = "john"
@@ -71,15 +66,15 @@ func Test_Redis_Get_Expired(t *testing.T) {
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Get_NotExist(t *testing.T) { func Test_SQLite3_Get_NotExist(t *testing.T) {
var store = testStore
result, err := store.Get("notexist") result, err := store.Get("notexist")
utils.AssertEqual(t, ErrNotExist, err) utils.AssertEqual(t, ErrNotExist, err)
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Delete(t *testing.T) { func Test_SQLite3_Delete(t *testing.T) {
var ( var (
store = testStore store = testStore
key = "john" key = "john"
@@ -97,7 +92,7 @@ func Test_Redis_Delete(t *testing.T) {
utils.AssertEqual(t, true, len(result) == 0) utils.AssertEqual(t, true, len(result) == 0)
} }
func Test_Redis_Clear(t *testing.T) { func Test_SQLite3_Clear(t *testing.T) {
var ( var (
store = testStore store = testStore
val = []byte("doe") val = []byte("doe")