graphql-client 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2c235ea2f0b7616533466fbc80031bf4d8d5a7ee
4
+ data.tar.gz: fc4192d111b17dc3cdf5e28a21e70818e2534695
5
+ SHA512:
6
+ metadata.gz: d21e6ae9e95bc4ce084d566d49d67ed08e7863aab08df6c35099714dee0e2bab0fa6ea581b5139a4cbed08306510b3278c020c4a5b57d7658ebb6d6a560445d7
7
+ data.tar.gz: d5ee1964fd2c9f01e0f60b4c99166a27eb8201928a10000f59b70414d84385abaa06600ad1d494399287db46a01cc6a771b29fd61012e3a86332ea92cdb94a42
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 GitHub, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,14 @@
1
+ require "graphql"
2
+ require "graphql/client/document"
3
+ require "graphql/client/fragment"
4
+ require "graphql/client/node"
5
+ require "graphql/client/query_result"
6
+ require "graphql/client/query"
7
+
8
+ module GraphQL
9
+ module Client
10
+ class << self
11
+ attr_accessor :schema
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,47 @@
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
@@ -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
@@ -0,0 +1,102 @@
1
+ require "graphql"
2
+ require "active_support/inflector"
3
+
4
+ module GraphQL
5
+ module Client
6
+ class QueryResult
7
+ def self.fields
8
+ @fields
9
+ end
10
+
11
+ def self.define(fields: {})
12
+ Class.new(self) do
13
+ @fields = {}
14
+
15
+ fields.each do |field, type|
16
+ @fields[field.to_sym] = type
17
+
18
+ send :attr_reader, field
19
+
20
+ # Convert GraphQL camelcase to snake case: commitComments -> commit_comments
21
+ field_alias = ActiveSupport::Inflector.underscore(field)
22
+ if field != field_alias
23
+ send :alias_method, field_alias, field
24
+ end
25
+
26
+ class_eval <<-RUBY, __FILE__, __LINE__
27
+ def #{field_alias}?
28
+ #{field_alias} ? true : false
29
+ end
30
+ RUBY
31
+ end
32
+
33
+ assigns = fields.map do |field, type|
34
+ if type
35
+ <<-RUBY
36
+ @#{field} = self.class.fields[:#{field}].cast(@data["#{field}"])
37
+ RUBY
38
+ else
39
+ <<-RUBY
40
+ @#{field} = @data["#{field}"]
41
+ RUBY
42
+ end
43
+ end
44
+
45
+ class_eval <<-RUBY, __FILE__, __LINE__
46
+ def initialize(data)
47
+ @data = data
48
+ #{assigns.join("\n")}
49
+ freeze
50
+ end
51
+ RUBY
52
+ end
53
+ end
54
+
55
+ def self.inspect
56
+ "#<GraphQL::Client::QueryResult fields=#{@fields.keys.inspect}>"
57
+ end
58
+
59
+ def self.cast(obj)
60
+ case obj
61
+ when Hash
62
+ new(obj)
63
+ when QueryResult
64
+ cast(obj.to_h)
65
+ when Array
66
+ obj.map { |e| cast(e) }
67
+ when NilClass
68
+ nil
69
+ else
70
+ raise TypeError, "#{obj.class}"
71
+ end
72
+ end
73
+
74
+ def self.new(obj)
75
+ case obj
76
+ when Hash
77
+ super
78
+ else
79
+ cast(obj)
80
+ end
81
+ end
82
+
83
+ attr_reader :data
84
+ alias_method :to_h, :data
85
+
86
+ def inspect
87
+ ivars = (self.class.fields.keys - [:__typename]).map { |sym| "#{sym}=#{instance_variable_get("@#{sym}").inspect}" }
88
+ buf = "#<GraphQL::Client::QueryResult"
89
+ buf << " " << @__typename if @__typename
90
+ buf << " " << ivars.join(" ") if ivars.any?
91
+ buf << ">"
92
+ buf
93
+ end
94
+
95
+ def method_missing(*args)
96
+ super
97
+ rescue NoMethodError => e
98
+ raise NoMethodError, "undefined method `#{e.name}' for #{inspect}"
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,21 @@
1
+ require "graphql"
2
+
3
+ module GraphQL
4
+ module Language
5
+ module Nodes
6
+ class AbstractNode
7
+ # Public: Freeze entire Node tree
8
+ #
9
+ # Returns self Node.
10
+ def deep_freeze
11
+ self.class.child_attributes.each do |attr_name|
12
+ public_send(attr_name).freeze.each do |node|
13
+ node.deep_freeze
14
+ end
15
+ end
16
+ freeze
17
+ end
18
+ end
19
+ end
20
+ end
21
+ 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 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,69 @@
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
+ {}
30
+ else
31
+ h.merge!(selection.selection_query_result_classes(shadow: shadow, **kargs))
32
+ end
33
+ else
34
+ raise TypeError, "expected selection to be of type Selection, but was #{selection.class}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ class Field < AbstractNode
41
+ # Public: Get GraphQL::QueryResult class for result of query.
42
+ #
43
+ # Returns subclass of QueryResult or nil.
44
+ def query_result_class(**kargs)
45
+ if self.selections.any?
46
+ super
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ def selection_query_result_classes(**kargs)
53
+ name = self.alias || self.name
54
+ { name => query_result_class(**kargs) }
55
+ end
56
+ end
57
+
58
+ class FragmentSpread < AbstractNode
59
+ def selection_query_result_classes(fragments: {}, shadow: Set.new, **kargs)
60
+ unless fragment = fragments[name.to_sym]
61
+ raise ArgumentError, "missing fragment '#{name}'"
62
+ end
63
+ return {} if shadow.include?(fragment)
64
+ fragment.selection_query_result_classes(fragments: fragments, shadow: shadow, **kargs)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ 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
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: graphql-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - GitHub
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: graphql
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.17'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.17'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '11.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '11.2'
69
+ description:
70
+ email:
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - LICENSE
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
+ - lib/graphql/client/query_result.rb
82
+ - 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
+ homepage:
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: 2.3.0
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.5.1
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: "???"
113
+ test_files: []
114
+ has_rdoc: