graphql 0.0.4 → 0.1.0

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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graph_ql/directive.rb +36 -0
  3. data/lib/graph_ql/directives/directive_chain.rb +33 -0
  4. data/lib/graph_ql/directives/include_directive.rb +15 -0
  5. data/lib/graph_ql/directives/skip_directive.rb +15 -0
  6. data/lib/graph_ql/enum.rb +34 -0
  7. data/lib/graph_ql/fields/abstract_field.rb +37 -0
  8. data/lib/graph_ql/fields/access_field.rb +24 -0
  9. data/lib/graph_ql/fields/field.rb +34 -0
  10. data/lib/graph_ql/interface.rb +14 -0
  11. data/lib/graph_ql/introspection/arguments_field.rb +5 -0
  12. data/lib/graph_ql/introspection/directive_type.rb +12 -0
  13. data/lib/graph_ql/introspection/enum_value_type.rb +10 -0
  14. data/lib/graph_ql/introspection/enum_values_field.rb +15 -0
  15. data/lib/graph_ql/introspection/field_type.rb +11 -0
  16. data/lib/graph_ql/introspection/fields_field.rb +14 -0
  17. data/lib/graph_ql/introspection/input_fields_field.rb +12 -0
  18. data/lib/graph_ql/introspection/input_value_type.rb +10 -0
  19. data/lib/graph_ql/introspection/of_type_field.rb +12 -0
  20. data/lib/graph_ql/introspection/possible_types_field.rb +12 -0
  21. data/lib/graph_ql/introspection/schema_type.rb +32 -0
  22. data/lib/graph_ql/introspection/type_kind_enum.rb +7 -0
  23. data/lib/graph_ql/introspection/type_type.rb +22 -0
  24. data/lib/graph_ql/parser/nodes.rb +72 -0
  25. data/lib/graph_ql/parser/parser.rb +108 -0
  26. data/lib/graph_ql/parser/transform.rb +86 -0
  27. data/lib/graph_ql/parser/visitor.rb +47 -0
  28. data/lib/graph_ql/query.rb +50 -0
  29. data/lib/graph_ql/query/arguments.rb +25 -0
  30. data/lib/graph_ql/query/field_resolution_strategy.rb +83 -0
  31. data/lib/graph_ql/query/fragment_spread_resolution_strategy.rb +16 -0
  32. data/lib/graph_ql/query/inline_fragment_resolution_strategy.rb +14 -0
  33. data/lib/graph_ql/query/operation_resolver.rb +28 -0
  34. data/lib/graph_ql/query/selection_resolver.rb +20 -0
  35. data/lib/graph_ql/query/type_resolver.rb +19 -0
  36. data/lib/graph_ql/repl.rb +27 -0
  37. data/lib/graph_ql/schema.rb +30 -0
  38. data/lib/graph_ql/schema/type_reducer.rb +44 -0
  39. data/lib/graph_ql/type_kinds.rb +15 -0
  40. data/lib/graph_ql/types/abstract_type.rb +14 -0
  41. data/lib/graph_ql/types/boolean_type.rb +6 -0
  42. data/lib/graph_ql/types/float_type.rb +6 -0
  43. data/lib/graph_ql/types/input_object_type.rb +17 -0
  44. data/lib/graph_ql/types/input_value.rb +10 -0
  45. data/lib/graph_ql/types/int_type.rb +6 -0
  46. data/lib/graph_ql/types/list_type.rb +10 -0
  47. data/lib/graph_ql/types/non_null_type.rb +18 -0
  48. data/lib/graph_ql/types/non_null_with_bang.rb +5 -0
  49. data/lib/graph_ql/types/object_type.rb +62 -0
  50. data/lib/graph_ql/types/scalar_type.rb +5 -0
  51. data/lib/graph_ql/types/string_type.rb +6 -0
  52. data/lib/graph_ql/types/type_definer.rb +16 -0
  53. data/lib/graph_ql/union.rb +35 -0
  54. data/lib/graph_ql/validations/fields_are_defined_on_type.rb +44 -0
  55. data/lib/graph_ql/validations/fields_will_merge.rb +80 -0
  56. data/lib/graph_ql/validations/fragments_are_used.rb +24 -0
  57. data/lib/graph_ql/validator.rb +29 -0
  58. data/lib/graph_ql/version.rb +3 -0
  59. data/lib/graphql.rb +92 -99
  60. data/readme.md +17 -177
  61. data/spec/graph_ql/directive_spec.rb +81 -0
  62. data/spec/graph_ql/enum_spec.rb +5 -0
  63. data/spec/graph_ql/fields/field_spec.rb +10 -0
  64. data/spec/graph_ql/interface_spec.rb +13 -0
  65. data/spec/graph_ql/introspection/directive_type_spec.rb +40 -0
  66. data/spec/graph_ql/introspection/schema_type_spec.rb +39 -0
  67. data/spec/graph_ql/introspection/type_type_spec.rb +104 -0
  68. data/spec/graph_ql/parser/parser_spec.rb +120 -0
  69. data/spec/graph_ql/parser/transform_spec.rb +109 -0
  70. data/spec/graph_ql/parser/visitor_spec.rb +31 -0
  71. data/spec/graph_ql/query/operation_resolver_spec.rb +14 -0
  72. data/spec/graph_ql/query_spec.rb +82 -0
  73. data/spec/graph_ql/schema/type_reducer_spec.rb +24 -0
  74. data/spec/graph_ql/types/input_object_type_spec.rb +12 -0
  75. data/spec/graph_ql/types/object_type_spec.rb +35 -0
  76. data/spec/graph_ql/union_spec.rb +27 -0
  77. data/spec/graph_ql/validations/fields_are_defined_on_type_spec.rb +28 -0
  78. data/spec/graph_ql/validations/fields_will_merge_spec.rb +40 -0
  79. data/spec/graph_ql/validations/fragments_are_used_spec.rb +28 -0
  80. data/spec/graph_ql/validator_spec.rb +24 -0
  81. data/spec/spec_helper.rb +2 -2
  82. data/spec/support/dummy_app.rb +123 -63
  83. data/spec/support/dummy_data.rb +11 -0
  84. metadata +107 -59
  85. data/lib/graphql/call.rb +0 -8
  86. data/lib/graphql/connection.rb +0 -65
  87. data/lib/graphql/field.rb +0 -12
  88. data/lib/graphql/field_definer.rb +0 -25
  89. data/lib/graphql/introspection/call_type.rb +0 -13
  90. data/lib/graphql/introspection/connection.rb +0 -9
  91. data/lib/graphql/introspection/field_type.rb +0 -10
  92. data/lib/graphql/introspection/root_call_argument_node.rb +0 -5
  93. data/lib/graphql/introspection/root_call_type.rb +0 -20
  94. data/lib/graphql/introspection/schema_call.rb +0 -8
  95. data/lib/graphql/introspection/schema_type.rb +0 -17
  96. data/lib/graphql/introspection/type_call.rb +0 -8
  97. data/lib/graphql/introspection/type_type.rb +0 -18
  98. data/lib/graphql/node.rb +0 -244
  99. data/lib/graphql/parser/parser.rb +0 -39
  100. data/lib/graphql/parser/transform.rb +0 -22
  101. data/lib/graphql/query.rb +0 -109
  102. data/lib/graphql/root_call.rb +0 -202
  103. data/lib/graphql/root_call_argument.rb +0 -11
  104. data/lib/graphql/root_call_argument_definer.rb +0 -17
  105. data/lib/graphql/schema/all.rb +0 -46
  106. data/lib/graphql/schema/schema.rb +0 -87
  107. data/lib/graphql/schema/schema_validation.rb +0 -32
  108. data/lib/graphql/syntax/call.rb +0 -8
  109. data/lib/graphql/syntax/field.rb +0 -9
  110. data/lib/graphql/syntax/fragment.rb +0 -7
  111. data/lib/graphql/syntax/node.rb +0 -8
  112. data/lib/graphql/syntax/query.rb +0 -8
  113. data/lib/graphql/syntax/variable.rb +0 -7
  114. data/lib/graphql/types/boolean_type.rb +0 -3
  115. data/lib/graphql/types/number_type.rb +0 -3
  116. data/lib/graphql/types/object_type.rb +0 -6
  117. data/lib/graphql/types/string_type.rb +0 -3
  118. data/lib/graphql/version.rb +0 -3
  119. data/spec/graphql/node_spec.rb +0 -69
  120. data/spec/graphql/parser/parser_spec.rb +0 -168
  121. data/spec/graphql/parser/transform_spec.rb +0 -157
  122. data/spec/graphql/query_spec.rb +0 -274
  123. data/spec/graphql/root_call_spec.rb +0 -69
  124. data/spec/graphql/schema/schema_spec.rb +0 -93
  125. data/spec/graphql/schema/schema_validation_spec.rb +0 -48
  126. data/spec/support/nodes.rb +0 -175
@@ -1,11 +0,0 @@
1
- # Created by {RootCall.argument}, used internally by GraphQL
2
- class GraphQL::RootCallArgument
3
- attr_reader :type, :name, :any_number
4
- attr_accessor :index
5
- def initialize(type:, name:, any_number: false, index: nil)
6
- @type = type
7
- @name = name
8
- @any_number = any_number
9
- @index = index
10
- end
11
- end
@@ -1,17 +0,0 @@
1
- # Enables the {RootCall.argument} API, used internall by GraphQL
2
- class GraphQL::RootCallArgumentDefiner
3
- ARGUMENT_TYPES = [:string, :object, :number]
4
-
5
- def initialize(owner)
6
- @owner = owner
7
- end
8
-
9
- def none
10
- end
11
-
12
- ARGUMENT_TYPES.each do |arg_type|
13
- define_method arg_type do |name, any_number: false|
14
- @owner.add_argument(GraphQL::RootCallArgument.new(type: arg_type.to_s, name: name.to_s, any_number: any_number))
15
- end
16
- end
17
- end
@@ -1,46 +0,0 @@
1
- # This query string yields the whole schema. Access it from {GraphQL::Schema::Schema#all}
2
- GraphQL::Schema::ALL = "
3
- schema() {
4
- calls {
5
- count,
6
- edges {
7
- node {
8
- name,
9
- returns,
10
- arguments {
11
- edges {
12
- node {
13
- name, type
14
- }
15
- }
16
- }
17
- }
18
- }
19
- },
20
- types {
21
- count,
22
- edges {
23
- node {
24
- name,
25
- fields {
26
- count,
27
- edges {
28
- node {
29
- name,
30
- type,
31
- calls {
32
- count,
33
- edges {
34
- node {
35
- name,
36
- arguments
37
- }
38
- }
39
- }
40
- }
41
- }
42
- }
43
- }
44
- }
45
- }
46
- }"
@@ -1,87 +0,0 @@
1
- # {GraphQL::SCHEMA} keeps track of defined nodes, fields and calls.
2
- #
3
- # Although you don't interact with it directly, it responds to queries for `schema()` and `__type__` info.
4
- #
5
- # You can validate it at runtime with {#validate}
6
- # @example
7
- # # validate the schema
8
- # GraphQL::SCHEMA.validate
9
- #
10
- require "singleton"
11
-
12
- class GraphQL::Schema::Schema
13
- include Singleton
14
- attr_reader :types, :calls, :class_names
15
- def initialize
16
- @types = {}
17
- @class_names = {}
18
- @calls = {}
19
- end
20
-
21
- # Queries the whole schema and returns the result
22
- def all
23
- GraphQL::Query.new(GraphQL::Schema::ALL).as_result
24
- end
25
-
26
- def validate
27
- validation = GraphQL::Schema::SchemaValidation.new
28
- validation.validate(self)
29
- end
30
-
31
- def add_call(call_class)
32
- remove_call(call_class)
33
- raise "You can't make #{call_class.name}'s type '#{call_class.schema_name}'" if call_class.schema_name.blank?
34
- @calls[call_class.schema_name] = call_class
35
- end
36
-
37
- def get_call(identifier)
38
- @calls[identifier.to_s] || raise(GraphQL::RootCallNotDefinedError.new(identifier))
39
- end
40
-
41
- def remove_call(call_class)
42
- existing_name = @calls.key(call_class)
43
- if existing_name
44
- @calls.delete(existing_name)
45
- end
46
- end
47
-
48
- def call_names
49
- @calls.keys
50
- end
51
-
52
- def add_type(node_class)
53
- existing_name = @types.key(node_class)
54
- if existing_name
55
- @types.delete(existing_name)
56
- end
57
-
58
- node_class.exposes_class_names.each do |exposes_class_name|
59
- @class_names[exposes_class_name] = node_class
60
- end
61
-
62
- @types[node_class.schema_name] = node_class
63
- end
64
-
65
- def get_type(identifier)
66
- @types[identifier.to_s] || raise(GraphQL::NodeNotDefinedError.new(identifier))
67
- end
68
-
69
- def type_names
70
- @types.keys.sort
71
- end
72
-
73
- def type_for_object(app_object)
74
- registered_class_names = @class_names.keys
75
- if app_object.is_a?(Class)
76
- app_class = app_object
77
- else
78
- app_class = app_object.class
79
- end
80
- app_class.ancestors.map(&:name).each do |class_name|
81
- if registered_class_names.include?(class_name)
82
- return @class_names[class_name]
83
- end
84
- end
85
- raise "Couldn't find node for class #{app_class} \"#{app_object}\" (ancestors: #{app_class.ancestors.map(&:name)}, defined: #{registered_class_names})"
86
- end
87
- end
@@ -1,32 +0,0 @@
1
- # Validates a schema (specifically, {GraphQL::SCHEMA}).
2
- #
3
- # It checks:
4
- # - All classes exposed by nodes actually exist
5
- # - Field types requested by nodes actually exist
6
- # - Fields' corresponding methods actually exist
7
- #
8
- # To validate a schema, use {GraphQL::Schema::Schema#validate}.
9
- class GraphQL::Schema::SchemaValidation
10
- # Validates the schema
11
- def validate(schema)
12
- schema.types.each do |type_name, type_class|
13
-
14
- type_class.exposes_class_names.each do |exposes_class_name|
15
- begin
16
- Object.const_get(exposes_class_name)
17
- rescue NameError
18
- raise GraphQL::ExposesClassMissingError.new(type_class)
19
- end
20
- end
21
-
22
- type_class.all_fields.each do |field_name, field_mapping|
23
- # Make sure the type exists
24
- field_mapping.type_class
25
- # Make sure the node can handle it
26
- if !type_class.respond_to_field?(field_mapping.name)
27
- raise GraphQL::FieldNotDefinedError.new(type_class, field_mapping.name)
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,8 +0,0 @@
1
- class GraphQL::Syntax::Call
2
- attr_reader :identifier, :arguments, :calls
3
- def initialize(identifier:, arguments: nil, calls: [])
4
- @identifier = identifier
5
- @arguments = arguments
6
- @calls = calls
7
- end
8
- end
@@ -1,9 +0,0 @@
1
- class GraphQL::Syntax::Field
2
- attr_reader :identifier, :alias_name, :calls, :fields
3
- def initialize(identifier:, alias_name: nil, calls: [], fields: [])
4
- @identifier = identifier
5
- @alias_name = alias_name
6
- @calls = calls
7
- @fields = fields
8
- end
9
- end
@@ -1,7 +0,0 @@
1
- class GraphQL::Syntax::Fragment
2
- attr_reader :identifier, :fields
3
- def initialize(identifier:, fields:)
4
- @identifier = identifier
5
- @fields = fields
6
- end
7
- end
@@ -1,8 +0,0 @@
1
- class GraphQL::Syntax::Node
2
- attr_reader :identifier, :arguments, :fields
3
- def initialize(identifier:, arguments:, fields: [])
4
- @identifier = identifier
5
- @arguments = arguments
6
- @fields = fields
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- class GraphQL::Syntax::Query
2
- attr_reader :nodes, :variables, :fragments
3
- def initialize(nodes:, variables:, fragments:)
4
- @nodes = nodes
5
- @variables = variables
6
- @fragments = fragments
7
- end
8
- end
@@ -1,7 +0,0 @@
1
- class GraphQL::Syntax::Variable
2
- attr_reader :identifier, :json_string
3
- def initialize(identifier:, json_string:)
4
- @identifier = identifier
5
- @json_string = json_string
6
- end
7
- end
@@ -1,3 +0,0 @@
1
- class GraphQL::Types::BooleanType < GraphQL::Types::ObjectType
2
- exposes("TrueClass", "FalseClass")
3
- end
@@ -1,3 +0,0 @@
1
- class GraphQL::Types::NumberType < GraphQL::Types::ObjectType
2
- exposes("Numeric")
3
- end
@@ -1,6 +0,0 @@
1
- class GraphQL::Types::ObjectType < GraphQL::Node
2
- exposes("Object")
3
- def as_result
4
- target
5
- end
6
- end
@@ -1,3 +0,0 @@
1
- class GraphQL::Types::StringType < GraphQL::Types::ObjectType
2
- exposes("String")
3
- end
@@ -1,3 +0,0 @@
1
- module GraphQL
2
- VERSION = "0.0.4"
3
- end
@@ -1,69 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe GraphQL::Node do
4
- let(:query_string) { "type(post) { name, description, fields { count, edges { node { name, type }}} }"}
5
- let(:result) { GraphQL::Query.new(query_string).as_result}
6
-
7
- describe '__type__' do
8
- let(:title_field) { result["post"]["fields"]["edges"].find {|e| e["node"]["name"] == "title"}["node"] }
9
-
10
- it 'has name' do
11
- assert_equal "post", result["post"]["name"]
12
- end
13
-
14
- it 'has description' do
15
- assert_equal "A blog post entry", result["post"]["description"]
16
- end
17
-
18
- it 'has fields' do
19
- assert_equal 8, result["post"]["fields"]["count"]
20
- assert_equal({ "name" => "title", "type" => "string"}, title_field)
21
- end
22
-
23
- describe 'getting the __type__ field' do
24
- before do
25
- @post = Post.create(id: 155, content: "Hello world")
26
- end
27
-
28
- after do
29
- @post.destroy
30
- end
31
-
32
- let(:query_string) { "post(155) { __type__ { name, fields { count } } }"}
33
-
34
- it 'exposes the type' do
35
- assert_equal "post", result["155"]["__type__"]["name"]
36
- assert_equal 8, result["155"]["__type__"]["fields"]["count"]
37
- end
38
- end
39
- end
40
-
41
- describe '.node_name' do
42
- let(:query_string) { "type(upvote) { name }"}
43
-
44
- it 'overrides __type__.name' do
45
- assert_equal "upvote", result["upvote"]["name"]
46
- end
47
- end
48
-
49
- describe '.field' do
50
- it 'doesnt add the field twice if you call it twice' do
51
- assert_equal 5, Nodes::CommentNode.all_fields.size
52
- Nodes::CommentNode.field.number(:id)
53
- Nodes::CommentNode.field.number(:id)
54
- assert_equal 5, Nodes::CommentNode.all_fields.size
55
- Nodes::CommentNode.remove_field(:id)
56
- end
57
-
58
- describe 'type:' do
59
- it 'uses symbols to find built-ins' do
60
- field_mapping = Nodes::CommentNode.all_fields["id"]
61
- assert_equal GraphQL::Types::NumberType, field_mapping.type_class
62
- end
63
- it 'uses the provided class as a superclass' do
64
- letters_field = Nodes::CommentNode.all_fields["letters"]
65
- assert_equal Nodes::LetterSelectionType, letters_field.type_class
66
- end
67
- end
68
- end
69
- end
@@ -1,168 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe GraphQL::Parser::Parser do
4
- let(:parser) { GraphQL::PARSER }
5
-
6
- describe 'query' do
7
- let(:query) { parser.query }
8
- it 'parses node-only' do
9
- assert query.parse_with_debug("node(4) { id, name } ")
10
- end
11
- it 'parses node and variables' do
12
- assert query.parse_with_debug(%{
13
- like_page(<page>) {
14
- $pageFragment
15
- }
16
- <page>: {
17
- "page": {"id": 1},
18
- "person" : { "id", 4}
19
- }
20
- <other>: {
21
- "page": {"id": 1},
22
- "person" : { "id", 4}
23
- }
24
-
25
- $pageFragment: {
26
- page { id }
27
- }
28
- })
29
- end
30
- end
31
-
32
- describe 'field' do
33
- let(:field) { parser.field }
34
- it 'finds words' do
35
- assert field.parse_with_debug("date_of_birth")
36
- end
37
-
38
- it 'finds aliases' do
39
- assert field.parse_with_debug("name as moniker")
40
- end
41
-
42
- it 'finds calls on fields' do
43
- assert field.parse_with_debug("url.site(www).upcase()")
44
- end
45
-
46
- describe 'fields that return objects' do
47
- it 'finds them' do
48
- assert field.parse_with_debug("birthdate { month, year }")
49
- end
50
-
51
- it 'finds them with aliases' do
52
- assert field.parse_with_debug("birthdate as d_o_b { month, year }")
53
- end
54
-
55
- it 'finds them with calls' do
56
- assert field.parse_with_debug("friends.after(123) { count { edges { node { id } } } }")
57
- end
58
-
59
- it 'finds them with calls and aliases' do
60
- assert field.parse_with_debug("friends.after(123) as pals { count { edges { node { id } } } }")
61
- end
62
- end
63
- end
64
-
65
- describe 'call' do
66
- let(:call) { parser.call }
67
- it 'finds bare calls' do
68
- assert call.parse_with_debug("node(123)")
69
- assert call.parse_with_debug("viewer()")
70
- end
71
-
72
- it 'finds calls with multiple arguments' do
73
- assert call.parse_with_debug("node(4, 6)")
74
- end
75
-
76
- it 'finds calls with variables' do
77
- assert call.parse_with_debug("like_page(<page>)")
78
- end
79
- end
80
-
81
- describe 'fields' do
82
- let(:fields) { parser.fields }
83
-
84
- it 'finds fields' do
85
- assert fields.parse_with_debug("{id,name}")
86
- assert fields.parse_with_debug("{ id, name, favorite_food }")
87
- assert fields.parse_with_debug("{\n id,\n name,\n favorite_food\n}")
88
- end
89
-
90
- it 'finds nested field list' do
91
- assert fields.parse_with_debug("{id,date_of_birth{month, year}}")
92
- end
93
- end
94
-
95
- describe 'node' do
96
- let(:node) { parser.node }
97
-
98
- it 'parses root calls' do
99
- assert node.parse_with_debug("viewer() {id}")
100
- end
101
-
102
- it 'parses query fragments' do
103
- assert node.parse_with_debug("viewer() { id, $someFrag }")
104
- end
105
-
106
- it 'parses nested nodes' do
107
- assert node.parse_with_debug("
108
- node(someone)
109
- {
110
- id,
111
- name,
112
- friends.after(12345).first(3) {
113
- cursor,
114
- node {
115
- id,
116
- name
117
- }
118
- }
119
- }
120
- ")
121
- end
122
- end
123
-
124
- describe 'variable' do
125
- let(:variable) { parser.variable }
126
-
127
- it 'gets scalar variables' do
128
- assert variable.parse_with_debug(%{<some_number>: 888})
129
- assert variable.parse_with_debug(%{<some_string>: my_string})
130
- end
131
- it 'gets json variables' do
132
- assert variable.parse_with_debug(%{<my_input>: {"key": "value"}})
133
- end
134
-
135
- it 'gets variables with nesting' do
136
- assert variable.parse_with_debug(%{
137
- <my_input>: {
138
- "key": "value",
139
- "1": 2,
140
- "true": false,
141
- "nested": {
142
- "key" : "value"
143
- }
144
- }
145
- })
146
- end
147
- end
148
-
149
- describe 'fragment' do
150
- let(:fragment) { parser.fragment }
151
-
152
- it 'gets parts of queries' do
153
- assert fragment.parse_with_debug(%{ $frag: { id } })
154
- end
155
-
156
- it 'gets nested parts of queries' do
157
- assert fragment.parse_with_debug(%{
158
- $frag: {
159
- item {
160
- name,
161
- price
162
- },
163
- $qtyFragment
164
- }
165
- })
166
- end
167
- end
168
- end