familia 1.0.0.pre.rc3 → 1.0.0.pre.rc5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +198 -48
- data/VERSION.yml +1 -1
- data/lib/familia/base.rb +29 -1
- data/lib/familia/features/expiration.rb +91 -0
- data/lib/familia/features/quantization.rb +56 -0
- data/lib/familia/features/safe_dump.rb +2 -33
- data/lib/familia/features.rb +5 -4
- data/lib/familia/horreum/class_methods.rb +112 -46
- data/lib/familia/horreum/commands.rb +9 -3
- data/lib/familia/horreum/relations_management.rb +2 -2
- data/lib/familia/horreum/serialization.rb +150 -41
- data/lib/familia/horreum/settings.rb +0 -8
- data/lib/familia/horreum/utils.rb +0 -1
- data/lib/familia/horreum.rb +2 -2
- data/lib/familia/logging.rb +26 -4
- data/lib/familia/redistype/serialization.rb +60 -38
- data/lib/familia/redistype.rb +50 -17
- data/lib/familia/settings.rb +11 -1
- data/lib/familia/tools.rb +68 -0
- data/lib/familia/types/hashkey.rb +5 -5
- data/lib/familia/types/list.rb +2 -2
- data/lib/familia/types/sorted_set.rb +12 -12
- data/lib/familia/types/string.rb +1 -1
- data/lib/familia/types/unsorted_set.rb +2 -2
- data/lib/familia/utils.rb +106 -51
- data/lib/familia/version.rb +2 -2
- data/try/10_familia_try.rb +4 -4
- data/try/20_redis_type_try.rb +9 -6
- data/try/26_redis_bool_try.rb +1 -1
- data/try/27_redis_horreum_try.rb +1 -1
- data/try/30_familia_object_try.rb +3 -2
- data/try/40_customer_try.rb +3 -3
- data/try/test_helpers.rb +9 -2
- metadata +5 -5
- data/lib/familia/features/api_version.rb +0 -19
- data/lib/familia/features/atomic_saves.rb +0 -8
- data/lib/familia/features/quantizer.rb +0 -35
data/lib/familia/logging.rb
CHANGED
@@ -126,26 +126,48 @@ module Familia
|
|
126
126
|
#
|
127
127
|
# @param label [Symbol] A label for the trace message (e.g., :EXPAND,
|
128
128
|
# :FROMREDIS, :LOAD, :EXISTS).
|
129
|
-
# @param redis_instance [
|
129
|
+
# @param redis_instance [Redis, Redis::Future, nil] The Redis instance or
|
130
|
+
# Future being used.
|
130
131
|
# @param ident [String] An identifier or key related to the operation being
|
131
132
|
# traced.
|
132
133
|
# @param context [Array<String>, String, nil] The calling context, typically
|
133
134
|
# obtained from `caller` or `caller.first`. Default is nil.
|
134
135
|
#
|
135
136
|
# @example
|
136
|
-
# Familia.trace :LOAD, Familia.redis(uri), objkey, caller if
|
137
|
-
#
|
137
|
+
# Familia.trace :LOAD, Familia.redis(uri), objkey, caller(1..1) if
|
138
|
+
# Familia.debug?
|
138
139
|
#
|
139
140
|
# @return [nil]
|
140
141
|
#
|
142
|
+
# @note This method only executes if LoggerTraceRefinement::ENABLED is true.
|
143
|
+
# @note The redis_instance can be a Redis object, Redis::Future (used in
|
144
|
+
# pipelined and multi blocks), or nil (when the redis connection isn't
|
145
|
+
# relevant).
|
146
|
+
#
|
141
147
|
def trace(label, redis_instance, ident, context = nil)
|
142
148
|
return unless LoggerTraceRefinement::ENABLED
|
143
|
-
|
149
|
+
|
150
|
+
# Usually redis_instance is a Redis object, but it could be
|
151
|
+
# a Redis::Future which is what is used inside of pipelined
|
152
|
+
# and multi blocks. In some contexts it's nil where the
|
153
|
+
# redis connection isn't relevant.
|
154
|
+
instance_id = if redis_instance
|
155
|
+
case redis_instance
|
156
|
+
when Redis
|
157
|
+
redis_instance.id.respond_to?(:to_s) ? redis_instance.id.to_s : redis_instance.class.name
|
158
|
+
when Redis::Future
|
159
|
+
"Redis::Future"
|
160
|
+
else
|
161
|
+
redis_instance.class.name
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
144
165
|
codeline = if context
|
145
166
|
context = [context].flatten
|
146
167
|
context.reject! { |line| line =~ %r{lib/familia} }
|
147
168
|
context.first
|
148
169
|
end
|
170
|
+
|
149
171
|
@logger.trace format('[%s] %s -> %s <- at %s', label, instance_id, ident, codeline)
|
150
172
|
end
|
151
173
|
|
@@ -4,63 +4,80 @@ class Familia::RedisType
|
|
4
4
|
|
5
5
|
module Serialization
|
6
6
|
|
7
|
-
# Serializes
|
8
|
-
#
|
9
|
-
# This method prepares a value for storage in Redis by converting it to a string representation.
|
10
|
-
# If a class option is specified, it uses that class's serialization method.
|
11
|
-
# Otherwise, it relies on the value's own `to_s` method for serialization.
|
7
|
+
# Serializes a value for storage in Redis.
|
12
8
|
#
|
13
9
|
# @param val [Object] The value to be serialized.
|
14
|
-
# @param strict_values [Boolean] Whether to enforce strict value
|
15
|
-
#
|
10
|
+
# @param strict_values [Boolean] Whether to enforce strict value
|
11
|
+
# serialization (default: true).
|
12
|
+
# @return [String, nil] The serialized representation of the value, or nil
|
13
|
+
# if serialization fails.
|
16
14
|
#
|
17
|
-
# @note When
|
18
|
-
#
|
15
|
+
# @note When a class option is specified, it uses that class's
|
16
|
+
# serialization method. Otherwise, it relies on Familia.distinguisher for
|
17
|
+
# serialization.
|
19
18
|
#
|
20
19
|
# @example With a class option
|
21
|
-
# to_redis(User.new(name: "
|
22
|
-
# to_redis(nil, strict_values: false) #=> "" (empty string)
|
23
|
-
# to_redis(true, strict_values: false) #=> "true"
|
20
|
+
# to_redis(User.new(name: "Cloe"), strict_values: false) #=> '{"name":"Cloe"}'
|
24
21
|
#
|
25
|
-
# @example Without a class option
|
26
|
-
# to_redis(123) #=> "123"
|
22
|
+
# @example Without a class option
|
23
|
+
# to_redis(123) #=> "123"
|
27
24
|
# to_redis("hello") #=> "hello"
|
28
|
-
# to_redis(nil) # raises an exception
|
29
|
-
# to_redis(true) # raises an exception
|
30
25
|
#
|
31
|
-
# @raise [Familia::HighRiskFactor]
|
26
|
+
# @raise [Familia::HighRiskFactor] If serialization fails under strict
|
27
|
+
# mode.
|
32
28
|
#
|
33
29
|
def to_redis(val, strict_values = true)
|
34
|
-
|
30
|
+
prepared = nil
|
35
31
|
|
36
32
|
Familia.trace :TOREDIS, redis, "#{val}<#{val.class}|#{opts[:class]}>", caller(1..1) if Familia.debug?
|
37
33
|
|
38
34
|
if opts[:class]
|
39
|
-
|
40
|
-
Familia.ld " from opts[class] <#{opts[:class]}>: #{
|
35
|
+
prepared = Familia.distinguisher(opts[:class], strict_values)
|
36
|
+
Familia.ld " from opts[class] <#{opts[:class]}>: #{prepared||'<nil>'}"
|
41
37
|
end
|
42
38
|
|
43
|
-
if
|
39
|
+
if prepared.nil?
|
44
40
|
# Enforce strict values when no class option is specified
|
45
|
-
|
46
|
-
Familia.ld " from
|
41
|
+
prepared = Familia.distinguisher(val, true)
|
42
|
+
Familia.ld " from <#{val.class}> => <#{prepared.class}>"
|
47
43
|
end
|
48
44
|
|
49
|
-
Familia.trace :TOREDIS, redis, "#{val}<#{val.class}|#{opts[:class]}> => #{
|
45
|
+
Familia.trace :TOREDIS, redis, "#{val}<#{val.class}|#{opts[:class]}> => #{prepared}<#{prepared.class}>", caller(1..1) if Familia.debug?
|
50
46
|
|
51
|
-
Familia.warn "[#{self.class}\#to_redis] nil returned for #{opts[:class]}\##{name}" if
|
52
|
-
|
47
|
+
Familia.warn "[#{self.class}\#to_redis] nil returned for #{opts[:class]}\##{name}" if prepared.nil?
|
48
|
+
prepared
|
53
49
|
end
|
54
50
|
|
51
|
+
# Deserializes multiple values from Redis, removing nil values.
|
52
|
+
#
|
53
|
+
# @param values [Array<String>] The values to deserialize.
|
54
|
+
# @return [Array<Object>] Deserialized objects, with nil values removed.
|
55
|
+
#
|
56
|
+
# @see #multi_from_redis_with_nil
|
57
|
+
#
|
55
58
|
def multi_from_redis(*values)
|
56
|
-
# Avoid using compact! here. Using compact! as the last expression in the
|
57
|
-
# can unintentionally return nil if no changes are made, which is
|
58
|
-
# Instead, use compact to ensure the method returns the
|
59
|
+
# Avoid using compact! here. Using compact! as the last expression in the
|
60
|
+
# method can unintentionally return nil if no changes are made, which is
|
61
|
+
# not desirable. Instead, use compact to ensure the method returns the
|
62
|
+
# expected value.
|
59
63
|
multi_from_redis_with_nil(*values).compact
|
60
64
|
end
|
61
65
|
|
66
|
+
# Deserializes multiple values from Redis, preserving nil values.
|
67
|
+
#
|
68
|
+
# @param values [Array<String>] The values to deserialize.
|
69
|
+
# @return [Array<Object, nil>] Deserialized objects, including nil values.
|
70
|
+
#
|
71
|
+
# @raise [Familia::Problem] If the specified class doesn't respond to the
|
72
|
+
# load method.
|
73
|
+
#
|
74
|
+
# @note This method attempts to deserialize each value using the specified
|
75
|
+
# class's load method. If deserialization fails for a value, it's
|
76
|
+
# replaced with nil.
|
77
|
+
#
|
62
78
|
# NOTE: `multi` in this method name refers to multiple values from
|
63
79
|
# redis and not the Redis server MULTI command.
|
80
|
+
#
|
64
81
|
def multi_from_redis_with_nil(*values)
|
65
82
|
Familia.ld "multi_from_redis: (#{@opts}) #{values}"
|
66
83
|
return [] if values.empty?
|
@@ -89,6 +106,20 @@ class Familia::RedisType
|
|
89
106
|
values
|
90
107
|
end
|
91
108
|
|
109
|
+
# Deserializes a single value from Redis.
|
110
|
+
#
|
111
|
+
# @param val [String, nil] The value to deserialize.
|
112
|
+
# @return [Object, nil] The deserialized object, the default value if
|
113
|
+
# val is nil, or nil if deserialization fails.
|
114
|
+
#
|
115
|
+
# @note If no class option is specified, the original value is
|
116
|
+
# returned unchanged.
|
117
|
+
#
|
118
|
+
# NOTE: Currently only the RedisType class uses this method. Horreum
|
119
|
+
# fields are a newer addition and don't support the full range of
|
120
|
+
# deserialization options that RedisType supports. It uses to_redis
|
121
|
+
# for serialization since everything becomes a string in Redis.
|
122
|
+
#
|
92
123
|
def from_redis(val)
|
93
124
|
return @opts[:default] if val.nil?
|
94
125
|
return val unless @opts[:class]
|
@@ -96,15 +127,6 @@ class Familia::RedisType
|
|
96
127
|
ret = multi_from_redis val
|
97
128
|
ret&.first # return the object or nil
|
98
129
|
end
|
99
|
-
|
100
|
-
def update_expiration(ttl = nil)
|
101
|
-
ttl ||= opts[:ttl]
|
102
|
-
return if ttl.to_i.zero? # nil will be zero
|
103
|
-
|
104
|
-
Familia.ld "#{rediskey} to #{ttl}"
|
105
|
-
expire ttl.to_i
|
106
|
-
end
|
107
|
-
|
108
130
|
end
|
109
131
|
|
110
132
|
end
|
data/lib/familia/redistype.rb
CHANGED
@@ -13,31 +13,29 @@ module Familia
|
|
13
13
|
# @abstract Subclass and implement Redis data type specific methods
|
14
14
|
class RedisType
|
15
15
|
include Familia::Base
|
16
|
+
extend Familia::Features
|
16
17
|
|
17
18
|
@registered_types = {}
|
18
19
|
@valid_options = %i[class parent ttl default db key redis]
|
19
20
|
@db = nil
|
20
|
-
|
21
|
+
|
22
|
+
feature :expiration
|
23
|
+
feature :quantization
|
21
24
|
|
22
25
|
class << self
|
23
26
|
attr_reader :registered_types, :valid_options
|
24
27
|
attr_accessor :parent
|
25
|
-
attr_writer :
|
28
|
+
attr_writer :db, :uri
|
26
29
|
|
27
30
|
# To be called inside every class that inherits RedisType
|
28
31
|
# +methname+ is the term used for the class and instance methods
|
29
32
|
# that are created for the given +klass+ (e.g. set, list, etc)
|
30
33
|
def register(klass, methname)
|
31
|
-
Familia.ld "[#{self}] Registering #{klass} as #{methname}"
|
34
|
+
Familia.ld "[#{self}] Registering #{klass} as #{methname.inspect}"
|
32
35
|
|
33
36
|
@registered_types[methname] = klass
|
34
37
|
end
|
35
38
|
|
36
|
-
def ttl(val = nil)
|
37
|
-
@ttl = val unless val.nil?
|
38
|
-
@ttl || parent&.ttl
|
39
|
-
end
|
40
|
-
|
41
39
|
def db(val = nil)
|
42
40
|
@db = val unless val.nil?
|
43
41
|
@db || parent&.db
|
@@ -49,8 +47,9 @@ module Familia
|
|
49
47
|
end
|
50
48
|
|
51
49
|
def inherited(obj)
|
50
|
+
Familia.trace :REDISTYPE, nil, "#{obj} is my kinda type", caller(1..1) if Familia.debug?
|
52
51
|
obj.db = db
|
53
|
-
obj.ttl = ttl
|
52
|
+
obj.ttl = ttl # method added via Features::Expiration
|
54
53
|
obj.uri = uri
|
55
54
|
obj.parent = self
|
56
55
|
super(obj)
|
@@ -101,6 +100,17 @@ module Familia
|
|
101
100
|
@opts = opts || {}
|
102
101
|
@opts = RedisType.valid_keys_only(@opts)
|
103
102
|
|
103
|
+
# Apply the options to instance method setters of the same name
|
104
|
+
@opts.each do |k, v|
|
105
|
+
# Bewarde logging :parent instance here implicitly calls #to_s which for
|
106
|
+
# some classes could include the identifier which could still be nil at
|
107
|
+
# this point. This would result in a Familia::Problem being raised. So
|
108
|
+
# to be on the safe-side here until we have a better understanding of
|
109
|
+
# the issue, we'll just log the class name for each key-value pair.
|
110
|
+
Familia.ld " [setting] #{k} #{v.class}"
|
111
|
+
send(:"#{k}=", v) if respond_to? :"#{k}="
|
112
|
+
end
|
113
|
+
|
104
114
|
init if respond_to? :init
|
105
115
|
end
|
106
116
|
|
@@ -110,10 +120,37 @@ module Familia
|
|
110
120
|
parent? ? parent.redis : Familia.redis(opts[:db])
|
111
121
|
end
|
112
122
|
|
113
|
-
# Produces the full
|
123
|
+
# Produces the full Redis key for this object.
|
124
|
+
#
|
125
|
+
# @return [String] The full Redis key.
|
126
|
+
#
|
127
|
+
# This method determines the appropriate Redis key based on the context of the RedisType object:
|
128
|
+
#
|
129
|
+
# 1. If a hardcoded key is set in the options, it returns that key.
|
130
|
+
# 2. For instance-level RedisType objects, it uses the parent instance's rediskey method.
|
131
|
+
# 3. For class-level RedisType objects, it uses the parent class's rediskey method.
|
132
|
+
# 4. For standalone RedisType objects, it uses the keystring as the full Redis key.
|
133
|
+
#
|
134
|
+
# For class-level RedisType objects (parent_class? == true):
|
135
|
+
# - The suffix is optional and used to differentiate between different types of objects.
|
136
|
+
# - If no suffix is provided, the class's default suffix is used (via the self.suffix method).
|
137
|
+
# - If a nil suffix is explicitly passed, it won't appear in the resulting Redis key.
|
138
|
+
# - Passing nil as the suffix is how class-level RedisType objects are created without
|
139
|
+
# the global default 'object' suffix.
|
140
|
+
#
|
141
|
+
# @example Instance-level RedisType
|
142
|
+
# user_instance.some_redistype.rediskey # => "user:123:some_redistype"
|
143
|
+
#
|
144
|
+
# @example Class-level RedisType
|
145
|
+
# User.some_redistype.rediskey # => "user:some_redistype"
|
146
|
+
#
|
147
|
+
# @example Standalone RedisType
|
148
|
+
# RedisType.new("mykey").rediskey # => "mykey"
|
149
|
+
#
|
150
|
+
# @example Class-level RedisType with explicit nil suffix
|
151
|
+
# User.rediskey("123", nil) # => "user:123"
|
152
|
+
#
|
114
153
|
def rediskey
|
115
|
-
Familia.ld "[rediskey] #{keystring} for #{self.class} (#{opts})"
|
116
|
-
|
117
154
|
# Return the hardcoded key if it's set. This is useful for
|
118
155
|
# support legacy keys that aren't derived in the same way.
|
119
156
|
return opts[:key] if opts[:key]
|
@@ -128,7 +165,7 @@ module Familia
|
|
128
165
|
parent.rediskey(keystring, nil)
|
129
166
|
else
|
130
167
|
# This is a standalone RedisType object where it's keystring
|
131
|
-
# is the full key.
|
168
|
+
# is the full redis key.
|
132
169
|
keystring
|
133
170
|
end
|
134
171
|
end
|
@@ -153,10 +190,6 @@ module Familia
|
|
153
190
|
@opts[:parent]
|
154
191
|
end
|
155
192
|
|
156
|
-
def ttl
|
157
|
-
@opts[:ttl] || self.class.ttl
|
158
|
-
end
|
159
|
-
|
160
193
|
def db
|
161
194
|
@opts[:db] || self.class.db
|
162
195
|
end
|
data/lib/familia/settings.rb
CHANGED
@@ -5,7 +5,7 @@ module Familia
|
|
5
5
|
@delim = ':'
|
6
6
|
@prefix = nil
|
7
7
|
@suffix = :object
|
8
|
-
@ttl = nil
|
8
|
+
@ttl = 0 # see update_expiration. Zero is skip. nil is an exception.
|
9
9
|
@db = nil
|
10
10
|
|
11
11
|
module Settings
|
@@ -27,6 +27,16 @@ module Familia
|
|
27
27
|
@suffix
|
28
28
|
end
|
29
29
|
|
30
|
+
def ttl(v = nil)
|
31
|
+
@ttl = v unless v.nil?
|
32
|
+
@ttl
|
33
|
+
end
|
34
|
+
|
35
|
+
def db(v = nil)
|
36
|
+
@db = v unless v.nil?
|
37
|
+
@db
|
38
|
+
end
|
39
|
+
|
30
40
|
# We define this do-nothing method because it reads better
|
31
41
|
# than simply Familia.suffix in some contexts.
|
32
42
|
def default_suffix
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Familia
|
4
|
+
module Tools
|
5
|
+
extend self
|
6
|
+
def move_keys(filter, source_uri, target_uri, &each_key)
|
7
|
+
raise "Source and target are the same (#{target_uri})" if target_uri == source_uri
|
8
|
+
|
9
|
+
Familia.connect target_uri
|
10
|
+
source_keys = Familia.redis(source_uri).keys(filter)
|
11
|
+
puts "Moving #{source_keys.size} keys from #{source_uri} to #{target_uri} (filter: #{filter})"
|
12
|
+
source_keys.each_with_index do |key, idx|
|
13
|
+
type = Familia.redis(source_uri).type key
|
14
|
+
ttl = Familia.redis(source_uri).ttl key
|
15
|
+
if source_uri.host == target_uri.host && source_uri.port == target_uri.port
|
16
|
+
Familia.redis(source_uri).move key, target_uri.db
|
17
|
+
else
|
18
|
+
case type
|
19
|
+
when 'string'
|
20
|
+
Familia.redis(source_uri).get key
|
21
|
+
when 'list'
|
22
|
+
Familia.redis(source_uri).lrange key, 0, -1
|
23
|
+
when 'set'
|
24
|
+
Familia.redis(source_uri).smembers key
|
25
|
+
else
|
26
|
+
raise Familia::Problem, "unknown key type: #{type}"
|
27
|
+
end
|
28
|
+
raise 'Not implemented'
|
29
|
+
end
|
30
|
+
yield(idx, type, key, ttl) unless each_key.nil?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Use the return value from each_key as the new key name
|
35
|
+
def rename(filter, source_uri, target_uri = nil, &each_key)
|
36
|
+
target_uri ||= source_uri
|
37
|
+
move_keys filter, source_uri, target_uri if source_uri != target_uri
|
38
|
+
source_keys = Familia.redis(source_uri).keys(filter)
|
39
|
+
puts "Renaming #{source_keys.size} keys from #{source_uri} (filter: #{filter})"
|
40
|
+
source_keys.each_with_index do |key, idx|
|
41
|
+
Familia.trace :RENAME1, Familia.redis(source_uri), "#{key}", ''
|
42
|
+
type = Familia.redis(source_uri).type key
|
43
|
+
ttl = Familia.redis(source_uri).ttl key
|
44
|
+
newkey = yield(idx, type, key, ttl) unless each_key.nil?
|
45
|
+
Familia.trace :RENAME2, Familia.redis(source_uri), "#{key} -> #{newkey}", caller(1..1).first
|
46
|
+
Familia.redis(source_uri).renamenx key, newkey
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_any(keyname, uri = nil)
|
51
|
+
type = Familia.redis(uri).type keyname
|
52
|
+
case type
|
53
|
+
when 'string'
|
54
|
+
Familia.redis(uri).get keyname
|
55
|
+
when 'list'
|
56
|
+
Familia.redis(uri).lrange(keyname, 0, -1) || []
|
57
|
+
when 'set'
|
58
|
+
Familia.redis(uri).smembers(keyname) || []
|
59
|
+
when 'zset'
|
60
|
+
Familia.redis(uri).zrange(keyname, 0, -1) || []
|
61
|
+
when 'hash'
|
62
|
+
Familia.redis(uri).hgetall(keyname) || {}
|
63
|
+
else
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -49,12 +49,12 @@ module Familia
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def values
|
52
|
-
|
53
|
-
multi_from_redis(*
|
52
|
+
elements = redis.hvals(rediskey)
|
53
|
+
multi_from_redis(*elements)
|
54
54
|
end
|
55
55
|
|
56
56
|
def hgetall
|
57
|
-
# TODO: Use from_redis. Also
|
57
|
+
# TODO: Use from_redis. Also alias `all` is confusing with
|
58
58
|
# Onetime::Customer.all which returns all customers.
|
59
59
|
redis.hgetall rediskey
|
60
60
|
end
|
@@ -98,8 +98,8 @@ module Familia
|
|
98
98
|
alias merge! update
|
99
99
|
|
100
100
|
def values_at *fields
|
101
|
-
|
102
|
-
multi_from_redis(*
|
101
|
+
elements = redis.hmget(rediskey, *fields.flatten.compact)
|
102
|
+
multi_from_redis(*elements)
|
103
103
|
end
|
104
104
|
|
105
105
|
Familia::RedisType.register self, :hash # legacy, deprecated
|
data/lib/familia/types/list.rb
CHANGED
@@ -75,8 +75,8 @@ module Familia
|
|
75
75
|
|
76
76
|
def members(count = -1, opts = {})
|
77
77
|
count -= 1 if count.positive?
|
78
|
-
|
79
|
-
multi_from_redis(*
|
78
|
+
elements = membersraw count, opts
|
79
|
+
multi_from_redis(*elements)
|
80
80
|
end
|
81
81
|
alias to_a members
|
82
82
|
alias all members
|
@@ -88,8 +88,8 @@ module Familia
|
|
88
88
|
|
89
89
|
def revmembers(count = -1, opts = {})
|
90
90
|
count -= 1 if count.positive?
|
91
|
-
|
92
|
-
multi_from_redis(*
|
91
|
+
elements = revmembersraw count, opts
|
92
|
+
multi_from_redis(*elements)
|
93
93
|
end
|
94
94
|
|
95
95
|
def revmembersraw(count = -1, opts = {})
|
@@ -131,8 +131,8 @@ module Familia
|
|
131
131
|
|
132
132
|
def range(sidx, eidx, opts = {})
|
133
133
|
echo :range, caller(1..1).first if Familia.debug
|
134
|
-
|
135
|
-
multi_from_redis(*
|
134
|
+
elements = rangeraw(sidx, eidx, opts)
|
135
|
+
multi_from_redis(*elements)
|
136
136
|
end
|
137
137
|
|
138
138
|
def rangeraw(sidx, eidx, opts = {})
|
@@ -148,8 +148,8 @@ module Familia
|
|
148
148
|
|
149
149
|
def revrange(sidx, eidx, opts = {})
|
150
150
|
echo :revrange, caller(1..1).first if Familia.debug
|
151
|
-
|
152
|
-
multi_from_redis(*
|
151
|
+
elements = revrangeraw(sidx, eidx, opts)
|
152
|
+
multi_from_redis(*elements)
|
153
153
|
end
|
154
154
|
|
155
155
|
def revrangeraw(sidx, eidx, opts = {})
|
@@ -159,8 +159,8 @@ module Familia
|
|
159
159
|
# e.g. obj.metrics.rangebyscore (now-12.hours), now, :limit => [0, 10]
|
160
160
|
def rangebyscore(sscore, escore, opts = {})
|
161
161
|
echo :rangebyscore, caller(1..1).first if Familia.debug
|
162
|
-
|
163
|
-
multi_from_redis(*
|
162
|
+
elements = rangebyscoreraw(sscore, escore, opts)
|
163
|
+
multi_from_redis(*elements)
|
164
164
|
end
|
165
165
|
|
166
166
|
def rangebyscoreraw(sscore, escore, opts = {})
|
@@ -171,8 +171,8 @@ module Familia
|
|
171
171
|
# e.g. obj.metrics.revrangebyscore (now-12.hours), now, :limit => [0, 10]
|
172
172
|
def revrangebyscore(sscore, escore, opts = {})
|
173
173
|
echo :revrangebyscore, caller(1..1).first if Familia.debug
|
174
|
-
|
175
|
-
multi_from_redis(*
|
174
|
+
elements = revrangebyscoreraw(sscore, escore, opts)
|
175
|
+
multi_from_redis(*elements)
|
176
176
|
end
|
177
177
|
|
178
178
|
def revrangebyscoreraw(sscore, escore, opts = {})
|
data/lib/familia/types/string.rb
CHANGED