ssdb 0.1.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.
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .yardoc/
3
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ssdb (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.3)
10
+ rake (10.0.4)
11
+ redcarpet (2.2.2)
12
+ rspec (2.13.0)
13
+ rspec-core (~> 2.13.0)
14
+ rspec-expectations (~> 2.13.0)
15
+ rspec-mocks (~> 2.13.0)
16
+ rspec-core (2.13.1)
17
+ rspec-expectations (2.13.0)
18
+ diff-lcs (>= 1.1.3, < 2.0)
19
+ rspec-mocks (2.13.1)
20
+ yard (0.8.6.1)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ bundler
27
+ rake
28
+ redcarpet
29
+ rspec
30
+ ssdb!
31
+ yard
@@ -0,0 +1,117 @@
1
+ # ssdb-rb
2
+
3
+ A Ruby client library for [SSDB][ssdb-home], heaviliy inspired by the great
4
+ [redis-rb][redisrb-home] library. Requires SSDB version 1.4.2 or higher.
5
+
6
+ [ssdb-home]: https://github.com/ideawu/ssdb
7
+ [redisrb-home]: https://github.com/redis/redis-rb
8
+
9
+ ### Installation
10
+
11
+ Install via rubygems:
12
+
13
+ ```ruby
14
+ gem install ssdb
15
+ ```
16
+
17
+ Use it with bundler, by adding the following line to your Gemfile:
18
+
19
+ ```ruby
20
+ gem "ssdb"
21
+ ```
22
+
23
+ For more information please visit http://gembundler.com/.
24
+
25
+ ### Basic usage
26
+
27
+ Connect to SSDB, assuming it is listening on `localhost`, port 8888.
28
+
29
+ ```ruby
30
+ require "ssdb"
31
+
32
+ ssdb = SSDB.new
33
+ ```
34
+
35
+ To connect to a custom server, please provide a custom `:url` option:
36
+
37
+ ```ruby
38
+ ssdb = SSDB.new url: "ssdb://1.2.3.4:8889"
39
+ ```
40
+
41
+ To execute commands:
42
+
43
+ ```ruby
44
+ ssdb.set("mykey", "hello world")
45
+ # => true
46
+
47
+ ssdb.get("mykey")
48
+ # => "hello world"
49
+ ```
50
+
51
+ Full documentation of all commands is available on [rdoc.info][rdoc].
52
+
53
+ [rdoc]: http://rdoc.info/github/bsm/ssdb-rb/
54
+
55
+ ### Batching/pipelining
56
+
57
+ Multiple commands can be executed as a batch operations. Instead of sending
58
+ commands one-by-one the client is able to send a batch of commands and
59
+ retrieve all responses as a single socket message exchange cycle.
60
+
61
+ Example:
62
+
63
+ ```ruby
64
+ ssdb.batch do
65
+ ssdb.set "foo", "5"
66
+ ssdb.get "foo"
67
+ ssdb.incr "foo"
68
+ end
69
+ # => [true, "5", 6]
70
+ ```
71
+
72
+ ### Futures
73
+
74
+ Results of individual batch operations are stored as *futures*. Future values
75
+ can be retrieved via the `#value` method once the batch execution is complete.
76
+
77
+ ```ruby
78
+ ssdb.batch do
79
+ v = ssdb.set "foo", "bar"
80
+ w = ssdc.incr "baz"
81
+ end
82
+
83
+ v.value
84
+ # => true
85
+
86
+ w.value
87
+ # => 1
88
+ ```
89
+
90
+ ### TODO
91
+
92
+ * Implement HASH operations
93
+
94
+ ### Licence (MIT)
95
+
96
+ ```
97
+ Copyright (c) 2013 Black Square Media Ltd
98
+
99
+ Permission is hereby granted, free of charge, to any person obtaining
100
+ a copy of this software and associated documentation files (the
101
+ "Software"), to deal in the Software without restriction, including
102
+ without limitation the rights to use, copy, modify, merge, publish,
103
+ distribute, sublicense, and/or sell copies of the Software, and to
104
+ permit persons to whom the Software is furnished to do so, subject to
105
+ the following conditions:
106
+
107
+ The above copyright notice and this permission notice shall be
108
+ included in all copies or substantial portions of the Software.
109
+
110
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
111
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
112
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
113
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
114
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
115
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
116
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
117
+ ```
@@ -0,0 +1,10 @@
1
+ require 'bundler/setup'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ YARD::Rake::YardocTask.new
8
+
9
+ desc 'Default: run specs.'
10
+ task :default => :spec
@@ -0,0 +1,431 @@
1
+ require "monitor"
2
+
3
+ class SSDB
4
+ include MonitorMixin
5
+
6
+ Error = Class.new(RuntimeError)
7
+ ConnectionError = Class.new(Error)
8
+ TimeoutError = Class.new(Error)
9
+ CommandError = Class.new(Error)
10
+ FutureNotReady = Class.new(Error)
11
+
12
+ T_BOOL = ->r { r == "1" }
13
+ T_INT = ->r { r.to_i }
14
+ T_CINT = ->r { r.to_i if r }
15
+ T_VBOOL = ->r { r.each_slice(2).map {|_, v| v == "1" }}
16
+ T_VINT = ->r { r.each_slice(2).map {|_, v| v.to_i }}
17
+ T_STRSTR = ->r { r.each_slice(2).to_a }
18
+ T_STRINT = ->r { r.each_slice(2).map {|v, s| [v, s.to_i] } }
19
+ T_MAPINT = ->r,n { h = {}; r.each_slice(2) {|k, v| h[k] = v }; n.map {|k| h[k].to_i } }
20
+ T_MAPSTR = ->r,n { h = {}; r.each_slice(2) {|k, v| h[k] = v }; n.map {|k| h[k] } }
21
+ BLANK = "".freeze
22
+
23
+ # @attr_reader [SSDB::Client] the client
24
+ attr_reader :client
25
+
26
+ # @return [SSDB] the current/global SSDB connection
27
+ def self.current
28
+ @current ||= SSDB.new
29
+ end
30
+
31
+ # @param [SSDB] ssdb the current/global SSDB connection
32
+ def self.current=(ssdb)
33
+ @current = ssdb
34
+ end
35
+
36
+ # @see SSDB::Client#initialize
37
+ def initialize(*a)
38
+ @client = Client.new(*a)
39
+ super() # Monitor#initialize
40
+ end
41
+
42
+ # Execute a batch operation
43
+ #
44
+ # @example simple batch
45
+ #
46
+ # ssdb.batch do
47
+ # ssdb.set "foo", "5"
48
+ # ssdb.get "foo"
49
+ # ssdb.incr "foo"
50
+ # end
51
+ # # => [true, "5", 6]
52
+ #
53
+ # @example batch with futures
54
+ #
55
+ # ssdb.batch do
56
+ # v = ssdb.set "foo", "5"
57
+ # w = ssdb.incr "foo"
58
+ # end
59
+ #
60
+ # v.value
61
+ # # => true
62
+ # w.value
63
+ # # => 6
64
+ #
65
+ def batch
66
+ mon_synchronize do
67
+ begin
68
+ original, @client = @client, SSDB::Batch.new
69
+ yield(self)
70
+ @client.values = original.perform(@client)
71
+ ensure
72
+ @client = original
73
+ end
74
+ end
75
+ end
76
+
77
+ # Returns value at `key`.
78
+ #
79
+ # @param [String] key the key
80
+ # @return [String] the value
81
+ def get(key)
82
+ mon_synchronize do
83
+ perform ["get", key]
84
+ end
85
+ end
86
+
87
+ # Sets `value` at `key`.
88
+ #
89
+ # @param [String] key the key
90
+ # @param [String] value the value
91
+ def set(key, value)
92
+ mon_synchronize do
93
+ perform ["set", key, value], proc: T_BOOL
94
+ end
95
+ end
96
+
97
+ # Increments a `key` by value
98
+ #
99
+ # @param [String] key the key
100
+ # @param [Integer] value the increment
101
+ def incr(key, value = 1)
102
+ mon_synchronize do
103
+ perform ["incr", key, value], proc: T_INT
104
+ end
105
+ end
106
+
107
+ # Decrements a `key` by value
108
+ #
109
+ # @param [String] key the key
110
+ # @param [Integer] value the decrement
111
+ def decr(key, value = 1)
112
+ mon_synchronize do
113
+ perform ["decr", key, value], proc: T_INT
114
+ end
115
+ end
116
+
117
+ # Checks existence of `key`.
118
+ #
119
+ # @param [String] key the key
120
+ # @return [Boolean] true if exists
121
+ def exists(key)
122
+ mon_synchronize do
123
+ perform ["exists", key], proc: T_BOOL
124
+ end
125
+ end
126
+ alias_method :exists?, :exists
127
+
128
+ # Delete `key`.
129
+ #
130
+ # @param [String] key the key
131
+ def del(key)
132
+ mon_synchronize do
133
+ perform ["del", key]
134
+ end
135
+ end
136
+
137
+ # Scans keys between `start` and `stop`.
138
+ #
139
+ # @param [String] start start at this key
140
+ # @param [String] stop stop at this key
141
+ # @param [Hash] opts options
142
+ # @option opts [Integer] :limit limit results
143
+ # @return [Array<String>] matching keys
144
+ def keys(start, stop, opts = {})
145
+ limit = opts[:limit] || -1
146
+ mon_synchronize do
147
+ perform ["keys", start, stop, limit], multi: true
148
+ end
149
+ end
150
+
151
+ # Scans keys between `start` and `stop`.
152
+ #
153
+ # @param [String] start start at this key
154
+ # @param [String] stop stop at this key
155
+ # @param [Hash] opts options
156
+ # @option opts [Integer] :limit limit results
157
+ # @return [Array<Array<String,String>>] key/value pairs
158
+ def scan(start, stop, opts = {})
159
+ limit = opts[:limit] || -1
160
+ mon_synchronize do
161
+ perform ["scan", start, stop, limit], multi: true, proc: T_STRSTR
162
+ end
163
+ end
164
+
165
+ # Reverse-scans keys between `start` and `stop`.
166
+ #
167
+ # @param [String] start start at this key
168
+ # @param [String] stop stop at this key
169
+ # @param [Hash] opts options
170
+ # @option opts [Integer] :limit limit results
171
+ # @return [Array<Array<String,String>>] key/value pairs in reverse order
172
+ def rscan(start, stop, opts = {})
173
+ limit = opts[:limit] || -1
174
+ mon_synchronize do
175
+ perform ["rscan", start, stop, limit], multi: true, proc: T_STRSTR
176
+ end
177
+ end
178
+
179
+ # Sets multiple keys
180
+ #
181
+ # @param [Hash] pairs key/value pairs
182
+ def multi_set(pairs)
183
+ mon_synchronize do
184
+ perform ["multi_set", *pairs.to_a].flatten, proc: T_INT
185
+ end
186
+ end
187
+
188
+ # Retrieves multiple keys
189
+ #
190
+ # @param [Array<String>] keys
191
+ # @return [Array<String>] values
192
+ def multi_get(keys)
193
+ keys = Array(keys) unless keys.is_a?(Array)
194
+ mon_synchronize do
195
+ perform ["multi_get", *keys], multi: true, proc: T_MAPSTR, args: [keys]
196
+ end
197
+ end
198
+
199
+ # Deletes multiple keys
200
+ #
201
+ # @param [Array<String>] keys
202
+ def multi_del(keys)
203
+ keys = Array(keys) unless keys.is_a?(Array)
204
+ mon_synchronize do
205
+ perform ["multi_del", *keys], proc: T_INT
206
+ end
207
+ end
208
+
209
+ # Checks existence of multiple keys
210
+ #
211
+ # @param [Array<String>] keys
212
+ # @return [Array<Boolean>] results
213
+ def multi_exists(keys)
214
+ keys = Array(keys) unless keys.is_a?(Array)
215
+ mon_synchronize do
216
+ perform ["multi_exists", *keys], multi: true, proc: T_VBOOL
217
+ end
218
+ end
219
+
220
+ # Returns the score of `member` at `key`.
221
+ #
222
+ # @param [String] key the key
223
+ # @param [String] member the member
224
+ # @return [Float] the score
225
+ def zget(key, member)
226
+ mon_synchronize do
227
+ perform ["zget", key, member], proc: T_CINT
228
+ end
229
+ end
230
+
231
+ # Sets the `score` of `member` at `key`.
232
+ #
233
+ # @param [String] key the key
234
+ # @param [String] member the member
235
+ # @param [Numeric] score the score
236
+ def zset(key, member, score)
237
+ mon_synchronize do
238
+ perform ["zset", key, member, score], proc: T_BOOL
239
+ end
240
+ end
241
+
242
+ # Redis 'compatibility'.
243
+ #
244
+ # @param [String] key the key
245
+ # @param [Numeric] score the score
246
+ # @param [String] member the member
247
+ def zadd(key, score, member)
248
+ zset(key, member, score)
249
+ end
250
+
251
+ # Increments the `member` in `key` by `score`
252
+ #
253
+ # @param [String] key the key
254
+ # @param [String] member the member
255
+ # @param [Integer] score the increment
256
+ def zincr(key, member, score = 1)
257
+ mon_synchronize do
258
+ perform ["zincr", key, member, score], proc: T_INT
259
+ end
260
+ end
261
+
262
+ # Decrements the `member` in `key` by `score`
263
+ #
264
+ # @param [String] key the key
265
+ # @param [String] member the member
266
+ # @param [Integer] score the decrement
267
+ def zdecr(key, member, score = 1)
268
+ mon_synchronize do
269
+ perform ["zdecr", key, member, score], proc: T_INT
270
+ end
271
+ end
272
+
273
+ # Checks existence of a zset at `key`.
274
+ #
275
+ # @param [String] key the key
276
+ # @return [Boolean] true if exists
277
+ def zexists(key)
278
+ mon_synchronize do
279
+ perform ["zexists", key], proc: T_BOOL
280
+ end
281
+ end
282
+ alias_method :zexists?, :zexists
283
+
284
+ # Returns the cardinality of a set `key`.
285
+ #
286
+ # @param [String] key the key
287
+ def zsize(key)
288
+ mon_synchronize do
289
+ perform ["zsize", key], proc: T_INT
290
+ end
291
+ end
292
+
293
+ # Delete an `member` from a zset `key`.
294
+ #
295
+ # @param [String] key the key
296
+ # @param [String] member the member
297
+ def zdel(key, member)
298
+ mon_synchronize do
299
+ perform ["zdel", key, member], proc: T_BOOL
300
+ end
301
+ end
302
+
303
+ # List zset keys between `start` and `stop`.
304
+ #
305
+ # @param [String] start start at this key
306
+ # @param [String] stop stop at this key
307
+ # @param [Hash] opts options
308
+ # @option opts [Integer] :limit limit results
309
+ # @return [Array<String>] matching zset keys
310
+ def zlist(start, stop, opts = {})
311
+ limit = opts[:limit] || -1
312
+ mon_synchronize do
313
+ perform ["zlist", start, stop, limit], multi: true
314
+ end
315
+ end
316
+
317
+ # Lists members at `key` starting at `start_member`
318
+ # between `start` and `stop` scores.
319
+ #
320
+ # @param [String] key the zset
321
+ # @param [Float] start start at this score
322
+ # @param [Float] stop stop at this score
323
+ # @param [Hash] opts options
324
+ # @option opts [Integer] :limit limit results
325
+ # @return [Array<String>] matching members
326
+ def zkeys(key, start, stop, opts = {})
327
+ limit = opts[:limit] || -1
328
+ mon_synchronize do
329
+ perform ["zkeys", key, BLANK, start, stop, limit], multi: true
330
+ end
331
+ end
332
+
333
+ # Scans for members at `key` starting at `start_member`
334
+ # between `start` and `stop` scores.
335
+ #
336
+ # @param [String] key the zset
337
+ # @param [Float] start start at this score
338
+ # @param [Float] stop stop at this score
339
+ # @param [Hash] opts options
340
+ # @option opts [Integer] :limit limit results
341
+ # @return [Array<Array<String,Float>>] member/score pairs
342
+ def zscan(key, start, stop, opts = {})
343
+ limit = opts[:limit] || -1
344
+ mon_synchronize do
345
+ perform ["zscan", key, BLANK, start, stop, limit], multi: true, proc: T_STRINT
346
+ end
347
+ end
348
+
349
+ # Reverse scans for members at `key` starting at `start_member`
350
+ # between `start` and `stop` scores.
351
+ #
352
+ # @param [String] key the zset
353
+ # @param [Float] start start at this score
354
+ # @param [Float] stop stop at this score
355
+ # @param [Hash] opts options
356
+ # @option opts [Integer] :limit limit results
357
+ # @return [Array<Array<String,Float>>] member/score pairs
358
+ def zrscan(key, start, stop, opts = {})
359
+ limit = opts[:limit] || -1
360
+ mon_synchronize do
361
+ perform ["zrscan", key, BLANK, start, stop, limit], multi: true, proc: T_STRINT
362
+ end
363
+ end
364
+
365
+ # Checks existence of multiple sets
366
+ #
367
+ # @param [Array<String>] keys
368
+ # @return [Array<Boolean>] results
369
+ def multi_zexists(keys)
370
+ keys = Array(keys) unless keys.is_a?(Array)
371
+ mon_synchronize do
372
+ perform ["multi_zexists", *keys], multi: true, proc: T_VBOOL
373
+ end
374
+ end
375
+
376
+ # Returns cardinalities of multiple sets
377
+ #
378
+ # @param [Array<String>] keys
379
+ # @return [Array<Boolean>] results
380
+ def multi_zsize(keys)
381
+ keys = Array(keys) unless keys.is_a?(Array)
382
+ mon_synchronize do
383
+ perform ["multi_zsize", *keys], multi: true, proc: T_VINT
384
+ end
385
+ end
386
+
387
+ # Sets multiple members of `key`
388
+ #
389
+ # @param [String] key the zset
390
+ # @param [Hash] pairs key/value pairs
391
+ def multi_zset(key, pairs)
392
+ mon_synchronize do
393
+ perform ["multi_zset", key, *pairs.to_a].flatten, proc: T_INT
394
+ end
395
+ end
396
+
397
+ # Retrieves multiple scores from `key`
398
+ #
399
+ # @param [String] key the zset
400
+ # @param [Array<String>] members
401
+ # @return [Array<Float>] scores
402
+ def multi_zget(key, members)
403
+ members = Array(members) unless members.is_a?(Array)
404
+ mon_synchronize do
405
+ perform ["multi_zget", key, *members], multi: true, proc: T_MAPINT, args: [members]
406
+ end
407
+ end
408
+
409
+ # Deletes multiple members from `key`
410
+ #
411
+ # @param [String] key the zset
412
+ # @param [Array<String>] members
413
+ def multi_zdel(key, members)
414
+ members = Array(members) unless members.is_a?(Array)
415
+ mon_synchronize do
416
+ perform ["multi_zdel", key, *members], proc: T_INT
417
+ end
418
+ end
419
+
420
+ private
421
+
422
+ def perform(chain, opts = {})
423
+ opts[:cmd] = chain.map(&:to_s)
424
+ client.call(opts)
425
+ end
426
+
427
+ end
428
+
429
+ %w|version client batch future|.each do |name|
430
+ require "ssdb/#{name}"
431
+ end