Class: Familia::MultiResult
- Inherits:
-
Object
- Object
- Familia::MultiResult
- Defined in:
- lib/familia/multi_result.rb
Overview
Represents the result of a Valkey/Redis transaction or pipeline operation.
This class encapsulates the outcome of a Database multi-command operation, providing access to both the command results and derived success status based on the presence of errors in the results.
A multi-command operation has three possible outcomes:
- Committed cleanly -- every queued command returned a value.
- Committed with errors -- the commands ran, but one or more returned an Exception object. Redis returns failed commands inside a transaction as exception objects rather than raising them, so the remaining commands still execute. #errors collects them.
- Aborted -- EXEC was discarded and no command ran at all. This is the documented outcome of a WATCH-guarded transaction whose watched key was modified by another client; redis-rb signals it by returning nil instead of an array. See #aborted?.
An aborted operation is a failure, but not an error in the sense of (2): no command ran, so there is nothing for #errors to report. #successful? is the method to test for the overall outcome; #errors? answers the narrower question of whether any individual command failed.
#results is always an Array -- an aborted operation reports an empty one rather than nil, so callers can index and iterate it unconditionally. Use #aborted? to tell an abort apart from an operation that committed zero commands.
Instances are read-only: #results and #errors are both frozen, since this object describes an operation that has already finished.
Instance Attribute Summary collapse
-
#results ⇒ Array
readonly
The raw return values from the Database commands.
Instance Method Summary collapse
-
#aborted? ⇒ Boolean
Whether the operation was discarded instead of executed.
-
#errors ⇒ Array<Exception>
Returns all Exception objects from the results array.
-
#errors? ⇒ Boolean
Checks if any individual command failed.
-
#initialize(results) ⇒ MultiResult
constructor
Creates a new MultiResult instance.
-
#inspect ⇒ String
Returns a summary of the outcome for logging and debugging.
-
#size ⇒ Integer
Returns the number of results in the multi-operation.
-
#successful? ⇒ Boolean
(also: #success?, #areyouhappynow?)
Checks if the operation ran and all commands completed successfully.
-
#to_h ⇒ Hash
Returns a hash representation of the result.
-
#tuple ⇒ Array
(also: #to_a)
Returns a tuple representing the result of the operation.
Constructor Details
#initialize(results) ⇒ MultiResult
Creates a new MultiResult instance.
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/familia/multi_result.rb', line 82 def initialize(results) @aborted = results.nil? # Frozen because this object describes an operation that already # finished -- its return values are history, not a working buffer. It # also keeps the memo in #errors coherent: that array is derived from # this one and cached, so a caller mutating this one afterwards would # leave the two disagreeing. Each instance freezes its own array rather # than sharing a constant, so no two results alias the same object. @results = (results || []).freeze end |
Instance Attribute Details
#results ⇒ Array (readonly)
Returns The raw return values from the Database commands. Always a frozen Array; empty for an aborted operation.
71 72 73 |
# File 'lib/familia/multi_result.rb', line 71 def results @results end |
Instance Method Details
#aborted? ⇒ Boolean
Whether the operation was discarded instead of executed.
redis-rb returns nil from #multi when EXEC is aborted, which happens when a WATCH-guarded transaction detects that a watched key changed under it. An aborted transaction applied none of its commands, so it reports no errors (#errors is empty) but is also not successful -- callers should retry rather than treat it as a no-op success.
This is the only way to distinguish an abort from an operation that committed zero commands, since both report an empty #results.
105 106 107 |
# File 'lib/familia/multi_result.rb', line 105 def aborted? @aborted end |
#errors ⇒ Array<Exception>
Returns all Exception objects from the results array.
This method is memoized for performance when called multiple times on the same MultiResult instance. The returned array is frozen: it is derived state backing that memo, not a collection for callers to modify.
118 119 120 |
# File 'lib/familia/multi_result.rb', line 118 def errors @errors ||= results.grep(Exception).freeze end |
#errors? ⇒ Boolean
Checks if any individual command failed.
An aborted operation reports false here -- it failed, but not because a command errored. Use #successful? to test the overall outcome.
128 129 130 |
# File 'lib/familia/multi_result.rb', line 128 def errors? !errors.empty? end |
#inspect ⇒ String
Returns a summary of the outcome for logging and debugging.
Deliberately omits the command return values: they routinely carry field values read back out of the database, which have no business landing in a log line or an exception trace by default. Reach for #results when the values are what you actually want.
189 190 191 |
# File 'lib/familia/multi_result.rb', line 189 def inspect "#<#{self.class.name} #{outcome} size=#{size}>" end |
#size ⇒ Integer
Returns the number of results in the multi-operation.
163 164 165 |
# File 'lib/familia/multi_result.rb', line 163 def size results.size end |
#successful? ⇒ Boolean Also known as: success?, areyouhappynow?
Checks if the operation ran and all commands completed successfully.
This is the primary method for determining if a multi-command operation completed without errors.
139 140 141 |
# File 'lib/familia/multi_result.rb', line 139 def successful? !aborted? && errors.empty? end |
#to_h ⇒ Hash
Returns a hash representation of the result.
Includes :aborted so a failed result is self-describing -- otherwise a dumped abort is indistinguishable from a failure whose errors went missing.
The :results value is this object's own frozen array, not a copy, so a caller cannot reach through the hash to mutate internal state.
177 178 179 |
# File 'lib/familia/multi_result.rb', line 177 def to_h { success: successful?, aborted: aborted?, results: results } end |
#tuple ⇒ Array Also known as: to_a
Returns a tuple representing the result of the operation.
154 155 156 |
# File 'lib/familia/multi_result.rb', line 154 def tuple [successful?, results] end |