graphql-client 0.7.0 → 0.8.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 +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
|