graphql-persisted_queries 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78784d32983df6d9d75af398dcf87f1239e37dce760eb99b73c3ebcf5856ee8c
4
- data.tar.gz: d2e0a437767dfa2a148654b32ebfe7669167273fcf123de9b9834ac733cc3f03
3
+ metadata.gz: 7a8319ef6ac9b60ce31f69b86163c9c77f700b2d663da6ab10018b76c96ebc2f
4
+ data.tar.gz: b197af199c9699cda0a7c3c5491d2f22b110b77f61a7632a1982ca3acbc49292
5
5
  SHA512:
6
- metadata.gz: b070e30dea650ae02e6164440cd1b7b1a73796b98db7e691c8ff10fce9b5eb9351daebcbf68f2d2d3e7d2ccdf8bb6503f00eae2060a674be66d1229811e3f375
7
- data.tar.gz: cb4f0137249ab7414857af926833de0d8060a8fc77eb7f29fb2853dfcb22f85382ed8341169a7b0015c21fd52429b7e735c67e1923545ba69d44441166c217e6
6
+ metadata.gz: 2f6f9f3d32aad7d89b263f60701c30f06cba0bb43934fa18360e70ef979c1bdf1f28050859b92788040a600e8d803d850f753383d700243dbdea0b59973bcaf5
7
+ data.tar.gz: 5505e5d9b983b8dc2a510dd17fe417eee561bc337da0deb203030b6f0889732ea46b5d76dc9694d5129ddc7538f43467040dcbe907651863b6a26d3c9888a2b3
@@ -20,8 +20,6 @@ jobs:
20
20
  matrix:
21
21
  ruby: [2.6, 2.7, 3.0]
22
22
  gemfile: [
23
- "gemfiles/graphql_1_10.gemfile",
24
- "gemfiles/graphql_1_11.gemfile",
25
23
  "gemfiles/graphql_1_12_0.gemfile",
26
24
  "gemfiles/graphql_1_12_4.gemfile",
27
25
  "gemfiles/graphql_1_13_7.gemfile",
@@ -17,5 +17,5 @@ jobs:
17
17
  ruby-version: 2.7
18
18
  - name: Lint Ruby code with RuboCop
19
19
  run: |
20
- bundle install --gemfile gemfiles/graphql_1_10.gemfile --jobs 4 --retry 3
21
- bundle exec --gemfile gemfiles/graphql_1_10.gemfile rubocop
20
+ bundle install --gemfile gemfiles/graphql_1_12_0.gemfile --jobs 4 --retry 3
21
+ bundle exec --gemfile gemfiles/graphql_1_12_0.gemfile rubocop
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.6.0 (2022-10-10)
6
+
7
+ - [PR#57](https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries/pull/57) Refactor code to use instrumentation instead of a monkey patch, deprecate graphql-ruby 1.10 and 1.11 ([@DmitryTsepelev][])
8
+
5
9
  ## 1.5.1 (2022-09-28)
6
10
 
7
11
  - [PR#56](https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries/pull/56) Support graphql-ruby 2.0.14 ([@DmitryTsepelev][])
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.required_ruby_version = ">= 2.6"
24
24
 
25
- spec.add_dependency "graphql", ">= 1.10"
25
+ spec.add_dependency "graphql", ">= 1.12"
26
26
 
27
27
  spec.add_development_dependency "rspec", "~> 3.9"
28
28
  spec.add_development_dependency "rake", ">= 10.0"
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module PersistedQueries
5
+ module CompiledQueries
6
+ # Instrumentation to support compiled queries
7
+ module Instrumentation
8
+ class << self
9
+ # Actions to perform before the query resolution
10
+ def before_query(query)
11
+ return unless query.context[:extensions]
12
+
13
+ resolver = resolver_for(query)
14
+ if (document = resolver.fetch)
15
+ query.fulfill_document(document)
16
+ else
17
+ query.not_loaded_document!
18
+ end
19
+
20
+ return if document || query.query_string
21
+
22
+ query.persisted_query_not_found!
23
+ query.context.errors << GraphQL::ExecutionError.new(NotFound::MESSAGE)
24
+ end
25
+
26
+ def after_query(*); end
27
+
28
+ private
29
+
30
+ def resolver_for(query)
31
+ CompiledQueries::Resolver.new(query.schema, query.context[:extensions])
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -21,7 +21,7 @@ module GraphQL
21
21
 
22
22
  def add_not_found_error(query)
23
23
  query.context.errors.clear
24
- query.context.errors << GraphQL::ExecutionError.new("PersistedQueryNotFound")
24
+ query.context.errors << GraphQL::ExecutionError.new(NotFound::MESSAGE)
25
25
  GraphQL::Execution::Multiplex::NO_OPERATION
26
26
  end
27
27
  end
@@ -5,6 +5,18 @@ module GraphQL
5
5
  module CompiledQueries
6
6
  # Patches GraphQL::Query to support compiled queries
7
7
  module QueryPatch
8
+ def fulfill_document(document)
9
+ @document = document
10
+ end
11
+
12
+ def not_loaded_document!
13
+ @not_loaded_document = true
14
+ end
15
+
16
+ def persisted_query_not_found!
17
+ @persisted_query_not_found = true
18
+ end
19
+
8
20
  def persisted_query_not_found?
9
21
  @persisted_query_not_found
10
22
  end
@@ -12,13 +24,12 @@ module GraphQL
12
24
  def prepare_ast
13
25
  return super unless @context[:extensions]
14
26
 
15
- @document = resolver.fetch
16
- not_loaded_document = @document.nil?
17
-
18
- @persisted_query_not_found = not_loaded_document && query_string.nil?
19
-
20
27
  super.tap do
21
- resolver.persist(query_string, @document) if not_loaded_document && query_string
28
+ if @context.errors.any?(&method(:not_found_error?))
29
+ @context.errors.select!(&method(:not_found_error?))
30
+ end
31
+
32
+ resolver.persist(query_string, @document) if @not_loaded_document && query_string
22
33
  end
23
34
  end
24
35
 
@@ -27,6 +38,10 @@ module GraphQL
27
38
  def resolver
28
39
  @resolver ||= Resolver.new(@schema, @context[:extensions])
29
40
  end
41
+
42
+ def not_found_error?(error)
43
+ error.message == GraphQL::PersistedQueries::NotFound::MESSAGE
44
+ end
30
45
  end
31
46
  end
32
47
  end
@@ -4,8 +4,10 @@ module GraphQL
4
4
  module PersistedQueries
5
5
  # Raised when persisted query is not found in the storage
6
6
  class NotFound < StandardError
7
+ MESSAGE = "PersistedQueryNotFound"
8
+
7
9
  def message
8
- "PersistedQueryNotFound"
10
+ MESSAGE
9
11
  end
10
12
  end
11
13
 
@@ -3,6 +3,7 @@
3
3
  require "graphql/persisted_queries/hash_generator_builder"
4
4
  require "graphql/persisted_queries/resolver"
5
5
  require "graphql/persisted_queries/multiplex_resolver"
6
+ require "graphql/persisted_queries/compiled_queries/instrumentation"
6
7
  require "graphql/persisted_queries/analyzers/http_method_validator"
7
8
 
8
9
  module GraphQL
@@ -13,10 +14,12 @@ module GraphQL
13
14
  def patch(schema, compiled_queries)
14
15
  schema.singleton_class.prepend(SchemaPatch)
15
16
 
16
- return if compiled_queries
17
-
18
- schema.singleton_class.class_eval { alias_method :multiplex_original, :multiplex }
19
- schema.singleton_class.prepend(MultiplexPatch)
17
+ if compiled_queries
18
+ schema.instrument :query, CompiledQueries::Instrumentation
19
+ else
20
+ schema.singleton_class.class_eval { alias_method :multiplex_original, :multiplex }
21
+ schema.singleton_class.prepend(MultiplexPatch)
22
+ end
20
23
  end
21
24
  end
22
25
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module PersistedQueries
5
- VERSION = "1.5.1"
5
+ VERSION = "1.6.0"
6
6
  end
7
7
  end
@@ -10,7 +10,6 @@ require "graphql/persisted_queries/builder_helpers"
10
10
 
11
11
  require "graphql/persisted_queries/compiled_queries/resolver"
12
12
  require "graphql/persisted_queries/compiled_queries/multiplex_patch"
13
- require "graphql/persisted_queries/compiled_queries/interpreter_patch"
14
13
  require "graphql/persisted_queries/compiled_queries/query_patch"
15
14
 
16
15
  module GraphQL
@@ -38,16 +37,12 @@ module GraphQL
38
37
  end
39
38
  # rubocop:enable Metrics/MethodLength
40
39
 
41
- def self.configure_compiled_queries # rubocop:disable Metrics/MethodLength
40
+ def self.configure_compiled_queries
42
41
  if Gem::Dependency.new("graphql", "< 1.12.0").match?("graphql", GraphQL::VERSION)
43
42
  raise ArgumentError, "compiled_queries are not supported for graphql-ruby < 1.12.0"
44
43
  end
45
44
 
46
- if Gem::Dependency.new("graphql", ">= 2.0.14").match?("graphql", GraphQL::VERSION)
47
- GraphQL::Execution::Interpreter.singleton_class.prepend(
48
- GraphQL::PersistedQueries::CompiledQueries::InterpreterPatch
49
- )
50
- else
45
+ if Gem::Dependency.new("graphql", "< 2.0.14").match?("graphql", GraphQL::VERSION)
51
46
  GraphQL::Execution::Multiplex.singleton_class.prepend(
52
47
  GraphQL::PersistedQueries::CompiledQueries::MultiplexPatch
53
48
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-persisted_queries
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DmitryTsepelev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-28 00:00:00.000000000 Z
11
+ date: 2022-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '1.12'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.10'
26
+ version: '1.12'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -136,8 +136,6 @@ files:
136
136
  - docs/hash.md
137
137
  - docs/http_cache.md
138
138
  - docs/tracing.md
139
- - gemfiles/graphql_1_10.gemfile
140
- - gemfiles/graphql_1_11.gemfile
141
139
  - gemfiles/graphql_1_12_0.gemfile
142
140
  - gemfiles/graphql_1_12_4.gemfile
143
141
  - gemfiles/graphql_1_13_7.gemfile
@@ -149,7 +147,7 @@ files:
149
147
  - lib/graphql/persisted_queries/analyzers/http_method_ast_analyzer.rb
150
148
  - lib/graphql/persisted_queries/analyzers/http_method_validator.rb
151
149
  - lib/graphql/persisted_queries/builder_helpers.rb
152
- - lib/graphql/persisted_queries/compiled_queries/interpreter_patch.rb
150
+ - lib/graphql/persisted_queries/compiled_queries/instrumentation.rb
153
151
  - lib/graphql/persisted_queries/compiled_queries/multiplex_patch.rb
154
152
  - lib/graphql/persisted_queries/compiled_queries/query_patch.rb
155
153
  - lib/graphql/persisted_queries/compiled_queries/resolver.rb
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "graphql", "~> 1.10.0"
4
-
5
- gemspec path: "../"
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "graphql", "~> 1.11.0"
4
-
5
- gemspec path: "../"
@@ -1,162 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQL
4
- module PersistedQueries
5
- module CompiledQueries
6
- # Patches GraphQL::Execution::Multiplex to support compiled queries
7
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Layout/IndentationWidth
8
- # rubocop:disable Metrics/PerceivedComplexity, Metrics/ModuleLength, Metrics/LineLength
9
- # rubocop:disable Metrics/BlockLength, Style/BracesAroundHashParameters, Style/CommentAnnotation
10
- # rubocop:disable Naming/RescuedExceptionsVariableName, Layout/SpaceInsideHashLiteralBraces
11
- # rubocop:disable Lint/ShadowingOuterLocalVariable, Style/BlockDelimiters, Metrics/MethodLength
12
- # rubocop:disable Style/Next, Layout/ElseAlignment, Layout/EndAlignment, Lint/RescueException
13
- module InterpreterPatch
14
- # This method is fully copied from the gem because I didn't find a way to patch it. In future we will
15
- # need to keep it in sync and migrate the monkey patch to newer versions of the file.
16
- def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
17
- queries = query_options.map do |opts|
18
- case opts
19
- when Hash
20
- GraphQL::Query.new(schema, nil, **opts)
21
- when GraphQL::Query
22
- opts
23
- else
24
- raise "Expected Hash or GraphQL::Query, not #{opts.class} (#{opts.inspect})"
25
- end
26
- end
27
-
28
- multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
29
- multiplex.trace("execute_multiplex", { multiplex: multiplex }) do
30
- schema = multiplex.schema
31
- queries = multiplex.queries
32
- query_instrumenters = schema.instrumenters[:query]
33
- multiplex_instrumenters = schema.instrumenters[:multiplex]
34
-
35
- # First, run multiplex instrumentation, then query instrumentation for each query
36
- call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
37
- each_query_call_hooks(query_instrumenters, queries) do
38
- schema = multiplex.schema
39
- multiplex_analyzers = schema.multiplex_analyzers
40
- queries = multiplex.queries
41
- if multiplex.max_complexity
42
- multiplex_analyzers += [GraphQL::Analysis::AST::MaxQueryComplexity]
43
- end
44
-
45
- schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
46
- begin
47
- # Since this is basically the batching context,
48
- # share it for a whole multiplex
49
- multiplex.context[:interpreter_instance] ||= multiplex.schema.query_execution_strategy.new
50
- # Do as much eager evaluation of the query as possible
51
- results = []
52
- queries.each_with_index do |query, idx|
53
- multiplex.dataloader.append_job {
54
- operation = query.selected_operation
55
- result =
56
- # MONKEY PATCH START
57
- if query.persisted_query_not_found?
58
- query.context.errors.clear
59
- query.context.errors << GraphQL::ExecutionError.new("PersistedQueryNotFound")
60
- singleton_class::NO_OPERATION
61
- # MONKEY PATCH END
62
- elsif operation.nil? || !query.valid? || query.context.errors.any?
63
- singleton_class::NO_OPERATION
64
- else
65
- begin
66
- # Although queries in a multiplex _share_ an Interpreter instance,
67
- # they also have another item of state, which is private to that query
68
- # in particular, assign it here:
69
- runtime = GraphQL::Execution::Interpreter::Runtime.new(query: query)
70
- query.context.namespace(:interpreter)[:runtime] = runtime
71
-
72
- query.trace("execute_query", {query: query}) do
73
- runtime.run_eager
74
- end
75
- rescue GraphQL::ExecutionError => err
76
- query.context.errors << err
77
- singleton_class::NO_OPERATION
78
- end
79
- end
80
- results[idx] = result
81
- }
82
- end
83
-
84
- multiplex.dataloader.run
85
-
86
- # Then, work through lazy results in a breadth-first way
87
- multiplex.dataloader.append_job {
88
- tracer = multiplex
89
- query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
90
- queries = multiplex ? multiplex.queries : [query]
91
- final_values = queries.map do |query|
92
- runtime = query.context.namespace(:interpreter)[:runtime]
93
- # it might not be present if the query has an error
94
- runtime ? runtime.final_result : nil
95
- end
96
- final_values.compact!
97
- tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
98
- GraphQL::Execution::Interpreter::Resolve.resolve_all(final_values, multiplex.dataloader)
99
- end
100
- queries.each do |query|
101
- runtime = query.context.namespace(:interpreter)[:runtime]
102
- if runtime
103
- runtime.delete_interpreter_context(:current_path)
104
- runtime.delete_interpreter_context(:current_field)
105
- runtime.delete_interpreter_context(:current_object)
106
- runtime.delete_interpreter_context(:current_arguments)
107
- end
108
- end
109
- }
110
- multiplex.dataloader.run
111
-
112
- # Then, find all errors and assign the result to the query object
113
- results.each_with_index do |data_result, idx|
114
- query = queries[idx]
115
- # Assign the result so that it can be accessed in instrumentation
116
- query.result_values = if data_result.equal?(singleton_class::NO_OPERATION)
117
- if !query.valid? || query.context.errors.any?
118
- # A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
119
- { "errors" => query.static_errors.map(&:to_h) }
120
- else
121
- data_result
122
- end
123
- else
124
- result = {
125
- "data" => query.context.namespace(:interpreter)[:runtime].final_result
126
- }
127
-
128
- if query.context.errors.any?
129
- error_result = query.context.errors.map(&:to_h)
130
- result["errors"] = error_result
131
- end
132
-
133
- result
134
- end
135
- if query.context.namespace?(:__query_result_extensions__)
136
- query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
137
- end
138
- # Get the Query::Result, not the Hash
139
- results[idx] = query.result
140
- end
141
-
142
- results
143
- rescue Exception
144
- # TODO rescue at a higher level so it will catch errors in analysis, too
145
- # Assign values here so that the query's `@executed` becomes true
146
- queries.map { |q| q.result_values ||= {} }
147
- raise
148
- end
149
- end
150
- end
151
- end
152
- end
153
- end
154
- end
155
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Layout/IndentationWidth
156
- # rubocop:enable Metrics/PerceivedComplexity, Metrics/ModuleLength, Metrics/LineLength
157
- # rubocop:enable Metrics/BlockLength, Style/BracesAroundHashParameters, Style/CommentAnnotation
158
- # rubocop:enable Naming/RescuedExceptionsVariableName, Layout/SpaceInsideHashLiteralBraces
159
- # rubocop:enable Lint/ShadowingOuterLocalVariable, Style/BlockDelimiters, Metrics/MethodLength
160
- # rubocop:enable Style/Next, Layout/ElseAlignment, Layout/EndAlignment, Lint/RescueException
161
- end
162
- end