File: transactions.rb

package info (click to toggle)
ruby-redis 5.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,160 kB
  • sloc: ruby: 11,445; makefile: 117; sh: 24
file content (115 lines) | stat: -rw-r--r-- 3,037 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# frozen_string_literal: true

class Redis
  module Commands
    module Transactions
      # Mark the start of a transaction block.
      #
      # @example With a block
      #   redis.multi do |multi|
      #     multi.set("key", "value")
      #     multi.incr("counter")
      #   end # => ["OK", 6]
      #
      # @yield [multi] the commands that are called inside this block are cached
      #   and written to the server upon returning from it
      # @yieldparam [Redis] multi `self`
      #
      # @return [Array<...>]
      #   - an array with replies
      #
      # @see #watch
      # @see #unwatch
      def multi
        synchronize do |client|
          client.multi do |raw_transaction|
            yield MultiConnection.new(raw_transaction)
          end
        end
      end

      # Watch the given keys to determine execution of the MULTI/EXEC block.
      #
      # Using a block is optional, but is necessary for thread-safety.
      #
      # An `#unwatch` is automatically issued if an exception is raised within the
      # block that is a subclass of StandardError and is not a ConnectionError.
      #
      # @example With a block
      #   redis.watch("key") do
      #     if redis.get("key") == "some value"
      #       redis.multi do |multi|
      #         multi.set("key", "other value")
      #         multi.incr("counter")
      #       end
      #     else
      #       redis.unwatch
      #     end
      #   end
      #     # => ["OK", 6]
      #
      # @example Without a block
      #   redis.watch("key")
      #     # => "OK"
      #
      # @param [String, Array<String>] keys one or more keys to watch
      # @return [Object] if using a block, returns the return value of the block
      # @return [String] if not using a block, returns `OK`
      #
      # @see #unwatch
      # @see #multi
      def watch(*keys)
        synchronize do |client|
          res = client.call_v([:watch] + keys)

          if block_given?
            begin
              yield(self)
            rescue ConnectionError
              raise
            rescue StandardError
              unwatch
              raise
            end
          else
            res
          end
        end
      end

      # Forget about all watched keys.
      #
      # @return [String] `OK`
      #
      # @see #watch
      # @see #multi
      def unwatch
        send_command([:unwatch])
      end

      # Execute all commands issued after MULTI.
      #
      # Only call this method when `#multi` was called **without** a block.
      #
      # @return [nil, Array<...>]
      #   - when commands were not executed, `nil`
      #   - when commands were executed, an array with their replies
      #
      # @see #multi
      # @see #discard
      def exec
        send_command([:exec])
      end

      # Discard all commands issued after MULTI.
      #
      # @return [String] `"OK"`
      #
      # @see #multi
      # @see #exec
      def discard
        send_command([:discard])
      end
    end
  end
end