graphql-remote_loader 1.0.5 → 1.0.6

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
  SHA1:
3
- metadata.gz: d72d37be4701ca0a4dd4bad71e989241b8557f01
4
- data.tar.gz: 0e4c7d0613383cd441d2dc887cc7c5647296a780
3
+ metadata.gz: acdeaf8aaaccf5ffeba1afb1f2034fb7d41fba34
4
+ data.tar.gz: c5478e13983b4ca67867571fc25553dadfd82ffa
5
5
  SHA512:
6
- metadata.gz: 53941e0b529fcf5c9f89809de804faf1f52e162c3fa8cccbb2f2c6a0b1f44c8d713a4bf291055504ae75c2fa001f926aa6e15a5bed1acfa949e4ec2d2f3553b1
7
- data.tar.gz: 017da570ea18310a6b3eb4801ffa24ff1e22d087cca6daf2b4d1370813c419443b809dfbdc6337b6f9c0690742b540bb2e0e89b1f3342cf32d12406684f9354e
6
+ metadata.gz: 8d3c97bbe137b06cff20c4687c2088e8ac0819963e1ee5ab493650508de826ecbeee872f13e2356ee00336713d4c52089fccc13e8cefa662f034b1c4e2feccf7
7
+ data.tar.gz: cd28610ee919d38b4f59e6bb271a4ea81a79dfcf5b1559a23fa94621120787fe6324cd4e3feda388af24b52e82fc356320b0b7a5500bafcf93c9041a56a57ad2
@@ -0,0 +1,24 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ build:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: Set up Ruby 2.6
17
+ uses: actions/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.6.x
20
+ - name: Build and test with Rake
21
+ run: |
22
+ gem install bundler
23
+ bundle install --jobs 4 --retry 3
24
+ bundle exec rspec
@@ -1,4 +1,6 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
3
+
2
4
  lib = File.expand_path('../lib', __FILE__)
3
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
6
  require 'graphql/remote_loader/version'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "graphql"
2
4
  require "graphql/batch"
3
5
 
@@ -1,4 +1,5 @@
1
- require "prime"
1
+ # frozen_string_literal: true
2
+
2
3
  require "json"
3
4
  require_relative "query_merger"
4
5
 
@@ -6,22 +7,18 @@ module GraphQL
6
7
  module RemoteLoader
7
8
  class Loader < GraphQL::Batch::Loader
8
9
  # Delegates to GraphQL::Batch::Loader#load
9
- # We include a unique prime as part of the batch key to use as part
10
+ # We include a unique id as part of the batch key to use as part
10
11
  # of the alias on all fields. This is used to
11
12
  # a) Avoid name collisions in the generated query
12
13
  # b) Determine which fields in the result JSON should be
13
14
  # handed fulfilled to each promise
14
15
  def self.load(query, context: {}, variables: {})
15
- @index ||= 1
16
+ @index ||= 0
16
17
  @index += 1
17
18
 
18
- prime = Prime.take(@index - 1).last
19
-
20
19
  store_context(context)
21
20
 
22
- interpolate_variables!(query, variables)
23
-
24
- self.for.load([query, prime, @context])
21
+ self.for.load([interpolate_variables(query, variables), @index, @context])
25
22
  end
26
23
 
27
24
  # Loads the value, then if the query was successful, fulfills promise with
@@ -69,24 +66,24 @@ module GraphQL
69
66
 
70
67
  private
71
68
 
72
- def perform(queries_and_primes)
73
- query_string = QueryMerger.merge(queries_and_primes).gsub(/\s+/, " ")
74
- context = queries_and_primes[-1][-1]
69
+ def perform(queries_and_ids)
70
+ query_string = QueryMerger.merge(queries_and_ids).gsub(/\s+/, " ")
71
+ context = queries_and_ids[-1][-1]
75
72
  response = query(query_string, context: context).to_h
76
73
 
77
74
  data, errors = response["data"], response["errors"]
78
75
 
79
- queries_and_primes.each do |query, prime, context|
76
+ queries_and_ids.each do |query, caller_id, context|
80
77
  response = {}
81
78
 
82
- response["data"] = filter_keys_on_data(data, prime)
79
+ response["data"] = filter_keys_on_data(data, caller_id)
83
80
 
84
- errors_key = filter_errors(errors, prime)
81
+ errors_key = filter_errors(errors, caller_id)
85
82
  response["errors"] = dup(errors_key) unless errors_key.empty?
86
83
 
87
- scrub_primes_from_error_paths!(response["errors"])
84
+ scrub_caller_ids_from_error_paths!(response["errors"])
88
85
 
89
- fulfill([query, prime, context], response)
86
+ fulfill([query, caller_id, context], response)
90
87
  end
91
88
  end
92
89
 
@@ -97,23 +94,37 @@ module GraphQL
97
94
  # E.g.
98
95
  # interpolate_variables("foo(bar: $my_var)", { my_var: "buzz" })
99
96
  # => "foo(bar: \"buzz\")"
97
+ def self.interpolate_variables(query, variables = {})
98
+ query.dup.tap { |mutable_query| interpolate_variables!(mutable_query, variables) }
99
+ end
100
+
100
101
  def self.interpolate_variables!(query, variables = {})
101
- variables.each do |variable, value|
102
- case value
103
- when Integer, Float, TrueClass, FalseClass
104
- # These types are safe to directly interpolate into the query, and GraphQL does not expect these types to be quoted.
105
- query.gsub!("$#{variable.to_s}", value.to_s)
106
- else
107
- # A string is either a GraphQL String or ID type.
108
- # This means we need to
109
- # a) Surround the value in quotes
110
- # b) escape special characters in the string
111
- #
112
- # This else also catches unknown objects, which could break the query if we directly interpolate.
113
- # These objects get converted to strings, then escaped.
114
-
115
- query.gsub!("$#{variable.to_s}", value.to_s.inspect)
116
- end
102
+ variables.each { |variable, value| query.gsub!("$#{variable.to_s}", stringify_variable(value)) }
103
+ end
104
+
105
+ def self.stringify_variable(value)
106
+ case value
107
+ when Integer, Float, TrueClass, FalseClass
108
+ # These types are safe to directly interpolate into the query, and GraphQL does not expect these types to be quoted.
109
+ value.to_s
110
+ when Array
111
+ # Arrays can contain elements with various types, so we need to check them one by one
112
+ stringified_elements = value.map { |element| stringify_variable(element) }
113
+ "[#{stringified_elements.join(', ')}]"
114
+ when Hash
115
+ # Hashes can contain values with various types, so we need to check them one by one
116
+ stringified_key_value_pairs = value.map { |key, value| "#{key}: #{stringify_variable(value)}" }
117
+ "{#{stringified_key_value_pairs.join(', ')}}"
118
+ else
119
+ # A string is either a GraphQL String or ID type.
120
+ # This means we need to
121
+ # a) Surround the value in quotes
122
+ # b) escape special characters in the string
123
+ #
124
+ # This else also catches unknown objects, which could break the query if we directly interpolate.
125
+ # These objects get converted to strings, then escaped.
126
+
127
+ value.to_s.inspect
117
128
  end
118
129
  end
119
130
 
@@ -121,10 +132,10 @@ module GraphQL
121
132
  JSON.parse(hash.to_json)
122
133
  end
123
134
 
124
- def filter_keys_on_data(obj, prime)
135
+ def filter_keys_on_data(obj, caller_id)
125
136
  case obj
126
137
  when Array
127
- obj.map { |element| filter_keys_on_data(element, prime) }
138
+ obj.map { |element| filter_keys_on_data(element, caller_id) }
128
139
  when Hash
129
140
  filtered_results = {}
130
141
 
@@ -133,27 +144,26 @@ module GraphQL
133
144
 
134
145
  # Filter methods that were not requested in this sub-query
135
146
  fields = fields.select do |field|
136
- prime_factor = field.match(/\Ap([0-9]+)/)[1].to_i
137
- (prime_factor % prime) == 0
147
+ graphql_caller = field.match(/\Ap([0-9]+)/)[1].to_i
148
+ graphql_caller[caller_id] == 1 # Fixnum#[] accesses bitwise representation of num
138
149
  end
139
150
 
140
- # redefine methods on new obj, recursively filter sub-selections
141
- fields.each do |method|
142
- method_name = method.match(/\Ap[0-9]+(.*)/)[1]
143
-
144
- method_value = obj[method]
145
- filtered_value = filter_keys_on_data(method_value, prime)
151
+ # redefine fields on new obj, recursively filter sub-selections
152
+ fields.each do |field|
153
+ field_name = field.match(/\Ap[0-9]+(.*)/)[1]
146
154
 
147
- filtered_results[underscore(method_name)] = filtered_value
155
+ value = obj[field]
156
+ filtered_results[underscore(field_name)] = filter_keys_on_data(value, caller_id)
148
157
  end
149
158
 
150
159
  filtered_results
151
160
  else
161
+ # Base case, no more recursion needed.
152
162
  return obj
153
163
  end
154
164
  end
155
165
 
156
- def filter_errors(errors, prime)
166
+ def filter_errors(errors, caller_id)
157
167
  return [] unless errors
158
168
 
159
169
  errors.select do |error|
@@ -165,13 +175,13 @@ module GraphQL
165
175
  error["path"].all? do |path_key|
166
176
  next true if path_key.is_a? Integer
167
177
 
168
- path_key_prime = path_key.match(/\Ap([0-9]+)/)[1].to_i
169
- path_key_prime % prime == 0
178
+ path_key_caller_id = path_key.match(/\Ap([0-9]+)/)[1].to_i
179
+ path_key_caller_id[caller_id]
170
180
  end
171
181
  end
172
182
  end
173
183
 
174
- def scrub_primes_from_error_paths!(error_array)
184
+ def scrub_caller_ids_from_error_paths!(error_array)
175
185
  return unless error_array
176
186
 
177
187
  error_array.map do |error|
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GraphQL
2
4
  module RemoteLoader
3
- # Given a list of queries and their prime UIDs, generate the merged and labeled
5
+ # Given a list of queries and their caller IDs, generate the merged and labeled
4
6
  # GraphQL query to be sent off to the remote backend.
5
7
  class QueryMerger
6
8
  class << self
7
- def merge(queries_and_primes)
8
- parsed_queries = queries_and_primes.map do |query, prime|
9
+ def merge(queries_and_caller_ids)
10
+ parsed_queries = queries_and_caller_ids.map do |query, caller_id|
9
11
  parsed_query = parse(query)
10
12
 
11
13
  parsed_query.definitions.each do |definition|
12
- attach_primes!(definition.children, prime)
14
+ attach_caller_id!(definition.children, caller_id)
13
15
  end
14
16
 
15
17
  parsed_query
@@ -75,10 +77,10 @@ module GraphQL
75
77
  end
76
78
 
77
79
  if matching_field
78
- new_prime = matching_field.instance_variable_get(:@prime) *
79
- a_query_selection.instance_variable_get(:@prime)
80
+ new_binary_id = matching_field.instance_variable_get(:@binary_id) +
81
+ a_query_selection.instance_variable_get(:@binary_id)
80
82
 
81
- matching_field.instance_variable_set(:@prime, new_prime)
83
+ matching_field.instance_variable_set(:@binary_id, new_binary_id)
82
84
  merge_query_recursive(a_query_selection, matching_field) unless exempt_node_types.any? { |type| matching_field.is_a?(type) }
83
85
  else
84
86
  b_query.instance_variable_set(:@selections, [b_query.selections, a_query_selection].flatten)
@@ -97,10 +99,10 @@ module GraphQL
97
99
  b.arguments.map { |arg| {name: arg.name, value: arg.value}.to_s }.sort
98
100
  end
99
101
 
100
- def attach_primes!(query_fields, prime)
102
+ def attach_caller_id!(query_fields, caller_id)
101
103
  query_fields.each do |field|
102
- field.instance_variable_set(:@prime, prime)
103
- attach_primes!(field.children, prime)
104
+ field.instance_variable_set(:@binary_id, 2 ** caller_id)
105
+ attach_caller_id!(field.children, caller_id)
104
106
  end
105
107
  end
106
108
 
@@ -112,12 +114,12 @@ module GraphQL
112
114
 
113
115
  query_selections.each do |selection|
114
116
  unless exempt_node_types.any? { |type| selection.is_a? type }
115
- prime_factor = selection.instance_variable_get(:@prime)
117
+ binary_id = selection.instance_variable_get(:@binary_id)
116
118
 
117
119
  selection.instance_variable_set(:@alias, if selection.alias
118
- "p#{prime_factor}#{selection.alias}"
120
+ "p#{binary_id}#{selection.alias}"
119
121
  else
120
- "p#{prime_factor}#{selection.name}"
122
+ "p#{binary_id}#{selection.name}"
121
123
  end)
122
124
  end
123
125
 
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GraphQL
2
4
  module RemoteLoader
3
- VERSION = "1.0.5"
5
+ VERSION = "1.0.6"
4
6
  end
5
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-remote_loader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathaniel Woodthorpe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-29 00:00:00.000000000 Z
11
+ date: 2020-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -103,6 +103,7 @@ executables: []
103
103
  extensions: []
104
104
  extra_rdoc_files: []
105
105
  files:
106
+ - ".github/workflows/ruby.yml"
106
107
  - ".gitignore"
107
108
  - ".travis.yml"
108
109
  - Gemfile