graphql-client 0.0.6 → 0.0.7

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: 852686ecf24561871545329aeb4868baaccb99de
4
- data.tar.gz: 2bd0845ad82f0ba555497e0a46c315a9d8a6fa0f
3
+ metadata.gz: 8414ab402cf8454eb7d34081edc3c17fff0611de
4
+ data.tar.gz: 2a1351fe377f4e9999b9a0c5cfedd04081240753
5
5
  SHA512:
6
- metadata.gz: 58701e7031146155bcf9584bf61cdbee25f6ac9bf61121eccd5e915970624d2755aef071f18c781d38fcbf3ca1878fccff4f22d33b7dbe3c537598a597658f23
7
- data.tar.gz: 8dfe674b8d2c39233fcdfd533e8ea516c010e0cecb7be38fb01c2128f76dc466e61e7dd334e0dff36e810465d9e9f6064d7c5f9969de9e65e081fa0dba0bc9ea
6
+ metadata.gz: b1b30fc5a6c9f06f03a8c3ed9e69614bb1f7d3a0cbd449bb72a2077d34a154a6b2b48bd3d0b988997b2d59716941a3121fe2958f5948dff6afcce17c779c3cdd
7
+ data.tar.gz: dfbe13c52c3bd8d9df76129b8de2ec7f4fe2bb430c1788f9d77966c8a75f57d8fcbdc973e280239f763fba1d6976be8babaffdb86590b0da35819b40e1c0fb26
@@ -1,100 +1,14 @@
1
- require "active_support/inflector"
2
1
  require "graphql"
3
- require "graphql/client/const_proxy"
2
+ require "graphql/client/document"
3
+ require "graphql/client/fragment"
4
+ require "graphql/client/node"
4
5
  require "graphql/client/query_result"
5
- require "graphql/language/mutator"
6
- require "graphql/language/nodes/deep_freeze_ext"
7
- require "graphql/language/operation_slice"
8
- require "graphql/relay/parser"
6
+ require "graphql/client/query"
9
7
 
10
8
  module GraphQL
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
9
+ module Client
10
+ class << self
11
+ attr_accessor :schema
98
12
  end
99
13
  end
100
14
  end
@@ -0,0 +1,48 @@
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
@@ -0,0 +1,32 @@
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
@@ -0,0 +1,36 @@
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
@@ -0,0 +1,30 @@
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,38 +1,15 @@
1
- require "active_support/inflector"
2
1
  require "graphql"
3
- require "set"
2
+ require "active_support/inflector"
4
3
 
5
4
  module GraphQL
6
- class Client
5
+ module Client
7
6
  class QueryResult
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)
7
+ def self.fields
8
+ @fields
29
9
  end
30
10
 
31
- # Internal
32
- def self.define(name:, source_node:, fields: {})
11
+ def self.define(fields: {})
33
12
  Class.new(self) do
34
- @name = name
35
- @source_node = source_node
36
13
  @fields = {}
37
14
 
38
15
  fields.each do |field, type|
@@ -85,20 +62,8 @@ module GraphQL
85
62
  end
86
63
  end
87
64
 
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
-
100
65
  def self.inspect
101
- "#<#{self.name} fields=#{@fields.keys.inspect}>"
66
+ "#<GraphQL::Client::QueryResult fields=#{@fields.keys.inspect}>"
102
67
  end
103
68
 
104
69
  def self.cast(obj)
@@ -106,14 +71,6 @@ module GraphQL
106
71
  when Hash
107
72
  new(obj)
108
73
  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
117
74
  cast(obj.to_h)
118
75
  when Array
119
76
  obj.map { |e| cast(e) }
@@ -142,8 +99,7 @@ module GraphQL
142
99
  new_fields[name] = value
143
100
  end
144
101
  end
145
- # TODO: Picking first source node seems error prone
146
- define(name: self.name, source_node: self.source_node, fields: new_fields)
102
+ define(fields: new_fields)
147
103
  end
148
104
 
149
105
  attr_reader :data
@@ -151,7 +107,7 @@ module GraphQL
151
107
 
152
108
  def inspect
153
109
  ivars = (self.class.fields.keys - [:__typename]).map { |sym| "#{sym}=#{instance_variable_get("@#{sym}").inspect}" }
154
- buf = "#<#{self.class.name}"
110
+ buf = "#<GraphQL::Client::QueryResult"
155
111
  buf << " " << @__typename if @__typename
156
112
  buf << " " << ivars.join(" ") if ivars.any?
157
113
  buf << ">"
@@ -0,0 +1,44 @@
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
@@ -0,0 +1,70 @@
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
@@ -0,0 +1,44 @@
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
@@ -0,0 +1,37 @@
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
@@ -0,0 +1,45 @@
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
@@ -0,0 +1,19 @@
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
@@ -0,0 +1,101 @@
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
@@ -0,0 +1,10 @@
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
@@ -74,12 +74,20 @@ extra_rdoc_files: []
74
74
  files:
75
75
  - LICENSE
76
76
  - lib/graphql/client.rb
77
- - lib/graphql/client/const_proxy.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
78
81
  - lib/graphql/client/query_result.rb
79
- - lib/graphql/language/mutator.rb
80
82
  - lib/graphql/language/nodes/deep_freeze_ext.rb
81
- - lib/graphql/language/operation_slice.rb
82
- - lib/graphql/relay/parser.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
83
91
  homepage:
84
92
  licenses:
85
93
  - MIT
@@ -1,29 +0,0 @@
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,45 +0,0 @@
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
@@ -1,31 +0,0 @@
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
@@ -1,27 +0,0 @@
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