graphql-client 0.6.3 → 0.7.0

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: 0dc218011045b6cacca2b4cf958da5327c947bfc
4
- data.tar.gz: 2edfa03b6d800d722609f5abbd76605a9a479b61
3
+ metadata.gz: bd882791666554b4b6999b5e6e1089187eb06e9a
4
+ data.tar.gz: 5c1e142aee92b113edef6c34a90484ff32b2fd0e
5
5
  SHA512:
6
- metadata.gz: c142fa08a17ff24e0e48b05a48439284ddded4d7496ce6c2739d1c2a1e2e7d12d5da76844f67cac1f2e1ae7b221c8d24061150925e65351f5b6ce1e3818e0f3a
7
- data.tar.gz: f6701168cf80f970c9230d7cb43ceeca0a78cba073365ff884ff0d4276142cd72a8d5a94db00301600949a5e696742979553462f43302dce8e87fd19b7d48bf9
6
+ metadata.gz: 242cd9508205d68cb2459a78bcd689a986c4317478113923d8fbd23d015bf8c936fd84619410228404699a7c229377f6333f857f216853d9991b32603e34443d
7
+ data.tar.gz: 74fb38b0777b0df123df5c5a09a6e1caf5f69ec3f5f765c859d041900c58e6403cebd0a59c882095524ba18cf08ab0e04dcfca7164b39c6d2e291e8f845b15f1
@@ -3,6 +3,7 @@ require "active_support/inflector"
3
3
  require "active_support/notifications"
4
4
  require "graphql"
5
5
  require "graphql/client/collocated_enforcement"
6
+ require "graphql/client/definition_variables"
6
7
  require "graphql/client/error"
7
8
  require "graphql/client/errors"
8
9
  require "graphql/client/query_result"
@@ -233,7 +234,10 @@ module GraphQL
233
234
 
234
235
  document_dependencies = Language::Nodes::Document.new(definitions: doc.definitions + definition_dependencies.to_a)
235
236
 
236
- rules = GraphQL::StaticValidation::ALL_RULES - [GraphQL::StaticValidation::FragmentsAreUsed]
237
+ rules = GraphQL::StaticValidation::ALL_RULES - [
238
+ GraphQL::StaticValidation::FragmentsAreUsed,
239
+ GraphQL::StaticValidation::FieldsHaveAppropriateSelections
240
+ ]
237
241
  validator = GraphQL::StaticValidation::Validator.new(schema: self.schema, rules: rules)
238
242
  query = GraphQL::Query.new(self.schema, document: document_dependencies)
239
243
 
@@ -293,6 +297,63 @@ module GraphQL
293
297
  end
294
298
  end
295
299
 
300
+ # Public: Create operation definition from a fragment definition.
301
+ #
302
+ # Automatically determines operation variable set.
303
+ #
304
+ # Examples
305
+ #
306
+ # FooFragment = Client.parse <<-'GRAPHQL'
307
+ # fragment on Mutation {
308
+ # updateFoo(id: $id, content: $content)
309
+ # }
310
+ # GRAPHQL
311
+ #
312
+ # # mutation($id: ID!, $content: String!) {
313
+ # # updateFoo(id: $id, content: $content)
314
+ # # }
315
+ # FooMutation = Client.create_operation(FooFragment)
316
+ #
317
+ # fragment - A FragmentDefinition definition.
318
+ #
319
+ # Returns an OperationDefinition.
320
+ def create_operation(fragment, filename = nil, lineno = nil)
321
+ unless fragment.is_a?(GraphQL::Client::FragmentDefinition)
322
+ raise TypeError, "expected fragment to be a GraphQL::Client::FragmentDefinition, but was #{fragment.class}"
323
+ end
324
+
325
+ if filename.nil? && lineno.nil?
326
+ location = caller_locations(1, 1).first
327
+ filename = location.path
328
+ lineno = location.lineno
329
+ end
330
+
331
+ variables = GraphQL::Client::DefinitionVariables.operation_variables(self.schema, fragment.document, fragment.definition_name)
332
+ type_name = fragment.definition_node.type.name
333
+
334
+ if schema.query && type_name == schema.query.name
335
+ operation_type = "query"
336
+ elsif schema.mutation && type_name == schema.mutation.name
337
+ operation_type = "mutation"
338
+ elsif schema.subscription && type_name == schema.subscription.name
339
+ operation_type = "subscription"
340
+ else
341
+ types = [schema.query, schema.mutation, schema.subscription].compact
342
+ raise Error, "Fragment must be defined on #{types.map(&:name).join(", ")}"
343
+ end
344
+
345
+ doc_ast = GraphQL::Language::Nodes::Document.new(definitions: [
346
+ GraphQL::Language::Nodes::OperationDefinition.new(
347
+ operation_type: operation_type,
348
+ variables: variables,
349
+ selections: [
350
+ GraphQL::Language::Nodes::FragmentSpread.new(name: fragment.name)
351
+ ]
352
+ )
353
+ ])
354
+ parse(doc_ast.to_query_string, filename, lineno)
355
+ end
356
+
296
357
  attr_reader :document
297
358
 
298
359
  def query(definition, variables: {}, context: {})
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+ require "graphql"
3
+
4
+ module GraphQL
5
+ class Client
6
+ # Internal: Detect variables used in a definition.
7
+ module DefinitionVariables
8
+ # Internal: Detect all variables used in a given operation or fragment
9
+ # definition.
10
+ #
11
+ # schema - A GraphQL::Schema
12
+ # document - A GraphQL::Language::Nodes::Document to scan
13
+ # definition_name - A String definition name. Defaults to anonymous definition.
14
+ #
15
+ # Returns a Hash[Symbol] to GraphQL::Type objects.
16
+ def self.variables(schema, document, definition_name = nil)
17
+ unless schema.is_a?(GraphQL::Schema)
18
+ raise TypeError, "expected schema to be a GraphQL::Schema, but was #{schema.class}"
19
+ end
20
+
21
+ unless document.is_a?(GraphQL::Language::Nodes::Document)
22
+ raise TypeError, "expected document to be a GraphQL::Language::Nodes::Document, but was #{document.class}"
23
+ end
24
+
25
+ sliced_document = GraphQL::Language::DefinitionSlice.slice(document, definition_name)
26
+
27
+ visitor = GraphQL::Language::Visitor.new(sliced_document)
28
+ type_stack = GraphQL::StaticValidation::TypeStack.new(schema, visitor)
29
+
30
+ variables = {}
31
+
32
+ visitor[GraphQL::Language::Nodes::VariableIdentifier] << ->(node, parent) do
33
+ if definition = type_stack.argument_definitions.last
34
+ existing_type = variables[node.name.to_sym]
35
+
36
+ if existing_type && existing_type.unwrap != definition.type.unwrap
37
+ raise GraphQL::Client::ValidationError, "$#{node.name} was already declared as #{existing_type.unwrap}, but was #{definition.type.unwrap}"
38
+ elsif !existing_type.is_a?(GraphQL::NonNullType)
39
+ variables[node.name.to_sym] = definition.type
40
+ end
41
+ end
42
+ end
43
+
44
+ visitor.visit
45
+
46
+ variables
47
+ end
48
+
49
+ # Internal: Detect all variables used in a given operation or fragment
50
+ # definition.
51
+ #
52
+ # schema - A GraphQL::Schema
53
+ # document - A GraphQL::Language::Nodes::Document to scan
54
+ # definition_name - A String definition name. Defaults to anonymous definition.
55
+ #
56
+ # Returns a Hash[Symbol] to VariableDefinition objects.
57
+ def self.operation_variables(schema, document, definition_name = nil)
58
+ variables(schema, document, definition_name).map { |name, type|
59
+ GraphQL::Language::Nodes::VariableDefinition.new(name: name.to_s, type: variable_node(type))
60
+ }
61
+ end
62
+
63
+ # Internal: Get AST node for GraphQL type.
64
+ #
65
+ # type - A GraphQL::Type
66
+ #
67
+ # Returns GraphQL::Language::Nodes::Type.
68
+ def self.variable_node(type)
69
+ case type
70
+ when GraphQL::NonNullType
71
+ GraphQL::Language::Nodes::NonNullType.new(of_type: variable_node(type.of_type))
72
+ when GraphQL::ListType
73
+ GraphQL::Language::Nodes::ListType.new(of_type: variable_node(type.of_type))
74
+ else
75
+ GraphQL::Language::Nodes::TypeName.new(name: type.name)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Client
5
+ # Public: Erubi enhancer that adds support for GraphQL static query sections.
6
+ #
7
+ # <%graphql
8
+ # query GetVerison {
9
+ # version
10
+ # }
11
+ # %>
12
+ # <%= data.version %>
13
+ #
14
+ module ErubiEnhancer
15
+ # Internal: Extend Erubi handler to simply ignore <%graphql sections.
16
+ def initialize(input, *args)
17
+ input = input.gsub(/<%graphql/, "<%#")
18
+ super(input, *args)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require "action_view"
3
+ require "graphql/client/erubis_enhancer"
3
4
 
4
5
  module GraphQL
5
6
  class Client
@@ -18,24 +19,12 @@ module GraphQL
18
19
  # ActionView::Template::Handlers::ERB.erb_implementation = GraphQL::Client::Erubis
19
20
  #
20
21
  class Erubis < ActionView::Template::Handlers::Erubis
21
- # Public: Extract GraphQL section from ERB template.
22
- #
23
- # src - String ERB text
24
- #
25
- # Returns String GraphQL query and line number or nil or no section was
26
- # defined.
22
+ # Deprecated: Use ViewModule.extract_graphql_section.
27
23
  def self.extract_graphql_section(src)
28
- query_string = src.scan(/<%graphql([^%]+)%>/).flatten.first
29
- return nil unless query_string
30
- [query_string, Regexp.last_match.pre_match.count("\n") + 1]
24
+ ViewModule.extract_graphql_section(src)
31
25
  end
32
26
 
33
- # Internal: Extend Rails' Erubis handler to simply ignore <%graphql
34
- # sections.
35
- def convert_input(src, input)
36
- input = input.gsub(/<%graphql/, "<%#")
37
- super(src, input)
38
- end
27
+ include ErubisEnhancer
39
28
  end
40
29
  end
41
30
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Client
5
+ # Public: Erubis enhancer that adds support for GraphQL static query sections.
6
+ #
7
+ # <%graphql
8
+ # query GetVerison {
9
+ # version
10
+ # }
11
+ # %>
12
+ # <%= data.version %>
13
+ #
14
+ module ErubisEnhancer
15
+ # Internal: Extend Erubis handler to simply ignore <%graphql sections.
16
+ def convert_input(src, input)
17
+ input = input.gsub(/<%graphql/, "<%#")
18
+ super(src, input)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -233,11 +233,13 @@ module GraphQL
233
233
  attr_reader :__typename
234
234
  alias typename __typename
235
235
 
236
- def type_of?(type)
237
- if type = self.class.schema.types.fetch(type.to_s, nil)
238
- self.class.schema.possible_types(type).any? { |t| @__typename == t.name }
239
- else
240
- false
236
+ def type_of?(*types)
237
+ types.any? do |type|
238
+ if type = self.class.schema.types.fetch(type.to_s, nil)
239
+ self.class.schema.possible_types(type).any? { |t| @__typename == t.name }
240
+ else
241
+ false
242
+ end
241
243
  end
242
244
  end
243
245
 
@@ -16,17 +16,20 @@ module GraphQL
16
16
  # Returns nothing.
17
17
  def self.insert_typename_fields(document, types: {})
18
18
  on_selections = ->(node, _parent) do
19
- return unless node.selections.any?
20
-
21
19
  type = types[node]
22
- case type && type.unwrap
23
- when NilClass, GraphQL::InterfaceType, GraphQL::UnionType
24
- names = node_flatten_selections(node.selections).map { |s| s.respond_to?(:name) ? s.name : nil }
25
- names = Set.new(names.compact)
26
20
 
27
- unless names.include?("__typename")
28
- node.selections = [GraphQL::Language::Nodes::Field.new(name: "__typename")] + node.selections
21
+ if node.selections.any?
22
+ case type && type.unwrap
23
+ when NilClass, GraphQL::InterfaceType, GraphQL::UnionType
24
+ names = node_flatten_selections(node.selections).map { |s| s.respond_to?(:name) ? s.name : nil }
25
+ names = Set.new(names.compact)
26
+
27
+ unless names.include?("__typename")
28
+ node.selections = [GraphQL::Language::Nodes::Field.new(name: "__typename")] + node.selections
29
+ end
29
30
  end
31
+ elsif type && type.unwrap.is_a?(GraphQL::ObjectType)
32
+ node.selections = [GraphQL::Language::Nodes::Field.new(name: "__typename")]
30
33
  end
31
34
  end
32
35
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require "active_support/dependencies"
3
3
  require "active_support/inflector"
4
- require "graphql/client/erubis"
4
+ require "graphql/client/erubis_enhancer"
5
5
 
6
6
  module GraphQL
7
7
  class Client
@@ -19,6 +19,18 @@ module GraphQL
19
19
  module ViewModule
20
20
  attr_accessor :client
21
21
 
22
+ # Public: Extract GraphQL section from ERB template.
23
+ #
24
+ # src - String ERB text
25
+ #
26
+ # Returns String GraphQL query and line number or nil or no section was
27
+ # defined.
28
+ def self.extract_graphql_section(src)
29
+ query_string = src.scan(/<%graphql([^%]+)%>/).flatten.first
30
+ return nil unless query_string
31
+ [query_string, Regexp.last_match.pre_match.count("\n") + 1]
32
+ end
33
+
22
34
  # Public: Eager load module and all subdependencies.
23
35
  #
24
36
  # Use in production when cache_classes is true.
@@ -124,7 +136,7 @@ module GraphQL
124
136
 
125
137
  if File.extname(path) == ".erb"
126
138
  contents = File.read(path)
127
- query, lineno = GraphQL::Client::Erubis.extract_graphql_section(contents)
139
+ query, lineno = ViewModule.extract_graphql_section(contents)
128
140
  mod = client.parse(query, path, lineno) if query
129
141
  end
130
142
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require "active_support/inflector"
3
3
  require "graphql"
4
- require "graphql/client/erubis"
4
+ require "graphql/client/view_module"
5
5
  require "rubocop"
6
6
 
7
7
  module RuboCop
@@ -13,7 +13,7 @@ module RuboCop
13
13
 
14
14
  def investigate(processed_source)
15
15
  erb = File.read(processed_source.buffer.name)
16
- query, = ::GraphQL::Client::Erubis.extract_graphql_section(erb)
16
+ query, = ::GraphQL::Client::ViewModule.extract_graphql_section(erb)
17
17
  return unless query
18
18
 
19
19
  aliases = {}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-13 00:00:00.000000000 Z
11
+ date: 2017-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -64,6 +64,34 @@ dependencies:
64
64
  - - "<"
65
65
  - !ruby/object:Gem::Version
66
66
  version: '6.0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: erubi
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '1.6'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.6'
81
+ - !ruby/object:Gem::Dependency
82
+ name: erubis
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '2.7'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '2.7'
67
95
  - !ruby/object:Gem::Dependency
68
96
  name: minitest
69
97
  requirement: !ruby/object:Gem::Requirement
@@ -130,10 +158,13 @@ files:
130
158
  - README.md
131
159
  - lib/graphql/client.rb
132
160
  - lib/graphql/client/collocated_enforcement.rb
161
+ - lib/graphql/client/definition_variables.rb
133
162
  - lib/graphql/client/document_types.rb
134
163
  - lib/graphql/client/error.rb
135
164
  - lib/graphql/client/errors.rb
165
+ - lib/graphql/client/erubi_enhancer.rb
136
166
  - lib/graphql/client/erubis.rb
167
+ - lib/graphql/client/erubis_enhancer.rb
137
168
  - lib/graphql/client/hash_with_indifferent_access.rb
138
169
  - lib/graphql/client/http.rb
139
170
  - lib/graphql/client/list.rb
@@ -166,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
197
  version: '0'
167
198
  requirements: []
168
199
  rubyforge_project:
169
- rubygems_version: 2.5.2
200
+ rubygems_version: 2.6.11
170
201
  signing_key:
171
202
  specification_version: 4
172
203
  summary: GraphQL Client