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 +4 -4
- data/lib/graphql/client.rb +62 -1
- data/lib/graphql/client/definition_variables.rb +80 -0
- data/lib/graphql/client/erubi_enhancer.rb +22 -0
- data/lib/graphql/client/erubis.rb +4 -15
- data/lib/graphql/client/erubis_enhancer.rb +22 -0
- data/lib/graphql/client/query_result.rb +7 -5
- data/lib/graphql/client/query_typename.rb +11 -8
- data/lib/graphql/client/view_module.rb +14 -2
- data/lib/rubocop/cop/graphql/overfetch.rb +2 -2
- metadata +34 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd882791666554b4b6999b5e6e1089187eb06e9a
|
4
|
+
data.tar.gz: 5c1e142aee92b113edef6c34a90484ff32b2fd0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 242cd9508205d68cb2459a78bcd689a986c4317478113923d8fbd23d015bf8c936fd84619410228404699a7c229377f6333f857f216853d9991b32603e34443d
|
7
|
+
data.tar.gz: 74fb38b0777b0df123df5c5a09a6e1caf5f69ec3f5f765c859d041900c58e6403cebd0a59c882095524ba18cf08ab0e04dcfca7164b39c6d2e291e8f845b15f1
|
data/lib/graphql/client.rb
CHANGED
@@ -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 - [
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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?(
|
237
|
-
|
238
|
-
self.class.schema.
|
239
|
-
|
240
|
-
|
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
|
-
|
28
|
-
|
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/
|
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 =
|
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/
|
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::
|
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.
|
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-
|
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.
|
200
|
+
rubygems_version: 2.6.11
|
170
201
|
signing_key:
|
171
202
|
specification_version: 4
|
172
203
|
summary: GraphQL Client
|