mirror of
https://github.com/gofiber/storage.git
synced 2025-10-04 16:22:52 +08:00
Add support to MSSQL
This commit is contained in:
5
go.mod
5
go.mod
@@ -1,3 +1,8 @@
|
|||||||
module github.com/gofiber/storage
|
module github.com/gofiber/storage
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/denisenkom/go-mssqldb v0.12.3
|
||||||
|
github.com/gofiber/utils v1.0.0
|
||||||
|
)
|
||||||
|
51
go.sum
51
go.sum
@@ -0,0 +1,51 @@
|
|||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
|
||||||
|
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
|
||||||
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
|
github.com/gofiber/utils v1.0.0 h1:goxlTmYidOhsCvuZuTLzT224DELpnz9c/+iw5eN9FJw=
|
||||||
|
github.com/gofiber/utils v1.0.0/go.mod h1:RYennBgjLkuNtU+dxg7QgBEU8tmixFQHQ2GE1ioZlxw=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
135
mssql/README.md
Normal file
135
mssql/README.md
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# MSSQL
|
||||||
|
|
||||||
|
A MSSQL storage driver using [denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb).
|
||||||
|
|
||||||
|
### Table of Contents
|
||||||
|
- [Signatures](#signatures)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Examples](#examples)
|
||||||
|
- [Config](#config)
|
||||||
|
- [Default Config](#default-config)
|
||||||
|
|
||||||
|
### Signatures
|
||||||
|
```go
|
||||||
|
func New(config ...Config) Storage
|
||||||
|
func (s *Storage) Get(key string) ([]byte, error)
|
||||||
|
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||||
|
func (s *Storage) Delete(key string) error
|
||||||
|
func (s *Storage) Reset() error
|
||||||
|
func (s *Storage) Close() error
|
||||||
|
func (s *Storage) Conn() *sql.DB
|
||||||
|
```
|
||||||
|
### Installation
|
||||||
|
MSSQL is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
|
||||||
|
```bash
|
||||||
|
go mod init github.com/<user>/<repo>
|
||||||
|
```
|
||||||
|
And then install the mssql implementation:
|
||||||
|
```bash
|
||||||
|
go get github.com/gofiber/storage/mssql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
Import the storage package.
|
||||||
|
```go
|
||||||
|
import "github.com/gofiber/storage/mssql"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use the following possibilities to create a storage:
|
||||||
|
```go
|
||||||
|
// Initialize default config
|
||||||
|
store := mssql.New()
|
||||||
|
|
||||||
|
// Initialize custom config
|
||||||
|
store := mssql.New(mssql.Config{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 1433,
|
||||||
|
Database: "fiber",
|
||||||
|
Table: "fiber_storage",
|
||||||
|
Reset: false,
|
||||||
|
GCInterval: 10 * time.Second,
|
||||||
|
SslMode: "disable",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Initialize custom config using connection string
|
||||||
|
store := mssql.New(mssql.Config{
|
||||||
|
ConnectionURI: "sqlserver://user:password@localhost:1433?database=fiber"
|
||||||
|
Reset: false,
|
||||||
|
GCInterval: 10 * time.Second,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Config
|
||||||
|
```go
|
||||||
|
// Config defines the config for storage.
|
||||||
|
type Config struct {
|
||||||
|
// Connection string to use for DB. Will override all other authentication values if used
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
ConnectionURI 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 1433
|
||||||
|
Port int
|
||||||
|
|
||||||
|
// Server username
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
Username string
|
||||||
|
|
||||||
|
// Server password
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
Password string
|
||||||
|
|
||||||
|
// Instance name
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
Instance string
|
||||||
|
|
||||||
|
// Database name
|
||||||
|
//
|
||||||
|
// Optional. Default is "fiber"
|
||||||
|
Database string
|
||||||
|
|
||||||
|
// Table name
|
||||||
|
//
|
||||||
|
// Optional. Default is "fiber_storage"
|
||||||
|
Table string
|
||||||
|
|
||||||
|
// Reset clears any existing keys in existing Table
|
||||||
|
//
|
||||||
|
// Optional. Default is false
|
||||||
|
Reset bool
|
||||||
|
|
||||||
|
// Time before deleting expired keys
|
||||||
|
//
|
||||||
|
// Optional. Default is 10 * time.Second
|
||||||
|
GCInterval time.Duration
|
||||||
|
|
||||||
|
// The SSL mode for the connection
|
||||||
|
//
|
||||||
|
// Optional. Default is "disable"
|
||||||
|
SslMode string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Default Config
|
||||||
|
```go
|
||||||
|
var ConfigDefault = Config{
|
||||||
|
ConnectionURI: "",
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 1433,
|
||||||
|
Database: "fiber",
|
||||||
|
Table: "fiber_storage",
|
||||||
|
Reset: false,
|
||||||
|
GCInterval: 10 * time.Second,
|
||||||
|
SslMode: "disable",
|
||||||
|
}
|
||||||
|
```
|
146
mssql/config.go
Normal file
146
mssql/config.go
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package mssql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config defines the config for storage.
|
||||||
|
type Config struct {
|
||||||
|
// Connection string to use for DB. Will override all other authentication values if used
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
ConnectionURI 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 1433
|
||||||
|
Port int
|
||||||
|
|
||||||
|
// Server username
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
Username string
|
||||||
|
|
||||||
|
// Server password
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
Password string
|
||||||
|
|
||||||
|
// Instance name
|
||||||
|
//
|
||||||
|
// Optional. Default is ""
|
||||||
|
Instance string
|
||||||
|
|
||||||
|
// Database name
|
||||||
|
//
|
||||||
|
// Optional. Default is "fiber"
|
||||||
|
Database string
|
||||||
|
|
||||||
|
// Table name
|
||||||
|
//
|
||||||
|
// Optional. Default is "fiber_storage"
|
||||||
|
Table string
|
||||||
|
|
||||||
|
// The SSL mode for the connection
|
||||||
|
//
|
||||||
|
// Optional. Default is "disable"
|
||||||
|
SslMode string
|
||||||
|
|
||||||
|
// Reset clears any existing keys in existing Table
|
||||||
|
//
|
||||||
|
// Optional. Default is false
|
||||||
|
Reset 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.
|
||||||
|
timeout time.Duration
|
||||||
|
|
||||||
|
// The maximum number of connections in the idle connection pool.
|
||||||
|
//
|
||||||
|
// If MaxOpenConns is greater than 0 but less than the new MaxIdleConns,
|
||||||
|
// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.
|
||||||
|
//
|
||||||
|
// If n <= 0, no idle connections are retained.
|
||||||
|
//
|
||||||
|
// The default max idle connections is currently 2. This may change in
|
||||||
|
// a future release.
|
||||||
|
maxIdleConns int
|
||||||
|
|
||||||
|
// The maximum number of open connections to the database.
|
||||||
|
//
|
||||||
|
// If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than
|
||||||
|
// MaxIdleConns, then MaxIdleConns will be reduced to match the new
|
||||||
|
// MaxOpenConns limit.
|
||||||
|
//
|
||||||
|
// If n <= 0, then there is no limit on the number of open connections.
|
||||||
|
// The default is 0 (unlimited).
|
||||||
|
maxOpenConns int
|
||||||
|
|
||||||
|
// The maximum amount of time a connection may be reused.
|
||||||
|
//
|
||||||
|
// Expired connections may be closed lazily before reuse.
|
||||||
|
//
|
||||||
|
// If d <= 0, connections are reused forever.
|
||||||
|
connMaxLifetime time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigDefault is the default config
|
||||||
|
var ConfigDefault = Config{
|
||||||
|
ConnectionURI: "",
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 1433,
|
||||||
|
Database: "fiber",
|
||||||
|
Table: "fiber_storage",
|
||||||
|
SslMode: "disable",
|
||||||
|
Reset: false,
|
||||||
|
GCInterval: 10 * time.Second,
|
||||||
|
maxOpenConns: 100,
|
||||||
|
maxIdleConns: 100,
|
||||||
|
connMaxLifetime: 1 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to set default values
|
||||||
|
func configDefault(config ...Config) Config {
|
||||||
|
// Return default config if nothing provided
|
||||||
|
if len(config) < 1 {
|
||||||
|
return ConfigDefault
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override default 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 cfg.SslMode == "" {
|
||||||
|
cfg.SslMode = ConfigDefault.SslMode
|
||||||
|
}
|
||||||
|
if int(cfg.GCInterval.Seconds()) <= 0 {
|
||||||
|
cfg.GCInterval = ConfigDefault.GCInterval
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
8
mssql/go.mod
Normal file
8
mssql/go.mod
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module github.com/gofiber/storage/mssql
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/denisenkom/go-mssqldb v0.12.3
|
||||||
|
github.com/gofiber/utils v0.1.2
|
||||||
|
)
|
40
mssql/go.sum
Normal file
40
mssql/go.sum
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
|
||||||
|
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
|
||||||
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
|
github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk=
|
||||||
|
github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
|
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
235
mssql/mssql.go
Normal file
235
mssql/mssql.go
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
package mssql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/denisenkom/go-mssqldb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Storage interface that is implemented by storage providers
|
||||||
|
type Storage struct {
|
||||||
|
db *sql.DB
|
||||||
|
gcInterval time.Duration
|
||||||
|
done chan struct{}
|
||||||
|
|
||||||
|
sqlSelect string
|
||||||
|
sqlInsert string
|
||||||
|
sqlDelete string
|
||||||
|
sqlReset string
|
||||||
|
sqlGC string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
checkSchemaMsg = "The `v` row has an incorrect data type. " +
|
||||||
|
"It should be VARBINARY(MAX) but is instead %s. This will cause encoding-related panics if the DB is not migrated (see https://github.com/gofiber/storage/blob/main/MIGRATE.md)."
|
||||||
|
dropQuery = `IF EXISTS(SELECT * FROM sys.tables WHERE name = '%s')
|
||||||
|
DROP TABLE %s;`
|
||||||
|
initQuery = []string{
|
||||||
|
`IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = '%s')
|
||||||
|
CREATE TABLE %s (
|
||||||
|
k VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT '',
|
||||||
|
v VARBINARY(MAX) NOT NULL,
|
||||||
|
e BIGINT NOT NULL DEFAULT '0'
|
||||||
|
);`,
|
||||||
|
`IF NOT EXISTS(SELECT * FROM sys.indexes WHERE name = 'e')
|
||||||
|
CREATE INDEX e ON %s (e);`,
|
||||||
|
}
|
||||||
|
checkSchemaQuery = `SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE table_name = '%s' AND COLUMN_NAME = 'v';`
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates a new storage
|
||||||
|
func New(config ...Config) *Storage {
|
||||||
|
// Set default config
|
||||||
|
cfg := configDefault(config...)
|
||||||
|
|
||||||
|
// Create data source name
|
||||||
|
var dsn string
|
||||||
|
if cfg.ConnectionURI != "" {
|
||||||
|
dsn = cfg.ConnectionURI
|
||||||
|
} else {
|
||||||
|
dsn = "sqlserver://"
|
||||||
|
if cfg.Username != "" {
|
||||||
|
dsn += url.QueryEscape(cfg.Username)
|
||||||
|
}
|
||||||
|
if cfg.Password != "" {
|
||||||
|
dsn += ":" + cfg.Password
|
||||||
|
}
|
||||||
|
if cfg.Username != "" || cfg.Password != "" {
|
||||||
|
dsn += "@"
|
||||||
|
}
|
||||||
|
// unix socket host path
|
||||||
|
if strings.HasPrefix(cfg.Host, "/") {
|
||||||
|
dsn += fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
|
||||||
|
} else {
|
||||||
|
dsn += fmt.Sprintf("%s:%d", url.QueryEscape(cfg.Host), cfg.Port)
|
||||||
|
}
|
||||||
|
if cfg.Instance != "" {
|
||||||
|
dsn += "/" + cfg.Instance
|
||||||
|
}
|
||||||
|
dsn += fmt.Sprintf("?database=%s&connection+timeout=%d&encrypt=%s",
|
||||||
|
url.QueryEscape(cfg.Database),
|
||||||
|
int64(cfg.timeout.Seconds()),
|
||||||
|
cfg.SslMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create db
|
||||||
|
db, err := sql.Open("sqlserver", dsn)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set database options
|
||||||
|
db.SetMaxOpenConns(cfg.maxOpenConns)
|
||||||
|
db.SetMaxIdleConns(cfg.maxIdleConns)
|
||||||
|
db.SetConnMaxLifetime(cfg.connMaxLifetime)
|
||||||
|
|
||||||
|
// Ping database
|
||||||
|
if err := db.Ping(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop table if set to true
|
||||||
|
if cfg.Reset {
|
||||||
|
if _, err = db.Exec(strings.Replace(dropQuery, "%s", cfg.Table, -1)); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init database queries
|
||||||
|
for _, query := range initQuery {
|
||||||
|
if _, err := db.Exec(strings.Replace(query, "%s", cfg.Table, -1)); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create storage
|
||||||
|
store := &Storage{
|
||||||
|
db: db,
|
||||||
|
gcInterval: cfg.GCInterval,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
sqlSelect: fmt.Sprintf(`SELECT v, e FROM %s WHERE k=@p1;`, cfg.Table),
|
||||||
|
sqlInsert: fmt.Sprintf(`MERGE INTO %s WITH (HOLDLOCK) AS T USING (VALUES(@p1)) AS S (k) ON (T.k = S.k)
|
||||||
|
WHEN MATCHED THEN UPDATE SET v = @p2, e = @p3
|
||||||
|
WHEN NOT MATCHED THEN INSERT (k, v, e) VALUES(@p1, @p2, @p3);`, cfg.Table),
|
||||||
|
sqlDelete: fmt.Sprintf("DELETE FROM %s WHERE k=@p1", cfg.Table),
|
||||||
|
sqlReset: fmt.Sprintf("TRUNCATE TABLE %s;", cfg.Table),
|
||||||
|
sqlGC: fmt.Sprintf("DELETE FROM %s WHERE e <= @p1 AND e != 0", cfg.Table),
|
||||||
|
}
|
||||||
|
|
||||||
|
store.checkSchema(cfg.Table)
|
||||||
|
|
||||||
|
// Start garbage collector
|
||||||
|
go store.gcTicker()
|
||||||
|
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
|
var noRows = errors.New("sql: no rows in result set")
|
||||||
|
|
||||||
|
// Get value by key
|
||||||
|
func (s *Storage) Get(key string) ([]byte, error) {
|
||||||
|
if len(key) <= 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
row := s.db.QueryRow(s.sqlSelect, key)
|
||||||
|
// Add db response to data
|
||||||
|
var (
|
||||||
|
data = []byte{}
|
||||||
|
exp int64 = 0
|
||||||
|
)
|
||||||
|
if err := row.Scan(&data, &exp); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the expiration time has already passed, then return nil
|
||||||
|
if exp != 0 && exp <= time.Now().Unix() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set key with value
|
||||||
|
func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
|
||||||
|
// Ain't Nobody Got Time For That
|
||||||
|
if len(key) <= 0 || len(val) <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var expSeconds int64
|
||||||
|
if exp != 0 {
|
||||||
|
expSeconds = time.Now().Add(exp).Unix()
|
||||||
|
}
|
||||||
|
_, err := s.db.Exec(s.sqlInsert, key, val, expSeconds)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete entry by key
|
||||||
|
func (s *Storage) Delete(key string) error {
|
||||||
|
// Ain't Nobody Got Time For That
|
||||||
|
if len(key) <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := s.db.Exec(s.sqlDelete, key)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset all entries, including unexpired
|
||||||
|
func (s *Storage) Reset() error {
|
||||||
|
_, err := s.db.Exec(s.sqlReset)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the database
|
||||||
|
func (s *Storage) Close() error {
|
||||||
|
s.done <- struct{}{}
|
||||||
|
return s.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return database client
|
||||||
|
func (s *Storage) Conn() *sql.DB {
|
||||||
|
return s.db
|
||||||
|
}
|
||||||
|
|
||||||
|
// gcTicker starts the gc ticker
|
||||||
|
func (s *Storage) gcTicker() {
|
||||||
|
ticker := time.NewTicker(s.gcInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
return
|
||||||
|
case t := <-ticker.C:
|
||||||
|
s.gc(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gc deletes all expired entries
|
||||||
|
func (s *Storage) gc(t time.Time) {
|
||||||
|
_, _ = s.db.Exec(s.sqlGC, t.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Storage) checkSchema(tableName string) {
|
||||||
|
var data []byte
|
||||||
|
|
||||||
|
row := s.db.QueryRow(fmt.Sprintf(checkSchemaQuery, tableName))
|
||||||
|
if err := row.Scan(&data); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ToLower(string(data)) != "varbinary" {
|
||||||
|
fmt.Printf(checkSchemaMsg, string(data))
|
||||||
|
}
|
||||||
|
}
|
183
mssql/mssql_test.go
Normal file
183
mssql/mssql_test.go
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
package mssql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testStore = New(Config{
|
||||||
|
Database: os.Getenv("MSSQL_DATABASE"),
|
||||||
|
Username: os.Getenv("MSSQL_USERNAME"),
|
||||||
|
Password: os.Getenv("MSSQL_PASSWORD"),
|
||||||
|
Reset: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
func Test_MSSQL_Set(t *testing.T) {
|
||||||
|
var (
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := testStore.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Set_Override(t *testing.T) {
|
||||||
|
var (
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := testStore.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = testStore.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Get(t *testing.T) {
|
||||||
|
var (
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := testStore.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := testStore.Get(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, val, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Set_Expiration(t *testing.T) {
|
||||||
|
var (
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
exp = 1 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
err := testStore.Set(key, val, exp)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
time.Sleep(1100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Get_Expired(t *testing.T) {
|
||||||
|
var (
|
||||||
|
key = "john"
|
||||||
|
)
|
||||||
|
|
||||||
|
result, err := testStore.Get(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Get_NotExist(t *testing.T) {
|
||||||
|
|
||||||
|
result, err := testStore.Get("notexist")
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Delete(t *testing.T) {
|
||||||
|
var (
|
||||||
|
key = "john"
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := testStore.Set(key, val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = testStore.Delete(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := testStore.Get(key)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Reset(t *testing.T) {
|
||||||
|
var (
|
||||||
|
val = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
err := testStore.Set("john1", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = testStore.Set("john2", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
err = testStore.Reset()
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := testStore.Get("john1")
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
|
||||||
|
result, err = testStore.Get("john2")
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, true, len(result) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_GC(t *testing.T) {
|
||||||
|
var (
|
||||||
|
testVal = []byte("doe")
|
||||||
|
)
|
||||||
|
|
||||||
|
// This key should expire
|
||||||
|
err := testStore.Set("john", testVal, time.Nanosecond)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
testStore.gc(time.Now())
|
||||||
|
row := testStore.db.QueryRow(testStore.sqlSelect, "john")
|
||||||
|
err = row.Scan(nil, nil)
|
||||||
|
utils.AssertEqual(t, sql.ErrNoRows, err)
|
||||||
|
|
||||||
|
// This key should not expire
|
||||||
|
err = testStore.Set("john", testVal, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
testStore.gc(time.Now())
|
||||||
|
val, err := testStore.Get("john")
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, testVal, val)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Non_UTF8(t *testing.T) {
|
||||||
|
val := []byte("0xF5")
|
||||||
|
|
||||||
|
err := testStore.Set("0xF6", val, 0)
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
|
||||||
|
result, err := testStore.Get("0xF6")
|
||||||
|
utils.AssertEqual(t, nil, err)
|
||||||
|
utils.AssertEqual(t, val, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_SslRequiredMode(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if recover() == nil {
|
||||||
|
utils.AssertEqual(t, true, nil, "Connection was established with a `require`")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
_ = New(Config{
|
||||||
|
Database: "fiber",
|
||||||
|
Username: "username",
|
||||||
|
Password: "password",
|
||||||
|
Reset: true,
|
||||||
|
SslMode: "require",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Close(t *testing.T) {
|
||||||
|
utils.AssertEqual(t, nil, testStore.Close())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MSSQL_Conn(t *testing.T) {
|
||||||
|
utils.AssertEqual(t, true, testStore.Conn() != nil)
|
||||||
|
}
|
Reference in New Issue
Block a user