redis-client 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +8 -8
- data/lib/redis_client/command_builder.rb +8 -0
- data/lib/redis_client/config.rb +13 -5
- data/lib/redis_client/connection_mixin.rb +2 -0
- data/lib/redis_client/version.rb +1 -1
- data/lib/redis_client.rb +22 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 770636c5814252674d680c45f75af4ea291b698c18382b49d93bec4e3d7ab45b
|
4
|
+
data.tar.gz: bdef4f0f80574a9aaf29613ec23d31d7a0c3d916ca3945ac412b36b55eecd73a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3367281b907b6e38e73ba1e9a74f63404e40f422b319c551645fec1efa694e87c09cd96c67d308c362407c84be59eb62435b9951740cd515727a554050ae3137
|
7
|
+
data.tar.gz: 9dc6f5e6638405c8841b267d0c9cf882d0721cbd04655984af71bddb66cc7e2f4698e7199e752582064e4db3ca8e3f45a77b56241df309ae0c2e231ebff1cf2b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
- Fix handling of connection URLs with empty passwords (`redis://:pass@example.com`).
|
4
|
+
- Handle URLs with IPv6 hosts.
|
5
|
+
- Add `RedisClient::Config#server_url` as a quick way to identify which server the client is pointing to.
|
6
|
+
- Add `CommandError#command` to expose the command that caused the error.
|
7
|
+
- Raise a more explicit error when connecting to older redises without RESP3 support (5.0 and older).
|
8
|
+
- Properly reject empty commands early.
|
9
|
+
|
3
10
|
# 0.4.0
|
4
11
|
|
5
12
|
- The `hiredis` driver have been moved to the `hiredis-client` gem.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
`redis-client` is a simple, low-level, client for Redis 6+.
|
4
4
|
|
5
|
-
Contrary to the `redis` gem, `redis-client` doesn't try to map all
|
5
|
+
Contrary to the `redis` gem, `redis-client` doesn't try to map all Redis commands to Ruby constructs,
|
6
6
|
it merely is a thin wrapper on top of the RESP3 protocol.
|
7
7
|
|
8
8
|
## Installation
|
@@ -63,7 +63,7 @@ redis.call("GET", "mykey")
|
|
63
63
|
### Configuration
|
64
64
|
|
65
65
|
- `url`: A Redis connection URL, e.g. `redis://example.com:6379/5`, a `rediss://` scheme enable SSL, and the path is interpreted as a database number.
|
66
|
-
Note
|
66
|
+
Note that all other configurations take precedence, e.g. `RedisClient.config(url: "redis://localhost:3000" port: 6380)` will connect on port `6380`.
|
67
67
|
- `host`: The server hostname or IP address. Defaults to `"localhost"`.
|
68
68
|
- `port`: The server port. Defaults to `6379`.
|
69
69
|
- `path`: The path to a UNIX socket, if set `url`, `host` and `port` are ignored.
|
@@ -142,7 +142,7 @@ is equivalent to:
|
|
142
142
|
redis.call("LPUSH", "list", "1", "2", "3", "4")
|
143
143
|
```
|
144
144
|
|
145
|
-
Hashes are
|
145
|
+
Hashes are flattened as well:
|
146
146
|
|
147
147
|
```ruby
|
148
148
|
redis.call("HMSET", "hash", { "foo" => "1", "bar" => "2" })
|
@@ -154,7 +154,7 @@ is equivalent to:
|
|
154
154
|
redis.call("HMSET", "hash", "foo", "1", "bar", "2")
|
155
155
|
```
|
156
156
|
|
157
|
-
Any other type requires the caller to
|
157
|
+
Any other type requires the caller to explicitly cast the argument as a string.
|
158
158
|
|
159
159
|
Keywords arguments are treated as Redis command flags:
|
160
160
|
|
@@ -170,7 +170,7 @@ redis.call("SET", "mykey", "value", "nx", "ex", "60")
|
|
170
170
|
redis.call("SET", "mykey", "value")
|
171
171
|
```
|
172
172
|
|
173
|
-
If flags are built dynamically, you'll have to
|
173
|
+
If flags are built dynamically, you'll have to explicitly pass them as keyword arguments with `**`:
|
174
174
|
|
175
175
|
```ruby
|
176
176
|
flags = {}
|
@@ -185,7 +185,7 @@ unclosed hash literals with string keys may be interpreted differently:
|
|
185
185
|
redis.call("HMSET", "hash", "foo" => "bar")
|
186
186
|
```
|
187
187
|
|
188
|
-
On Ruby 2 `"foo" => "bar"` will be passed as a
|
188
|
+
On Ruby 2 `"foo" => "bar"` will be passed as a positional argument, but on Ruby 3 it will be interpreted as keyword
|
189
189
|
arguments. To avoid such problem, make sure to enclose hash literals:
|
190
190
|
|
191
191
|
```ruby
|
@@ -196,7 +196,7 @@ redis.call("HMSET", "hash", { "foo" => "bar" })
|
|
196
196
|
|
197
197
|
Contrary to the `redis` gem, `redis-client` doesn't do any type casting on the return value of commands.
|
198
198
|
|
199
|
-
If you wish to cast the return value, you can pass a block to the `#call`
|
199
|
+
If you wish to cast the return value, you can pass a block to the `#call` family of methods:
|
200
200
|
|
201
201
|
```ruby
|
202
202
|
redis.call("INCR", "counter") # => 1
|
@@ -297,7 +297,7 @@ end
|
|
297
297
|
|
298
298
|
If the transaction wasn't successful, `#multi` will return `nil`.
|
299
299
|
|
300
|
-
Note that transactions using optimistic locking aren't automatically retried
|
300
|
+
Note that transactions using optimistic locking aren't automatically retried upon connection errors.
|
301
301
|
|
302
302
|
### Publish / Subscribe
|
303
303
|
|
@@ -40,6 +40,10 @@ class RedisClient
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
if command.empty?
|
44
|
+
raise ArgumentError, "can't issue an empty redis command"
|
45
|
+
end
|
46
|
+
|
43
47
|
command
|
44
48
|
end
|
45
49
|
else
|
@@ -76,6 +80,10 @@ class RedisClient
|
|
76
80
|
end
|
77
81
|
end
|
78
82
|
|
83
|
+
if command.empty?
|
84
|
+
raise ArgumentError, "can't issue an empty redis command"
|
85
|
+
end
|
86
|
+
|
79
87
|
command
|
80
88
|
end
|
81
89
|
end
|
data/lib/redis_client/config.rb
CHANGED
@@ -82,6 +82,14 @@ class RedisClient
|
|
82
82
|
@ssl_context ||= @driver.ssl_context(@ssl_params)
|
83
83
|
end
|
84
84
|
|
85
|
+
def server_url
|
86
|
+
if path
|
87
|
+
"#{path}/#{db}"
|
88
|
+
else
|
89
|
+
"redis#{'s' if ssl?}://#{host}:#{port}/#{db}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
85
93
|
private
|
86
94
|
|
87
95
|
def build_connection_prelude
|
@@ -110,15 +118,15 @@ class RedisClient
|
|
110
118
|
path: nil,
|
111
119
|
**kwargs
|
112
120
|
)
|
113
|
-
|
114
|
-
|
121
|
+
if url
|
122
|
+
uri = URI.parse(url)
|
115
123
|
kwargs[:ssl] = uri.scheme == "rediss" unless kwargs.key?(:ssl)
|
116
124
|
|
117
|
-
kwargs[:username] ||= uri.user && uri.
|
125
|
+
kwargs[:username] ||= uri.user if uri.password && !uri.user.empty?
|
118
126
|
|
119
127
|
kwargs[:password] ||= if uri.user && !uri.password
|
120
128
|
URI.decode_www_form_component(uri.user)
|
121
|
-
elsif uri
|
129
|
+
elsif uri.user && uri.password
|
122
130
|
URI.decode_www_form_component(uri.password)
|
123
131
|
end
|
124
132
|
|
@@ -127,7 +135,7 @@ class RedisClient
|
|
127
135
|
|
128
136
|
super(**kwargs)
|
129
137
|
|
130
|
-
@host = host || uri&.host || DEFAULT_HOST
|
138
|
+
@host = host || uri&.host&.sub(/\A\[(.*)\]\z/, '\1') || DEFAULT_HOST
|
131
139
|
@port = port || uri&.port || DEFAULT_PORT
|
132
140
|
@path = path
|
133
141
|
end
|
@@ -6,6 +6,7 @@ class RedisClient
|
|
6
6
|
write(command)
|
7
7
|
result = read(timeout)
|
8
8
|
if result.is_a?(CommandError)
|
9
|
+
result._set_command(command)
|
9
10
|
raise result
|
10
11
|
else
|
11
12
|
result
|
@@ -23,6 +24,7 @@ class RedisClient
|
|
23
24
|
timeout = timeouts && timeouts[index]
|
24
25
|
result = read(timeout)
|
25
26
|
if result.is_a?(CommandError)
|
27
|
+
result._set_command(commands[index])
|
26
28
|
exception ||= result
|
27
29
|
end
|
28
30
|
results[index] = result
|
data/lib/redis_client/version.rb
CHANGED
data/lib/redis_client.rb
CHANGED
@@ -78,6 +78,8 @@ class RedisClient
|
|
78
78
|
|
79
79
|
Error = Class.new(StandardError)
|
80
80
|
|
81
|
+
UnsupportedServer = Class.new(Error)
|
82
|
+
|
81
83
|
ConnectionError = Class.new(Error)
|
82
84
|
|
83
85
|
FailoverError = Class.new(ConnectionError)
|
@@ -89,6 +91,8 @@ class RedisClient
|
|
89
91
|
CheckoutTimeoutError = Class.new(ConnectTimeoutError)
|
90
92
|
|
91
93
|
class CommandError < Error
|
94
|
+
attr_reader :command
|
95
|
+
|
92
96
|
class << self
|
93
97
|
def parse(error_message)
|
94
98
|
code = error_message.split(' ', 2).first
|
@@ -96,6 +100,10 @@ class RedisClient
|
|
96
100
|
klass.new(error_message)
|
97
101
|
end
|
98
102
|
end
|
103
|
+
|
104
|
+
def _set_command(command)
|
105
|
+
@command = command
|
106
|
+
end
|
99
107
|
end
|
100
108
|
|
101
109
|
AuthenticationError = Class.new(CommandError)
|
@@ -140,6 +148,11 @@ class RedisClient
|
|
140
148
|
@disable_reconnection = false
|
141
149
|
end
|
142
150
|
|
151
|
+
def inspect
|
152
|
+
id_string = " id=#{id}" if id
|
153
|
+
"#<#{self.class.name} #{config.server_url}#{id_string}>"
|
154
|
+
end
|
155
|
+
|
143
156
|
def size
|
144
157
|
1
|
145
158
|
end
|
@@ -405,8 +418,9 @@ class RedisClient
|
|
405
418
|
|
406
419
|
def _coerce!(results)
|
407
420
|
if results
|
408
|
-
results.
|
421
|
+
results.each_with_index do |result, index|
|
409
422
|
if result.is_a?(CommandError)
|
423
|
+
result._set_command(@commands[index + 1])
|
410
424
|
raise result
|
411
425
|
end
|
412
426
|
end
|
@@ -558,6 +572,13 @@ class RedisClient
|
|
558
572
|
end
|
559
573
|
|
560
574
|
connection
|
575
|
+
rescue CommandError => error
|
576
|
+
if error.message.include?("ERR unknown command `HELLO`")
|
577
|
+
raise UnsupportedServer,
|
578
|
+
"Your Redis server version is too old. redis-client requires Redis 6+. (#{config.server_url})"
|
579
|
+
else
|
580
|
+
raise
|
581
|
+
end
|
561
582
|
end
|
562
583
|
end
|
563
584
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|