File: legacy_hooks_trace.rb

package info (click to toggle)
ruby-graphql 2.2.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,584 kB
  • sloc: ruby: 67,505; ansic: 1,753; yacc: 831; javascript: 331; makefile: 6
file content (74 lines) | stat: -rw-r--r-- 2,585 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
# frozen_string_literal: true
module GraphQL
  module Tracing
    module LegacyHooksTrace
      def execute_multiplex(multiplex:)
        multiplex_instrumenters = multiplex.schema.instrumenters[:multiplex]
        query_instrumenters = multiplex.schema.instrumenters[:query]
        # First, run multiplex instrumentation, then query instrumentation for each query
        RunHooks.call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
          RunHooks.each_query_call_hooks(query_instrumenters, multiplex.queries) do
            super
          end
        end
      end

      module RunHooks
        module_function
        # Call the before_ hooks of each query,
        # Then yield if no errors.
        # `call_hooks` takes care of appropriate cleanup.
        def each_query_call_hooks(instrumenters, queries, i = 0)
          if i >= queries.length
            yield
          else
            query = queries[i]
            call_hooks(instrumenters, query, :before_query, :after_query) {
              each_query_call_hooks(instrumenters, queries, i + 1) {
                yield
              }
            }
          end
        end

        # Call each before hook, and if they all succeed, yield.
        # If they don't all succeed, call after_ for each one that succeeded.
        def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
          begin
            successful = []
            instrumenters.each do |instrumenter|
              instrumenter.public_send(before_hook_name, object)
              successful << instrumenter
            end

            # if any before hooks raise an exception, quit calling before hooks,
            # but call the after hooks on anything that succeeded but also
            # raise the exception that came from the before hook.
          rescue GraphQL::ExecutionError => err
            object.context.errors << err
          rescue => e
            raise call_after_hooks(successful, object, after_hook_name, e)
          end

          begin
            yield # Call the user code
          ensure
            ex = call_after_hooks(successful, object, after_hook_name, nil)
            raise ex if ex
          end
        end

        def call_after_hooks(instrumenters, object, after_hook_name, ex)
          instrumenters.reverse_each do |instrumenter|
            begin
              instrumenter.public_send(after_hook_name, object)
            rescue => e
              ex = e
            end
          end
          ex
        end
      end
    end
  end
end