1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
// Tideland Go Library - Redis Client - Connection
//
// Copyright (C) 2009-2017 Frank Mueller / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.
package redis
//--------------------
// IMPORTS
//--------------------
import (
"strings"
"github.com/tideland/golib/errors"
"github.com/tideland/golib/identifier"
"github.com/tideland/golib/monitoring"
)
//--------------------
// CONNECTION
//--------------------
// Connection manages one connection to a Redis database.
type Connection struct {
database *Database
resp *resp
}
// newConnection creates a new connection instance.
func newConnection(db *Database) (*Connection, error) {
conn := &Connection{
database: db,
}
err := conn.ensureProtocol()
if err != nil {
return nil, err
}
// Perform authentication and database selection.
err = conn.resp.authenticate()
if err != nil {
conn.database.pool.kill(conn.resp)
return nil, err
}
err = conn.resp.selectDatabase()
if err != nil {
conn.database.pool.kill(conn.resp)
return nil, err
}
return conn, nil
}
// Do executes one Redis command and returns
// the result as result set.
func (conn *Connection) Do(cmd string, args ...interface{}) (*ResultSet, error) {
cmd = strings.ToLower(cmd)
if strings.Contains(cmd, "subscribe") {
return nil, errors.New(ErrUseSubscription, errorMessages)
}
err := conn.ensureProtocol()
if err != nil {
return nil, err
}
if conn.database.monitoring {
m := monitoring.BeginMeasuring(identifier.Identifier("redis", "command", cmd))
defer m.EndMeasuring()
}
err = conn.resp.sendCommand(cmd, args...)
logCommand(cmd, args, err, conn.database.logging)
if err != nil {
return nil, err
}
result, err := conn.resp.receiveResultSet()
return result, err
}
// DoValue executes one Redis command and returns a single value.
func (conn *Connection) DoValue(cmd string, args ...interface{}) (Value, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return nil, err
}
return result.ValueAt(0)
}
// DoOK executes one Redis command and checks if
// it returns the OK string.
func (conn *Connection) DoOK(cmd string, args ...interface{}) (bool, error) {
value, err := conn.DoValue(cmd, args...)
if err != nil {
return false, err
}
return value.IsOK(), nil
}
// DoBool executes one Redis command and interpretes
// the result as bool value.
func (conn *Connection) DoBool(cmd string, args ...interface{}) (bool, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return false, err
}
return result.BoolAt(0)
}
// DoInt executes one Redis command and interpretes
// the result as int value.
func (conn *Connection) DoInt(cmd string, args ...interface{}) (int, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return 0, err
}
return result.IntAt(0)
}
// DoString executes one Redis command and interpretes
// the result as string value.
func (conn *Connection) DoString(cmd string, args ...interface{}) (string, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return "", err
}
return result.StringAt(0)
}
// DoStrings executes one Redis command and interpretes
// the result as a slice of strings.
func (conn *Connection) DoStrings(cmd string, args ...interface{}) ([]string, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return nil, err
}
return result.Strings(), nil
}
// DoKeyValues executes on Redis command and interpretes
// the result as a list of keys and values.
func (conn *Connection) DoKeyValues(cmd string, args ...interface{}) (KeyValues, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return nil, err
}
return result.KeyValues()
}
// DoHash executes on Redis command and interpretes
// the result as a hash.
func (conn *Connection) DoHash(cmd string, args ...interface{}) (Hash, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return nil, err
}
return result.Hash()
}
// DoScoredValues executes on Redis command and interpretes
// the result as scored values.
func (conn *Connection) DoScoredValues(cmd string, args ...interface{}) (ScoredValues, error) {
var withScores bool
for _, arg := range args {
if s, ok := arg.(string); ok {
if strings.ToLower(s) == "withscores" {
withScores = true
break
}
}
}
result, err := conn.Do(cmd, args...)
if err != nil {
return nil, err
}
return result.ScoredValues(withScores)
}
// DoScan executes one Redis command which should be one of the
// scan commands. It returns the cursor and the result set containing
// the key, values or scored values depending on the scan command.
func (conn *Connection) DoScan(cmd string, args ...interface{}) (int, *ResultSet, error) {
result, err := conn.Do(cmd, args...)
if err != nil {
return 0, nil, err
}
return result.Scanned()
}
// Return passes the connection back into the database pool.
func (conn *Connection) Return() error {
err := conn.database.pool.push(conn.resp)
conn.resp = nil
return err
}
// ensureProtocol retrieves a protocol from the pool if needed.
func (conn *Connection) ensureProtocol() error {
if conn.resp == nil {
p, err := conn.database.pool.pull(unforcedPull)
if err != nil {
return err
}
conn.resp = p
}
return nil
}
// EOF
|