graphql 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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