redis 3.3.5 → 5.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +290 -2
  3. data/README.md +146 -146
  4. data/lib/redis/client.rb +79 -541
  5. data/lib/redis/commands/bitmaps.rb +66 -0
  6. data/lib/redis/commands/cluster.rb +28 -0
  7. data/lib/redis/commands/connection.rb +53 -0
  8. data/lib/redis/commands/geo.rb +84 -0
  9. data/lib/redis/commands/hashes.rb +254 -0
  10. data/lib/redis/commands/hyper_log_log.rb +37 -0
  11. data/lib/redis/commands/keys.rb +437 -0
  12. data/lib/redis/commands/lists.rb +339 -0
  13. data/lib/redis/commands/pubsub.rb +54 -0
  14. data/lib/redis/commands/scripting.rb +114 -0
  15. data/lib/redis/commands/server.rb +188 -0
  16. data/lib/redis/commands/sets.rb +214 -0
  17. data/lib/redis/commands/sorted_sets.rb +884 -0
  18. data/lib/redis/commands/streams.rb +402 -0
  19. data/lib/redis/commands/strings.rb +314 -0
  20. data/lib/redis/commands/transactions.rb +115 -0
  21. data/lib/redis/commands.rb +237 -0
  22. data/lib/redis/distributed.rb +328 -108
  23. data/lib/redis/errors.rb +23 -1
  24. data/lib/redis/hash_ring.rb +36 -79
  25. data/lib/redis/pipeline.rb +69 -83
  26. data/lib/redis/subscribe.rb +26 -19
  27. data/lib/redis/version.rb +3 -1
  28. data/lib/redis.rb +115 -2695
  29. metadata +38 -218
  30. data/.gitignore +0 -16
  31. data/.travis/Gemfile +0 -11
  32. data/.travis.yml +0 -89
  33. data/.yardopts +0 -3
  34. data/Gemfile +0 -4
  35. data/Rakefile +0 -87
  36. data/benchmarking/logging.rb +0 -71
  37. data/benchmarking/pipeline.rb +0 -51
  38. data/benchmarking/speed.rb +0 -21
  39. data/benchmarking/suite.rb +0 -24
  40. data/benchmarking/worker.rb +0 -71
  41. data/examples/basic.rb +0 -15
  42. data/examples/consistency.rb +0 -114
  43. data/examples/dist_redis.rb +0 -43
  44. data/examples/incr-decr.rb +0 -17
  45. data/examples/list.rb +0 -26
  46. data/examples/pubsub.rb +0 -37
  47. data/examples/sentinel/sentinel.conf +0 -9
  48. data/examples/sentinel/start +0 -49
  49. data/examples/sentinel.rb +0 -41
  50. data/examples/sets.rb +0 -36
  51. data/examples/unicorn/config.ru +0 -3
  52. data/examples/unicorn/unicorn.rb +0 -20
  53. data/lib/redis/connection/command_helper.rb +0 -44
  54. data/lib/redis/connection/hiredis.rb +0 -66
  55. data/lib/redis/connection/registry.rb +0 -12
  56. data/lib/redis/connection/ruby.rb +0 -429
  57. data/lib/redis/connection/synchrony.rb +0 -133
  58. data/lib/redis/connection.rb +0 -9
  59. data/redis.gemspec +0 -44
  60. data/test/bitpos_test.rb +0 -69
  61. data/test/blocking_commands_test.rb +0 -42
  62. data/test/client_test.rb +0 -59
  63. data/test/command_map_test.rb +0 -30
  64. data/test/commands_on_hashes_test.rb +0 -21
  65. data/test/commands_on_hyper_log_log_test.rb +0 -21
  66. data/test/commands_on_lists_test.rb +0 -20
  67. data/test/commands_on_sets_test.rb +0 -77
  68. data/test/commands_on_sorted_sets_test.rb +0 -137
  69. data/test/commands_on_strings_test.rb +0 -101
  70. data/test/commands_on_value_types_test.rb +0 -133
  71. data/test/connection_handling_test.rb +0 -277
  72. data/test/connection_test.rb +0 -57
  73. data/test/db/.gitkeep +0 -0
  74. data/test/distributed_blocking_commands_test.rb +0 -46
  75. data/test/distributed_commands_on_hashes_test.rb +0 -10
  76. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  77. data/test/distributed_commands_on_lists_test.rb +0 -22
  78. data/test/distributed_commands_on_sets_test.rb +0 -83
  79. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  80. data/test/distributed_commands_on_strings_test.rb +0 -59
  81. data/test/distributed_commands_on_value_types_test.rb +0 -95
  82. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  83. data/test/distributed_connection_handling_test.rb +0 -23
  84. data/test/distributed_internals_test.rb +0 -79
  85. data/test/distributed_key_tags_test.rb +0 -52
  86. data/test/distributed_persistence_control_commands_test.rb +0 -26
  87. data/test/distributed_publish_subscribe_test.rb +0 -92
  88. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  89. data/test/distributed_scripting_test.rb +0 -102
  90. data/test/distributed_sorting_test.rb +0 -20
  91. data/test/distributed_test.rb +0 -58
  92. data/test/distributed_transactions_test.rb +0 -32
  93. data/test/encoding_test.rb +0 -18
  94. data/test/error_replies_test.rb +0 -59
  95. data/test/fork_safety_test.rb +0 -65
  96. data/test/helper.rb +0 -232
  97. data/test/helper_test.rb +0 -24
  98. data/test/internals_test.rb +0 -417
  99. data/test/lint/blocking_commands.rb +0 -150
  100. data/test/lint/hashes.rb +0 -162
  101. data/test/lint/hyper_log_log.rb +0 -60
  102. data/test/lint/lists.rb +0 -143
  103. data/test/lint/sets.rb +0 -140
  104. data/test/lint/sorted_sets.rb +0 -316
  105. data/test/lint/strings.rb +0 -260
  106. data/test/lint/value_types.rb +0 -122
  107. data/test/persistence_control_commands_test.rb +0 -26
  108. data/test/pipelining_commands_test.rb +0 -242
  109. data/test/publish_subscribe_test.rb +0 -282
  110. data/test/remote_server_control_commands_test.rb +0 -118
  111. data/test/scanning_test.rb +0 -413
  112. data/test/scripting_test.rb +0 -78
  113. data/test/sentinel_command_test.rb +0 -80
  114. data/test/sentinel_test.rb +0 -255
  115. data/test/sorting_test.rb +0 -59
  116. data/test/ssl_test.rb +0 -73
  117. data/test/support/connection/hiredis.rb +0 -1
  118. data/test/support/connection/ruby.rb +0 -1
  119. data/test/support/connection/synchrony.rb +0 -17
  120. data/test/support/redis_mock.rb +0 -130
  121. data/test/support/ssl/gen_certs.sh +0 -31
  122. data/test/support/ssl/trusted-ca.crt +0 -25
  123. data/test/support/ssl/trusted-ca.key +0 -27
  124. data/test/support/ssl/trusted-cert.crt +0 -81
  125. data/test/support/ssl/trusted-cert.key +0 -28
  126. data/test/support/ssl/untrusted-ca.crt +0 -26
  127. data/test/support/ssl/untrusted-ca.key +0 -27
  128. data/test/support/ssl/untrusted-cert.crt +0 -82
  129. data/test/support/ssl/untrusted-cert.key +0 -28
  130. data/test/support/wire/synchrony.rb +0 -24
  131. data/test/support/wire/thread.rb +0 -5
  132. data/test/synchrony_driver.rb +0 -88
  133. data/test/test.conf.erb +0 -9
  134. data/test/thread_safety_test.rb +0 -62
  135. data/test/transactions_test.rb +0 -264
  136. data/test/unknown_commands_test.rb +0 -14
  137. data/test/url_param_test.rb +0 -138
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ module Commands
5
+ module Bitmaps
6
+ # Sets or clears the bit at offset in the string value stored at key.
7
+ #
8
+ # @param [String] key
9
+ # @param [Integer] offset bit offset
10
+ # @param [Integer] value bit value `0` or `1`
11
+ # @return [Integer] the original bit value stored at `offset`
12
+ def setbit(key, offset, value)
13
+ send_command([:setbit, key, offset, value])
14
+ end
15
+
16
+ # Returns the bit value at offset in the string value stored at key.
17
+ #
18
+ # @param [String] key
19
+ # @param [Integer] offset bit offset
20
+ # @return [Integer] `0` or `1`
21
+ def getbit(key, offset)
22
+ send_command([:getbit, key, offset])
23
+ end
24
+
25
+ # Count the number of set bits in a range of the string value stored at key.
26
+ #
27
+ # @param [String] key
28
+ # @param [Integer] start start index
29
+ # @param [Integer] stop stop index
30
+ # @return [Integer] the number of bits set to 1
31
+ def bitcount(key, start = 0, stop = -1)
32
+ send_command([:bitcount, key, start, stop])
33
+ end
34
+
35
+ # Perform a bitwise operation between strings and store the resulting string in a key.
36
+ #
37
+ # @param [String] operation e.g. `and`, `or`, `xor`, `not`
38
+ # @param [String] destkey destination key
39
+ # @param [String, Array<String>] keys one or more source keys to perform `operation`
40
+ # @return [Integer] the length of the string stored in `destkey`
41
+ def bitop(operation, destkey, *keys)
42
+ keys.flatten!(1)
43
+ command = [:bitop, operation, destkey]
44
+ command.concat(keys)
45
+ send_command(command)
46
+ end
47
+
48
+ # Return the position of the first bit set to 1 or 0 in a string.
49
+ #
50
+ # @param [String] key
51
+ # @param [Integer] bit whether to look for the first 1 or 0 bit
52
+ # @param [Integer] start start index
53
+ # @param [Integer] stop stop index
54
+ # @return [Integer] the position of the first 1/0 bit.
55
+ # -1 if looking for 1 and it is not found or start and stop are given.
56
+ def bitpos(key, bit, start = nil, stop = nil)
57
+ raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
58
+
59
+ command = [:bitpos, key, bit]
60
+ command << start if start
61
+ command << stop if stop
62
+ send_command(command)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ module Commands
5
+ module Cluster
6
+ # Sends `CLUSTER *` command to random node and returns its reply.
7
+ #
8
+ # @see https://redis.io/commands#cluster Reference of cluster command
9
+ #
10
+ # @param subcommand [String, Symbol] the subcommand of cluster command
11
+ # e.g. `:slots`, `:nodes`, `:slaves`, `:info`
12
+ #
13
+ # @return [Object] depends on the subcommand
14
+ def cluster(subcommand, *args)
15
+ send_command([:cluster, subcommand] + args)
16
+ end
17
+
18
+ # Sends `ASKING` command to random node and returns its reply.
19
+ #
20
+ # @see https://redis.io/topics/cluster-spec#ask-redirection ASK redirection
21
+ #
22
+ # @return [String] `'OK'`
23
+ def asking
24
+ send_command(%i[asking])
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ module Commands
5
+ module Connection
6
+ # Authenticate to the server.
7
+ #
8
+ # @param [Array<String>] args includes both username and password
9
+ # or only password
10
+ # @return [String] `OK`
11
+ # @see https://redis.io/commands/auth AUTH command
12
+ def auth(*args)
13
+ send_command([:auth, *args])
14
+ end
15
+
16
+ # Ping the server.
17
+ #
18
+ # @param [optional, String] message
19
+ # @return [String] `PONG`
20
+ def ping(message = nil)
21
+ send_command([:ping, message].compact)
22
+ end
23
+
24
+ # Echo the given string.
25
+ #
26
+ # @param [String] value
27
+ # @return [String]
28
+ def echo(value)
29
+ send_command([:echo, value])
30
+ end
31
+
32
+ # Change the selected database for the current connection.
33
+ #
34
+ # @param [Integer] db zero-based index of the DB to use (0 to 15)
35
+ # @return [String] `OK`
36
+ def select(db)
37
+ send_command([:select, db])
38
+ end
39
+
40
+ # Close the connection.
41
+ #
42
+ # @return [String] `OK`
43
+ def quit
44
+ synchronize do |client|
45
+ client.call_v([:quit])
46
+ rescue ConnectionError
47
+ ensure
48
+ client.close
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ module Commands
5
+ module Geo
6
+ # Adds the specified geospatial items (latitude, longitude, name) to the specified key
7
+ #
8
+ # @param [String] key
9
+ # @param [Array] member arguemnts for member or members: longitude, latitude, name
10
+ # @return [Integer] number of elements added to the sorted set
11
+ def geoadd(key, *member)
12
+ send_command([:geoadd, key, *member])
13
+ end
14
+
15
+ # Returns geohash string representing position for specified members of the specified key.
16
+ #
17
+ # @param [String] key
18
+ # @param [String, Array<String>] member one member or array of members
19
+ # @return [Array<String, nil>] returns array containg geohash string if member is present, nil otherwise
20
+ def geohash(key, member)
21
+ send_command([:geohash, key, member])
22
+ end
23
+
24
+ # Query a sorted set representing a geospatial index to fetch members matching a
25
+ # given maximum distance from a point
26
+ #
27
+ # @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
28
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
29
+ # or the farthest to the nearest relative to the center
30
+ # @param [Integer] count limit the results to the first N matching items
31
+ # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
32
+ # @return [Array<String>] may be changed with `options`
33
+ def georadius(*args, **geoptions)
34
+ geoarguments = _geoarguments(*args, **geoptions)
35
+
36
+ send_command([:georadius, *geoarguments])
37
+ end
38
+
39
+ # Query a sorted set representing a geospatial index to fetch members matching a
40
+ # given maximum distance from an already existing member
41
+ #
42
+ # @param [Array] args key, member, radius, unit(m|km|ft|mi)
43
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
44
+ # to the nearest relative to the center
45
+ # @param [Integer] count limit the results to the first N matching items
46
+ # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
47
+ # @return [Array<String>] may be changed with `options`
48
+ def georadiusbymember(*args, **geoptions)
49
+ geoarguments = _geoarguments(*args, **geoptions)
50
+
51
+ send_command([:georadiusbymember, *geoarguments])
52
+ end
53
+
54
+ # Returns longitude and latitude of members of a geospatial index
55
+ #
56
+ # @param [String] key
57
+ # @param [String, Array<String>] member one member or array of members
58
+ # @return [Array<Array<String>, nil>] returns array of elements, where each
59
+ # element is either array of longitude and latitude or nil
60
+ def geopos(key, member)
61
+ send_command([:geopos, key, member])
62
+ end
63
+
64
+ # Returns the distance between two members of a geospatial index
65
+ #
66
+ # @param [String ]key
67
+ # @param [Array<String>] members
68
+ # @param ['m', 'km', 'mi', 'ft'] unit
69
+ # @return [String, nil] returns distance in spefied unit if both members present, nil otherwise.
70
+ def geodist(key, member1, member2, unit = 'm')
71
+ send_command([:geodist, key, member1, member2, unit])
72
+ end
73
+
74
+ private
75
+
76
+ def _geoarguments(*args, options: nil, sort: nil, count: nil)
77
+ args << sort if sort
78
+ args << 'COUNT' << Integer(count) if count
79
+ args << options if options
80
+ args
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,254 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ module Commands
5
+ module Hashes
6
+ # Get the number of fields in a hash.
7
+ #
8
+ # @param [String] key
9
+ # @return [Integer] number of fields in the hash
10
+ def hlen(key)
11
+ send_command([:hlen, key])
12
+ end
13
+
14
+ # Set one or more hash values.
15
+ #
16
+ # @example
17
+ # redis.hset("hash", "f1", "v1", "f2", "v2") # => 2
18
+ # redis.hset("hash", { "f1" => "v1", "f2" => "v2" }) # => 2
19
+ #
20
+ # @param [String] key
21
+ # @param [Array<String> | Hash<String, String>] attrs array or hash of fields and values
22
+ # @return [Integer] The number of fields that were added to the hash
23
+ def hset(key, *attrs)
24
+ attrs = attrs.first.flatten if attrs.size == 1 && attrs.first.is_a?(Hash)
25
+
26
+ send_command([:hset, key, *attrs])
27
+ end
28
+
29
+ # Set the value of a hash field, only if the field does not exist.
30
+ #
31
+ # @param [String] key
32
+ # @param [String] field
33
+ # @param [String] value
34
+ # @return [Boolean] whether or not the field was **added** to the hash
35
+ def hsetnx(key, field, value)
36
+ send_command([:hsetnx, key, field, value], &Boolify)
37
+ end
38
+
39
+ # Set one or more hash values.
40
+ #
41
+ # @example
42
+ # redis.hmset("hash", "f1", "v1", "f2", "v2")
43
+ # # => "OK"
44
+ #
45
+ # @param [String] key
46
+ # @param [Array<String>] attrs array of fields and values
47
+ # @return [String] `"OK"`
48
+ #
49
+ # @see #mapped_hmset
50
+ def hmset(key, *attrs)
51
+ send_command([:hmset, key] + attrs)
52
+ end
53
+
54
+ # Set one or more hash values.
55
+ #
56
+ # @example
57
+ # redis.mapped_hmset("hash", { "f1" => "v1", "f2" => "v2" })
58
+ # # => "OK"
59
+ #
60
+ # @param [String] key
61
+ # @param [Hash] hash a non-empty hash with fields mapping to values
62
+ # @return [String] `"OK"`
63
+ #
64
+ # @see #hmset
65
+ def mapped_hmset(key, hash)
66
+ hmset(key, hash.flatten)
67
+ end
68
+
69
+ # Get the value of a hash field.
70
+ #
71
+ # @param [String] key
72
+ # @param [String] field
73
+ # @return [String]
74
+ def hget(key, field)
75
+ send_command([:hget, key, field])
76
+ end
77
+
78
+ # Get the values of all the given hash fields.
79
+ #
80
+ # @example
81
+ # redis.hmget("hash", "f1", "f2")
82
+ # # => ["v1", "v2"]
83
+ #
84
+ # @param [String] key
85
+ # @param [Array<String>] fields array of fields
86
+ # @return [Array<String>] an array of values for the specified fields
87
+ #
88
+ # @see #mapped_hmget
89
+ def hmget(key, *fields, &blk)
90
+ fields.flatten!(1)
91
+ send_command([:hmget, key].concat(fields), &blk)
92
+ end
93
+
94
+ # Get the values of all the given hash fields.
95
+ #
96
+ # @example
97
+ # redis.mapped_hmget("hash", "f1", "f2")
98
+ # # => { "f1" => "v1", "f2" => "v2" }
99
+ #
100
+ # @param [String] key
101
+ # @param [Array<String>] fields array of fields
102
+ # @return [Hash] a hash mapping the specified fields to their values
103
+ #
104
+ # @see #hmget
105
+ def mapped_hmget(key, *fields)
106
+ fields.flatten!(1)
107
+ hmget(key, fields) do |reply|
108
+ if reply.is_a?(Array)
109
+ Hash[fields.zip(reply)]
110
+ else
111
+ reply
112
+ end
113
+ end
114
+ end
115
+
116
+ # Get one or more random fields from a hash.
117
+ #
118
+ # @example Get one random field
119
+ # redis.hrandfield("hash")
120
+ # # => "f1"
121
+ # @example Get multiple random fields
122
+ # redis.hrandfield("hash", 2)
123
+ # # => ["f1, "f2"]
124
+ # @example Get multiple random fields with values
125
+ # redis.hrandfield("hash", 2, with_values: true)
126
+ # # => [["f1", "s1"], ["f2", "s2"]]
127
+ #
128
+ # @param [String] key
129
+ # @param [Integer] count
130
+ # @param [Hash] options
131
+ # - `:with_values => true`: include values in output
132
+ #
133
+ # @return [nil, String, Array<String>, Array<[String, Float]>]
134
+ # - when `key` does not exist, `nil`
135
+ # - when `count` is not specified, a field name
136
+ # - when `count` is specified and `:with_values` is not specified, an array of field names
137
+ # - when `:with_values` is specified, an array with `[field, value]` pairs
138
+ def hrandfield(key, count = nil, withvalues: false, with_values: withvalues)
139
+ if with_values && count.nil?
140
+ raise ArgumentError, "count argument must be specified"
141
+ end
142
+
143
+ args = [:hrandfield, key]
144
+ args << count if count
145
+ args << "WITHVALUES" if with_values
146
+
147
+ parser = Pairify if with_values
148
+ send_command(args, &parser)
149
+ end
150
+
151
+ # Delete one or more hash fields.
152
+ #
153
+ # @param [String] key
154
+ # @param [String, Array<String>] field
155
+ # @return [Integer] the number of fields that were removed from the hash
156
+ def hdel(key, *fields)
157
+ fields.flatten!(1)
158
+ send_command([:hdel, key].concat(fields))
159
+ end
160
+
161
+ # Determine if a hash field exists.
162
+ #
163
+ # @param [String] key
164
+ # @param [String] field
165
+ # @return [Boolean] whether or not the field exists in the hash
166
+ def hexists(key, field)
167
+ send_command([:hexists, key, field], &Boolify)
168
+ end
169
+
170
+ # Increment the integer value of a hash field by the given integer number.
171
+ #
172
+ # @param [String] key
173
+ # @param [String] field
174
+ # @param [Integer] increment
175
+ # @return [Integer] value of the field after incrementing it
176
+ def hincrby(key, field, increment)
177
+ send_command([:hincrby, key, field, Integer(increment)])
178
+ end
179
+
180
+ # Increment the numeric value of a hash field by the given float number.
181
+ #
182
+ # @param [String] key
183
+ # @param [String] field
184
+ # @param [Float] increment
185
+ # @return [Float] value of the field after incrementing it
186
+ def hincrbyfloat(key, field, increment)
187
+ send_command([:hincrbyfloat, key, field, Float(increment)], &Floatify)
188
+ end
189
+
190
+ # Get all the fields in a hash.
191
+ #
192
+ # @param [String] key
193
+ # @return [Array<String>]
194
+ def hkeys(key)
195
+ send_command([:hkeys, key])
196
+ end
197
+
198
+ # Get all the values in a hash.
199
+ #
200
+ # @param [String] key
201
+ # @return [Array<String>]
202
+ def hvals(key)
203
+ send_command([:hvals, key])
204
+ end
205
+
206
+ # Get all the fields and values in a hash.
207
+ #
208
+ # @param [String] key
209
+ # @return [Hash<String, String>]
210
+ def hgetall(key)
211
+ send_command([:hgetall, key], &Hashify)
212
+ end
213
+
214
+ # Scan a hash
215
+ #
216
+ # @example Retrieve the first batch of key/value pairs in a hash
217
+ # redis.hscan("hash", 0)
218
+ #
219
+ # @param [String, Integer] cursor the cursor of the iteration
220
+ # @param [Hash] options
221
+ # - `:match => String`: only return keys matching the pattern
222
+ # - `:count => Integer`: return count keys at most per iteration
223
+ #
224
+ # @return [String, Array<[String, String]>] the next cursor and all found keys
225
+ def hscan(key, cursor, **options)
226
+ _scan(:hscan, cursor, [key], **options) do |reply|
227
+ [reply[0], reply[1].each_slice(2).to_a]
228
+ end
229
+ end
230
+
231
+ # Scan a hash
232
+ #
233
+ # @example Retrieve all of the key/value pairs in a hash
234
+ # redis.hscan_each("hash").to_a
235
+ # # => [["key70", "70"], ["key80", "80"]]
236
+ #
237
+ # @param [Hash] options
238
+ # - `:match => String`: only return keys matching the pattern
239
+ # - `:count => Integer`: return count keys at most per iteration
240
+ #
241
+ # @return [Enumerator] an enumerator for all found keys
242
+ def hscan_each(key, **options, &block)
243
+ return to_enum(:hscan_each, key, **options) unless block_given?
244
+
245
+ cursor = 0
246
+ loop do
247
+ cursor, values = hscan(key, cursor, **options)
248
+ values.each(&block)
249
+ break if cursor == "0"
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ module Commands
5
+ module HyperLogLog
6
+ # Add one or more members to a HyperLogLog structure.
7
+ #
8
+ # @param [String] key
9
+ # @param [String, Array<String>] member one member, or array of members
10
+ # @return [Boolean] true if at least 1 HyperLogLog internal register was altered. false otherwise.
11
+ def pfadd(key, member)
12
+ send_command([:pfadd, key, member], &Boolify)
13
+ end
14
+
15
+ # Get the approximate cardinality of members added to HyperLogLog structure.
16
+ #
17
+ # If called with multiple keys, returns the approximate cardinality of the
18
+ # union of the HyperLogLogs contained in the keys.
19
+ #
20
+ # @param [String, Array<String>] keys
21
+ # @return [Integer]
22
+ def pfcount(*keys)
23
+ send_command([:pfcount] + keys.flatten(1))
24
+ end
25
+
26
+ # Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
27
+ # the observed Sets of the source HyperLogLog structures.
28
+ #
29
+ # @param [String] dest_key destination key
30
+ # @param [String, Array<String>] source_key source key, or array of keys
31
+ # @return [Boolean]
32
+ def pfmerge(dest_key, *source_key)
33
+ send_command([:pfmerge, dest_key, *source_key], &BoolifySet)
34
+ end
35
+ end
36
+ end
37
+ end