redis-objects 1.5.1 → 2.0.0.alpha
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 +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +9 -4
- data/CHANGELOG.rdoc +8 -0
- data/README.md +56 -5
- data/lib/redis/hash_key.rb +8 -16
- data/lib/redis/helpers/core_commands.rb +4 -0
- data/lib/redis/objects/locks.rb +1 -1
- data/lib/redis/objects/version.rb +1 -1
- data/lib/redis/objects.rb +83 -6
- data/redis-objects.gemspec +5 -1
- data/spec/redis_autoload_objects_spec.rb +1 -1
- data/spec/redis_legacy_key_naming_spec.rb +419 -0
- data/spec/redis_objects_conn_spec.rb +18 -27
- data/spec/redis_objects_custom_serializer.rb +1 -0
- data/spec/redis_objects_instance_spec.rb +113 -29
- data/spec/redis_objects_model_spec.rb +59 -2
- data/spec/spec_helper.rb +15 -2
- metadata +39 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 22b6b39234249ccd4c9485061bb918a211c539b3612d1a916a56eab0e13e031f
|
|
4
|
+
data.tar.gz: 9465be0b72fb8d160421eae75cf5cc5996a2aaa6b507bac6492f6a0b66fad788
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff4f516b5618e2a010c32ee0360dbfdbc172d400d3570cae3e5078aff845188171f3900849bdbb9c9c8cc869cc419d1995c9162b79e09a2a7d750d05b0591987
|
|
7
|
+
data.tar.gz: 75677a0da407ad97925c69ea51a55d51d4fc3b7a036768e4c5cb2457adbeefdeb924160d3ec8656949b4d2369785c8de4a272a4284ccc12f379eb89b3a7496b3
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.rdoc
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
= Changelog for Redis::Objects
|
|
2
2
|
|
|
3
|
+
== 1.7.0 (29 Apr 2022)
|
|
4
|
+
|
|
5
|
+
* Bumped version to 1.7.0 to revert redis-rb version lock [Nate Wiger]
|
|
6
|
+
|
|
7
|
+
== 1.6.0 (29 Apr 2022)
|
|
8
|
+
|
|
9
|
+
* Upgrade version to 1.6.0 due to redis-rb changes to Redis.current [Nate Wiger]
|
|
10
|
+
|
|
3
11
|
== 1.5.1 (10 Jul 2021)
|
|
4
12
|
|
|
5
13
|
* Added double-splat for **options to account for Ruby 3.0 [Nate Wiger]
|
data/README.md
CHANGED
|
@@ -1,9 +1,60 @@
|
|
|
1
1
|
Redis::Objects - Map Redis types directly to Ruby objects
|
|
2
2
|
=========================================================
|
|
3
3
|
|
|
4
|
-
[](https://travis-ci.com/github/nateware/redis-objects)
|
|
5
|
+
[](https://codecov.io/gh/nateware/redis-objects)
|
|
5
6
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MJF7JU5M7F8VL)
|
|
6
7
|
|
|
8
|
+
Important 2.0 changes
|
|
9
|
+
---------------------
|
|
10
|
+
Redis::Objects 2.0 introduces several important backwards incompatible changes.
|
|
11
|
+
Currently 2.0 can be installed with `gem install redis-objects --pre` or by listing it
|
|
12
|
+
explicitly in your Gemfile:
|
|
13
|
+
~~~ruby
|
|
14
|
+
# Gemfile
|
|
15
|
+
gem 'redis-objects', '>= 2.0.0.alpha'
|
|
16
|
+
~~~
|
|
17
|
+
You're encouraged to try it out in test code (not production) to ensure it works for you.
|
|
18
|
+
Official release is expected later in 2022.
|
|
19
|
+
|
|
20
|
+
Key Naming Changes
|
|
21
|
+
==================
|
|
22
|
+
The internal key naming scheme has changed for `Nested::Class::Namespaces` to fix a longstanding bug.
|
|
23
|
+
**This means your existing data in Redis will not be accessible until you call `migrate_redis_legacy_keys`.**
|
|
24
|
+
|
|
25
|
+
To fix this (only needed once), create a script like this:
|
|
26
|
+
|
|
27
|
+
~~~ruby
|
|
28
|
+
class YouClassNameHere < ActiveRecord::Base
|
|
29
|
+
include Redis::Objects
|
|
30
|
+
# ... your relevant definitions here ...
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
YourClassName.migrate_redis_legacy_keys
|
|
34
|
+
~~~
|
|
35
|
+
|
|
36
|
+
Then, you need to find a time when you can temporarily pause writes to your redis server
|
|
37
|
+
so that you can run that script. It uses `redis.scan` internally so it should be able to
|
|
38
|
+
handle a high number of keys. For large data sets, it could take a while.
|
|
39
|
+
|
|
40
|
+
For more details on the issue and fix refer to [#213](https://github.com/nateware/redis-objects/issues/231).
|
|
41
|
+
|
|
42
|
+
Rename of `lock` Method
|
|
43
|
+
=======================
|
|
44
|
+
The `lock` method that collided with `ActiveRecord::Base` has been renamed `redis_lock`.
|
|
45
|
+
This means your classes need to be updated to call `redis_lock` instead:
|
|
46
|
+
|
|
47
|
+
~~~ruby
|
|
48
|
+
class YouClassNameHere < ActiveRecord::Base
|
|
49
|
+
include Redis::Objects
|
|
50
|
+
redis_lock :mylock # formerly just "lock"
|
|
51
|
+
end
|
|
52
|
+
~~~
|
|
53
|
+
|
|
54
|
+
For more details on the issue and fix refer to [#213](https://github.com/nateware/redis-objects/issues/231).
|
|
55
|
+
|
|
56
|
+
Overview
|
|
57
|
+
--------
|
|
7
58
|
This is **not** an ORM. People that are wrapping ORM’s around Redis are missing the point.
|
|
8
59
|
|
|
9
60
|
The killer feature of Redis is that it allows you to perform _atomic_ operations
|
|
@@ -118,7 +169,7 @@ Here's an example that integrates several data types with an ActiveRecord model:
|
|
|
118
169
|
class Team < ActiveRecord::Base
|
|
119
170
|
include Redis::Objects
|
|
120
171
|
|
|
121
|
-
|
|
172
|
+
redis_lock :trade_players, :expiration => 15 # sec
|
|
122
173
|
value :at_bat
|
|
123
174
|
counter :hits
|
|
124
175
|
counter :runs
|
|
@@ -523,7 +574,7 @@ Locks work similarly. On completion or exception the lock is released:
|
|
|
523
574
|
|
|
524
575
|
~~~ruby
|
|
525
576
|
class Team < ActiveRecord::Base
|
|
526
|
-
|
|
577
|
+
redis_lock :reorder # declare a lock
|
|
527
578
|
end
|
|
528
579
|
|
|
529
580
|
@team.reorder_lock.lock do
|
|
@@ -547,7 +598,7 @@ lock time.
|
|
|
547
598
|
|
|
548
599
|
~~~ruby
|
|
549
600
|
class Team < ActiveRecord::Base
|
|
550
|
-
|
|
601
|
+
redis_lock :reorder, :expiration => 15.minutes
|
|
551
602
|
end
|
|
552
603
|
~~~
|
|
553
604
|
|
|
@@ -595,5 +646,5 @@ end
|
|
|
595
646
|
|
|
596
647
|
Author
|
|
597
648
|
=======
|
|
598
|
-
Copyright (c) 2009-
|
|
649
|
+
Copyright (c) 2009-2022 [Nate Wiger](http://nateware.com). All Rights Reserved.
|
|
599
650
|
Released under the [Artistic License](http://www.opensource.org/licenses/artistic-license-2.0.php).
|
data/lib/redis/hash_key.rb
CHANGED
|
@@ -123,24 +123,20 @@ class Redis
|
|
|
123
123
|
hsh
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
-
# Get values in bulk, takes an array of
|
|
126
|
+
# Get values in bulk, takes an array of fields as arguments.
|
|
127
127
|
# Values are returned in a collection in the same order than their keys in *keys Redis: HMGET
|
|
128
|
-
def bulk_values(*
|
|
129
|
-
|
|
130
|
-
return [] if
|
|
131
|
-
res = redis.hmget(key,
|
|
132
|
-
|
|
128
|
+
def bulk_values(*fields)
|
|
129
|
+
get_fields = *fields.flatten
|
|
130
|
+
return [] if get_fields.empty?
|
|
131
|
+
res = redis.hmget(key, get_fields)
|
|
132
|
+
get_fields.collect{|k| unmarshal(res.shift, options[:marshal_keys][k])}
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
# Increment value by integer at field. Redis: HINCRBY
|
|
136
136
|
def incrby(field, by=1)
|
|
137
137
|
allow_expiration do
|
|
138
138
|
ret = redis.hincrby(key, field, by)
|
|
139
|
-
|
|
140
|
-
ret.to_i
|
|
141
|
-
else
|
|
142
|
-
nil
|
|
143
|
-
end
|
|
139
|
+
ret.to_i
|
|
144
140
|
end
|
|
145
141
|
end
|
|
146
142
|
alias_method :incr, :incrby
|
|
@@ -155,11 +151,7 @@ class Redis
|
|
|
155
151
|
def incrbyfloat(field, by=1.0)
|
|
156
152
|
allow_expiration do
|
|
157
153
|
ret = redis.hincrbyfloat(key, field, by)
|
|
158
|
-
|
|
159
|
-
ret.to_f
|
|
160
|
-
else
|
|
161
|
-
nil
|
|
162
|
-
end
|
|
154
|
+
ret.to_f
|
|
163
155
|
end
|
|
164
156
|
end
|
|
165
157
|
|
data/lib/redis/objects/locks.rb
CHANGED
|
@@ -14,7 +14,7 @@ class Redis
|
|
|
14
14
|
module ClassMethods
|
|
15
15
|
# Define a new lock. It will function like a model attribute,
|
|
16
16
|
# so it can be used alongside ActiveRecord/DataMapper, etc.
|
|
17
|
-
def
|
|
17
|
+
def redis_lock(name, options={})
|
|
18
18
|
options[:timeout] ||= 5 # seconds
|
|
19
19
|
lock_name = "#{name}_lock"
|
|
20
20
|
redis_objects[lock_name.to_sym] = options.merge(:type => :lock)
|
data/lib/redis/objects.rb
CHANGED
|
@@ -101,16 +101,93 @@ class Redis
|
|
|
101
101
|
@redis_objects ||= {}
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
-
#
|
|
105
|
-
|
|
104
|
+
# Toggles whether to use the legacy redis key naming scheme, which causes
|
|
105
|
+
# naming conflicts in certain cases.
|
|
106
|
+
attr_accessor :redis_legacy_naming
|
|
107
|
+
attr_accessor :redis_silence_warnings
|
|
108
|
+
|
|
109
|
+
# Set the Redis redis_prefix to use. Defaults to class_name.
|
|
110
|
+
def redis_prefix=(redis_prefix)
|
|
111
|
+
@silence_warnings_as_redis_prefix_was_set_manually = true
|
|
112
|
+
@redis_prefix = redis_prefix
|
|
113
|
+
end
|
|
114
|
+
|
|
106
115
|
def redis_prefix(klass = self) #:nodoc:
|
|
107
|
-
@redis_prefix ||=
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
116
|
+
@redis_prefix ||=
|
|
117
|
+
if redis_legacy_naming
|
|
118
|
+
redis_legacy_prefix(klass)
|
|
119
|
+
else
|
|
120
|
+
redis_legacy_naming_warning_message(klass)
|
|
121
|
+
redis_modern_prefix(klass)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
@redis_prefix
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def redis_modern_prefix(klass = self) #:nodoc:
|
|
128
|
+
klass.name.to_s.
|
|
129
|
+
gsub(/::/, '__'). # Nested::Class => Nested__Class
|
|
130
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). # ClassName => Class_Name
|
|
131
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2'). # className => class_Name
|
|
132
|
+
downcase
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def redis_legacy_prefix(klass = self) #:nodoc:
|
|
136
|
+
klass.name.to_s.
|
|
137
|
+
sub(%r{(.*::)}, ''). # Nested::Class => Class (problematic)
|
|
138
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). # ClassName => Class_Name
|
|
139
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2'). # className => class_Name
|
|
111
140
|
downcase
|
|
112
141
|
end
|
|
113
142
|
|
|
143
|
+
# Temporary warning to help with migrating key names
|
|
144
|
+
def redis_legacy_naming_warning_message(klass)
|
|
145
|
+
# warn @silence_warnings_as_redis_prefix_was_set_manually.inspect
|
|
146
|
+
unless redis_legacy_naming || redis_silence_warnings || @silence_warnings_as_redis_prefix_was_set_manually
|
|
147
|
+
modern = redis_modern_prefix(klass)
|
|
148
|
+
legacy = redis_legacy_prefix(klass)
|
|
149
|
+
if modern != legacy
|
|
150
|
+
warn <<EOW
|
|
151
|
+
WARNING: In redis-objects 2.0.0, key naming will change to fix longstanding bugs.
|
|
152
|
+
Your class #{klass.name.to_s} will be affected by this change!
|
|
153
|
+
Current key prefix: #{legacy.inspect}
|
|
154
|
+
Future key prefix: #{modern.inspect}
|
|
155
|
+
Read more at https://github.com/nateware/redis-objects/issues/231
|
|
156
|
+
EOW
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def migrate_redis_legacy_keys
|
|
162
|
+
cursor = 0
|
|
163
|
+
legacy = redis_legacy_prefix
|
|
164
|
+
total_keys = 0
|
|
165
|
+
if legacy == redis_prefix
|
|
166
|
+
raise "Failed to migrate keys for #{self.name.to_s} as legacy and new redis_prefix are the same (#{redis_prefix})"
|
|
167
|
+
end
|
|
168
|
+
warn "Migrating keys from #{legacy} prefix to #{redis_prefix}"
|
|
169
|
+
|
|
170
|
+
loop do
|
|
171
|
+
cursor, keys = redis.scan(cursor, :match => "#{legacy}:*")
|
|
172
|
+
total_keys += keys.length
|
|
173
|
+
keys.each do |key|
|
|
174
|
+
# Split key name apart on ':'
|
|
175
|
+
base_class, id, name = key.split(':')
|
|
176
|
+
|
|
177
|
+
# Figure out the new name
|
|
178
|
+
new_key = redis_field_key(name, id=id, context=self)
|
|
179
|
+
|
|
180
|
+
# Rename the key
|
|
181
|
+
warn "Rename '#{key}', '#{new_key}'"
|
|
182
|
+
ok = redis.rename(key, new_key)
|
|
183
|
+
warn "Warning: Rename '#{key}', '#{new_key}' failed: #{ok}" if ok != 'OK'
|
|
184
|
+
end
|
|
185
|
+
break if cursor == "0"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
warn "Migrated #{total_keys} total number of redis keys"
|
|
189
|
+
end
|
|
190
|
+
|
|
114
191
|
def redis_options(name)
|
|
115
192
|
klass = first_ancestor_with(name)
|
|
116
193
|
return klass.redis_objects[name.to_sym] || {}
|
data/redis-objects.gemspec
CHANGED
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
20
|
|
|
21
21
|
# Only fix this one version or else tests break
|
|
22
|
-
spec.add_dependency "redis"
|
|
22
|
+
spec.add_dependency "redis"
|
|
23
23
|
|
|
24
24
|
# Ignore gemspec warnings on these. Trying to fix them to versions breaks TravisCI
|
|
25
25
|
spec.add_development_dependency "bundler"
|
|
@@ -29,6 +29,10 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
|
|
30
30
|
# Compatibility testing
|
|
31
31
|
spec.add_development_dependency "redis-namespace"
|
|
32
|
+
spec.add_development_dependency "activesupport"
|
|
32
33
|
spec.add_development_dependency "activerecord"
|
|
33
34
|
spec.add_development_dependency "sqlite3"
|
|
35
|
+
|
|
36
|
+
# Code coverage
|
|
37
|
+
spec.add_development_dependency "simplecov-cobertura"
|
|
34
38
|
end
|
|
@@ -4,7 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
|
4
4
|
# tests whether autoload functionality works correctly; had issues previously
|
|
5
5
|
|
|
6
6
|
require 'redis/objects'
|
|
7
|
-
|
|
7
|
+
Redis::Objects.redis = REDIS_HANDLE
|
|
8
8
|
|
|
9
9
|
describe 'Redis::Objects' do
|
|
10
10
|
it "should autoload everything" do
|