async-redis 0.3.4 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4cf3ca6e7a1400dd30aa057b8688fe5c36dfd259ed6a62e74452e72706026434
4
- data.tar.gz: 377bb98eb47f7e21bde259224c2cbc61fa9e960804d6037c4b7e8556d1892bb1
3
+ metadata.gz: c94ef3534e5271a37e5588ac9906f88e421f03db3a3251de8e3f0b8aa414f91a
4
+ data.tar.gz: d8503520edb25b468aed41db06ce61a38ddb753bf5ec8034f9b129ec60e2a600
5
5
  SHA512:
6
- metadata.gz: 1ab1e184597d78757881a5a692763e00d0be075480a98600bb2ec87b87484bd17b3840692cd07bdc7d024ab3860b5ed410ae4c618df26a8bb0b8743425a68dff
7
- data.tar.gz: b4ce7600597fea36ba4f9e5b6d68db84fe286a259f4946e001a7ebade416989694a5c760eac08285f446b49956b8569402adfa0f7ed9a61189feec61d1e5df30
6
+ metadata.gz: b2926a1fccbba8221ed83b9b46e62f82fc2f4a44104e74d1b29973124375305eb3a3da0cdeef03071adb6b967ab7d72f2747829a243e20db9bebb34139973370
7
+ data.tar.gz: 57636bc3338aad4c34aa411034a67a586e753e0729c3436b290c9d84a59387b8d2c69a4be8f72f48b34a9f2590d2186c9944eba78fecbfa4c31bfc4f56681177
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+ .covered.db
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in async-io.gemspec
4
4
  gemspec
5
5
 
6
+ # gem "protocol-redis", path: "../protocol-redis"
7
+
6
8
  group :development do
7
9
  gem 'pry'
8
10
  end
data/README.md CHANGED
@@ -35,7 +35,7 @@ require 'async/redis'
35
35
  endpoint = Async::Redis.local_endpoint
36
36
  client = Async::Redis::Client.new(endpoint)
37
37
 
38
- Async.run do
38
+ Async do
39
39
  pp client.info
40
40
  ensure
41
41
  client.close
@@ -45,12 +45,13 @@ end
45
45
  ### Variables
46
46
 
47
47
  ```ruby
48
+ require 'async'
48
49
  require 'async/redis'
49
50
 
50
51
  endpoint = Async::Redis.local_endpoint
51
52
  client = Async::Redis::Client.new(endpoint)
52
53
 
53
- Async.run do
54
+ Async do
54
55
  client.set('X', 10)
55
56
  pp client.get('X')
56
57
  ensure
@@ -61,24 +62,30 @@ end
61
62
  ### Subscriptions
62
63
 
63
64
  ```ruby
65
+ require 'async'
64
66
  require 'async/redis'
65
- require 'json'
66
67
 
67
68
  endpoint = Async::Redis.local_endpoint
68
69
  client = Async::Redis::Client.new(endpoint)
69
70
 
70
- Async.run do |task|
71
+ Async do |task|
72
+ condition = Async::Condition.new
73
+
74
+ publisher = task.async do
75
+ condition.wait
76
+
77
+ client.publish 'status.frontend', 'good'
78
+ end
79
+
71
80
  subscriber = task.async do
72
81
  client.subscribe 'status.frontend' do |context|
82
+ condition.signal # We are waiting for messages.
83
+
73
84
  type, name, message = context.listen
74
85
 
75
86
  pp type, name, message
76
87
  end
77
88
  end
78
-
79
- publisher = task.async do
80
- client.publish 'status.frontend', 'good'
81
- end
82
89
  ensure
83
90
  client.close
84
91
  end
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.add_dependency("async", "~> 1.8")
21
21
  spec.add_dependency("async-io", "~> 1.10")
22
22
 
23
+ spec.add_dependency("protocol-redis", "~> 0.2.0")
24
+
23
25
  spec.add_development_dependency "async-rspec", "~> 1.1"
24
26
  spec.add_development_dependency "redis"
25
27
  spec.add_development_dependency "benchmark-ips"
@@ -18,31 +18,31 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative 'protocol/resp'
22
21
  require_relative 'pool'
23
- require_relative 'context/multi'
22
+ require_relative 'context/pipeline'
23
+ require_relative 'context/transaction'
24
24
  require_relative 'context/subscribe'
25
25
 
26
- require_relative 'methods/strings'
27
- require_relative 'methods/keys'
28
- require_relative 'methods/lists'
29
- require_relative 'methods/server'
26
+ require_relative 'protocol/resp2'
30
27
 
31
28
  require 'async/io'
29
+ require 'async/io/stream'
30
+
31
+ require 'protocol/redis/methods'
32
32
 
33
33
  module Async
34
34
  module Redis
35
+ # Legacy.
36
+ ServerError = ::Protocol::Redis::ServerError
37
+
35
38
  def self.local_endpoint
36
39
  Async::IO::Endpoint.tcp('localhost', 6379)
37
40
  end
38
41
 
39
42
  class Client
40
- include Methods::Strings
41
- include Methods::Keys
42
- include Methods::Lists
43
- include Methods::Server
43
+ include ::Protocol::Redis::Methods
44
44
 
45
- def initialize(endpoint = Redis.local_endpoint, protocol = Protocol::RESP, **options)
45
+ def initialize(endpoint = Redis.local_endpoint, protocol = Protocol::RESP2, **options)
46
46
  @endpoint = endpoint
47
47
  @protocol = protocol
48
48
 
@@ -100,8 +100,8 @@ module Async
100
100
  end
101
101
  end
102
102
 
103
- def nested(&block)
104
- context = Context::Nested.new(@pool)
103
+ def transaction(&block)
104
+ context = Context::Transaction.new(@pool)
105
105
 
106
106
  return context unless block_given?
107
107
 
@@ -111,11 +111,28 @@ module Async
111
111
  context.close
112
112
  end
113
113
  end
114
+
115
+ def pipeline(&block)
116
+ context = Context::Pipeline.new(@pool)
117
+
118
+ return context unless block_given?
119
+
120
+ begin
121
+ yield context
122
+ ensure
123
+ context.close
124
+ end
125
+ end
126
+
127
+ # Deprecated.
128
+ alias nested pipeline
114
129
 
115
130
  def call(*arguments)
116
131
  @pool.acquire do |connection|
117
132
  connection.write_request(arguments)
118
133
 
134
+ connection.flush
135
+
119
136
  return connection.read_response
120
137
  end
121
138
  end
@@ -19,18 +19,12 @@
19
19
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
20
  # THE SOFTWARE.
21
21
 
22
- require_relative '../methods/strings'
23
- require_relative '../methods/keys'
24
- require_relative '../methods/lists'
22
+ require 'protocol/redis/methods'
25
23
 
26
24
  module Async
27
25
  module Redis
28
26
  module Context
29
- class Nested
30
- include Methods::Strings
31
- include Methods::Keys
32
- include Methods::Lists
33
-
27
+ class Generic
34
28
  def initialize(pool, *args)
35
29
  @pool = pool
36
30
  @connection = pool.acquire
@@ -43,10 +37,21 @@ module Async
43
37
  end
44
38
  end
45
39
 
46
- def call(command, *args)
40
+ def write_request(command, *args)
47
41
  @connection.write_request([command, *args])
42
+ end
43
+
44
+ def read_response
45
+ @connection.flush
46
+
48
47
  return @connection.read_response
49
48
  end
49
+
50
+ def call(command, *args)
51
+ write_request(command, *args)
52
+
53
+ return read_response
54
+ end
50
55
  end
51
56
  end
52
57
  end
@@ -0,0 +1,104 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ # Copyright, 2019, by Huba Nagy.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ require_relative 'generic'
23
+
24
+ module Async
25
+ module Redis
26
+ module Context
27
+ # Send multiple commands without waiting for the response, instead of sending them one by one.
28
+ class Pipeline < Generic
29
+ include ::Protocol::Redis::Methods
30
+
31
+ class Sync
32
+ include ::Protocol::Redis::Methods
33
+
34
+ def initialize(pipeline)
35
+ @pipeline = pipeline
36
+ end
37
+
38
+ # This method just accumulates the commands and their params.
39
+ def call(command, *args)
40
+ @pipeline.call(command, *args)
41
+
42
+ @pipeline.flush(1)
43
+
44
+ return @pipeline.read_response
45
+ end
46
+ end
47
+
48
+ def initialize(pool)
49
+ super(pool)
50
+
51
+ @count = 0
52
+ @sync = nil
53
+ end
54
+
55
+ # Flush responses.
56
+ # @param count [Integer] leave this many responses.
57
+ def flush(count = 0)
58
+ while @count > count
59
+ read_response
60
+ end
61
+ end
62
+
63
+ def sync
64
+ @sync ||= Sync.new(self)
65
+ end
66
+
67
+ # This method just accumulates the commands and their params.
68
+ def write_request(*)
69
+ super
70
+
71
+ @count += 1
72
+ end
73
+
74
+ # This method just accumulates the commands and their params.
75
+ def call(command, *args)
76
+ write_request(command, *args)
77
+
78
+ return nil
79
+ end
80
+
81
+ def read_response
82
+ if @count > 0
83
+ @count -= 1
84
+ super
85
+ else
86
+ raise RuntimeError, "No more responses available!"
87
+ end
88
+ end
89
+
90
+ def collect
91
+ yield
92
+
93
+ @count.times.map{read_response}
94
+ end
95
+
96
+ def close
97
+ flush
98
+
99
+ super
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -19,14 +19,12 @@
19
19
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
20
  # THE SOFTWARE.
21
21
 
22
- require_relative 'nested'
23
-
24
- require 'set'
22
+ require_relative 'generic'
25
23
 
26
24
  module Async
27
25
  module Redis
28
26
  module Context
29
- class Subscribe < Nested
27
+ class Subscribe < Generic
30
28
  def initialize(pool, channels)
31
29
  super(pool)
32
30
 
@@ -43,6 +41,7 @@ module Async
43
41
 
44
42
  def subscribe(channels)
45
43
  @connection.write_request ['SUBSCRIBE', *channels]
44
+ @connection.flush
46
45
 
47
46
  response = nil
48
47
 
@@ -0,0 +1,51 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ # Copyright, 2018, by Huba Nagy.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ require_relative 'pipeline'
23
+
24
+ module Async
25
+ module Redis
26
+ module Context
27
+ class Transaction < Pipeline
28
+ def initialize(pool, *args)
29
+ super(pool)
30
+ end
31
+
32
+ def multi
33
+ call('MULTI')
34
+ end
35
+
36
+ def watch(*keys)
37
+ sync.call('WATCH', *keys)
38
+ end
39
+
40
+ # Execute all queued commands, provided that no watched keys have been modified. It's important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands.
41
+ def execute
42
+ sync.call('EXEC')
43
+ end
44
+
45
+ def discard
46
+ sync.call('DISCARD')
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,5 +1,4 @@
1
1
  # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- # Copyright, 2018, by Huba Nagy.
3
2
  #
4
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -21,27 +20,37 @@
21
20
 
22
21
  module Async
23
22
  module Redis
24
- module Methods
25
- module Server
26
- # Get info from server.
27
- # @return [Hash] the server metadata.
28
- def info
29
- metadata = {}
30
-
31
- call('INFO').each_line(Protocol::CRLF) do |line|
32
- key, value = line.split(':')
33
-
34
- if value
35
- metadata[key.to_sym] = value.chomp!
36
- end
37
- end
38
-
39
- return metadata
40
- end
41
-
42
- def flushdb!
43
- call 'FLUSHDB'
44
- end
23
+ class Key
24
+ def self.[] path
25
+ self.new(path)
26
+ end
27
+
28
+ include Comparable
29
+
30
+ def initialize(path)
31
+ @path = path
32
+ end
33
+
34
+ def size
35
+ @path.bytesize
36
+ end
37
+
38
+ attr :path
39
+
40
+ def to_s
41
+ @path
42
+ end
43
+
44
+ def to_str
45
+ @path
46
+ end
47
+
48
+ def [] key
49
+ self.class.new("#{@path}:#{key}")
50
+ end
51
+
52
+ def <=> other
53
+ @path <=> other.to_str
45
54
  end
46
55
  end
47
56
  end
@@ -72,7 +72,7 @@ module Async
72
72
  end
73
73
 
74
74
  def to_s
75
- "\#<#{self.class} resources=#{resources.count} limit=#{@limit}>"
75
+ "\#<#{self.class} resources=#{resources.size} limit=#{@limit}>"
76
76
  end
77
77
 
78
78
  protected
@@ -1,5 +1,4 @@
1
1
  # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- # Copyright, 2018, by Huba Nagy.
3
2
  #
4
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -19,27 +18,16 @@
19
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
19
  # THE SOFTWARE.
21
20
 
22
- require_relative 'nested'
21
+ require 'protocol/redis'
23
22
 
24
23
  module Async
25
24
  module Redis
26
- module Context
27
- class Multi < Nested
28
- def initialize(pool, *args)
29
- super(pool)
30
-
31
- @connection.write_request(['MULTI'])
32
- @connection.read_response
33
- end
34
-
35
- def execute
36
- return call 'EXEC'
37
- end
38
-
39
- def discard
40
- return call 'DISCARD'
25
+ module Protocol
26
+ module RESP2
27
+ def self.client(stream)
28
+ ::Protocol::Redis::Connection.new(stream)
41
29
  end
42
30
  end
43
31
  end
44
- end
32
+ end
45
33
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module Redis
23
- VERSION = "0.3.4"
23
+ VERSION = "0.4.0"
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-05-05 00:00:00.000000000 Z
12
+ date: 2019-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: async
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
41
  version: '1.10'
42
+ - !ruby/object:Gem::Dependency
43
+ name: protocol-redis
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 0.2.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 0.2.0
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: async-rspec
44
58
  requirement: !ruby/object:Gem::Requirement
@@ -169,15 +183,13 @@ files:
169
183
  - async-redis.gemspec
170
184
  - lib/async/redis.rb
171
185
  - lib/async/redis/client.rb
172
- - lib/async/redis/context/multi.rb
173
- - lib/async/redis/context/nested.rb
186
+ - lib/async/redis/context/generic.rb
187
+ - lib/async/redis/context/pipeline.rb
174
188
  - lib/async/redis/context/subscribe.rb
175
- - lib/async/redis/methods/keys.rb
176
- - lib/async/redis/methods/lists.rb
177
- - lib/async/redis/methods/server.rb
178
- - lib/async/redis/methods/strings.rb
189
+ - lib/async/redis/context/transaction.rb
190
+ - lib/async/redis/key.rb
179
191
  - lib/async/redis/pool.rb
180
- - lib/async/redis/protocol/resp.rb
192
+ - lib/async/redis/protocol/resp2.rb
181
193
  - lib/async/redis/version.rb
182
194
  homepage: https://github.com/socketry/async-redis
183
195
  licenses: []
@@ -1,140 +0,0 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- # Copyright, 2018, by Huba Nagy.
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy
5
- # of this software and associated documentation files (the "Software"), to deal
6
- # in the Software without restriction, including without limitation the rights
7
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- # copies of the Software, and to permit persons to whom the Software is
9
- # furnished to do so, subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in
12
- # all copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- # THE SOFTWARE.
21
-
22
- require 'date'
23
-
24
- module Async
25
- module Redis
26
- module Methods
27
- module Keys
28
- def del(key, *keys)
29
- return call('DEL', key, *keys)
30
- end
31
-
32
- def dump(key)
33
- return call('DUMP', key)
34
- end
35
-
36
- def exists(key, *keys)
37
- return call('EXISTS', key, *keys)
38
- end
39
-
40
- def expire(key, seconds)
41
- return call('EXPIRE', key, seconds)
42
- end
43
-
44
- def expireat(key, time)
45
- case time
46
- when DateTime, Time, Date
47
- timestamp = time.strftime('%s').to_i
48
- else
49
- timestamp = time
50
- end
51
-
52
- return call('EXPIREAT', key, timestamp)
53
- end
54
-
55
- def keys(pattern)
56
- return call('KEYS', pattern)
57
- end
58
-
59
- def migrate
60
-
61
- end
62
-
63
- def move(key, db)
64
- return call('MOVE', key, db)
65
- end
66
-
67
- def object
68
-
69
- end
70
-
71
- def persist(key)
72
- return call('PERSIST', key)
73
- end
74
-
75
- def pexpire(key, milliseconds)
76
- return call('PEXPIRE', milliseconds)
77
- end
78
-
79
- def pexpireat(key, time)
80
- case time.class
81
- when DateTime, Time, Date
82
- timestamp = time.strftime('%Q').to_i
83
- else
84
- timestamp = time
85
- end
86
-
87
- return call('PEXPIREAT', key, timestamp)
88
- end
89
-
90
- def pttl(key)
91
- return call('PTTL', key)
92
- end
93
-
94
- def randomkey
95
- return call('RANDOMKEY')
96
- end
97
-
98
- def rename(key, new_key)
99
- return call('RENAME', key, new_key)
100
- end
101
-
102
- def renamenx(key, new_key)
103
- return call('RENAMENX', key, new_key)
104
- end
105
-
106
- def restore(key, serialized_value, ttl=0)
107
- return call('RESTORE', key, ttl, serialized_value)
108
- end
109
-
110
- def sort
111
-
112
- end
113
-
114
- def touch(key, *keys)
115
- return call('TOUCH', key, *keys)
116
- end
117
-
118
- def ttl(key)
119
- return call('TTL', key)
120
- end
121
-
122
- def type(key)
123
- return call('TYPE', key)
124
- end
125
-
126
- def unlink(key)
127
- return call('UNLINK', key)
128
- end
129
-
130
- def wait(newreplicas, timeout)
131
-
132
- end
133
-
134
- def scan
135
-
136
- end
137
- end
138
- end
139
- end
140
- end
@@ -1,118 +0,0 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- # Copyright, 2018, by Huba Nagy.
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy
5
- # of this software and associated documentation files (the "Software"), to deal
6
- # in the Software without restriction, including without limitation the rights
7
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- # copies of the Software, and to permit persons to whom the Software is
9
- # furnished to do so, subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in
12
- # all copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- # THE SOFTWARE.
21
-
22
- module Async
23
- module Redis
24
- module Methods
25
- module Lists
26
- def blpop(*keys, timeout: 0)
27
- return call('BLPOP', *keys, timeout)
28
- end
29
-
30
- def brpop(*keys, timeout: 0)
31
- return call('BRPOP', *keys, timeout)
32
- end
33
-
34
- def brpoplpush(source, destination, timeout)
35
- return call('BRPOPLPUSH', source, destination, timeout)
36
- end
37
-
38
- def lindex(key, index)
39
- return call('LINDEX', key, index)
40
- end
41
-
42
- def linsert(key, position=:before, index, value)
43
- if position == :before
44
- offset = 'BEFORE'
45
- else
46
- offset = 'AFTER'
47
- end
48
-
49
- return call('LINSERT', key, offset, index, value)
50
- end
51
-
52
- def llen(key)
53
- return call('LLEN', key)
54
- end
55
-
56
- def lpop(key)
57
- return call('LPOP', key)
58
- end
59
-
60
- def lpush(key, value, *values)
61
- case value
62
- when Array
63
- values = value
64
- else
65
- values = [value] + values
66
- end
67
-
68
- return call('LPUSH', key, *values)
69
- end
70
-
71
- def lpushx(key, value)
72
- return call('LPUSHX', key, value)
73
- end
74
-
75
- def lrange(key, start, stop)
76
- return call('LRANGE', key, start, stop)
77
- end
78
-
79
- def lrem(key, count, value)
80
- return call('LREM', key, count)
81
- end
82
-
83
- def lset(key, index, values)
84
- return call('LSET', key, index, values)
85
- end
86
-
87
- def ltrim(key, start, stop)
88
- return call('LTRIM', key, start, stop)
89
- end
90
-
91
- def rpop(key)
92
- return call('RPOP', key)
93
- end
94
-
95
- def rpoplpush(source, destination=nil)
96
- destination = source if destination.nil?
97
-
98
- return call('RPOPLPUSH', source, destination)
99
- end
100
-
101
- def rpush(key, value, *values)
102
- case value
103
- when Array
104
- values = value
105
- else
106
- values = [value] + values
107
- end
108
-
109
- return call('RPUSH', key, *values)
110
- end
111
-
112
- def rpushx(key, value)
113
- return call('RPUSHX', key, value)
114
- end
115
- end
116
- end
117
- end
118
- end
@@ -1,132 +0,0 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- # Copyright, 2018, by Huba Nagy.
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy
5
- # of this software and associated documentation files (the "Software"), to deal
6
- # in the Software without restriction, including without limitation the rights
7
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- # copies of the Software, and to permit persons to whom the Software is
9
- # furnished to do so, subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in
12
- # all copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- # THE SOFTWARE.
21
-
22
- module Async
23
- module Redis
24
- module Methods
25
- module Strings
26
- def append(key, value)
27
- return call('APPEND', key, value)
28
- end
29
-
30
- def bitcount(key, *range)
31
- return call('BITCOUNT', key, *range)
32
- end
33
-
34
- def decr(key)
35
- return call('DECR', key)
36
- end
37
-
38
- def decrby(key, decrement)
39
- return call('DECRBY', key, decrement)
40
- end
41
-
42
- def get(key)
43
- return call('GET', key)
44
- end
45
-
46
- def getbit(key, offset)
47
- return call('GETBIT', key, offset)
48
- end
49
-
50
- def getrange(key, start_index, end_index)
51
- return call('GETRANGE', key, start_index, end_index)
52
- end
53
-
54
- def getset(key, value)
55
- return call('GETSET', key, value)
56
- end
57
-
58
- def incr(key)
59
- return call('INCR', key)
60
- end
61
-
62
- def incrby(key, increment)
63
- return call('INCRBY', key, increment)
64
- end
65
-
66
- def incrbyfloat(key, increment)
67
- return call('INCRBYFLOAT', key, increment)
68
- end
69
-
70
- def mget(key, *keys)
71
- return call('MGET', key, *keys)
72
- end
73
-
74
- def mset(pairs)
75
- flattened_pairs = pairs.keys.zip(pairs.values).flatten
76
- return call('MSET', *flattened_pairs)
77
- end
78
-
79
- def msetnx(pairs)
80
- flattened_pairs = pairs.keys.zip(pairs.values).flatten
81
- return call('MSETNX', *flattened_pairs)
82
- end
83
-
84
- def psetex(key, milliseconds, value)
85
- return set key, value, milliseconds: milliseconds
86
- end
87
-
88
- def set(key, value, **options)
89
- arguments = []
90
-
91
- if options.has_key? :seconds
92
- arguments << 'EX'
93
- arguments << options[:seconds]
94
- end
95
-
96
- if options.has_key? :milliseconds
97
- arguments << 'PX'
98
- arguments << options[:milliseconds]
99
- end
100
-
101
- if options[:condition] == :nx
102
- arguments << 'NX'
103
- elsif options[:condition] == :xx
104
- arguments << 'XX'
105
- end
106
-
107
- return call('SET', key, value, *arguments)
108
- end
109
-
110
- def setbit(key, offset, value)
111
- return call('SETBIT', key, offset, value)
112
- end
113
-
114
- def setex(key, seconds, value)
115
- return set key, value, seconds: seconds
116
- end
117
-
118
- def setnx(key, value)
119
- return set key, value, condition: :nx
120
- end
121
-
122
- def setrange(key, offset, value)
123
- return call('SETRANGE', key, offset, value)
124
- end
125
-
126
- def strlen(key)
127
- return call('STRLEN', key)
128
- end
129
- end
130
- end
131
- end
132
- end
@@ -1,143 +0,0 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'async/io/protocol/line'
22
-
23
- module Async
24
- module Redis
25
- class ServerError < StandardError
26
- end
27
-
28
- module Protocol
29
- CRLF = "\r\n".freeze
30
-
31
- class RESP < Async::IO::Protocol::Line
32
- class << self
33
- alias client new
34
- end
35
-
36
- def initialize(stream)
37
- super(stream, CRLF)
38
- end
39
-
40
- def closed?
41
- @stream.closed?
42
- end
43
-
44
- # The redis server doesn't want actual objects (e.g. integers) but only bulk strings. So, we inline it for performance.
45
- def write_request(arguments)
46
- write_lines("*#{arguments.count}")
47
-
48
- arguments.each do |argument|
49
- string = argument.to_s
50
-
51
- write_lines("$#{string.bytesize}", string)
52
- end
53
-
54
- @stream.flush
55
- end
56
-
57
- def write_object(object)
58
- case object
59
- when String
60
- write_lines("$#{object.bytesize}", object)
61
- when Array
62
- write_array(object)
63
- when Integer
64
- write_lines(":#{object}")
65
- else
66
- write_object(object.to_redis)
67
- end
68
- end
69
-
70
- def read_data(length)
71
- buffer = @stream.read(length) or @stream.eof!
72
-
73
- # Eat trailing whitespace because length does not include the CRLF:
74
- @stream.read(2) or @stream.eof!
75
-
76
- return buffer
77
- end
78
-
79
- def read_object
80
- line = read_line
81
- token = line.slice!(0, 1)
82
-
83
- case token
84
- when '$'
85
- length = line.to_i
86
-
87
- if length == -1
88
- return nil
89
- else
90
- return read_data(length)
91
- end
92
- when '*'
93
- count = line.to_i
94
-
95
- # Null array (https://redis.io/topics/protocol#resp-arrays):
96
- return nil if count == -1
97
-
98
- array = Array.new(count) {read_object}
99
-
100
- return array
101
- when ':'
102
- return line.to_i
103
-
104
- when '-'
105
- raise ServerError.new(line)
106
-
107
- when '+'
108
- return line
109
-
110
- else
111
- @stream.flush
112
-
113
- raise NotImplementedError, "Implementation for token #{token} missing"
114
- end
115
-
116
- # TODO: If an exception (e.g. Async::TimeoutError) propagates out of this function, perhaps @stream should be closed? Otherwise it might be in a weird state.
117
- end
118
-
119
- alias read_response read_object
120
-
121
- private
122
-
123
- # Override Async::IO::Protocol::Line#write_line
124
- # The original method performs a flush. This one does not and moves the
125
- # responsibility of flushing to the caller of the method.
126
- # In the case of Redis, we do not want to perform a flush in every line,
127
- # because each Redis command contains several lines. Flushing once per
128
- # command is more efficient because it avoids unnecessary writes to the
129
- # socket.
130
- def write_lines(*args)
131
- if args.empty?
132
- @stream.write(@eol)
133
- else
134
- args.each do |arg|
135
- @stream.write(arg)
136
- @stream.write(@eol)
137
- end
138
- end
139
- end
140
- end
141
- end
142
- end
143
- end