graphql-persisted_queries 1.5.1 β†’ 1.6.1

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: fa710e0a1af1fe00953679781bf408f3c78201b67920671f9af36ff57edefcc0
4
+ data.tar.gz: cc46697bf61938af0d4359fb9b5bf4898f3bc5108b4f562f94d3003a857064a6
5
5
  SHA512:
6
- metadata.gz: b070e30dea650ae02e6164440cd1b7b1a73796b98db7e691c8ff10fce9b5eb9351daebcbf68f2d2d3e7d2ccdf8bb6503f00eae2060a674be66d1229811e3f375
7
- data.tar.gz: cb4f0137249ab7414857af926833de0d8060a8fc77eb7f29fb2853dfcb22f85382ed8341169a7b0015c21fd52429b7e735c67e1923545ba69d44441166c217e6
6
+ metadata.gz: 6028cb87dc1e0c7a78f18f29c7afbff2d2aae46fadbec983d6ebbb217016523a8722f27c993570b914b3fec6cebe0d16ad26e7091844a0e60f4bf0d80217cb11
7
+ data.tar.gz: a0d0dada8b7f34298a69aed43dd988ce077e010866faf33c8d206375ee0cb2f00afed1f0794753983a5b2b01f266888f7988d77a031f33c6f55d2779abd62e35
@@ -20,11 +20,10 @@ 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",
26
+ "gemfiles/graphql_1_13_16.gemfile",
28
27
  "gemfiles/graphql_2_0_0.gemfile",
29
28
  "gemfiles/graphql_master.gemfile"
30
29
  ]
@@ -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,15 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.6.1 (2022-11-17)
6
+
7
+ - [PR#60](https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries/pull/60)
8
+ Handle situations when prepare_ast happens before instrumentation ([@DmitryTsepelev][])
9
+
10
+ ## 1.6.0 (2022-10-10)
11
+
12
+ - [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][])
13
+
5
14
  ## 1.5.1 (2022-09-28)
6
15
 
7
16
  - [PR#56](https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries/pull/56) Support graphql-ruby 2.0.14 ([@DmitryTsepelev][])
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GraphQL::PersistedQueries
1
+ # GraphQL::PersistedQueries ![](https://ruby-gem-downloads-badge.herokuapp.com/graphql-persisted_queries?type=total)
2
2
 
3
3
  `GraphQL::PersistedQueries` is the implementation of [persisted queries](https://www.apollographql.com/docs/react/api/link/persisted-queries/) for [graphql-ruby](https://github.com/rmosolgo/graphql-ruby). With this plugin your backend will cache all the queries, while frontend will send the full query only when it's not found at the backend storage.
4
4
 
@@ -6,13 +6,6 @@
6
6
  - 🀝**Clients share cached queries** – it's enough to miss cache only once for each unique query
7
7
  - πŸŽ…**Works for clients without persisted query support**
8
8
 
9
-
10
- <p align="center">
11
- <a href="https://evilmartians.com/?utm_source=graphql-ruby-persisted_queries">
12
- <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
13
- </a>
14
- </p>
15
-
16
9
  ## Getting started
17
10
 
18
11
  First of all, install and configure [apollo's persisted queries](https://www.apollographql.com/docs/react/api/link/persisted-queries/) on the front–end side:
@@ -92,6 +85,10 @@ An experimental tracing feature can be enabled by setting `tracing: true` when c
92
85
  > πŸ“– Read more about the gem internals: [Persisted queries in GraphQL:
93
86
  Slim down Apollo requests to your Ruby application](https://evilmartians.com/chronicles/persisted-queries-in-graphql-slim-down-apollo-requests-to-your-ruby-application)
94
87
 
88
+ ## Credits
89
+
90
+ Initially sponsored by [Evil Martians](http://evilmartians.com).
91
+
95
92
  ## Contributing
96
93
 
97
94
  Bug reports and pull requests are welcome on GitHub at https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries.
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "graphql", "~> 1.10.0"
3
+ gem "graphql", "~> 1.13.16"
4
4
 
5
5
  gemspec path: "../"
@@ -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,25 @@
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
+ query.try_load_document!
14
+ return if query.document || query.query_string
15
+
16
+ query.persisted_query_not_found!
17
+ query.context.errors << GraphQL::ExecutionError.new(NotFound::MESSAGE)
18
+ end
19
+
20
+ def after_query(*); end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ 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,28 +5,47 @@ module GraphQL
5
5
  module CompiledQueries
6
6
  # Patches GraphQL::Query to support compiled queries
7
7
  module QueryPatch
8
+ def persisted_query_not_found!
9
+ @persisted_query_not_found = true
10
+ end
11
+
8
12
  def persisted_query_not_found?
9
13
  @persisted_query_not_found
10
14
  end
11
15
 
12
16
  def prepare_ast
13
- return super unless @context[:extensions]
14
-
15
- @document = resolver.fetch
16
- not_loaded_document = @document.nil?
17
+ return super if @context[:extensions].nil? || @document
17
18
 
18
- @persisted_query_not_found = not_loaded_document && query_string.nil?
19
+ try_load_document!
19
20
 
20
21
  super.tap do
21
- resolver.persist(query_string, @document) if not_loaded_document && query_string
22
+ if @context.errors.any?(&method(:not_found_error?))
23
+ @context.errors.select!(&method(:not_found_error?))
24
+ end
25
+
26
+ if @persisted_document_not_found && query_string
27
+ resolver.persist(query_string, @document)
28
+ end
22
29
  end
23
30
  end
24
31
 
32
+ def try_load_document!
33
+ return if @document || @persisted_document_not_found
34
+
35
+ compiled_query_resolver = CompiledQueries::Resolver.new(schema, context[:extensions])
36
+ @document = compiled_query_resolver.fetch
37
+ @persisted_document_not_found = @document.nil?
38
+ end
39
+
25
40
  private
26
41
 
27
42
  def resolver
28
43
  @resolver ||= Resolver.new(@schema, @context[:extensions])
29
44
  end
45
+
46
+ def not_found_error?(error)
47
+ error.message == GraphQL::PersistedQueries::NotFound::MESSAGE
48
+ end
30
49
  end
31
50
  end
32
51
  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.1"
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.1
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-11-17 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,10 +136,9 @@ 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
141
+ - gemfiles/graphql_1_13_16.gemfile
143
142
  - gemfiles/graphql_1_13_7.gemfile
144
143
  - gemfiles/graphql_2_0_0.gemfile
145
144
  - gemfiles/graphql_master.gemfile
@@ -149,7 +148,7 @@ files:
149
148
  - lib/graphql/persisted_queries/analyzers/http_method_ast_analyzer.rb
150
149
  - lib/graphql/persisted_queries/analyzers/http_method_validator.rb
151
150
  - lib/graphql/persisted_queries/builder_helpers.rb
152
- - lib/graphql/persisted_queries/compiled_queries/interpreter_patch.rb
151
+ - lib/graphql/persisted_queries/compiled_queries/instrumentation.rb
153
152
  - lib/graphql/persisted_queries/compiled_queries/multiplex_patch.rb
154
153
  - lib/graphql/persisted_queries/compiled_queries/query_patch.rb
155
154
  - lib/graphql/persisted_queries/compiled_queries/resolver.rb
@@ -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