redis-objects 1.5.1 → 2.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.
|
4
|
+
[![Build Status](https://app.travis-ci.com/nateware/redis-objects.svg?branch=master)](https://travis-ci.com/github/nateware/redis-objects)
|
5
|
+
[![Code Coverage](https://codecov.io/gh/nateware/redis-objects/branch/master/graph/badge.svg)](https://codecov.io/gh/nateware/redis-objects)
|
5
6
|
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](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
|