familia 1.0.0.pre.rc7 → 1.1.0.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +3 -1
  4. data/README.md +5 -5
  5. data/VERSION.yml +2 -2
  6. data/familia.gemspec +1 -2
  7. data/lib/familia/base.rb +11 -11
  8. data/lib/familia/connection.rb +18 -2
  9. data/lib/familia/errors.rb +14 -0
  10. data/lib/familia/features/expiration.rb +13 -2
  11. data/lib/familia/features/quantization.rb +1 -1
  12. data/lib/familia/horreum/class_methods.rb +31 -21
  13. data/lib/familia/horreum/commands.rb +53 -14
  14. data/lib/familia/horreum/relations_management.rb +9 -2
  15. data/lib/familia/horreum/serialization.rb +32 -23
  16. data/lib/familia/horreum.rb +5 -1
  17. data/lib/familia/redistype/commands.rb +5 -2
  18. data/lib/familia/redistype/serialization.rb +17 -16
  19. data/lib/familia/redistype/types/hashkey.rb +166 -0
  20. data/lib/familia/{types → redistype/types}/list.rb +19 -14
  21. data/lib/familia/{types → redistype/types}/sorted_set.rb +23 -19
  22. data/lib/familia/{types → redistype/types}/string.rb +8 -6
  23. data/lib/familia/{types → redistype/types}/unsorted_set.rb +16 -12
  24. data/lib/familia/redistype.rb +19 -9
  25. data/lib/familia.rb +5 -1
  26. data/try/10_familia_try.rb +1 -1
  27. data/try/20_redis_type_try.rb +1 -1
  28. data/try/21_redis_type_zset_try.rb +1 -1
  29. data/try/22_redis_type_set_try.rb +1 -1
  30. data/try/23_redis_type_list_try.rb +2 -2
  31. data/try/24_redis_type_string_try.rb +3 -3
  32. data/try/25_redis_type_hash_try.rb +1 -1
  33. data/try/26_redis_bool_try.rb +2 -2
  34. data/try/27_redis_horreum_try.rb +2 -2
  35. data/try/30_familia_object_try.rb +8 -5
  36. data/try/40_customer_try.rb +6 -6
  37. metadata +15 -15
  38. data/lib/familia/types/hashkey.rb +0 -108
@@ -97,15 +97,8 @@ module Familia
97
97
  # connection. Don't worry, it puts everything back where it found it when it's done.
98
98
  #
99
99
  def transaction
100
- original_redis = self.redis
101
-
102
- begin
103
- redis.multi do |conn|
104
- self.instance_variable_set(:@redis, conn)
105
- yield(conn)
106
- end
107
- ensure
108
- self.redis = original_redis
100
+ redis.multi do |conn|
101
+ yield(conn)
109
102
  end
110
103
  end
111
104
 
@@ -130,15 +123,15 @@ module Familia
130
123
 
131
124
  # Update our object's life story
132
125
  self.key ||= self.identifier
133
- self.updated = Familia.now.to_i
134
- self.created ||= Familia.now.to_i
126
+ self.created ||= Familia.now.to_i if respond_to?(:created)
127
+ self.updated = Familia.now.to_i if respond_to?(:updated)
135
128
 
136
129
  # Commit our tale to the Redis chronicles
137
130
  #
138
131
  # e.g. `ret` # => MultiResult.new(true, ["OK", "OK"])
139
132
  ret = commit_fields(update_expiration: update_expiration)
140
133
 
141
- Familia.ld "[save] #{self.class} #{rediskey} #{ret}"
134
+ Familia.ld "[save] #{self.class} #{rediskey} #{ret} (update_expiration: #{update_expiration})"
142
135
 
143
136
  # Did Redis accept our offering?
144
137
  ret.successful?
@@ -174,6 +167,10 @@ module Familia
174
167
  # It executes a transaction that includes setting field values and,
175
168
  # if applicable, updating the expiration time.
176
169
  #
170
+ # @param update_expiration [Boolean] Whether to update the expiration time
171
+ # of the Redis key. This is true by default, but can be disabled if you
172
+ # don't want to mess with the cosmic balance of your key's lifespan.
173
+ #
177
174
  # @return [MultiResult] A mystical object containing:
178
175
  # - success: A boolean indicating if all Redis commands succeeded
179
176
  # - results: An array of strings, cryptic messages from the Redis gods
@@ -213,13 +210,12 @@ module Familia
213
210
  def commit_fields update_expiration: true
214
211
  Familia.ld "[commit_fields1] #{self.class} #{rediskey} #{to_h} (update_expiration: #{update_expiration})"
215
212
  command_return_values = transaction do |conn|
216
- hmset
217
-
218
- # Only classes that have the expiration ferature enabled will
219
- # actually set an expiration time on their keys. Otherwise
220
- # this will be a no-op that simply logs the attempt.
221
- self.update_expiration if update_expiration
213
+ conn.hmset rediskey(suffix), self.to_h # using the prepared connection
222
214
  end
215
+ # Only classes that have the expiration ferature enabled will
216
+ # actually set an expiration time on their keys. Otherwise
217
+ # this will be a no-op that simply logs the attempt.
218
+ self.update_expiration(ttl: nil) if update_expiration
223
219
 
224
220
  # The acceptable redis command return values are defined in the
225
221
  # Horreum class. This is to ensure that all commands return values
@@ -256,6 +252,11 @@ module Familia
256
252
  # rocky.destroy!
257
253
  # # => *poof* Rocky is no more. A moment of silence, please.
258
254
  #
255
+ # This method is part of Familia's high-level object lifecycle management. While `delete!`
256
+ # operates directly on Redis keys, `destroy!` operates at the object level and is used for
257
+ # ORM-style operations. Use `destroy!` when removing complete objects from the system, and
258
+ # `delete!` when working directly with Redis keys.
259
+ #
259
260
  # @note If debugging is enabled, this method will leave a trace of its
260
261
  # destructive path, like breadcrumbs for future data archaeologists.
261
262
  #
@@ -276,14 +277,19 @@ module Familia
276
277
  # Gone quicker than cake at a hobbit's birthday party. Unsaved spells
277
278
  # will definitely be forgotten.
278
279
  #
279
- # @return What do you get for this daring act of digital amnesia? A shiny
280
+ # @return [void] What do you get for this daring act of digital amnesia? A shiny
280
281
  # list of all the brain bits that got a makeover!
281
282
  #
282
283
  # Remember: In the game of Redis-Refresh, you win or you... well, you
283
284
  # always win, but sometimes you forget why you played in the first place.
284
285
  #
286
+ # @raise [Familia::KeyNotFoundError] If the Redis key does not exist.
287
+ #
288
+ # @example
289
+ # object.refresh!
285
290
  def refresh!
286
291
  Familia.trace :REFRESH, redis, redisuri, caller(1..1) if Familia.debug?
292
+ raise Familia::KeyNotFoundError, rediskey unless redis.exists(rediskey)
287
293
  fields = hgetall
288
294
  Familia.ld "[refresh!] #{self.class} #{rediskey} #{fields.keys}"
289
295
  optimistic_refresh(**fields)
@@ -303,6 +309,8 @@ module Familia
303
309
  # @return [self] Your object, freshly bathed in Redis waters, ready
304
310
  # to dance with more methods in a conga line of Ruby joy!
305
311
  #
312
+ # @raise [Familia::KeyNotFoundError] If the Redis key does not exist.
313
+ #
306
314
  def refresh
307
315
  refresh!
308
316
  self
@@ -326,7 +334,7 @@ module Familia
326
334
  def to_h
327
335
  self.class.fields.inject({}) do |hsh, field|
328
336
  val = send(field)
329
- prepared = to_redis(val)
337
+ prepared = serialize_value(val)
330
338
  Familia.ld " [to_h] field: #{field} val: #{val.class} prepared: #{prepared.class}"
331
339
  hsh[field] = prepared
332
340
  hsh
@@ -351,7 +359,7 @@ module Familia
351
359
  def to_a
352
360
  self.class.fields.map do |field|
353
361
  val = send(field)
354
- prepared = to_redis(val)
362
+ prepared = serialize_value(val)
355
363
  Familia.ld " [to_a] field: #{field} val: #{val.class} prepared: #{prepared.class}"
356
364
  prepared
357
365
  end
@@ -392,7 +400,7 @@ module Familia
392
400
  #
393
401
  # @return [String] The transformed, Redis-ready value.
394
402
  #
395
- def to_redis(val)
403
+ def serialize_value(val)
396
404
  prepared = Familia.distinguisher(val, strict_values: false)
397
405
 
398
406
  if prepared.nil? && val.respond_to?(dump_method)
@@ -400,11 +408,12 @@ module Familia
400
408
  end
401
409
 
402
410
  if prepared.nil?
403
- Familia.ld "[#{self.class}#to_redis] nil returned for #{self.class}##{name}"
411
+ Familia.ld "[#{self.class}#serialize_value] nil returned for #{self.class}##{name}"
404
412
  end
405
413
 
406
414
  prepared
407
415
  end
416
+ alias to_redis serialize_value
408
417
 
409
418
  end
410
419
  # End of Serialization module
@@ -54,6 +54,10 @@ module Familia
54
54
  # but not existing instances of the class.
55
55
  #
56
56
  class << self
57
+ attr_accessor :parent
58
+ attr_writer :redis, :dump_method, :load_method
59
+ attr_reader :has_relations
60
+
57
61
  # Extends ClassMethods to subclasses and tracks Familia members
58
62
  def inherited(member)
59
63
  Familia.trace :HORREUM, nil, "Welcome #{member} to the family", caller(1..1) if Familia.debug?
@@ -82,7 +86,7 @@ module Familia
82
86
  # Define the 'key' field for this class
83
87
  # This approach allows flexibility in how identifiers are generated
84
88
  # while ensuring each object has a consistent way to be referenced
85
- self.class.field :key # , default: -> { identifier }
89
+ self.class.field :key
86
90
  end
87
91
 
88
92
  # If there are positional arguments, they should be the field
@@ -22,11 +22,14 @@ class Familia::RedisType
22
22
  redis.type rediskey
23
23
  end
24
24
 
25
+ # Deletes the entire Redis key
26
+ # @return [Boolean] true if the key was deleted, false otherwise
25
27
  def delete!
26
- redis.del rediskey
28
+ Familia.trace :DELETE!, redis, redisuri, caller(1..1) if Familia.debug?
29
+ ret = redis.del rediskey
30
+ ret.positive?
27
31
  end
28
32
  alias clear delete!
29
- alias del delete!
30
33
 
31
34
  def exists?
32
35
  redis.exists(rediskey) && !size.zero?
@@ -17,16 +17,16 @@ class Familia::RedisType
17
17
  # serialization.
18
18
  #
19
19
  # @example With a class option
20
- # to_redis(User.new(name: "Cloe"), strict_values: false) #=> '{"name":"Cloe"}'
20
+ # serialize_value(User.new(name: "Cloe"), strict_values: false) #=> '{"name":"Cloe"}'
21
21
  #
22
22
  # @example Without a class option
23
- # to_redis(123) #=> "123"
24
- # to_redis("hello") #=> "hello"
23
+ # serialize_value(123) #=> "123"
24
+ # serialize_value("hello") #=> "hello"
25
25
  #
26
26
  # @raise [Familia::HighRiskFactor] If serialization fails under strict
27
27
  # mode.
28
28
  #
29
- def to_redis(val, strict_values: true)
29
+ def serialize_value(val, strict_values: true)
30
30
  prepared = nil
31
31
 
32
32
  Familia.trace :TOREDIS, redis, "#{val}<#{val.class}|#{opts[:class]}>", caller(1..1) if Familia.debug?
@@ -44,24 +44,26 @@ class Familia::RedisType
44
44
 
45
45
  Familia.trace :TOREDIS, redis, "#{val}<#{val.class}|#{opts[:class]}> => #{prepared}<#{prepared.class}>", caller(1..1) if Familia.debug?
46
46
 
47
- Familia.warn "[#{self.class}\#to_redis] nil returned for #{opts[:class]}\##{name}" if prepared.nil?
47
+ Familia.warn "[#{self.class}\#serialize_value] nil returned for #{opts[:class]}\##{name}" if prepared.nil?
48
48
  prepared
49
49
  end
50
+ alias to_redis serialize_value
50
51
 
51
52
  # Deserializes multiple values from Redis, removing nil values.
52
53
  #
53
54
  # @param values [Array<String>] The values to deserialize.
54
55
  # @return [Array<Object>] Deserialized objects, with nil values removed.
55
56
  #
56
- # @see #multi_from_redis_with_nil
57
+ # @see #deserialize_values_with_nil
57
58
  #
58
- def multi_from_redis(*values)
59
+ def deserialize_values(*values)
59
60
  # Avoid using compact! here. Using compact! as the last expression in the
60
61
  # method can unintentionally return nil if no changes are made, which is
61
62
  # not desirable. Instead, use compact to ensure the method returns the
62
63
  # expected value.
63
- multi_from_redis_with_nil(*values).compact
64
+ deserialize_values_with_nil(*values).compact
64
65
  end
66
+ alias from_redis deserialize_values
65
67
 
66
68
  # Deserializes multiple values from Redis, preserving nil values.
67
69
  #
@@ -75,11 +77,8 @@ class Familia::RedisType
75
77
  # class's load method. If deserialization fails for a value, it's
76
78
  # replaced with nil.
77
79
  #
78
- # NOTE: `multi` in this method name refers to multiple values from
79
- # redis and not the Redis server MULTI command.
80
- #
81
- def multi_from_redis_with_nil(*values)
82
- Familia.ld "multi_from_redis: (#{@opts}) #{values}"
80
+ def deserialize_values_with_nil(*values)
81
+ Familia.ld "deserialize_values: (#{@opts}) #{values}"
83
82
  return [] if values.empty?
84
83
  return values.flatten unless @opts[:class]
85
84
 
@@ -92,7 +91,7 @@ class Familia::RedisType
92
91
 
93
92
  val = @opts[:class].send load_method, obj
94
93
  if val.nil?
95
- Familia.ld "[#{self.class}\#multi_from_redis] nil returned for #{@opts[:class]}\##{name}"
94
+ Familia.ld "[#{self.class}\#deserialize_values] nil returned for #{@opts[:class]}\##{name}"
96
95
  end
97
96
 
98
97
  val
@@ -105,6 +104,7 @@ class Familia::RedisType
105
104
 
106
105
  values
107
106
  end
107
+ alias from_redis_with_nil deserialize_values_with_nil
108
108
 
109
109
  # Deserializes a single value from Redis.
110
110
  #
@@ -120,13 +120,14 @@ class Familia::RedisType
120
120
  # deserialization options that RedisType supports. It uses to_redis
121
121
  # for serialization since everything becomes a string in Redis.
122
122
  #
123
- def from_redis(val)
123
+ def deserialize_value(val)
124
124
  return @opts[:default] if val.nil?
125
125
  return val unless @opts[:class]
126
126
 
127
- ret = multi_from_redis val
127
+ ret = deserialize_values val
128
128
  ret&.first # return the object or nil
129
129
  end
130
+ alias from_redis deserialize_value
130
131
  end
131
132
 
132
133
  end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Familia
4
+ class HashKey < RedisType
5
+ # Returns the number of fields in the hash
6
+ # @return [Integer] number of fields
7
+ def field_count
8
+ redis.hlen rediskey
9
+ end
10
+ alias size field_count
11
+
12
+ def empty?
13
+ field_count.zero?
14
+ end
15
+
16
+ # +return+ [Integer] Returns 1 if the field is new and added, 0 if the
17
+ # field already existed and the value was updated.
18
+ def []=(field, val)
19
+ ret = redis.hset rediskey, field, serialize_value(val)
20
+ update_expiration
21
+ ret
22
+ rescue TypeError => e
23
+ Familia.le "[hset]= #{e.message}"
24
+ Familia.ld "[hset]= #{rediskey} #{field}=#{val}" if Familia.debug
25
+ echo :hset, caller(1..1).first if Familia.debug # logs via echo to redis and back
26
+ klass = val.class
27
+ msg = "Cannot store #{field} => #{val.inspect} (#{klass}) in #{rediskey}"
28
+ raise e.class, msg
29
+ end
30
+ alias put []=
31
+ alias store []=
32
+
33
+ def [](field)
34
+ deserialize_value redis.hget(rediskey, field)
35
+ end
36
+ alias get []
37
+
38
+ def fetch(field, default = nil)
39
+ ret = self[field]
40
+ if ret.nil?
41
+ raise IndexError, "No such index for: #{field}" if default.nil?
42
+
43
+ default
44
+ else
45
+ ret
46
+ end
47
+ end
48
+
49
+ def keys
50
+ redis.hkeys rediskey
51
+ end
52
+
53
+ def values
54
+ redis.hvals(rediskey).map { |v| deserialize_value v }
55
+ end
56
+
57
+ def hgetall
58
+ redis.hgetall(rediskey).each_with_object({}) do |(k,v), ret|
59
+ ret[k] = deserialize_value v
60
+ end
61
+ end
62
+ alias all hgetall
63
+
64
+ def key?(field)
65
+ redis.hexists rediskey, field
66
+ end
67
+ alias has_key? key?
68
+ alias include? key?
69
+ alias member? key?
70
+
71
+ # Removes a field from the hash
72
+ # @param field [String] The field to remove
73
+ # @return [Integer] The number of fields that were removed (0 or 1)
74
+ def remove_field(field)
75
+ redis.hdel rediskey, field
76
+ end
77
+ alias remove remove_field # deprecated
78
+
79
+ def increment(field, by = 1)
80
+ redis.hincrby(rediskey, field, by).to_i
81
+ end
82
+ alias incr increment
83
+ alias incrby increment
84
+
85
+ def decrement(field, by = 1)
86
+ increment field, -by
87
+ end
88
+ alias decr decrement
89
+ alias decrby decrement
90
+
91
+ def update(hsh = {})
92
+ raise ArgumentError, 'Argument to bulk_set must be a hash' unless hsh.is_a?(Hash)
93
+
94
+ data = hsh.inject([]) { |ret, pair| ret << [pair[0], serialize_value(pair[1])] }.flatten
95
+
96
+ ret = redis.hmset(rediskey, *data)
97
+ update_expiration
98
+ ret
99
+ end
100
+ alias merge! update
101
+
102
+ def values_at *fields
103
+ elements = redis.hmget(rediskey, *fields.flatten.compact)
104
+ deserialize_values(*elements)
105
+ end
106
+
107
+ # The Great Redis Refresh-o-matic 3000 for HashKey!
108
+ #
109
+ # This method performs a complete refresh of the hash's state from Redis.
110
+ # It's like giving your hash a memory transfusion - out with the old state,
111
+ # in with the fresh data straight from Redis!
112
+ #
113
+ # @note This operation is atomic - it either succeeds completely or fails
114
+ # safely. Any unsaved changes to the hash will be overwritten.
115
+ #
116
+ # @return [void] Returns nothing, but your hash will be sparkling clean
117
+ # with all its fields synchronized with Redis.
118
+ #
119
+ # @raise [Familia::KeyNotFoundError] If the Redis key for this hash no
120
+ # longer exists. Time travelers beware!
121
+ #
122
+ # @example Basic usage
123
+ # my_hash.refresh! # ZAP! Fresh data loaded
124
+ #
125
+ # @example With error handling
126
+ # begin
127
+ # my_hash.refresh!
128
+ # rescue Familia::KeyNotFoundError
129
+ # puts "Oops! Our hash seems to have vanished into the Redis void!"
130
+ # end
131
+ def refresh!
132
+ Familia.trace :REFRESH, redis, redisuri, caller(1..1) if Familia.debug?
133
+ raise Familia::KeyNotFoundError, rediskey unless redis.exists(rediskey)
134
+
135
+ fields = hgetall
136
+ Familia.ld "[refresh!] #{self.class} #{rediskey} #{fields.keys}"
137
+
138
+ # For HashKey, we update by merging the fresh data
139
+ update(fields)
140
+ end
141
+
142
+ # The friendly neighborhood refresh method!
143
+ #
144
+ # This method is like refresh! but with better manners - it returns self
145
+ # so you can chain it with other methods. It's perfect for when you want
146
+ # to refresh your hash and immediately do something with it.
147
+ #
148
+ # @return [self] Returns the refreshed hash, ready for more adventures!
149
+ #
150
+ # @raise [Familia::KeyNotFoundError] If the Redis key does not exist.
151
+ # The hash must exist in Redis-land for this to work!
152
+ #
153
+ # @example Refresh and chain
154
+ # my_hash.refresh.keys # Refresh and get all keys
155
+ # my_hash.refresh['field'] # Refresh and get a specific field
156
+ #
157
+ # @see #refresh! For the heavy lifting behind the scenes
158
+ def refresh
159
+ refresh!
160
+ self
161
+ end
162
+
163
+ Familia::RedisType.register self, :hash # legacy, deprecated
164
+ Familia::RedisType.register self, :hashkey
165
+ end
166
+ end
@@ -2,18 +2,21 @@
2
2
 
3
3
  module Familia
4
4
  class List < RedisType
5
- def size
5
+
6
+ # Returns the number of elements in the list
7
+ # @return [Integer] number of elements
8
+ def element_count
6
9
  redis.llen rediskey
7
10
  end
8
- alias length size
11
+ alias size element_count
9
12
 
10
13
  def empty?
11
- size.zero?
14
+ element_count.zero?
12
15
  end
13
16
 
14
17
  def push *values
15
18
  echo :push, caller(1..1).first if Familia.debug
16
- values.flatten.compact.each { |v| redis.rpush rediskey, to_redis(v) }
19
+ values.flatten.compact.each { |v| redis.rpush rediskey, serialize_value(v) }
17
20
  redis.ltrim rediskey, -@opts[:maxlength], -1 if @opts[:maxlength]
18
21
  update_expiration
19
22
  self
@@ -26,7 +29,7 @@ module Familia
26
29
  alias add <<
27
30
 
28
31
  def unshift *values
29
- values.flatten.compact.each { |v| redis.lpush rediskey, to_redis(v) }
32
+ values.flatten.compact.each { |v| redis.lpush rediskey, serialize_value(v) }
30
33
  # TODO: test maxlength
31
34
  redis.ltrim rediskey, 0, @opts[:maxlength] - 1 if @opts[:maxlength]
32
35
  update_expiration
@@ -35,11 +38,11 @@ module Familia
35
38
  alias prepend unshift
36
39
 
37
40
  def pop
38
- from_redis redis.rpop(rediskey)
41
+ deserialize_value redis.rpop(rediskey)
39
42
  end
40
43
 
41
44
  def shift
42
- from_redis redis.lpop(rediskey)
45
+ deserialize_value redis.lpop(rediskey)
43
46
  end
44
47
 
45
48
  def [](idx, count = nil)
@@ -57,16 +60,18 @@ module Familia
57
60
  end
58
61
  alias slice []
59
62
 
60
- def delete(v, count = 0)
61
- redis.lrem rediskey, count, to_redis(v)
63
+ # Removes elements equal to value from the list
64
+ # @param value The value to remove
65
+ # @param count [Integer] Number of elements to remove (0 means all)
66
+ # @return [Integer] The number of removed elements
67
+ def remove_element(value, count = 0)
68
+ redis.lrem rediskey, count, serialize_value(value)
62
69
  end
63
- alias remove delete
64
- alias rem delete
65
- alias del delete
70
+ alias remove remove_element
66
71
 
67
72
  def range(sidx = 0, eidx = -1)
68
73
  elements = rangeraw sidx, eidx
69
- multi_from_redis(*elements)
74
+ deserialize_values(*elements)
70
75
  end
71
76
 
72
77
  def rangeraw(sidx = 0, eidx = -1)
@@ -119,7 +124,7 @@ module Familia
119
124
  end
120
125
 
121
126
  def at(idx)
122
- from_redis redis.lindex(rediskey, idx)
127
+ deserialize_value redis.lindex(rediskey, idx)
123
128
  end
124
129
 
125
130
  def first
@@ -2,13 +2,16 @@
2
2
 
3
3
  module Familia
4
4
  class SortedSet < RedisType
5
- def size
5
+
6
+ # Returns the number of elements in the sorted set
7
+ # @return [Integer] number of elements
8
+ def element_count
6
9
  redis.zcard rediskey
7
10
  end
8
- alias length size
11
+ alias size element_count
9
12
 
10
13
  def empty?
11
- size.zero?
14
+ element_count.zero?
12
15
  end
13
16
 
14
17
  # Adds a new element to the sorted set with the current timestamp as the
@@ -44,13 +47,13 @@ module Familia
44
47
  end
45
48
 
46
49
  def add(score, val)
47
- ret = redis.zadd rediskey, score, to_redis(val)
50
+ ret = redis.zadd rediskey, score, serialize_value(val)
48
51
  update_expiration
49
52
  ret
50
53
  end
51
54
 
52
55
  def score(val)
53
- ret = redis.zscore rediskey, to_redis(val, strict_values: false)
56
+ ret = redis.zscore rediskey, serialize_value(val, strict_values: false)
54
57
  ret&.to_f
55
58
  end
56
59
  alias [] score
@@ -63,20 +66,20 @@ module Familia
63
66
 
64
67
  # rank of member +v+ when ordered lowest to highest (starts at 0)
65
68
  def rank(v)
66
- ret = redis.zrank rediskey, to_redis(v, strict_values: false)
69
+ ret = redis.zrank rediskey, serialize_value(v, strict_values: false)
67
70
  ret&.to_i
68
71
  end
69
72
 
70
73
  # rank of member +v+ when ordered highest to lowest (starts at 0)
71
74
  def revrank(v)
72
- ret = redis.zrevrank rediskey, to_redis(v, strict_values: false)
75
+ ret = redis.zrevrank rediskey, serialize_value(v, strict_values: false)
73
76
  ret&.to_i
74
77
  end
75
78
 
76
79
  def members(count = -1, opts = {})
77
80
  count -= 1 if count.positive?
78
81
  elements = membersraw count, opts
79
- multi_from_redis(*elements)
82
+ deserialize_values(*elements)
80
83
  end
81
84
  alias to_a members
82
85
  alias all members
@@ -89,7 +92,7 @@ module Familia
89
92
  def revmembers(count = -1, opts = {})
90
93
  count -= 1 if count.positive?
91
94
  elements = revmembersraw count, opts
92
- multi_from_redis(*elements)
95
+ deserialize_values(*elements)
93
96
  end
94
97
 
95
98
  def revmembersraw(count = -1, opts = {})
@@ -132,7 +135,7 @@ module Familia
132
135
  def range(sidx, eidx, opts = {})
133
136
  echo :range, caller(1..1).first if Familia.debug
134
137
  elements = rangeraw(sidx, eidx, opts)
135
- multi_from_redis(*elements)
138
+ deserialize_values(*elements)
136
139
  end
137
140
 
138
141
  def rangeraw(sidx, eidx, opts = {})
@@ -149,7 +152,7 @@ module Familia
149
152
  def revrange(sidx, eidx, opts = {})
150
153
  echo :revrange, caller(1..1).first if Familia.debug
151
154
  elements = revrangeraw(sidx, eidx, opts)
152
- multi_from_redis(*elements)
155
+ deserialize_values(*elements)
153
156
  end
154
157
 
155
158
  def revrangeraw(sidx, eidx, opts = {})
@@ -160,7 +163,7 @@ module Familia
160
163
  def rangebyscore(sscore, escore, opts = {})
161
164
  echo :rangebyscore, caller(1..1).first if Familia.debug
162
165
  elements = rangebyscoreraw(sscore, escore, opts)
163
- multi_from_redis(*elements)
166
+ deserialize_values(*elements)
164
167
  end
165
168
 
166
169
  def rangebyscoreraw(sscore, escore, opts = {})
@@ -172,7 +175,7 @@ module Familia
172
175
  def revrangebyscore(sscore, escore, opts = {})
173
176
  echo :revrangebyscore, caller(1..1).first if Familia.debug
174
177
  elements = revrangebyscoreraw(sscore, escore, opts)
175
- multi_from_redis(*elements)
178
+ deserialize_values(*elements)
176
179
  end
177
180
 
178
181
  def revrangebyscoreraw(sscore, escore, opts = {})
@@ -201,18 +204,19 @@ module Familia
201
204
  alias decr decrement
202
205
  alias decrby decrement
203
206
 
204
- def delete(val)
205
- Familia.trace :DELETE, redis, "#{val}<#{val.class}>", caller(1..1) if Familia.debug?
207
+ # Removes a member from the sorted set
208
+ # @param value The value to remove from the sorted set
209
+ # @return [Integer] The number of members that were removed (0 or 1)
210
+ def remove_element(value)
211
+ Familia.trace :REMOVE_ELEMENT, redis, "#{value}<#{value.class}>", caller(1..1) if Familia.debug?
206
212
  # We use `strict_values: false` here to allow for the deletion of values
207
213
  # that are in the sorted set. If it's a horreum object, the value is
208
214
  # the identifier and not a serialized version of the object. So either
209
215
  # the value exists in the sorted set or it doesn't -- we don't need to
210
216
  # raise an error if it's not found.
211
- redis.zrem rediskey, to_redis(val, strict_values: false)
217
+ redis.zrem rediskey, serialize_value(value, strict_values: false)
212
218
  end
213
- alias remove delete
214
- alias rem delete
215
- alias del delete
219
+ alias remove remove_element # deprecated
216
220
 
217
221
  def at(idx)
218
222
  range(idx, idx).first