graphql-client 0.6.3 → 0.7.0

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