graphql-remote_loader 1.0.5 → 1.0.6

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
  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