Class: Familia::SortedSet
- Includes:
- DataType::CollectionBase
- Defined in:
- lib/familia/data_type/types/sorted_set.rb
Instance Attribute Summary collapse
-
#features_enabled ⇒ Object
included
from Features
readonly
Returns the value of attribute features_enabled.
- #logical_database(val = nil) ⇒ Object included from DataType::ClassMethods
-
#parent ⇒ Object
included
from DataType::ClassMethods
Returns the value of attribute parent.
-
#prefix ⇒ Object
included
from DataType::ClassMethods
Returns the value of attribute prefix.
-
#suffix ⇒ Object
included
from DataType::ClassMethods
Returns the value of attribute suffix.
-
#uri(val = nil) ⇒ Object
included
from DataType::ClassMethods
Returns the value of attribute uri.
Attributes included from Settings
#current_key_version, #default_expiration, #delim, #encryption_hkdf_salt, #encryption_hkdf_salt_history, #encryption_keys, #encryption_personalization, #logical_database, #prefix, #raise_on_unsaved_parent_write, #schema_path, #schema_validator, #schemas, #strict_write_order, #suffix, #transaction_mode
Instance Method Summary collapse
-
#<<(val) ⇒ Integer
Adds a new element to the sorted set with the current timestamp as the score.
-
#[]=(val, score) ⇒ Object
NOTE: The argument order is the reverse of #add.
-
#add(val, score = nil, nx: false, xx: false, gt: false, lt: false, ch: false) ⇒ Boolean
(also: #add_element)
Adds an element to the sorted set with an optional score and ZADD options.
- #at(idx) ⇒ Object
- #collectraw ⇒ Object
- #decrement(val, by = 1) ⇒ Object (also: #decr, #decrby)
-
#diff(*other_sets, withscores: false) ⇒ Array
Returns the difference between this sorted set and other sorted sets.
-
#diffstore(destination, *other_sets) ⇒ Integer
Stores the difference of sorted sets into a destination key.
-
#each(since: nil, batch_size: 100, **kwargs) {|member| ... } ⇒ Enumerator, self
Iterates over members of the sorted set.
- #eachraw ⇒ Object
- #eachraw_with_index ⇒ Object
-
#element_count ⇒ Integer
(also: #size, #length, #count)
Returns the number of elements in the sorted set.
- #empty? ⇒ Boolean
-
#first ⇒ Object
Return the first element in the list.
- #increment(val, by = 1) ⇒ Object (also: #incr, #incrby)
-
#inter(*other_sets, weights: nil, aggregate: nil, withscores: false) ⇒ Array
Returns the intersection of this sorted set with other sorted sets.
-
#interstore(destination, *other_sets, weights: nil, aggregate: nil) ⇒ Integer
Stores the intersection of sorted sets into a destination key.
-
#last ⇒ Object
Return the last element in the list.
-
#lexcount(min, max) ⇒ Integer
Counts members in a lexicographical range.
- #member?(val) ⇒ Boolean (also: #include?)
- #members(count = -1,, opts = {}) ⇒ Object (also: #to_a, #all)
- #membersraw(count = -1,, opts = {}) ⇒ Object
-
#mscore(*members) ⇒ Array<Float, nil>
Gets scores for multiple members at once.
-
#popmax(count = 1) ⇒ Array?
Removes and returns the member(s) with the highest score(s).
-
#popmin(count = 1) ⇒ Array?
Removes and returns the member(s) with the lowest score(s).
-
#randmember(count = nil, withscores: false) ⇒ Object, ...
Returns random member(s) from the sorted set.
- #range(sidx, eidx, opts = {}) ⇒ Object
-
#rangebylex(min, max, limit: nil) ⇒ Array
Returns members in a lexicographical range (requires all members have same score).
-
#rangebyscore(sscore, escore, opts = {}) ⇒ Object
e.g.
- #rangebyscoreraw(sscore, escore, opts = {}) ⇒ Object
- #rangeraw(sidx, eidx, opts = {}) ⇒ Object
-
#rank(v) ⇒ Object
rank of member +v+ when ordered lowest to highest (starts at 0).
-
#remove_element(value) ⇒ Integer
(also: #remove)
Removes a member from the sorted set.
-
#remrangebylex(min, max) ⇒ Integer
Removes members in a lexicographical range.
- #remrangebyrank(srank, erank) ⇒ Object
- #remrangebyscore(sscore, escore) ⇒ Object
- #revmembers(count = -1,, opts = {}) ⇒ Object
- #revmembersraw(count = -1,, opts = {}) ⇒ Object
- #revrange(sidx, eidx, opts = {}) ⇒ Object
-
#revrangebylex(max, min, limit: nil) ⇒ Array
Returns members in reverse lexicographical range.
-
#revrangebyscore(sscore, escore, opts = {}) ⇒ Object
e.g.
- #revrangebyscoreraw(sscore, escore, opts = {}) ⇒ Object
- #revrangeraw(sidx, eidx, opts = {}) ⇒ Object
-
#revrank(v) ⇒ Object
rank of member +v+ when ordered highest to lowest (starts at 0).
-
#scan(cursor = 0, match: nil, count: nil) ⇒ Array
Iterates over members using cursor-based scanning.
- #score(val) ⇒ Object (also: #[])
-
#score_count(min, max) ⇒ Integer
(also: #zcount)
Counts members within a score range.
- #selectraw ⇒ Object
-
#union(*other_sets, weights: nil, aggregate: nil, withscores: false) ⇒ Array
Returns the union of this sorted set with other sorted sets.
-
#unionstore(destination, *other_sets, weights: nil, aggregate: nil) ⇒ Integer
Stores the union of sorted sets into a destination key.
-
#update(hsh = {}) ⇒ Integer
(also: #merge!)
Bulk-adds or updates multiple members in a single ZADD.
Methods included from DataType::CollectionBase
#collection_type?, #each_record
Methods included from Features::Autoloader
autoload_files, included, normalize_to_config_name
Methods included from DataType::Serialization
#deserialize_value, #deserialize_values, #deserialize_values_with_nil, #serialize_value, #strip_legacy_json_encoding
Methods included from DataType::DatabaseCommands
#current_expiration, #delete!, #echo, #exists?, #expire, #expireat, #move, #persist, #rename, #renamenx, #type
Methods included from DataType::Connection
Methods included from Connection::Behavior
#connect, #create_dbclient, #multi, #normalize_uri, #pipeline, #pipelined, #transaction, #uri=, #url, #url=
Methods included from Settings
#configure, #default_suffix, #dirty_write_warnings, #dirty_write_warnings=, #pipelined_mode, #pipelined_mode=
Methods included from Base
add_feature, #as_json, #expired?, #expires?, find_feature, #generate_id, #to_json, #to_s, #ttl, #update_expiration, #uuid
Constructor Details
This class inherits a constructor from Familia::DataType
Instance Attribute Details
#features_enabled ⇒ Object (readonly) Originally defined in module Features
Returns the value of attribute features_enabled.
#logical_database(val = nil) ⇒ Object Originally defined in module DataType::ClassMethods
#parent ⇒ Object Originally defined in module DataType::ClassMethods
Returns the value of attribute parent.
#prefix ⇒ Object Originally defined in module DataType::ClassMethods
Returns the value of attribute prefix.
#suffix ⇒ Object Originally defined in module DataType::ClassMethods
Returns the value of attribute suffix.
#uri(val = nil) ⇒ Object Originally defined in module DataType::ClassMethods
Returns the value of attribute uri.
Instance Method Details
#<<(val) ⇒ Integer
This is a non-standard operation for sorted sets as it doesn't allow
specifying a custom score. Use add or []= for more control.
Adds a new element to the sorted set with the current timestamp as the score.
This method provides a convenient way to add elements to the sorted set without explicitly specifying a score. It uses the current Unix timestamp as the score, which effectively sorts elements by their insertion time.
38 39 40 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 38 def <<(val) add(val) end |
#[]=(val, score) ⇒ Object
NOTE: The argument order is the reverse of #add. We do this to more naturally align with how the [] and []= methods are used.
e.g. obj.metrics[VALUE] = SCORE obj.metrics[VALUE] # => SCORE
49 50 51 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 49 def []=(val, score) add val, score end |
#add(val, score = nil, nx: false, xx: false, gt: false, lt: false, ch: false) ⇒ Boolean Also known as: add_element
GT and LT options do NOT prevent adding new elements, they only affect update behavior for existing elements.
Default behavior (no options) adds new elements and updates existing ones unconditionally, matching standard Redis ZADD semantics.
INCR option is not supported. Use the increment method for ZINCRBY operations.
This method executes a Redis ZADD immediately, unlike scalar field setters which are deferred until save. If the parent object has unsaved scalar field changes, consider calling save first to avoid split-brain state.
Adds an element to the sorted set with an optional score and ZADD options.
This method supports Redis ZADD options for conditional adds and updates:
- NX: Only add new elements (don't update existing)
- XX: Only update existing elements (don't add new)
- GT: Only update if new score > current score
- LT: Only update if new score < current score
- CH: Return changed count (new + updated) instead of just new count
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 111 def add(val, score = nil, nx: false, xx: false, gt: false, lt: false, ch: false) warn_if_dirty! score ||= Familia.now # Validate mutual exclusivity (nx: nx, xx: xx, gt: gt, lt: lt) # Build options hash for redis gem opts = {} opts[:nx] = true if nx opts[:xx] = true if xx opts[:gt] = true if gt opts[:lt] = true if lt opts[:ch] = true if ch # Pass options to ZADD ret = if opts.empty? dbclient.zadd(dbkey, score, serialize_value(val)) else dbclient.zadd(dbkey, score, serialize_value(val), **opts) end update_expiration ret end |
#at(idx) ⇒ Object
405 406 407 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 405 def at(idx) range(idx, idx).first end |
#collectraw ⇒ Object
311 312 313 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 311 def collectraw(&) membersraw.collect(&) end |
#decrement(val, by = 1) ⇒ Object Also known as: decr, decrby
387 388 389 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 387 def decrement(val, by = 1) increment val, -by end |
#diff(*other_sets, withscores: false) ⇒ Array
Returns the difference between this sorted set and other sorted sets.
729 730 731 732 733 734 735 736 737 738 739 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 729 def diff(*other_sets, withscores: false) keys = [dbkey] + resolve_set_keys(other_sets) result = if withscores dbclient.zdiff(*keys, withscores: true) else dbclient.zdiff(*keys) end process_set_operation_result(result, withscores: withscores) end |
#diffstore(destination, *other_sets) ⇒ Integer
Stores the difference of sorted sets into a destination key.
747 748 749 750 751 752 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 747 def diffstore(destination, *other_sets) keys = [dbkey] + resolve_set_keys(other_sets) result = dbclient.zdiffstore(destination, keys) update_expiration result end |
#each(since: nil, batch_size: 100, **kwargs) {|member| ... } ⇒ Enumerator, self
The until: parameter uses Ruby keyword syntax. Since until is
a reserved word, it's accessed via **kwargs internally.
Score-cursor pagination: bounded queries paginate using the last seen score as the next exclusive minimum. This is O(n) total work, unlike offset-based LIMIT which is O(n²). However, members with identical scores may be skipped between pages. Use high-precision floats (e.g., Familia.now) for scores to avoid collisions.
Iterates over members of the sorted set.
When called with score bounds (since/until), uses ZRANGEBYSCORE for efficient range queries. Otherwise uses ZSCAN for memory-efficient iteration over large sets.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 263 def each(since: nil, batch_size: 100, **kwargs, &block) until_score = kwargs.delete(:until) raise ArgumentError, "unknown keyword(s): #{kwargs.keys.join(', ')}" if kwargs.any? return to_enum(:each, since: since, until: until_score, batch_size: batch_size) unless block # Convert Time objects to numeric scores since_score = since.is_a?(Time) ? since.to_f : since until_score_val = until_score.is_a?(Time) ? until_score.to_f : until_score if since_score || until_score_val # Score-cursor pagination: track last score, use exclusive bound for next page min = since_score || '-inf' max = until_score_val || '+inf' loop do # with_scores returns nested pairs: [["a", 1.0], ["b", 2.0]] pairs = rangebyscoreraw(min, max, limit: [0, batch_size], with_scores: true) break if pairs.empty? pairs.each do |raw_member, score| yield deserialize_value(raw_member) min = "(#{score}" # exclusive bound for next iteration end break if pairs.size < batch_size end else # Use ZSCAN for unbounded iteration (memory-efficient) cursor = 0 loop do new_cursor, pairs = scan(cursor, count: batch_size) pairs.each { |member, _score| block.call(member) } cursor = new_cursor break if cursor.zero? end end self end |
#eachraw ⇒ Object
303 304 305 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 303 def eachraw(&) membersraw.each(&) end |
#eachraw_with_index ⇒ Object
307 308 309 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 307 def eachraw_with_index(&) membersraw.each_with_index(&) end |
#element_count ⇒ Integer Also known as: size, length, count
Returns the number of elements in the sorted set
11 12 13 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 11 def element_count dbclient.zcard dbkey end |
#empty? ⇒ Boolean
18 19 20 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 18 def empty? element_count.zero? end |
#first ⇒ Object
Return the first element in the list. Redis: ZRANGE(0)
410 411 412 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 410 def first at(0) end |
#increment(val, by = 1) ⇒ Object Also known as: incr, incrby
379 380 381 382 383 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 379 def increment(val, by = 1) ret = dbclient.zincrby(dbkey, by, serialize_value(val)).to_f update_expiration ret end |
#inter(*other_sets, weights: nil, aggregate: nil, withscores: false) ⇒ Array
Returns the intersection of this sorted set with other sorted sets.
558 559 560 561 562 563 564 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 558 def inter(*other_sets, weights: nil, aggregate: nil, withscores: false) keys = [dbkey] + resolve_set_keys(other_sets) opts = build_set_operation_opts(weights: weights, aggregate: aggregate, withscores: withscores) result = dbclient.zinter(*keys, **opts) process_set_operation_result(result, withscores: withscores) end |
#interstore(destination, *other_sets, weights: nil, aggregate: nil) ⇒ Integer
Stores the intersection of sorted sets into a destination key.
711 712 713 714 715 716 717 718 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 711 def interstore(destination, *other_sets, weights: nil, aggregate: nil) keys = [dbkey] + resolve_set_keys(other_sets) opts = build_set_operation_opts(weights: weights, aggregate: aggregate) result = dbclient.zinterstore(destination, keys, **opts) update_expiration result end |
#last ⇒ Object
Return the last element in the list. Redis: ZRANGE(-1)
415 416 417 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 415 def last at(-1) end |
#lexcount(min, max) ⇒ Integer
Counts members in a lexicographical range.
615 616 617 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 615 def lexcount(min, max) dbclient.zlexcount(dbkey, min, max) end |
#member?(val) ⇒ Boolean Also known as: include?
189 190 191 192 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 189 def member?(val) Familia.trace :MEMBER, nil, "#{val}<#{val.class}>" if Familia.debug? !rank(val).nil? end |
#members(count = -1,, opts = {}) ⇒ Object Also known as: to_a, all
207 208 209 210 211 212 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 207 def members(count = -1, opts = {}) # NOTE: count math (positive count -> end index) is handled once by # membersraw. Do not decrement here too, or members(n) returns n-1. elements = membersraw count, opts deserialize_values(*elements) end |
#membersraw(count = -1,, opts = {}) ⇒ Object
216 217 218 219 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 216 def membersraw(count = -1, opts = {}) count -= 1 if count.positive? rangeraw 0, count, opts end |
#mscore(*members) ⇒ Array<Float, nil>
Gets scores for multiple members at once.
516 517 518 519 520 521 522 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 516 def mscore(*members) return [] if members.empty? serialized = members.map { |m| serialize_value(m) } result = dbclient.zmscore(dbkey, *serialized) result.map { |s| s&.to_f } end |
#popmax(count = 1) ⇒ Array?
Removes and returns the member(s) with the highest score(s).
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 467 def popmax(count = 1) warn_if_dirty! # Normalize explicit nil to the default so the structural dispatch below # behaves identically whether the arg is omitted or passed as nil. # redis-rb treats nil as count <= 1 and returns a flat pair. count = 1 if count.nil? result = dbclient.zpopmax(dbkey, count) return nil if result.nil? || result.empty? update_expiration # redis-rb returns a flat [member, score] pair when count <= 1, and a # nested [[member, score], ...] array when count > 1. Normalize by # inspecting the result's structure rather than relying on count alone, # so that a redis-rb version change or a member that serializes to an # array-like string cannot mislead the dispatch. if count == 1 pair = result.first.is_a?(Array) ? result.first : result [deserialize_value(pair[0]), pair[1].to_f] else result.map { |member, score| [deserialize_value(member), score.to_f] } end end |
#popmin(count = 1) ⇒ Array?
Removes and returns the member(s) with the lowest score(s).
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 431 def popmin(count = 1) warn_if_dirty! # Normalize explicit nil to the default so the structural dispatch below # behaves identically whether the arg is omitted or passed as nil. # redis-rb treats nil as count <= 1 and returns a flat pair. count = 1 if count.nil? result = dbclient.zpopmin(dbkey, count) return nil if result.nil? || result.empty? update_expiration # redis-rb returns a flat [member, score] pair when count <= 1, and a # nested [[member, score], ...] array when count > 1. Normalize by # inspecting the result's structure rather than relying on count alone, # so that a redis-rb version change or a member that serializes to an # array-like string cannot mislead the dispatch. if count == 1 pair = result.first.is_a?(Array) ? result.first : result [deserialize_value(pair[0]), pair[1].to_f] else result.map { |member, score| [deserialize_value(member), score.to_f] } end end |
#randmember(count = nil, withscores: false) ⇒ Object, ...
Returns random member(s) from the sorted set.
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 634 def randmember(count = nil, withscores: false) if count.nil? result = dbclient.zrandmember(dbkey) return nil if result.nil? deserialize_value(result) else result = if withscores dbclient.zrandmember(dbkey, count, withscores: true) else dbclient.zrandmember(dbkey, count) end return [] if result.nil? || result.empty? if withscores result.map { |member, score| [deserialize_value(member), score.to_f] } else deserialize_values(*result) end end end |
#range(sidx, eidx, opts = {}) ⇒ Object
319 320 321 322 323 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 319 def range(sidx, eidx, opts = {}) echo :range, Familia.pretty_stack(limit: 1) if Familia.debug elements = rangeraw(sidx, eidx, opts) deserialize_values(*elements) end |
#rangebylex(min, max, limit: nil) ⇒ Array
Returns members in a lexicographical range (requires all members have same score).
579 580 581 582 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 579 def rangebylex(min, max, limit: nil) result = dbclient.zrangebylex(dbkey, min, max, limit: limit) deserialize_values(*result) end |
#rangebyscore(sscore, escore, opts = {}) ⇒ Object
e.g. obj.metrics.rangebyscore (now-12.hours), now, :limit => [0, 10]
341 342 343 344 345 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 341 def rangebyscore(sscore, escore, opts = {}) echo :rangebyscore, Familia.pretty_stack(limit: 1) if Familia.debug elements = rangebyscoreraw(sscore, escore, opts) deserialize_values(*elements) end |
#rangebyscoreraw(sscore, escore, opts = {}) ⇒ Object
347 348 349 350 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 347 def rangebyscoreraw(sscore, escore, opts = {}) echo :rangebyscoreraw, Familia.pretty_stack(limit: 1) if Familia.debug dbclient.zrangebyscore(dbkey, sscore, escore, **opts) end |
#rangeraw(sidx, eidx, opts = {}) ⇒ Object
325 326 327 328 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 325 def rangeraw(sidx, eidx, opts = {}) # NOTE: Redis 5.x gem uses :with_scores (with underscore) dbclient.zrange(dbkey, sidx, eidx, **opts) end |
#rank(v) ⇒ Object
rank of member +v+ when ordered lowest to highest (starts at 0)
196 197 198 199 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 196 def rank(v) ret = dbclient.zrank dbkey, serialize_value(v) ret&.to_i end |
#remove_element(value) ⇒ Integer Also known as: remove
Removes a member from the sorted set
396 397 398 399 400 401 402 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 396 def remove_element(value) warn_if_dirty! Familia.trace :REMOVE_ELEMENT, nil, "#{value}<#{value.class}>" if Familia.debug? ret = dbclient.zrem dbkey, serialize_value(value) update_expiration ret end |
#remrangebylex(min, max) ⇒ Integer
Removes members in a lexicographical range.
602 603 604 605 606 607 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 602 def remrangebylex(min, max) warn_if_dirty! result = dbclient.zremrangebylex(dbkey, min, max) update_expiration result end |
#remrangebyrank(srank, erank) ⇒ Object
365 366 367 368 369 370 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 365 def remrangebyrank(srank, erank) warn_if_dirty! ret = dbclient.zremrangebyrank dbkey, srank, erank update_expiration ret end |
#remrangebyscore(sscore, escore) ⇒ Object
372 373 374 375 376 377 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 372 def remrangebyscore(sscore, escore) warn_if_dirty! ret = dbclient.zremrangebyscore dbkey, sscore, escore update_expiration ret end |
#revmembers(count = -1,, opts = {}) ⇒ Object
221 222 223 224 225 226 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 221 def revmembers(count = -1, opts = {}) # See #members: revmembersraw already converts a positive count to the # correct end index; decrementing here as well would drop one element. elements = revmembersraw count, opts deserialize_values(*elements) end |
#revmembersraw(count = -1,, opts = {}) ⇒ Object
228 229 230 231 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 228 def revmembersraw(count = -1, opts = {}) count -= 1 if count.positive? revrangeraw 0, count, opts end |
#revrange(sidx, eidx, opts = {}) ⇒ Object
330 331 332 333 334 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 330 def revrange(sidx, eidx, opts = {}) echo :revrange, Familia.pretty_stack(limit: 1) if Familia.debug elements = revrangeraw(sidx, eidx, opts) deserialize_values(*elements) end |
#revrangebylex(max, min, limit: nil) ⇒ Array
Returns members in reverse lexicographical range.
591 592 593 594 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 591 def revrangebylex(max, min, limit: nil) result = dbclient.zrevrangebylex(dbkey, max, min, limit: limit) deserialize_values(*result) end |
#revrangebyscore(sscore, escore, opts = {}) ⇒ Object
e.g. obj.metrics.revrangebyscore (now-12.hours), now, :limit => [0, 10]
353 354 355 356 357 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 353 def revrangebyscore(sscore, escore, opts = {}) echo :revrangebyscore, Familia.pretty_stack(limit: 1) if Familia.debug elements = revrangebyscoreraw(sscore, escore, opts) deserialize_values(*elements) end |
#revrangebyscoreraw(sscore, escore, opts = {}) ⇒ Object
359 360 361 362 363 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 359 def revrangebyscoreraw(sscore, escore, opts = {}) echo :revrangebyscoreraw, Familia.pretty_stack(limit: 1) if Familia.debug opts[:with_scores] = true if opts[:withscores] dbclient.zrevrangebyscore(dbkey, sscore, escore, **opts) end |
#revrangeraw(sidx, eidx, opts = {}) ⇒ Object
336 337 338 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 336 def revrangeraw(sidx, eidx, opts = {}) dbclient.zrevrange(dbkey, sidx, eidx, **opts) end |
#revrank(v) ⇒ Object
rank of member +v+ when ordered highest to lowest (starts at 0)
202 203 204 205 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 202 def revrank(v) ret = dbclient.zrevrank dbkey, serialize_value(v) ret&.to_i end |
#scan(cursor = 0, match: nil, count: nil) ⇒ Array
Iterates over members using cursor-based scanning.
675 676 677 678 679 680 681 682 683 684 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 675 def scan(cursor = 0, match: nil, count: nil) opts = {} opts[:match] = match if match opts[:count] = count if count new_cursor, result = dbclient.zscan(dbkey, cursor, **opts) members = result.map { |member, score| [deserialize_value(member), score.to_f] } [new_cursor.to_i, members] end |
#score(val) ⇒ Object Also known as: []
183 184 185 186 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 183 def score(val) ret = dbclient.zscore dbkey, serialize_value(val) ret&.to_f end |
#score_count(min, max) ⇒ Integer Also known as: zcount
Counts members within a score range.
503 504 505 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 503 def score_count(min, max) dbclient.zcount(dbkey, min, max) end |
#selectraw ⇒ Object
315 316 317 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 315 def selectraw(&) membersraw.select(&) end |
#union(*other_sets, weights: nil, aggregate: nil, withscores: false) ⇒ Array
Returns the union of this sorted set with other sorted sets.
540 541 542 543 544 545 546 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 540 def union(*other_sets, weights: nil, aggregate: nil, withscores: false) keys = [dbkey] + resolve_set_keys(other_sets) opts = build_set_operation_opts(weights: weights, aggregate: aggregate, withscores: withscores) result = dbclient.zunion(*keys, **opts) process_set_operation_result(result, withscores: withscores) end |
#unionstore(destination, *other_sets, weights: nil, aggregate: nil) ⇒ Integer
Stores the union of sorted sets into a destination key.
694 695 696 697 698 699 700 701 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 694 def unionstore(destination, *other_sets, weights: nil, aggregate: nil) keys = [dbkey] + resolve_set_keys(other_sets) opts = build_set_operation_opts(weights: weights, aggregate: aggregate) result = dbclient.zunionstore(destination, keys, **opts) update_expiration result end |
#update(hsh = {}) ⇒ Integer Also known as: merge!
Unlike single-value #add, scores are required: this bulk path does not default a missing score to Familia.now. A non-Numeric score (e.g. nil) raises ArgumentError rather than surfacing a low-level client error.
Like #add, this executes immediately (not deferred) and cascades expiration. Empty input is a no-op returning 0.
Bulk-adds or updates multiple members in a single ZADD.
Mirrors HashKey#update/merge! -- the established Familia pattern for bulk-setting keyed collections. A sorted set is member => score, the same pair shape as HashKey's field => value, so it takes a Hash rather than the variadic splat used by the value-only UnsortedSet/ListKey.
Issues exactly one ZADD instead of one round-trip per member, which is what makes populating a large sorted set fast.
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/familia/data_type/types/sorted_set.rb', line 165 def update(hsh = {}) warn_if_dirty! raise ArgumentError, 'Argument to bulk add must be a hash' unless hsh.is_a?(Hash) return 0 if hsh.empty? pairs = hsh.map do |member, score| unless score.is_a?(Numeric) raise ArgumentError, "SortedSet#update score for #{member.inspect} must be Numeric, got #{score.class}" end [score, serialize_value(member)] end ret = dbclient.zadd(dbkey, pairs) update_expiration ret end |