graphql-client 0.0.5 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f327b5063c82073f7208c75d7a8e178694b67ce5
4
- data.tar.gz: 2fba5fd397e36ff3f3cd81cc1515a9dd2573476a
3
+ metadata.gz: 852686ecf24561871545329aeb4868baaccb99de
4
+ data.tar.gz: 2bd0845ad82f0ba555497e0a46c315a9d8a6fa0f
5
5
  SHA512:
6
- metadata.gz: 55bf804e30c3d080d899d49c2016aab6932699565a95d0eae7e90a16bfcd645077a179ac11c08aba366bb583b4ee7ddf73dafad57bea2c0851f081587a6a0191
7
- data.tar.gz: f1fe23003faefe5a176c696cfe6fb68b63cb2edc6c0c14bfb65ffb12c823943e4518bffb39b718d5f04270f3f8e8be224280a4990e3e527212b83ba83dcee97c
6
+ metadata.gz: 58701e7031146155bcf9584bf61cdbee25f6ac9bf61121eccd5e915970624d2755aef071f18c781d38fcbf3ca1878fccff4f22d33b7dbe3c537598a597658f23
7
+ data.tar.gz: 8dfe674b8d2c39233fcdfd533e8ea516c010e0cecb7be38fb01c2128f76dc466e61e7dd334e0dff36e810465d9e9f6064d7c5f9969de9e65e081fa0dba0bc9ea
@@ -1,14 +1,100 @@
1
+ require "active_support/inflector"
1
2
  require "graphql"
2
- require "graphql/client/document"
3
- require "graphql/client/fragment"
4
- require "graphql/client/node"
3
+ require "graphql/client/const_proxy"
5
4
  require "graphql/client/query_result"
6
- require "graphql/client/query"
5
+ require "graphql/language/mutator"
6
+ require "graphql/language/nodes/deep_freeze_ext"
7
+ require "graphql/language/operation_slice"
8
+ require "graphql/relay/parser"
7
9
 
8
10
  module GraphQL
9
- module Client
10
- class << self
11
- attr_accessor :schema
11
+ class Client
12
+ class Error < StandardError; end
13
+ class ValidationError < Error; end
14
+
15
+ attr_reader :schema
16
+
17
+ def initialize(schema:)
18
+ @schema = schema
19
+ @definitions = []
20
+ end
21
+
22
+ class Definition
23
+ def initialize(name:, client:, source:)
24
+ @name = name
25
+ @client = client
26
+ @_nodes = @client._parse(@name, source)
27
+ @query_result = GraphQL::Client::QueryResult.wrap(@_nodes.first, name: name)
28
+ end
29
+
30
+ attr_reader :_nodes
31
+
32
+ def operation_name
33
+ if op = @_nodes.find { |d| d.is_a?(GraphQL::Language::Nodes::OperationDefinition) }
34
+ op.name
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ def document
41
+ @document ||= Language::OperationSlice.slice(@client.document, operation_name).deep_freeze
42
+ end
43
+
44
+ def new(*args)
45
+ @query_result.new(*args)
46
+ end
47
+ end
48
+
49
+ def parse(str)
50
+ definition = ConstProxy.new { |name| Definition.new(client: self, name: name, source: str) }
51
+ @definitions << definition
52
+ definition
53
+ end
54
+
55
+ def _parse(name, str)
56
+ str = str.strip
57
+
58
+ str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)+)(\.([a-zA-Z0-9_]+))?/) { |m|
59
+ const_name, fragment_name = $1, $4
60
+ nodes = ActiveSupport::Inflector.constantize(const_name)._nodes
61
+
62
+ fragment_name = fragment_name ?
63
+ nodes.find { |n| n.name.end_with?(fragment_name) }.name : # XXX
64
+ nodes.first.name
65
+
66
+ "...#{fragment_name}"
67
+ }
68
+
69
+ doc = GraphQL::Relay::Parser.parse(str)
70
+
71
+ mutator = GraphQL::Language::Mutator.new(doc)
72
+
73
+ aliases = {}
74
+ doc.definitions.each do |definition|
75
+ aliases[definition.name] = (name.split("::") << definition.name).compact.join("__")
76
+ end
77
+ mutator.rename_definitions(aliases)
78
+
79
+ # TODO: Make this __typename injection optional
80
+ mutator.prepend_selection(GraphQL::Language::Nodes::Field.new(name: "__typename").deep_freeze)
81
+
82
+ doc.definitions.map(&:deep_freeze)
83
+ end
84
+
85
+ def document
86
+ GraphQL::Language::Nodes::Document.new(definitions: @definitions.flat_map(&:_nodes)).deep_freeze
87
+ end
88
+
89
+ def validate!
90
+ validator = StaticValidation::Validator.new(schema: @schema)
91
+ query = Query.new(@schema, document: document)
92
+
93
+ validator.validate(query).fetch(:errors).each do |error|
94
+ raise ValidationError, error["message"]
95
+ end
96
+
97
+ nil
12
98
  end
13
99
  end
14
100
  end
@@ -0,0 +1,29 @@
1
+ module GraphQL
2
+ class Client
3
+ # Internal: Hack to track the constant name an object is assigned to.
4
+ #
5
+ # FooConstant = ConstProxy.new { |name|
6
+ # name # "FooConstant"
7
+ # }
8
+ #
9
+ module ConstProxy
10
+ def self.new(&initializer)
11
+ raise ArgumentError, "initializer required" unless block_given?
12
+
13
+ Module.new do
14
+ extend ConstProxy
15
+ @initializer = initializer
16
+ end
17
+ end
18
+
19
+ def name
20
+ super || raise(RuntimeError, "expected object to be assigned to a constant")
21
+ end
22
+
23
+ def method_missing(*args, &block)
24
+ @target ||= @initializer.call(self.name)
25
+ @target.send(*args, &block)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -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 << ">"
@@ -0,0 +1,45 @@
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
+ def rename_definitions(definitions)
12
+ rename_node = -> (node, parent) {
13
+ node.name = definitions.fetch(node.name, node.name)
14
+ }
15
+
16
+ visitor = Visitor.new(@document)
17
+ visitor[Nodes::FragmentDefinition].leave << rename_node
18
+ visitor[Nodes::OperationDefinition].leave << rename_node
19
+ visitor[Nodes::FragmentSpread].leave << rename_node
20
+ visitor.visit
21
+
22
+ nil
23
+ end
24
+
25
+ def prepend_selection(selection)
26
+ on_selections = -> (node, parent) {
27
+ return if !node.selections.any?
28
+ # TODO: Simplify if AbstractNode#eql? is implemented
29
+ existing_selections = Set.new(node.selections.map { |s| s.respond_to?(:name) ? s.name : nil }.compact)
30
+ selections_to_prepend = [selection].reject { |s| existing_selections.include?(s.name) }
31
+ node.selections = selections_to_prepend + node.selections
32
+ }
33
+
34
+ visitor = Visitor.new(@document)
35
+ visitor[Nodes::Field].leave << on_selections
36
+ visitor[Nodes::FragmentDefinition].leave << on_selections
37
+ visitor[Nodes::InlineFragment].leave << on_selections
38
+ visitor[Nodes::OperationDefinition].leave << on_selections
39
+ visitor.visit
40
+
41
+ nil
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
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
+ definitions = []
17
+ definitions << document.definitions.find { |d| d.name == operation_name }
18
+
19
+ visitor = Visitor.new(document)
20
+ visitor[Nodes::FragmentSpread] << -> (node, parent) {
21
+ if fragment = document.definitions.find { |d| d.name == node.name }
22
+ definitions << fragment
23
+ end
24
+ }
25
+ visitor.visit
26
+
27
+ Nodes::Document.new(definitions: definitions.uniq)
28
+ end
29
+ end
30
+ end
31
+ 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.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-19 00:00:00.000000000 Z
11
+ date: 2016-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -74,20 +74,12 @@ 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
77
+ - lib/graphql/client/const_proxy.rb
81
78
  - lib/graphql/client/query_result.rb
79
+ - lib/graphql/language/mutator.rb
82
80
  - 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
81
+ - lib/graphql/language/operation_slice.rb
82
+ - lib/graphql/relay/parser.rb
91
83
  homepage:
92
84
  licenses:
93
85
  - MIT
@@ -108,9 +100,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
100
  version: '0'
109
101
  requirements: []
110
102
  rubyforge_project:
111
- rubygems_version: 2.5.1
103
+ rubygems_version: 2.4.5.1
112
104
  signing_key:
113
105
  specification_version: 4
114
106
  summary: "???"
115
107
  test_files: []
116
- has_rdoc:
@@ -1,47 +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
-
26
- document.definitions.inject({}) do |doc, definition|
27
- name = definition.name.to_sym
28
-
29
- case definition
30
- when GraphQL::Language::Nodes::OperationDefinition
31
- query = GraphQL::Client::Query.new(definition.deep_freeze, fragments.values).freeze
32
- query.node.validate!(schema: schema) if schema
33
- doc[name] = query
34
-
35
- when GraphQL::Language::Nodes::FragmentDefinition
36
- definition = GraphQL::Language::Nodes::InlineFragment.new(type: definition.type, directives: definition.directives, selections: definition.selections)
37
- fragment = GraphQL::Client::Fragment.new(definition.deep_freeze, fragments.values).freeze
38
- fragment.node.validate!(schema: schema) if schema
39
- doc[name] = fragment
40
- end
41
-
42
- doc
43
- end
44
- end
45
- end
46
- end
47
- 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