redis-objects-legacy 1.6.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,65 @@
1
+ require File.dirname(__FILE__) + '/base_object'
2
+ require 'zlib'
3
+
4
+ class Redis
5
+ #
6
+ # Class representing a simple value. You can use standard Ruby operations on it.
7
+ #
8
+ class Value < BaseObject
9
+ def value=(val)
10
+ allow_expiration do
11
+ if val.nil?
12
+ delete
13
+ else
14
+ redis.set key, marshal(val)
15
+ end
16
+ end
17
+ end
18
+ alias_method :set, :value=
19
+
20
+ def value
21
+ value = unmarshal(redis.get(key))
22
+ if value.nil? && !@options[:default].nil?
23
+ @options[:default]
24
+ else
25
+ value
26
+ end
27
+ end
28
+ alias_method :get, :value
29
+
30
+ def marshal(value, *args)
31
+ if !value.nil? && options[:compress]
32
+ compress(super)
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ def unmarshal(value, *args)
39
+ if !value.nil? && options[:compress]
40
+ super(decompress(value), *args)
41
+ else
42
+ super
43
+ end
44
+ end
45
+
46
+ def decompress(value)
47
+ Zlib::Inflate.inflate(value)
48
+ end
49
+
50
+ def compress(value)
51
+ Zlib::Deflate.deflate(value)
52
+ end
53
+
54
+ def inspect
55
+ "#<Redis::Value #{value.inspect}>"
56
+ end
57
+
58
+ def ==(other); value == other end
59
+ def nil?; value.nil? end
60
+
61
+ def method_missing(*args)
62
+ self.value.send *args
63
+ end
64
+ end
65
+ end
@@ -0,0 +1 @@
1
+ require 'redis/objects'
@@ -0,0 +1,46 @@
1
+
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ # tests whether autoload functionality works correctly; had issues previously
5
+
6
+ require 'redis/objects'
7
+ # $redis used automatically
8
+
9
+ describe 'Redis::Objects' do
10
+ it "should autoload everything" do
11
+ defined?(::Redis::Counter).should == "constant"
12
+ x = Redis::Counter.new('x')
13
+ x.class.name.should == "Redis::Counter"
14
+ x.redis.should == REDIS_HANDLE
15
+
16
+ defined?(::Redis::HashKey).should == "constant"
17
+ x = Redis::HashKey.new('x')
18
+ x.class.name.should == "Redis::HashKey"
19
+ x.redis.should == REDIS_HANDLE
20
+
21
+ defined?(::Redis::List).should == "constant"
22
+ x = Redis::List.new('x')
23
+ x.class.name.should == "Redis::List"
24
+ x.redis.should == REDIS_HANDLE
25
+
26
+ defined?(::Redis::Lock).should == "constant"
27
+ x = Redis::Lock.new('x')
28
+ x.class.name.should == "Redis::Lock"
29
+ x.redis.should == REDIS_HANDLE
30
+
31
+ defined?(::Redis::Set).should == "constant"
32
+ x = Redis::Set.new('x')
33
+ x.class.name.should == "Redis::Set"
34
+ x.redis.should == REDIS_HANDLE
35
+
36
+ defined?(::Redis::SortedSet).should == "constant"
37
+ x = Redis::SortedSet.new('x')
38
+ x.class.name.should == "Redis::SortedSet"
39
+ x.redis.should == REDIS_HANDLE
40
+
41
+ defined?(::Redis::Value).should == "constant"
42
+ x = Redis::Value.new('x')
43
+ x.class.name.should == "Redis::Value"
44
+ x.redis.should == REDIS_HANDLE
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require 'redis/objects'
4
+ Redis::Objects.redis = REDIS_HANDLE
5
+
6
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../redis-namespace/lib')
7
+ begin
8
+ require 'redis/namespace'
9
+
10
+ describe 'Redis::Namespace compat' do
11
+ it "tests the compatibility of Hash and ::Hash conflicts" do
12
+ ns = Redis::Namespace.new("resque", :redis => REDIS_HANDLE)
13
+ ns.instance_eval { rem_namespace({"resque:x" => nil}) }.should == {"x"=>nil}
14
+ class Foo
15
+ include Redis::Objects
16
+ end
17
+ ns.instance_eval { rem_namespace({"resque:x" => nil}) }.should == {"x"=>nil}
18
+ end
19
+ end
20
+
21
+ rescue LoadError
22
+ # Redis::Namespace not installed
23
+ puts "Skipping Redis::Namespace tests as redis-namespace is not installed"
24
+ end
@@ -0,0 +1,162 @@
1
+
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ require 'redis/objects'
5
+ # $redis used automatically
6
+
7
+ begin
8
+ require 'active_record'
9
+ ActiveRecord::Base.establish_connection(
10
+ :adapter => 'sqlite3',
11
+ :database => File.expand_path(File.dirname(__FILE__) + '/redis_objects_test.sqlite3')
12
+ )
13
+
14
+ # monkey patch to use migrations both in Rails 4.x and 5.x
15
+ class ActiveRecord::Migration
16
+ class << self
17
+ def [](version)
18
+ self
19
+ end
20
+ end
21
+ end unless ActiveRecord::Migration.respond_to?(:[])
22
+
23
+ class CreateBlogs < ActiveRecord::Migration[4.2]
24
+ def self.up
25
+ create_table :blogs do |t|
26
+ t.string :name
27
+ # t.integer :num_posts, :default => 0
28
+ t.timestamps null: true
29
+ end
30
+ end
31
+
32
+ def self.down
33
+ drop_table :blogs
34
+ end
35
+ end
36
+
37
+ class Blog < ActiveRecord::Base
38
+ include Redis::Objects
39
+ has_many :posts
40
+ counter :num_posts
41
+ end
42
+
43
+ class CreatePosts < ActiveRecord::Migration[4.2]
44
+ def self.up
45
+ create_table :posts do |t|
46
+ t.string :title
47
+ t.string :description, :length => 200
48
+ t.integer :total
49
+ t.integer :blog_id
50
+ t.timestamps null: true
51
+ end
52
+ end
53
+
54
+ def self.down
55
+ drop_table :posts
56
+ end
57
+ end
58
+
59
+ class Post < ActiveRecord::Base
60
+ include Redis::Objects
61
+ counter :total
62
+ counter :num_comments
63
+ # Unfortunately, counter counter_cache appears to be broken
64
+ # belongs_to :blog, :counter_cache => :num_posts
65
+ belongs_to :blog
66
+ has_many :comments
67
+ end
68
+
69
+ class CreateComments < ActiveRecord::Migration[4.2]
70
+ def self.up
71
+ create_table :comments do |t|
72
+ t.string :body
73
+ t.integer :post_id
74
+ t.timestamps null: true
75
+ end
76
+ end
77
+
78
+ def self.down
79
+ drop_table :comments
80
+ end
81
+ end
82
+
83
+ class Comment < ActiveRecord::Base
84
+ include Redis::Objects
85
+ belongs_to :post
86
+ # Unfortunately, counter counter_cache appears to be broken
87
+ # belongs_to :post, :counter_cache => :num_comments
88
+ end
89
+
90
+ describe ActiveRecord do
91
+ before do
92
+ CreateComments.up
93
+ CreatePosts.up
94
+ CreateBlogs.up
95
+ end
96
+ after do
97
+ CreateComments.down
98
+ CreatePosts.down
99
+ CreateBlogs.down
100
+ end
101
+
102
+ it "exercises ActiveRecord in more detail" do
103
+ @ar = Post.new
104
+ should.raise(Redis::Objects::NilObjectId){ @ar.total }
105
+ @ar.save!
106
+ @ar.destroy
107
+
108
+ # @ar.total.reset
109
+ @ar2 = Post.new
110
+ @ar2.save!
111
+ @ar2.total.reset
112
+ @ar2.total.increment.should == 1
113
+ @ar2.id.should == 2
114
+ @ar2.increment(:total).should == 2
115
+ @ar2[:total].should == nil # DB column
116
+ @ar2.redis.get(@ar2.redis_field_key('total')).to_i.should == 2
117
+ @ar2[:total] = 3 # DB column
118
+ @ar2.total.decrement.should == 1
119
+ @ar2.total.reset
120
+ @ar2.total.should == 0
121
+ @ar2.total.reset(55)
122
+ @ar2.total.should == 55
123
+ @ar2.total.getset(12).should == 55
124
+ @ar2.total.should == 12
125
+ @ar2.destroy
126
+ end
127
+
128
+ it "uses the redis objects counter cache when present" do
129
+ blog = Blog.create
130
+ post = Post.create :blog => blog
131
+ blog.num_posts.incr
132
+ blog.num_posts.should == 1
133
+ Post.counter_defined?(:num_comments).should == true
134
+ post.num_comments.should == 0
135
+
136
+ comment = Comment.create :post => post
137
+ post.num_comments.incr
138
+ post.comments.count.should == 1
139
+ post.id.should == 1
140
+ comment.destroy
141
+ blog.num_posts.delete
142
+ blog.destroy
143
+ end
144
+
145
+ it "falls back to ActiveRecord if redis counter is not defined" do
146
+ blog = Blog.create
147
+ blog.id.should == 1
148
+ blog.num_posts.should == 0
149
+ post = Post.create :blog => blog
150
+ blog.num_posts.incr
151
+ blog.num_posts.should == 1
152
+ blog2 = Blog.create
153
+ Post.create :blog => blog2
154
+ Post.create :blog => blog2
155
+ blog.reload.num_posts.should == 1
156
+ blog2.num_posts.incr
157
+ blog2.num_posts.incr
158
+ blog2.reload.num_posts.should == 2
159
+ blog.num_posts.should == 1
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,276 @@
1
+ #
2
+ # Connection tests - a bit ugly but important
3
+ #
4
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
5
+
6
+ require 'redis/objects'
7
+ require 'connection_pool'
8
+
9
+ BAD_REDIS = "totally bad bogus redis handle"
10
+
11
+ # Grab a global handle
12
+ describe 'Connection tests' do
13
+ it "should support overriding object handles with a vanilla redis connection" do
14
+ class CustomConnectionObject
15
+ include Redis::Objects
16
+
17
+ def id
18
+ return 1
19
+ end
20
+
21
+ redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 31)
22
+ value :redis_value, :redis => redis_handle, :key => 'rval'
23
+ value :default_redis_value, :key => 'rval'
24
+ end
25
+
26
+ obj = CustomConnectionObject.new
27
+
28
+ obj.default_redis_value.value.should == nil
29
+ obj.redis_value.value.should == nil
30
+
31
+ obj.default_redis_value.value = 'foo'
32
+ obj.default_redis_value.value.should == 'foo'
33
+ obj.redis_value.value.should == nil
34
+
35
+ obj.default_redis_value.clear
36
+ obj.redis_value.value = 'foo'
37
+ obj.redis_value.value.should == 'foo'
38
+ obj.default_redis_value.value.should == nil
39
+
40
+ obj.redis_value.clear
41
+ obj.default_redis_value.clear
42
+ end
43
+
44
+ it "should support mget" do
45
+ class CustomConnectionObject
46
+ include Redis::Objects
47
+
48
+ def id
49
+ return 1
50
+ end
51
+
52
+ redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 31)
53
+ value :redis_value, :key => 'rval'
54
+ end
55
+
56
+ obj = CustomConnectionObject.new
57
+
58
+ obj.redis_value.value = 'foo'
59
+
60
+ obj.class.mget(:redis_value, []).should == []
61
+ obj.class.mget(:redis_value, [obj]).should == ['foo']
62
+
63
+ obj.redis_value.clear
64
+ end
65
+
66
+ it "should support overriding object handles with a connection_pool" do
67
+ class CustomConnectionObject
68
+ include Redis::Objects
69
+
70
+ def id
71
+ return 1
72
+ end
73
+
74
+ redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 31) }
75
+ value :redis_value, :redis => redis_handle, :key => 'rval'
76
+ value :default_redis_value, :key => 'rval'
77
+ end
78
+
79
+ obj = CustomConnectionObject.new
80
+
81
+ obj.default_redis_value.value.should == nil
82
+ obj.redis_value.value.should == nil
83
+
84
+ obj.default_redis_value.value = 'foo'
85
+ obj.default_redis_value.value.should == 'foo'
86
+ obj.redis_value.value.should == nil
87
+
88
+ obj.default_redis_value.clear
89
+ obj.redis_value.value = 'foo'
90
+ obj.redis_value.value.should == 'foo'
91
+ obj.default_redis_value.value.should == nil
92
+
93
+ obj.redis_value.clear
94
+ obj.default_redis_value.clear
95
+ end
96
+
97
+ it "should support local handles with a vanilla redis connection" do
98
+ Redis.current = nil # reset from other tests
99
+ Redis::Objects.redis = nil
100
+ @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
101
+
102
+ # Redis.current is lazily auto-populated to touch 6379
103
+ # This why we choose the weird 9212 port to avoid
104
+ Redis.current.inspect.should == Redis.new.inspect
105
+ Redis::Objects.redis.inspect.should == Redis.new.inspect
106
+
107
+ v = Redis::Value.new('conn/value', @redis_handle)
108
+ v.clear
109
+ v.value = 'yay'
110
+ v.value.should == 'yay'
111
+
112
+ h = Redis::HashKey.new('conn/hash', @redis_handle)
113
+ h.clear
114
+ h['k'] = 'v'
115
+
116
+ l = Redis::List.new('conn/list', @redis_handle)
117
+ l.clear
118
+ l << 3
119
+ l << 4
120
+ l << 5
121
+
122
+ s = Redis::Set.new('conn/set', @redis_handle)
123
+ s.clear
124
+ s << 5
125
+ s << 5
126
+ s << 6
127
+ s << 7
128
+
129
+ z = Redis::SortedSet.new('conn/zset', @redis_handle)
130
+ z.clear
131
+ z['a'] = 8
132
+ z['b'] = 7
133
+ z['c'] = 9
134
+ z['d'] = 6
135
+
136
+ c = Redis::Counter.new('conn/counter', @redis_handle)
137
+ c.reset
138
+ c.incr(3)
139
+ c.decr(1)
140
+ end
141
+
142
+ it "should support local handles with a connection_pool" do
143
+ Redis.current = nil # reset from other tests
144
+ Redis::Objects.redis = nil
145
+ @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
146
+
147
+ # Redis.current is lazily auto-populated to touch 6379
148
+ # This why we choose the weird 9212 port to avoid
149
+ Redis.current.inspect.should == Redis.new.inspect
150
+ Redis::Objects.redis.inspect.should == Redis.new.inspect
151
+
152
+ v = Redis::Value.new('conn/value', @redis_handle)
153
+ v.clear
154
+ v.value = 'yay'
155
+ v.value.should == 'yay'
156
+
157
+ h = Redis::HashKey.new('conn/hash', @redis_handle)
158
+ h.clear
159
+ h['k'] = 'v'
160
+
161
+ l = Redis::List.new('conn/list', @redis_handle)
162
+ l.clear
163
+ l << 3
164
+ l << 4
165
+ l << 5
166
+
167
+ s = Redis::Set.new('conn/set', @redis_handle)
168
+ s.clear
169
+ s << 5
170
+ s << 5
171
+ s << 6
172
+ s << 7
173
+
174
+ z = Redis::SortedSet.new('conn/zset', @redis_handle)
175
+ z.clear
176
+ z['a'] = 8
177
+ z['b'] = 7
178
+ z['c'] = 9
179
+ z['d'] = 6
180
+
181
+ c = Redis::Counter.new('conn/counter', @redis_handle)
182
+ c.reset
183
+ c.incr(3)
184
+ c.decr(1)
185
+ end
186
+
187
+ it "should support Redis.current" do
188
+ Redis.current = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
189
+
190
+ Redis::Value.new('conn/value').should == 'yay'
191
+ Redis::HashKey.new('conn/hash').keys.should == ['k']
192
+ Redis::List.new('conn/list').sort.should == ['3', '4', '5']
193
+ Redis::Set.new('conn/set').sort.should == ['5', '6', '7']
194
+ Redis::SortedSet.new('conn/zset').should == ['d', 'b', 'a', 'c']
195
+ Redis::Counter.new('conn/counter').should == 2
196
+ end
197
+
198
+ it "should support Redis::Objects.redis= with a connection_pool" do
199
+ @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
200
+
201
+ # Redis.current is lazily auto-populated to touch 6379
202
+ # This why we choose the weird 9212 port to avoid
203
+ Redis.current = BAD_REDIS
204
+ Redis::Objects.redis.should == BAD_REDIS
205
+
206
+ # This set of tests sucks, it fucks up the per-data-type handles
207
+ # because Redis.current is then set to a BS value, and the lazy
208
+ # init code in redis-rb will keep that value until we clear it.
209
+ # This ends up fucking any sequential tests.
210
+ raises_exception{ Redis::Value.new('conn/value').should.be.nil }
211
+ raises_exception{ Redis::HashKey.new('conn/hash').keys.should == [] }
212
+ raises_exception{ Redis::List.new('conn/list').sort.should == [] }
213
+ raises_exception{ Redis::Set.new('conn/set').sort.should == [] }
214
+ raises_exception{ Redis::SortedSet.new('conn/zset').should == [] }
215
+ raises_exception{ Redis::Counter.new('conn/counter').get.should == 0 }
216
+
217
+ Redis::Objects.redis = @redis_handle
218
+ Redis::Value.new('fart').redis.is_a?(Redis::Objects::ConnectionPoolProxy).should == true
219
+
220
+ # These should now get the correct handle
221
+ Redis::Value.new('conn/value').should == 'yay'
222
+ Redis::HashKey.new('conn/hash').keys.should == ['k']
223
+ Redis::List.new('conn/list').sort.should == ['3', '4', '5']
224
+ Redis::Set.new('conn/set').sort.should == ['5', '6', '7']
225
+ Redis::SortedSet.new('conn/zset').should == ['d', 'b', 'a', 'c']
226
+ Redis::Counter.new('conn/counter').should == 2
227
+
228
+ end
229
+
230
+ it "should support Redis::Objects.redis= with a vanilla redis connection" do
231
+ # reset redis
232
+ Redis::Objects.redis = nil
233
+ @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
234
+
235
+ # Redis.current is lazily auto-populated to touch 6379
236
+ # This why we choose the weird 9212 port to avoid
237
+ Redis.current = BAD_REDIS
238
+ Redis::Objects.redis.should == BAD_REDIS
239
+
240
+ # This set of tests sucks, it fucks up the per-data-type handles
241
+ # because Redis.current is then set to a BS value, and the lazy
242
+ # init code in redis-rb will keep that value until we clear it.
243
+ # This ends up fucking any sequential tests.
244
+ raises_exception{ Redis::Value.new('conn/value').should.be.nil }
245
+ raises_exception{ Redis::HashKey.new('conn/hash').keys.should == [] }
246
+ raises_exception{ Redis::List.new('conn/list').sort.should == [] }
247
+ raises_exception{ Redis::Set.new('conn/set').sort.should == [] }
248
+ raises_exception{ Redis::SortedSet.new('conn/zset').should == [] }
249
+ raises_exception{ Redis::Counter.new('conn/counter').get.should == 0 }
250
+
251
+ Redis::Objects.redis = @redis_handle
252
+ Redis::Value.new('fart').redis.should == @redis_handle
253
+
254
+ # These should now get the correct handle
255
+ Redis::Value.new('conn/value').should == 'yay'
256
+ Redis::HashKey.new('conn/hash').keys.should == ['k']
257
+ Redis::List.new('conn/list').sort.should == ['3', '4', '5']
258
+ Redis::Set.new('conn/set').sort.should == ['5', '6', '7']
259
+ Redis::SortedSet.new('conn/zset').should == ['d', 'b', 'a', 'c']
260
+ Redis::Counter.new('conn/counter').should == 2
261
+
262
+ # Fix for future tests
263
+ Redis.current = @redis_handle
264
+ end
265
+
266
+ it "should support pipelined changes" do
267
+ list = Redis::List.new('pipelined/list')
268
+ key = Redis::HashKey.new('pipelined/hash')
269
+ Redis::Objects.redis.pipelined do
270
+ key['foo'] = 'bar'
271
+ list.push 1, 2
272
+ end
273
+ key.all.should == { 'foo' => 'bar' }
274
+ list.values.should == %w[1 2]
275
+ end
276
+ end