graphql-client 0.7.0 → 0.8.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 +3 -90
- data/lib/graphql/client/collocated_enforcement.rb +6 -1
- data/lib/graphql/client/definition.rb +83 -0
- data/lib/graphql/client/fragment_definition.rb +11 -0
- data/lib/graphql/client/operation_definition.rb +14 -0
- data/lib/graphql/client/query_result.rb +8 -4
- data/lib/graphql/client/view_module.rb +51 -69
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c735cc6d34d7372e777934b15cbf86540cf994a
|
4
|
+
data.tar.gz: 329f6769cf02065e726dd26e9006cb1143f3f8df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd69bd130b837dff72de557d1b0c51e7a4f0b499af231af00d8b2df65a638116021f45660be83c8695aa27bbf808741db5317d4791e68f6bf0db9f059dbf9273
|
7
|
+
data.tar.gz: 20d75c1fa9d08f56a096328cf499e163eea4b7d13bfc9767f8fa743004e87c9a611d32d6533cbc0f28d72770b41635eff526549baf81bd52cc319ed0437ccb4c
|
data/lib/graphql/client.rb
CHANGED
@@ -3,9 +3,12 @@ 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"
|
6
7
|
require "graphql/client/definition_variables"
|
7
8
|
require "graphql/client/error"
|
8
9
|
require "graphql/client/errors"
|
10
|
+
require "graphql/client/fragment_definition"
|
11
|
+
require "graphql/client/operation_definition"
|
9
12
|
require "graphql/client/query_result"
|
10
13
|
require "graphql/client/query_typename"
|
11
14
|
require "graphql/client/response"
|
@@ -88,96 +91,6 @@ module GraphQL
|
|
88
91
|
@enforce_collocated_callers = enforce_collocated_callers
|
89
92
|
end
|
90
93
|
|
91
|
-
# Definitions are constructed by Client.parse and wrap a parsed AST of the
|
92
|
-
# query string as well as hold references to any external query definition
|
93
|
-
# dependencies.
|
94
|
-
#
|
95
|
-
# Definitions MUST be assigned to a constant.
|
96
|
-
class Definition < Module
|
97
|
-
def self.for(node:, **kargs)
|
98
|
-
case node
|
99
|
-
when Language::Nodes::OperationDefinition
|
100
|
-
OperationDefinition.new(node: node, **kargs)
|
101
|
-
when Language::Nodes::FragmentDefinition
|
102
|
-
FragmentDefinition.new(node: node, **kargs)
|
103
|
-
else
|
104
|
-
raise TypeError, "expected node to be a definition type, but was #{node.class}"
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def initialize(node:, document:, schema:, document_types:, source_location:, enforce_collocated_callers:)
|
109
|
-
@definition_node = node
|
110
|
-
@document = document
|
111
|
-
@schema = schema
|
112
|
-
@document_types = document_types
|
113
|
-
@source_location = source_location
|
114
|
-
@enforce_collocated_callers = enforce_collocated_callers
|
115
|
-
end
|
116
|
-
|
117
|
-
# Internal: Get underlying operation or fragment defintion AST node for
|
118
|
-
# definition.
|
119
|
-
#
|
120
|
-
# Returns OperationDefinition or FragmentDefinition object.
|
121
|
-
attr_reader :definition_node
|
122
|
-
|
123
|
-
# Public: Global name of definition in client document.
|
124
|
-
#
|
125
|
-
# Returns a GraphQL safe name of the Ruby constant String.
|
126
|
-
#
|
127
|
-
# "Users::UserQuery" #=> "Users__UserQuery"
|
128
|
-
#
|
129
|
-
# Returns String.
|
130
|
-
def definition_name
|
131
|
-
return @definition_name if defined?(@definition_name)
|
132
|
-
|
133
|
-
if name
|
134
|
-
@definition_name = name.gsub("::", "__").freeze
|
135
|
-
else
|
136
|
-
"#{self.class.name}_#{object_id}".gsub("::", "__").freeze
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
# Public: Get document with only the definitions needed to perform this
|
141
|
-
# operation.
|
142
|
-
#
|
143
|
-
# Returns GraphQL::Language::Nodes::Document with one OperationDefinition
|
144
|
-
# and any FragmentDefinition dependencies.
|
145
|
-
attr_reader :document
|
146
|
-
|
147
|
-
# Internal: Mapping of document nodes to schema types.
|
148
|
-
attr_reader :document_types
|
149
|
-
|
150
|
-
attr_reader :schema
|
151
|
-
|
152
|
-
# Public: Returns the Ruby source filename and line number containing this
|
153
|
-
# definition was not defined in Ruby.
|
154
|
-
#
|
155
|
-
# Returns Array pair of [String, Fixnum].
|
156
|
-
attr_reader :source_location
|
157
|
-
|
158
|
-
attr_reader :enforce_collocated_callers
|
159
|
-
|
160
|
-
def new(*args)
|
161
|
-
type.new(*args)
|
162
|
-
end
|
163
|
-
|
164
|
-
def type
|
165
|
-
# TODO: Fix type indirection
|
166
|
-
@type ||= GraphQL::Client::QueryResult.wrap(self, definition_node, name: "#{name}.type")
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
# Specific operation definition subtype for queries, mutations or
|
171
|
-
# subscriptions.
|
172
|
-
class OperationDefinition < Definition
|
173
|
-
# Public: Alias for definition name.
|
174
|
-
alias operation_name definition_name
|
175
|
-
end
|
176
|
-
|
177
|
-
# Specific fragment definition subtype.
|
178
|
-
class FragmentDefinition < Definition
|
179
|
-
end
|
180
|
-
|
181
94
|
def parse(str, filename = nil, lineno = nil)
|
182
95
|
if filename.nil? && lineno.nil?
|
183
96
|
location = caller_locations(1, 1).first
|
@@ -3,6 +3,10 @@ require "graphql/client/error"
|
|
3
3
|
|
4
4
|
module GraphQL
|
5
5
|
class Client
|
6
|
+
|
7
|
+
# Collcation will not be enforced if a stack trace includes any of these gems.
|
8
|
+
WHITELISTED_GEM_NAMES = %w{pry byebug}
|
9
|
+
|
6
10
|
# Raised when method is called from outside the expected file scope.
|
7
11
|
class NonCollocatedCallerError < Error; end
|
8
12
|
|
@@ -30,7 +34,8 @@ module GraphQL
|
|
30
34
|
return super(*args, &block) if Thread.current[:query_result_caller_location_ignore]
|
31
35
|
|
32
36
|
locations = caller_locations(1, 1)
|
33
|
-
|
37
|
+
|
38
|
+
if (locations.first.path != path) && !(caller_locations.any? { |cl| WHITELISTED_GEM_NAMES.any? { |g| cl.path.include?("gems/#{g}") } })
|
34
39
|
error = NonCollocatedCallerError.new("#{method} was called outside of '#{path}' https://git.io/v1syX")
|
35
40
|
error.set_backtrace(caller(1))
|
36
41
|
raise error
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Client
|
4
|
+
# Definitions are constructed by Client.parse and wrap a parsed AST of the
|
5
|
+
# query string as well as hold references to any external query definition
|
6
|
+
# dependencies.
|
7
|
+
#
|
8
|
+
# Definitions MUST be assigned to a constant.
|
9
|
+
class Definition < Module
|
10
|
+
def self.for(node:, **kargs)
|
11
|
+
case node
|
12
|
+
when Language::Nodes::OperationDefinition
|
13
|
+
OperationDefinition.new(node: node, **kargs)
|
14
|
+
when Language::Nodes::FragmentDefinition
|
15
|
+
FragmentDefinition.new(node: node, **kargs)
|
16
|
+
else
|
17
|
+
raise TypeError, "expected node to be a definition type, but was #{node.class}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(node:, document:, schema:, document_types:, source_location:, enforce_collocated_callers:)
|
22
|
+
@definition_node = node
|
23
|
+
@document = document
|
24
|
+
@schema = schema
|
25
|
+
@document_types = document_types
|
26
|
+
@source_location = source_location
|
27
|
+
@enforce_collocated_callers = enforce_collocated_callers
|
28
|
+
end
|
29
|
+
|
30
|
+
# Internal: Get underlying operation or fragment defintion AST node for
|
31
|
+
# definition.
|
32
|
+
#
|
33
|
+
# Returns OperationDefinition or FragmentDefinition object.
|
34
|
+
attr_reader :definition_node
|
35
|
+
|
36
|
+
# Public: Global name of definition in client document.
|
37
|
+
#
|
38
|
+
# Returns a GraphQL safe name of the Ruby constant String.
|
39
|
+
#
|
40
|
+
# "Users::UserQuery" #=> "Users__UserQuery"
|
41
|
+
#
|
42
|
+
# Returns String.
|
43
|
+
def definition_name
|
44
|
+
return @definition_name if defined?(@definition_name)
|
45
|
+
|
46
|
+
if name
|
47
|
+
@definition_name = name.gsub("::", "__").freeze
|
48
|
+
else
|
49
|
+
"#{self.class.name}_#{object_id}".gsub("::", "__").freeze
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Public: Get document with only the definitions needed to perform this
|
54
|
+
# operation.
|
55
|
+
#
|
56
|
+
# Returns GraphQL::Language::Nodes::Document with one OperationDefinition
|
57
|
+
# and any FragmentDefinition dependencies.
|
58
|
+
attr_reader :document
|
59
|
+
|
60
|
+
# Internal: Mapping of document nodes to schema types.
|
61
|
+
attr_reader :document_types
|
62
|
+
|
63
|
+
attr_reader :schema
|
64
|
+
|
65
|
+
# Public: Returns the Ruby source filename and line number containing this
|
66
|
+
# definition was not defined in Ruby.
|
67
|
+
#
|
68
|
+
# Returns Array pair of [String, Fixnum].
|
69
|
+
attr_reader :source_location
|
70
|
+
|
71
|
+
attr_reader :enforce_collocated_callers
|
72
|
+
|
73
|
+
def new(*args)
|
74
|
+
type.new(*args)
|
75
|
+
end
|
76
|
+
|
77
|
+
def type
|
78
|
+
# TODO: Fix type indirection
|
79
|
+
@type ||= GraphQL::Client::QueryResult.wrap(self, definition_node, name: "#{name}.type")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/client/definition"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
class Client
|
7
|
+
# Specific operation definition subtype for queries, mutations or
|
8
|
+
# subscriptions.
|
9
|
+
class OperationDefinition < Definition
|
10
|
+
# Public: Alias for definition name.
|
11
|
+
alias operation_name definition_name
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -227,12 +227,16 @@ module GraphQL
|
|
227
227
|
# Returns Errors collection.
|
228
228
|
attr_reader :errors
|
229
229
|
|
230
|
-
attr_reader :data
|
231
|
-
alias to_h data
|
232
|
-
|
233
230
|
attr_reader :__typename
|
234
231
|
alias typename __typename
|
235
232
|
|
233
|
+
# Public: Returns the raw response data
|
234
|
+
#
|
235
|
+
# Returns Hash
|
236
|
+
def to_h
|
237
|
+
@data
|
238
|
+
end
|
239
|
+
|
236
240
|
def type_of?(*types)
|
237
241
|
types.any? do |type|
|
238
242
|
if type = self.class.schema.types.fetch(type.to_s, nil)
|
@@ -272,7 +276,7 @@ module GraphQL
|
|
272
276
|
raise UnimplementedFieldError, "undefined field `#{e.name}' on #{type} type. https://git.io/v1y3m"
|
273
277
|
end
|
274
278
|
|
275
|
-
if data[field.name]
|
279
|
+
if @data[field.name]
|
276
280
|
error_class = ImplicitlyFetchedFieldError
|
277
281
|
message = "implicitly fetched field `#{field.name}' on #{type} type. https://git.io/v1yGL"
|
278
282
|
else
|
@@ -44,14 +44,14 @@ module GraphQL
|
|
44
44
|
#
|
45
45
|
# Returns nothing.
|
46
46
|
def eager_load!
|
47
|
-
return unless File.directory?(
|
47
|
+
return unless File.directory?(load_path)
|
48
48
|
|
49
|
-
Dir.entries(
|
49
|
+
Dir.entries(load_path).each do |entry|
|
50
50
|
next if entry == "." || entry == ".."
|
51
51
|
name = entry.sub(/(\.\w+)+$/, "").camelize.to_sym
|
52
|
-
if ViewModule.valid_constant_name?(name)
|
53
|
-
mod =
|
54
|
-
mod.eager_load!
|
52
|
+
if ViewModule.valid_constant_name?(name)
|
53
|
+
mod = const_defined?(name, false) ? const_get(name) : load_and_set_module(name)
|
54
|
+
mod.eager_load! if mod
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -73,76 +73,67 @@ module GraphQL
|
|
73
73
|
name.to_s =~ /^[A-Z][a-zA-Z0-9_]*$/
|
74
74
|
end
|
75
75
|
|
76
|
-
# Public:
|
77
|
-
# view directory or template namespace.
|
78
|
-
#
|
79
|
-
# name - String or Symbol constant name
|
80
|
-
# inherit - If the lookup will also search the ancestors (default: true)
|
81
|
-
#
|
82
|
-
# Returns true if definition is found, otherwise false.
|
83
|
-
# def const_defined?(name, inherit = true)
|
84
|
-
# if super(name.to_sym, inherit)
|
85
|
-
# true
|
86
|
-
# elsif const_path(name)
|
87
|
-
# true
|
88
|
-
# else
|
89
|
-
# false
|
90
|
-
# end
|
91
|
-
# end
|
92
|
-
|
93
|
-
def loadable_const_defined?(name)
|
94
|
-
if const_defined?(name.to_sym, false)
|
95
|
-
true
|
96
|
-
elsif const_path(name)
|
97
|
-
true
|
98
|
-
else
|
99
|
-
false
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Public: Source location that defined the Module.
|
76
|
+
# Public: Directory to retrieve nested GraphQL definitions from.
|
104
77
|
#
|
105
78
|
# Returns absolute String path under app/views.
|
106
|
-
attr_accessor :
|
79
|
+
attr_accessor :load_path
|
80
|
+
alias_method :path=, :load_path=
|
81
|
+
alias_method :path, :load_path
|
107
82
|
|
108
|
-
#
|
109
|
-
#
|
110
|
-
# name - String or Symbol constant name
|
83
|
+
# Public: if this module was defined by a view
|
111
84
|
#
|
112
|
-
#
|
113
|
-
|
114
|
-
# Views.const_path(:Users) #=> "app/views/users"
|
115
|
-
# Views::Users.const_path(:Show) #=> "app/views/users/show.html.erb"
|
116
|
-
# Views::Users.const_path(:Profile) #=> "app/views/users/_profile.html.erb"
|
117
|
-
#
|
118
|
-
# Returns String absolute path to file, otherwise nil.
|
119
|
-
def const_path(name)
|
120
|
-
pathname = ActiveSupport::Inflector.underscore(name.to_s)
|
121
|
-
Dir[File.join(path, "{#{pathname},_#{pathname}}{/,.*}")].map { |fn| File.expand_path(fn) }.first
|
122
|
-
end
|
85
|
+
# Returns absolute String path under app/views.
|
86
|
+
attr_accessor :source_path
|
123
87
|
|
124
88
|
# Internal: Initialize new module for constant name and load ERB statics.
|
125
89
|
#
|
126
|
-
#
|
90
|
+
# name - String or Symbol constant name.
|
127
91
|
#
|
128
92
|
# Examples
|
129
93
|
#
|
130
|
-
# load_module(
|
131
|
-
# load_module(
|
94
|
+
# Views::Users.load_module(:Profile)
|
95
|
+
# Views::Users::Profile.load_module(:Show)
|
132
96
|
#
|
133
97
|
# Returns new Module implementing Loadable concern.
|
134
|
-
def load_module(
|
135
|
-
|
98
|
+
def load_module(name)
|
99
|
+
pathname = ActiveSupport::Inflector.underscore(name.to_s)
|
100
|
+
path = Dir[File.join(load_path, "{#{pathname},_#{pathname}}{.*}")].map { |fn| File.expand_path(fn) }.first
|
136
101
|
|
137
|
-
if File.extname(path)
|
138
|
-
contents = File.read(path)
|
139
|
-
query, lineno = ViewModule.extract_graphql_section(contents)
|
140
|
-
mod = client.parse(query, path, lineno) if query
|
141
|
-
end
|
102
|
+
return if !path || File.extname(path) != ".erb"
|
142
103
|
|
104
|
+
contents = File.read(path)
|
105
|
+
query, lineno = ViewModule.extract_graphql_section(contents)
|
106
|
+
return unless query
|
107
|
+
|
108
|
+
mod = client.parse(query, path, lineno)
|
143
109
|
mod.extend(ViewModule)
|
110
|
+
mod.load_path = File.join(load_path, pathname)
|
111
|
+
mod.source_path = path
|
144
112
|
mod.client = client
|
145
|
-
mod
|
113
|
+
mod
|
114
|
+
end
|
115
|
+
|
116
|
+
def placeholder_module(name)
|
117
|
+
dirname = File.join(load_path, ActiveSupport::Inflector.underscore(name.to_s))
|
118
|
+
return nil unless Dir.exist?(dirname)
|
119
|
+
|
120
|
+
Module.new.tap do |mod|
|
121
|
+
mod.extend(ViewModule)
|
122
|
+
mod.load_path = dirname
|
123
|
+
mod.client = client
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def load_and_set_module(name)
|
128
|
+
placeholder = placeholder_module(name)
|
129
|
+
const_set(name, placeholder) if placeholder
|
130
|
+
|
131
|
+
mod = load_module(name)
|
132
|
+
return placeholder unless mod
|
133
|
+
|
134
|
+
remove_const(name) if placeholder
|
135
|
+
const_set(name, mod)
|
136
|
+
mod.unloadable
|
146
137
|
mod
|
147
138
|
end
|
148
139
|
|
@@ -152,16 +143,7 @@ module GraphQL
|
|
152
143
|
#
|
153
144
|
# Returns module or raises NameError if missing.
|
154
145
|
def const_missing(name)
|
155
|
-
|
156
|
-
|
157
|
-
if path
|
158
|
-
mod = load_module(path)
|
159
|
-
const_set(name, mod)
|
160
|
-
mod.unloadable
|
161
|
-
mod
|
162
|
-
else
|
163
|
-
super
|
164
|
-
end
|
146
|
+
load_and_set_module(name) || super
|
165
147
|
end
|
166
148
|
end
|
167
149
|
end
|
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.8.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-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- README.md
|
159
159
|
- lib/graphql/client.rb
|
160
160
|
- lib/graphql/client/collocated_enforcement.rb
|
161
|
+
- lib/graphql/client/definition.rb
|
161
162
|
- lib/graphql/client/definition_variables.rb
|
162
163
|
- lib/graphql/client/document_types.rb
|
163
164
|
- lib/graphql/client/error.rb
|
@@ -165,10 +166,12 @@ files:
|
|
165
166
|
- lib/graphql/client/erubi_enhancer.rb
|
166
167
|
- lib/graphql/client/erubis.rb
|
167
168
|
- lib/graphql/client/erubis_enhancer.rb
|
169
|
+
- lib/graphql/client/fragment_definition.rb
|
168
170
|
- lib/graphql/client/hash_with_indifferent_access.rb
|
169
171
|
- lib/graphql/client/http.rb
|
170
172
|
- lib/graphql/client/list.rb
|
171
173
|
- lib/graphql/client/log_subscriber.rb
|
174
|
+
- lib/graphql/client/operation_definition.rb
|
172
175
|
- lib/graphql/client/query_result.rb
|
173
176
|
- lib/graphql/client/query_typename.rb
|
174
177
|
- lib/graphql/client/railtie.rb
|
@@ -197,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
200
|
version: '0'
|
198
201
|
requirements: []
|
199
202
|
rubyforge_project:
|
200
|
-
rubygems_version: 2.
|
203
|
+
rubygems_version: 2.5.2
|
201
204
|
signing_key:
|
202
205
|
specification_version: 4
|
203
206
|
summary: GraphQL Client
|