graphql-persisted_queries 1.5.1 β†’ 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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