graphql-client 0.0.7 → 0.0.8

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: 8414ab402cf8454eb7d34081edc3c17fff0611de
4
- data.tar.gz: 2a1351fe377f4e9999b9a0c5cfedd04081240753
3
+ metadata.gz: cee45489051065d2c8d47c6f8c68c6b3c98d75ca
4
+ data.tar.gz: e462bb5c2fb1997f8679bb0fea315f8abd751539
5
5
  SHA512:
6
- metadata.gz: b1b30fc5a6c9f06f03a8c3ed9e69614bb1f7d3a0cbd449bb72a2077d34a154a6b2b48bd3d0b988997b2d59716941a3121fe2958f5948dff6afcce17c779c3cdd
7
- data.tar.gz: dfbe13c52c3bd8d9df76129b8de2ec7f4fe2bb430c1788f9d77966c8a75f57d8fcbdc973e280239f763fba1d6976be8babaffdb86590b0da35819b40e1c0fb26
6
+ metadata.gz: 9f335b9446f04fe5e684218b1f0f377b16412ac4918065ac610b2abff61d00792a461131b1ab615cd6512ba611a8dde6929af9c1b229f4a36c713e7e0983a22d
7
+ data.tar.gz: 428487913828790e402b3a3c51daceafe8c338ebabfd234d0570424c8af426bc54bfa6f8fbf306d365fd674174a5708936e8a350cce5fcdf5c6426f5d3f1bd37
@@ -1,15 +1,38 @@
1
- require "graphql"
2
1
  require "active_support/inflector"
2
+ require "graphql"
3
+ require "set"
3
4
 
4
5
  module GraphQL
5
- module Client
6
+ class Client
6
7
  class QueryResult
7
- def self.fields
8
- @fields
8
+ # Internal: Get QueryResult class for result of query.
9
+ #
10
+ # Returns subclass of QueryResult or nil.
11
+ def self.wrap(node, name: nil)
12
+ fields = {}
13
+
14
+ node.selections.each do |selection|
15
+ case selection
16
+ when Language::Nodes::FragmentSpread
17
+ when Language::Nodes::Field
18
+ field_name = selection.alias || selection.name
19
+ field_klass = selection.selections.any? ? wrap(selection, name: "#{name}.#{field_name}") : nil
20
+ fields[field_name] ? fields[field_name] |= field_klass : fields[field_name] = field_klass
21
+ when Language::Nodes::InlineFragment
22
+ wrap(selection, name: name).fields.each do |fragment_name, klass|
23
+ fields[fragment_name.to_s] ? fields[fragment_name.to_s] |= klass : fields[fragment_name.to_s] = klass
24
+ end
25
+ end
26
+ end
27
+
28
+ define(name: name, source_node: node, fields: fields)
9
29
  end
10
30
 
11
- def self.define(fields: {})
31
+ # Internal
32
+ def self.define(name:, source_node:, fields: {})
12
33
  Class.new(self) do
34
+ @name = name
35
+ @source_node = source_node
13
36
  @fields = {}
14
37
 
15
38
  fields.each do |field, type|
@@ -62,8 +85,20 @@ module GraphQL
62
85
  end
63
86
  end
64
87
 
88
+ def self.source_node
89
+ @source_node
90
+ end
91
+
92
+ def self.fields
93
+ @fields
94
+ end
95
+
96
+ def self.name
97
+ @name || super || GraphQL::Client::QueryResult.name
98
+ end
99
+
65
100
  def self.inspect
66
- "#<GraphQL::Client::QueryResult fields=#{@fields.keys.inspect}>"
101
+ "#<#{self.name} fields=#{@fields.keys.inspect}>"
67
102
  end
68
103
 
69
104
  def self.cast(obj)
@@ -71,6 +106,14 @@ module GraphQL
71
106
  when Hash
72
107
  new(obj)
73
108
  when QueryResult
109
+ spreads = Set.new(obj.class.source_node.selections.select { |s| s.is_a?(GraphQL::Language::Nodes::FragmentSpread) }.map(&:name))
110
+
111
+ if !spreads.include?(self.source_node.name)
112
+ message = "couldn't cast #{obj.inspect} to #{self.inspect}\n\n"
113
+ suggestion = "\n ...#{name || "YourFragment"} # SUGGESTION"
114
+ message << GraphQL::Language::Generation.generate(obj.class.source_node).sub(/\n}$/, "#{suggestion}\n}")
115
+ raise TypeError, message
116
+ end
74
117
  cast(obj.to_h)
75
118
  when Array
76
119
  obj.map { |e| cast(e) }
@@ -99,7 +142,8 @@ module GraphQL
99
142
  new_fields[name] = value
100
143
  end
101
144
  end
102
- define(fields: new_fields)
145
+ # TODO: Picking first source node seems error prone
146
+ define(name: self.name, source_node: self.source_node, fields: new_fields)
103
147
  end
104
148
 
105
149
  attr_reader :data
@@ -107,7 +151,7 @@ module GraphQL
107
151
 
108
152
  def inspect
109
153
  ivars = (self.class.fields.keys - [:__typename]).map { |sym| "#{sym}=#{instance_variable_get("@#{sym}").inspect}" }
110
- buf = "#<GraphQL::Client::QueryResult"
154
+ buf = "#<#{self.class.name}"
111
155
  buf << " " << @__typename if @__typename
112
156
  buf << " " << ivars.join(" ") if ivars.any?
113
157
  buf << ">"
@@ -1,14 +1,138 @@
1
+ require "active_support/inflector"
1
2
  require "graphql"
2
- require "graphql/client/document"
3
- require "graphql/client/fragment"
4
- require "graphql/client/node"
5
3
  require "graphql/client/query_result"
6
- require "graphql/client/query"
4
+ require "graphql/language/mutator"
5
+ require "graphql/language/nodes/deep_freeze_ext"
6
+ require "graphql/language/operation_slice"
7
+ require "graphql/relay/parser"
7
8
 
8
9
  module GraphQL
9
- module Client
10
- class << self
11
- attr_accessor :schema
10
+ class Client
11
+ class Error < StandardError; end
12
+ class ValidationError < Error; end
13
+
14
+ attr_reader :schema
15
+
16
+ def initialize(schema:)
17
+ @schema = schema
18
+ @definitions = []
19
+ @document = GraphQL::Language::Nodes::Document.new(definitions: @definitions)
20
+ @document_slices = {}
21
+ end
22
+
23
+ class Definition < Module
24
+ def initialize(node:)
25
+ @definition_node = node
26
+ end
27
+
28
+ # Internal: Get underlying operation or fragment defintion AST node for
29
+ # definition.
30
+ #
31
+ # Returns OperationDefinition or FragmentDefinition object.
32
+ attr_reader :definition_node
33
+
34
+ # Public: Ruby constant name of definition.
35
+ #
36
+ # Returns String or errors if definition was not assigned to a constant.
37
+ def name
38
+ @name ||= super || raise(RuntimeError, "definition must be assigned to a constant")
39
+ end
40
+
41
+ # Public: Global name of definition in client document.
42
+ #
43
+ # Returns a GraphQL safe name of the Ruby constant String.
44
+ #
45
+ # "Users::UserQuery" #=> "Users__UserQuery"
46
+ #
47
+ # Returns String.
48
+ def definition_name
49
+ @definition_name ||= name.gsub("::", "__").freeze
50
+ end
51
+
52
+ def new(*args)
53
+ query_result_class.new(*args)
54
+ end
55
+
56
+ private
57
+ def query_result_class
58
+ @query_result_class ||= GraphQL::Client::QueryResult.wrap(definition_node, name: name)
59
+ end
60
+ end
61
+
62
+ class OperationDefinition < Definition
63
+ # Public: Alias for definition name.
64
+ alias_method :operation_name, :definition_name
65
+ end
66
+
67
+ class FragmentDefinition < Definition
68
+ end
69
+
70
+ def parse(str)
71
+ str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)+)/) { |m|
72
+ const_name = $1
73
+ case fragment = ActiveSupport::Inflector.safe_constantize(const_name)
74
+ when FragmentDefinition
75
+ "...#{fragment.definition_name}"
76
+ when nil
77
+ raise NameError, "uninitialized constant #{const_name}\n#{str}"
78
+ else
79
+ raise TypeError, "expected #{const_name} to be a #{FragmentDefinition}, but was a #{fragment.class}"
80
+ end
81
+ }
82
+
83
+ doc = GraphQL::Relay::Parser.parse(str)
84
+
85
+ mutator = GraphQL::Language::Mutator.new(doc)
86
+
87
+ # TODO: Make this __typename injection optional
88
+ mutator.prepend_selection(GraphQL::Language::Nodes::Field.new(name: "__typename").deep_freeze)
89
+
90
+ definitions, renames = {}, {}
91
+ doc.definitions.each do |node|
92
+ local_name = node.name
93
+ definition = case node
94
+ when Language::Nodes::OperationDefinition
95
+ OperationDefinition.new(node: node)
96
+ when Language::Nodes::FragmentDefinition
97
+ FragmentDefinition.new(node: node)
98
+ end
99
+ definitions[local_name] = definition
100
+ renames[local_name] = -> { definition.definition_name }
101
+ end
102
+ mutator.rename_definitions(renames)
103
+
104
+ doc.deep_freeze
105
+
106
+ self.document.definitions.concat(doc.definitions)
107
+
108
+ if definitions[nil]
109
+ definitions[nil]
110
+ else
111
+ Module.new do
112
+ definitions.each do |name, definition|
113
+ const_set(name, definition)
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ def document
120
+ @document
121
+ end
122
+
123
+ def document_slice(operation_name)
124
+ @document_slices[operation_name] ||= Language::OperationSlice.slice(document, operation_name).deep_freeze
125
+ end
126
+
127
+ def validate!
128
+ validator = StaticValidation::Validator.new(schema: @schema)
129
+ query = Query.new(@schema, document: document)
130
+
131
+ validator.validate(query).fetch(:errors).each do |error|
132
+ raise ValidationError, error["message"]
133
+ end
134
+
135
+ nil
12
136
  end
13
137
  end
14
138
  end
@@ -0,0 +1,54 @@
1
+ require "graphql"
2
+ require "set"
3
+
4
+ module GraphQL
5
+ module Language
6
+ class Mutator
7
+ def initialize(document)
8
+ @document = document
9
+ end
10
+
11
+ module LazyName
12
+ def name
13
+ @name.call
14
+ end
15
+ end
16
+
17
+ def rename_definitions(definitions)
18
+ rename_node = -> (node, parent) {
19
+ if name = definitions[node.name]
20
+ node.extend(LazyName) if name.is_a?(Proc)
21
+ node.name = name
22
+ end
23
+ }
24
+
25
+ visitor = Visitor.new(@document)
26
+ visitor[Nodes::FragmentDefinition].leave << rename_node
27
+ visitor[Nodes::OperationDefinition].leave << rename_node
28
+ visitor[Nodes::FragmentSpread].leave << rename_node
29
+ visitor.visit
30
+
31
+ nil
32
+ end
33
+
34
+ def prepend_selection(selection)
35
+ on_selections = -> (node, parent) {
36
+ return if !node.selections.any?
37
+ # TODO: Simplify if AbstractNode#eql? is implemented
38
+ existing_selections = Set.new(node.selections.map { |s| s.respond_to?(:name) ? s.name : nil }.compact)
39
+ selections_to_prepend = [selection].reject { |s| existing_selections.include?(s.name) }
40
+ node.selections = selections_to_prepend + node.selections
41
+ }
42
+
43
+ visitor = Visitor.new(@document)
44
+ visitor[Nodes::Field].leave << on_selections
45
+ visitor[Nodes::FragmentDefinition].leave << on_selections
46
+ visitor[Nodes::InlineFragment].leave << on_selections
47
+ visitor[Nodes::OperationDefinition].leave << on_selections
48
+ visitor.visit
49
+
50
+ nil
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,40 @@
1
+ require "graphql"
2
+
3
+ module GraphQL
4
+ module Language
5
+ module OperationSlice
6
+ # Public: Return's minimal document to represent operation.
7
+ #
8
+ # Find's target operation and any fragment dependencies and returns a
9
+ # new document with just those definitions.
10
+ #
11
+ # document - The Nodes::Document to find definitions.
12
+ # operation_name - The String name of Nodes::OperationDefinition
13
+ #
14
+ # Returns new Nodes::Document.
15
+ def self.slice(document, operation_name)
16
+ seen = Set.new([operation_name])
17
+ stack = [operation_name]
18
+
19
+ while name = stack.pop
20
+ names = find_definition_fragment_spreads(document, name)
21
+ seen.merge(names)
22
+ stack.concat(names.to_a)
23
+ end
24
+
25
+ Nodes::Document.new(definitions: document.definitions.select { |node| seen.include?(node.name) })
26
+ end
27
+
28
+ def self.find_definition_fragment_spreads(document, definition_name)
29
+ definition = document.definitions.find { |node| node.name == definition_name }
30
+ spreads = Set.new
31
+ visitor = Visitor.new(definition)
32
+ visitor[Nodes::FragmentSpread].enter << -> (node, parent) {
33
+ spreads << node.name
34
+ }
35
+ visitor.visit
36
+ spreads
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ require "graphql"
2
+
3
+ module GraphQL
4
+ module Relay
5
+ module Parser
6
+ ANONYMOUS_SENTINEL = "__anonymous__".freeze
7
+
8
+ # Public: Extended GraphQL.parse that supports Relay style anonymous
9
+ # fragments.
10
+ #
11
+ # TODO: See about getting support for this upstreamed to the graphql-ruby
12
+ # gem.
13
+ #
14
+ # str - A GraphQL String
15
+ #
16
+ # Returns a GraphQL::Language::Nodes::Document.
17
+ def self.parse(str)
18
+ str = str.sub(/fragment on /, "fragment #{ANONYMOUS_SENTINEL} on ")
19
+ document = GraphQL.parse(str)
20
+ document.definitions.each do |node|
21
+ node.name = nil if node.name == ANONYMOUS_SENTINEL
22
+ end
23
+ document
24
+ end
25
+ end
26
+ end
27
+ 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.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-05 00:00:00.000000000 Z
11
+ date: 2016-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -74,20 +74,11 @@ extra_rdoc_files: []
74
74
  files:
75
75
  - LICENSE
76
76
  - lib/graphql/client.rb
77
- - lib/graphql/client/document.rb
78
- - lib/graphql/client/fragment.rb
79
- - lib/graphql/client/node.rb
80
- - lib/graphql/client/query.rb
81
77
  - lib/graphql/client/query_result.rb
78
+ - lib/graphql/language/mutator.rb
82
79
  - lib/graphql/language/nodes/deep_freeze_ext.rb
83
- - lib/graphql/language/nodes/inject_selection_ext.rb
84
- - lib/graphql/language/nodes/query_result_class_ext.rb
85
- - lib/graphql/language/nodes/replace_fragment_spread_ext.rb
86
- - lib/graphql/language/nodes/selection_ext.rb
87
- - lib/graphql/language/nodes/validate_ext.rb
88
- - lib/graphql/relay/node_query.rb
89
- - lib/graphql/schema/json_loader.rb
90
- - lib/graphql/schema_load_json.rb
80
+ - lib/graphql/language/operation_slice.rb
81
+ - lib/graphql/relay/parser.rb
91
82
  homepage:
92
83
  licenses:
93
84
  - MIT
@@ -1,48 +0,0 @@
1
- require "graphql"
2
- require "graphql/client/fragment"
3
- require "graphql/client/node"
4
- require "graphql/client/query"
5
- require "graphql/language/nodes/deep_freeze_ext"
6
- require "graphql/language/nodes/inject_selection_ext"
7
- require "graphql/language/nodes/replace_fragment_spread_ext"
8
- require "graphql/language/nodes/validate_ext"
9
-
10
- module GraphQL
11
- module Client
12
- class Document < Node
13
- def self.parse(str, schema: GraphQL::Client.schema)
14
- str = str.strip
15
- str, fragments = scan_interpolated_fragments(str)
16
-
17
- document = GraphQL.parse(str)
18
- document = document.inject_selection(GraphQL::Language::Nodes::Field.new(name: "__typename"))
19
-
20
- document.definitions.each do |definition|
21
- fragments[definition.name.to_sym] = definition if definition.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
22
- end
23
-
24
- document = document.replace_fragment_spread(fragments)
25
- document = document.replace_fragment_spread(fragments) # XXX: Multiple pass
26
-
27
- document.definitions.inject({}) do |doc, definition|
28
- name = definition.name.to_sym
29
-
30
- case definition
31
- when GraphQL::Language::Nodes::OperationDefinition
32
- query = GraphQL::Client::Query.new(definition.deep_freeze, fragments.values).freeze
33
- query.node.validate!(schema: schema) if schema
34
- doc[name] = query
35
-
36
- when GraphQL::Language::Nodes::FragmentDefinition
37
- definition = GraphQL::Language::Nodes::InlineFragment.new(type: definition.type, directives: definition.directives, selections: definition.selections)
38
- fragment = GraphQL::Client::Fragment.new(definition.deep_freeze, fragments.values).freeze
39
- fragment.node.validate!(schema: schema) if schema
40
- doc[name] = fragment
41
- end
42
-
43
- doc
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,32 +0,0 @@
1
- require "graphql"
2
- require "graphql/client/node"
3
- require "graphql/language/nodes/deep_freeze_ext"
4
- require "graphql/language/nodes/inject_selection_ext"
5
- require "graphql/language/nodes/replace_fragment_spread_ext"
6
- require "graphql/language/nodes/validate_ext"
7
-
8
- module GraphQL
9
- module Client
10
- class Fragment < Node
11
- def self.parse(str, schema: GraphQL::Client.schema)
12
- str = str.strip
13
- str, fragments = scan_interpolated_fragments(str)
14
-
15
- if str.start_with?("fragment")
16
- str = str.sub(/^fragment on /, "fragment __anonymous__ on ")
17
- doc = GraphQL.parse(str)
18
- doc = doc.inject_selection(GraphQL::Language::Nodes::Field.new(name: "__typename"))
19
- doc = doc.replace_fragment_spread(fragments)
20
- fragment = doc.definitions.first
21
- node = GraphQL::Language::Nodes::InlineFragment.new(type: fragment.type, directives: fragment.directives, selections: fragment.selections)
22
- else
23
- raise ArgumentError, "expected string to be a fragment:\n#{str}"
24
- end
25
-
26
- fragment = new(node.deep_freeze, fragments.values).freeze
27
- fragment.node.validate!(schema: schema) if schema
28
- fragment
29
- end
30
- end
31
- end
32
- end
@@ -1,36 +0,0 @@
1
- require "active_support/inflector"
2
- require "graphql"
3
- require "graphql/language/nodes/query_result_class_ext"
4
-
5
- module GraphQL
6
- module Client
7
- class Node
8
- def self.scan_interpolated_fragments(str)
9
- fragments, index = {}, 1
10
- str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)+)/) { |m|
11
- index += 1
12
- name = "__fragment#{index}__"
13
- fragments[name.to_sym] = ActiveSupport::Inflector.constantize($1).node
14
- "...#{name}"
15
- }
16
- return str, fragments
17
- end
18
-
19
- attr_reader :node
20
-
21
- attr_reader :fragments
22
-
23
- attr_reader :type
24
-
25
- def initialize(node, fragments)
26
- @node = node
27
- @fragments = fragments
28
- @type = node.query_result_class(shadow: fragments)
29
- end
30
-
31
- def new(*args)
32
- type.new(*args)
33
- end
34
- end
35
- end
36
- end
@@ -1,30 +0,0 @@
1
- require "graphql"
2
- require "graphql/client/node"
3
- require "graphql/language/nodes/deep_freeze_ext"
4
- require "graphql/language/nodes/inject_selection_ext"
5
- require "graphql/language/nodes/replace_fragment_spread_ext"
6
- require "graphql/language/nodes/validate_ext"
7
-
8
- module GraphQL
9
- module Client
10
- class Query < Node
11
- def self.parse(str, schema: GraphQL::Client.schema)
12
- str = str.strip
13
- str, fragments = scan_interpolated_fragments(str)
14
-
15
- if str.start_with?("query")
16
- doc = GraphQL.parse(str)
17
- doc = doc.inject_selection(GraphQL::Language::Nodes::Field.new(name: "__typename"))
18
- doc = doc.replace_fragment_spread(fragments)
19
- node = doc.definitions.first
20
- else
21
- raise ArgumentError, "expected string to be a query:\n#{str}"
22
- end
23
-
24
- query = new(node.deep_freeze, fragments.values).freeze
25
- query.node.validate!(schema: schema) if schema
26
- query
27
- end
28
- end
29
- end
30
- end
@@ -1,44 +0,0 @@
1
- require "graphql"
2
- require "graphql/language/nodes/selection_ext"
3
-
4
- module GraphQL
5
- module Language
6
- module Nodes
7
- module Selections
8
- def inject_selection(*selections)
9
- other = self.dup
10
- other.selections = selections + self.selections.map do |selection|
11
- case selection
12
- when Selections
13
- selection.inject_selection(*selections)
14
- else
15
- selection
16
- end
17
- end
18
- other
19
- end
20
- end
21
-
22
- class Document < AbstractNode
23
- def inject_selection(*args)
24
- other = self.dup
25
- other.definitions = self.definitions.map do |definition|
26
- case definition
27
- when Selections
28
- definition.inject_selection(*args)
29
- else
30
- definition
31
- end
32
- end
33
- other
34
- end
35
- end
36
-
37
- class Field < AbstractNode
38
- def inject_selection(*selections)
39
- self.selections.any? ? super : self
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,70 +0,0 @@
1
- require "graphql"
2
- require "graphql/language/nodes/selection_ext"
3
- require "graphql/client/query_result"
4
- require "set"
5
-
6
- module GraphQL
7
- module Language
8
- module Nodes
9
- module Selections
10
- # Public: Get GraphQL::QueryResult class for result of query.
11
- #
12
- # Returns subclass of QueryResult or nil.
13
- def query_result_class(**kargs)
14
- GraphQL::Client::QueryResult.define(fields: selections_query_result_classes(**kargs))
15
- end
16
-
17
- def selection_query_result_classes(**kargs)
18
- selections_query_result_classes(**kargs)
19
- end
20
-
21
- # Internal: Gather QueryResult classes for each selection.
22
- #
23
- # Returns a Hash[String => (QueryResult|nil)].
24
- def selections_query_result_classes(shadow: Set.new, **kargs)
25
- self.selections.inject({}) do |h, selection|
26
- case selection
27
- when Selection
28
- if !shadow.include?(selection)
29
- selection.selection_query_result_classes(shadow: shadow, **kargs).each do |name, klass|
30
- h[name] ? h[name] |= klass : h[name] = klass
31
- end
32
- end
33
- h
34
- else
35
- raise TypeError, "expected selection to be of type Selection, but was #{selection.class}"
36
- end
37
- end
38
- end
39
- end
40
-
41
- class Field < AbstractNode
42
- # Public: Get GraphQL::QueryResult class for result of query.
43
- #
44
- # Returns subclass of QueryResult or nil.
45
- def query_result_class(**kargs)
46
- if self.selections.any?
47
- super
48
- else
49
- nil
50
- end
51
- end
52
-
53
- def selection_query_result_classes(**kargs)
54
- name = self.alias || self.name
55
- { name => query_result_class(**kargs) }
56
- end
57
- end
58
-
59
- class FragmentSpread < AbstractNode
60
- def selection_query_result_classes(fragments: {}, shadow: Set.new, **kargs)
61
- unless fragment = fragments[name.to_sym]
62
- raise ArgumentError, "missing fragment '#{name}'"
63
- end
64
- return {} if shadow.include?(fragment)
65
- fragment.selection_query_result_classes(fragments: fragments, shadow: shadow, **kargs)
66
- end
67
- end
68
- end
69
- end
70
- end
@@ -1,44 +0,0 @@
1
- require "graphql"
2
- require "graphql/language/nodes/selection_ext"
3
-
4
- module GraphQL
5
- module Language
6
- module Nodes
7
- module Selections
8
- def replace_fragment_spread(fragments)
9
- other = self.dup
10
- other.selections = self.selections.map do |selection|
11
- case selection
12
- when FragmentSpread
13
- if fragment = fragments[selection.name.to_sym]
14
- InlineFragment.new(type: fragment.type, directives: fragment.directives, selections: fragment.selections)
15
- else
16
- selection
17
- end
18
- when Selections
19
- selection.replace_fragment_spread(fragments)
20
- else
21
- selection
22
- end
23
- end
24
- other
25
- end
26
- end
27
-
28
- class Document < AbstractNode
29
- def replace_fragment_spread(fragments)
30
- other = self.dup
31
- other.definitions = self.definitions.map do |definition|
32
- case definition
33
- when Selections
34
- definition.replace_fragment_spread(fragments)
35
- else
36
- definition
37
- end
38
- end
39
- other
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,37 +0,0 @@
1
- require "graphql"
2
-
3
- module GraphQL
4
- module Language
5
- module Nodes
6
- # Public: Define shared trait for Nodes that have a "selections" collection.
7
- module Selections
8
- end
9
-
10
- # Public: Define shared trait for Nodes that may be in a "selections" collection.
11
- module Selection
12
- end
13
-
14
- class Field < AbstractNode
15
- include Selection
16
- include Selections
17
- end
18
-
19
- class FragmentDefinition < AbstractNode
20
- include Selections
21
- end
22
-
23
- class FragmentSpread < AbstractNode
24
- include Selection
25
- end
26
-
27
- class InlineFragment < AbstractNode
28
- include Selection
29
- include Selections
30
- end
31
-
32
- class OperationDefinition < AbstractNode
33
- include Selections
34
- end
35
- end
36
- end
37
- end
@@ -1,45 +0,0 @@
1
- require "graphql"
2
-
3
- module GraphQL
4
- class ValidationError < GraphQL::ExecutionError
5
- end
6
-
7
- module Language
8
- module Nodes
9
- class Document < AbstractNode
10
- def validate!(schema:, rules: StaticValidation::ALL_RULES)
11
- validator = StaticValidation::Validator.new(schema: schema, rules: rules)
12
- query = Query.new(schema, document: self)
13
-
14
- validator.validate(query).fetch(:errors).each do |error|
15
- raise ValidationError, error["message"]
16
- end
17
-
18
- nil
19
- end
20
- end
21
-
22
- class FragmentDefinition < AbstractNode
23
- def validate!(schema:, **kargs)
24
- document = Document.new(definitions: [self])
25
- rules = StaticValidation::ALL_RULES - [StaticValidation::FragmentsAreUsed]
26
- document.validate!(schema: schema, rules: rules, **kargs)
27
- end
28
- end
29
-
30
- class OperationDefinition < AbstractNode
31
- def validate!(schema:, **kargs)
32
- document = Document.new(definitions: [self])
33
- document.validate!(schema: schema, **kargs)
34
- end
35
- end
36
-
37
- class InlineFragment < AbstractNode
38
- def validate!(schema:, **kargs)
39
- fragment = FragmentDefinition.new(name: "FooFragment", type: self.type, directives: self.directives, selections: self.selections)
40
- fragment.validate!(schema: schema, **kargs)
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,19 +0,0 @@
1
- require "graphql"
2
- require "graphql/language/nodes/deep_freeze_ext"
3
-
4
- module GraphQL
5
- module Relay
6
- NODE_QUERY = GraphQL.parse(<<-'GRAPHQL').definitions.first.deep_freeze
7
- query($id: ID!) {
8
- node(id: $id) {
9
- ...NodeFragment
10
- }
11
- }
12
- GRAPHQL
13
-
14
- def self.NodeQuery(fragment)
15
- fragment = GraphQL::Language::Nodes::FragmentDefinition.new(name: "NodeFragment", type: fragment.type, selections: fragment.selections)
16
- GraphQL::Language::Nodes::Document.new(definitions: [NODE_QUERY, fragment])
17
- end
18
- end
19
- end
@@ -1,101 +0,0 @@
1
- require "graphql"
2
- require "json"
3
-
4
- module GraphQL
5
- class Schema
6
- module JSONLoader
7
- def self.define_schema(json)
8
- schema = JSON.load(json).fetch("data").fetch("__schema")
9
- types = Schema::JSONLoader.define_types(schema)
10
- # TODO: handle schema["mutationType"]
11
- # TODO: handle schema["subscriptionType"]
12
- query = types.fetch(schema.fetch("queryType").fetch("name"))
13
- Schema.new(query: query, types: types.values)
14
- end
15
-
16
- def self.define_types(schema)
17
- schema.fetch("types").inject({}) do |types, type|
18
- type_kind, type_name = type.fetch("kind"), type.fetch("name")
19
-
20
- if !type_name.start_with?("__")
21
- case type_kind
22
- when "INTERFACE"
23
- types[type_name] = define_interface(types, type)
24
- when "OBJECT"
25
- types[type_name] = define_object(types, type)
26
- when "SCALAR"
27
- types[type_name] = define_scalar(types, type)
28
- else
29
- # TODO: handle other type kinds
30
- fail NotImplementedError, type_kind + " not implemented"
31
- end
32
- end
33
-
34
- types
35
- end
36
- end
37
-
38
- def self.resolve_type(types, type)
39
- case kind = type.fetch("kind")
40
- when "INTERFACE"
41
- types.fetch(type.fetch("name"))
42
- when "LIST"
43
- ListType.new(of_type: resolve_type(types, type.fetch("ofType")))
44
- when "NON_NULL"
45
- NonNullType.new(of_type: resolve_type(types, type.fetch("ofType")))
46
- when "OBJECT"
47
- types.fetch(type.fetch("name"))
48
- when "SCALAR"
49
- types.fetch(type.fetch("name"))
50
- else
51
- # TODO: handle other type kinds
52
- fail NotImplementedError, kind + " not implemented"
53
- end
54
- end
55
-
56
- def self.define_interface(types, type)
57
- InterfaceType.define do
58
- name type.fetch("name")
59
- end
60
- end
61
-
62
- def self.define_object(types, type)
63
- ObjectType.define do
64
- name type.fetch("name")
65
- description type["description"]
66
-
67
- Array(type["fields"]).each do |field_data|
68
- field field_data["name"] do
69
- type JSONLoader.resolve_type(types, field_data["type"])
70
- description field_data["description"]
71
- field_data["args"].each do |arg|
72
- argument arg["name"] do
73
- type JSONLoader.resolve_type(types, arg["type"])
74
- description arg["description"]
75
- end
76
- end
77
- end
78
- end
79
- end
80
- end
81
-
82
- def self.define_scalar(types, type)
83
- case name = type.fetch("name")
84
- when "Int"
85
- INT_TYPE
86
- when "String"
87
- STRING_TYPE
88
- when "Float"
89
- FLOAT_TYPE
90
- when "Boolean"
91
- BOOLEAN_TYPE
92
- when "ID"
93
- ID_TYPE
94
- else
95
- # TODO: handle other scalar names
96
- fail NotImplementedError, name + " scalar not implemented"
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,10 +0,0 @@
1
- require "graphql"
2
- require "graphql/schema/json_loader"
3
-
4
- module GraphQL
5
- class Schema
6
- def self.load_json(json)
7
- Schema::JSONLoader.define_schema(json)
8
- end
9
- end
10
- end