3
3
require "cgi"
4
4
5
5
class Redis
6
+ # Redis::Client handles the connection to Redis, sending and receiving commands.
7
+ #
8
+ # Usage:
9
+ #
10
+ # client = Redis::Client.new
11
+ #
12
+ # client.call(["PING"])
13
+ # => "PONG"
14
+ #
15
+ # client.call(["SET", "key", "value"])
16
+ # => "OK"
17
+ #
18
+ # client.call(["INCR", "key"])
19
+ # => 1
20
+ #
21
+ # It provides an API for command pipelining:
22
+ #
23
+ # client.queue(["SET", "key", "value"])
24
+ # client.queue(["GET", "key"])
25
+ # client.commit
26
+ # => ["OK", "value"]
27
+ #
6
28
class Client
7
29
8
30
DEFAULTS = {
@@ -84,6 +106,47 @@ def initialize(options = {})
84
106
else
85
107
@connector = Connector . new ( @options )
86
108
end
109
+
110
+ @queue = [ ]
111
+ end
112
+
113
+ # Sends a command to Redis and returns its reply.
114
+ #
115
+ # Replies are converted to Ruby objects according to the RESP protocol, so
116
+ # you can expect a Ruby array, integer or nil when Redis sends one. Higher
117
+ # level transformations, such as converting an array of pairs into a Ruby
118
+ # hash, are up to consumers.
119
+ #
120
+ # Redis error replies are raised as Ruby exceptions.
121
+ def call ( command , &block )
122
+ reply = process ( [ command ] ) { read }
123
+ raise reply if reply . is_a? ( CommandError )
124
+
125
+ if block
126
+ block . call ( reply )
127
+ else
128
+ reply
129
+ end
130
+ end
131
+
132
+ # Queues a command for pipelining.
133
+ #
134
+ # Commands in the queue are executed with the Redis::Client#commit method.
135
+ #
136
+ # See http://redis.io/topics/pipelining for more details.
137
+ #
138
+ def queue ( command )
139
+ @queue << command
140
+ end
141
+
142
+ # Sends all commands in the queue.
143
+ #
144
+ # See http://redis.io/topics/pipelining for more details.
145
+ #
146
+ def commit
147
+ call_pipelined ( @queue )
148
+ ensure
149
+ @queue . clear
87
150
end
88
151
89
152
def connect
@@ -108,17 +171,6 @@ def location
108
171
path || "#{ host } :#{ port } "
109
172
end
110
173
111
- def call ( command , &block )
112
- reply = process ( [ command ] ) { read }
113
- raise reply if reply . is_a? ( CommandError )
114
-
115
- if block
116
- block . call ( reply )
117
- else
118
- reply
119
- end
120
- end
121
-
122
174
def call_loop ( command )
123
175
error = nil
124
176
@@ -174,15 +226,21 @@ def call_pipelined(commands)
174
226
reconnect = @reconnect
175
227
176
228
begin
229
+ exception = nil
230
+
177
231
process ( commands ) do
178
232
result [ 0 ] = read
179
233
180
234
@reconnect = false
181
235
182
236
( commands . size - 1 ) . times do |i |
183
- result [ i + 1 ] = read
237
+ reply = read
238
+ result [ i + 1 ] = reply
239
+ exception = reply if exception . nil? && reply . is_a? ( CommandError )
184
240
end
185
241
end
242
+
243
+ raise exception if exception
186
244
ensure
187
245
@reconnect = reconnect
188
246
end
0 commit comments