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