graphql 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +24 -15
- data/lib/graphql/call.rb +1 -0
- data/lib/graphql/connection.rb +44 -0
- data/lib/graphql/field.rb +72 -7
- data/lib/graphql/field_definer.rb +6 -0
- data/lib/graphql/parser.rb +3 -0
- data/lib/graphql/query.rb +3 -1
- data/lib/graphql/root_call.rb +41 -28
- data/lib/graphql/root_call_argument.rb +1 -0
- data/lib/graphql/root_call_argument_definer.rb +1 -0
- data/lib/graphql/schema.rb +1 -1
- data/lib/graphql/transform.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/readme.md +7 -7
- data/spec/graphql/field_spec.rb +1 -4
- data/spec/spec_helper.rb +3 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6184108ff2ba0151d12bfaeb02feeacbdeba74cc
|
4
|
+
data.tar.gz: 2a9cb034382d28f96a7e29024814848b63596a49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bb555f0b19ce78ea3f79ba7388f31509c26e2518fc1c207a25e83bcdd4f38e3670194bcb26a1447dc134a5949e58d10e12da79846bb2b3fb4dab0d688561a8a
|
7
|
+
data.tar.gz: 695837ba820b7709453584800eaa6d3f4082edc9d443055ab52d42e0db3b895189c2c10113a04d43e44c70726365621b99a878cc68a371acd85b46aeb05b925a
|
data/lib/graphql.rb
CHANGED
@@ -5,20 +5,21 @@ require "parslet"
|
|
5
5
|
require "singleton"
|
6
6
|
|
7
7
|
module GraphQL
|
8
|
-
autoload(:Call,
|
9
|
-
autoload(:Connection,
|
10
|
-
autoload(:Field,
|
11
|
-
autoload(:FieldDefiner,
|
12
|
-
autoload(:Node,
|
13
|
-
autoload(:Parser,
|
14
|
-
autoload(:Query,
|
15
|
-
autoload(:RootCall,
|
8
|
+
autoload(:Call, "graphql/call")
|
9
|
+
autoload(:Connection, "graphql/connection")
|
10
|
+
autoload(:Field, "graphql/field")
|
11
|
+
autoload(:FieldDefiner, "graphql/field_definer")
|
12
|
+
autoload(:Node, "graphql/node")
|
13
|
+
autoload(:Parser, "graphql/parser")
|
14
|
+
autoload(:Query, "graphql/query")
|
15
|
+
autoload(:RootCall, "graphql/root_call")
|
16
16
|
autoload(:RootCallArgument, "graphql/root_call_argument")
|
17
|
-
autoload(:RootCallArgumentDefiner,
|
18
|
-
autoload(:Schema,
|
19
|
-
autoload(:Transform,
|
20
|
-
autoload(:VERSION,
|
17
|
+
autoload(:RootCallArgumentDefiner, "graphql/root_call_argument_definer")
|
18
|
+
autoload(:Schema, "graphql/schema")
|
19
|
+
autoload(:Transform, "graphql/transform")
|
20
|
+
autoload(:VERSION, "graphql/version")
|
21
21
|
|
22
|
+
# These objects are used for introspections (eg, responding to `schema()` calls).
|
22
23
|
module Introspection
|
23
24
|
autoload(:CallNode, "graphql/introspection/call_node")
|
24
25
|
autoload(:Connection, "graphql/introspection/connection")
|
@@ -31,7 +32,7 @@ module GraphQL
|
|
31
32
|
autoload(:TypeNode, "graphql/introspection/type_node")
|
32
33
|
end
|
33
34
|
|
34
|
-
|
35
|
+
# These objects are skinny wrappers for going from the AST to actual {Node} and {Field} instances.
|
35
36
|
module Syntax
|
36
37
|
autoload(:Call, "graphql/syntax/call")
|
37
38
|
autoload(:Field, "graphql/syntax/field")
|
@@ -40,6 +41,7 @@ module GraphQL
|
|
40
41
|
autoload(:Variable, "graphql/syntax/variable")
|
41
42
|
end
|
42
43
|
|
44
|
+
# These fields wrap Ruby data types and some GraphQL internal values.
|
43
45
|
module Types
|
44
46
|
autoload(:BooleanField, "graphql/types/boolean_field")
|
45
47
|
autoload(:ConnectionField, "graphql/types/connection_field")
|
@@ -49,35 +51,41 @@ module GraphQL
|
|
49
51
|
autoload(:StringField, "graphql/types/string_field")
|
50
52
|
autoload(:TypeField, "graphql/types/type_field")
|
51
53
|
end
|
52
|
-
|
54
|
+
# @abstract
|
55
|
+
# Base class for all errors, so you can rescue from all graphql errors at once.
|
53
56
|
class Error < RuntimeError; end
|
57
|
+
# This node doesn't have a field with that name.
|
54
58
|
class FieldNotDefinedError < Error
|
55
59
|
def initialize(class_name, field_name)
|
56
60
|
super("#{class_name}##{field_name} was requested, but it isn't defined. Defined fields are: #{SCHEMA.field_names}")
|
57
61
|
end
|
58
62
|
end
|
63
|
+
# There's no Node defined for that kind of object.
|
59
64
|
class NodeNotDefinedError < Error
|
60
65
|
def initialize(node_name)
|
61
66
|
super("#{node_name} was requested but was not found. Defined nodes are: #{SCHEMA.type_names}")
|
62
67
|
end
|
63
68
|
end
|
69
|
+
# This node doesn't have a connection with that name.
|
64
70
|
class ConnectionNotDefinedError < Error
|
65
71
|
def initialize(node_name)
|
66
72
|
super("#{node_name} was requested but was not found. Defined connections are: #{SCHEMA.connection_names}")
|
67
73
|
end
|
68
74
|
end
|
75
|
+
# The root call of this query isn't in the schema.
|
69
76
|
class RootCallNotDefinedError < Error
|
70
77
|
def initialize(name)
|
71
78
|
super("Call '#{name}' was requested but was not found. Defined calls are: #{SCHEMA.call_names}")
|
72
79
|
end
|
73
80
|
end
|
81
|
+
# The query couldn't be parsed.
|
74
82
|
class SyntaxError < Error
|
75
83
|
def initialize(line, col, string)
|
76
84
|
lines = string.split("\n")
|
77
85
|
super("Syntax Error at (#{line}, #{col}), check usage: #{string}")
|
78
86
|
end
|
79
87
|
end
|
80
|
-
|
88
|
+
# This root call takes different arguments.
|
81
89
|
class RootCallArgumentError < Error
|
82
90
|
def initialize(declaration, actual)
|
83
91
|
super("Wrong type for #{declaration.name}: expected a #{declaration.type} but got #{actual}")
|
@@ -85,6 +93,7 @@ module GraphQL
|
|
85
93
|
end
|
86
94
|
|
87
95
|
PARSER = Parser.new
|
96
|
+
# This singleton contains all defined nodes and fields.
|
88
97
|
SCHEMA = Schema.instance
|
89
98
|
TRANSFORM = Transform.new
|
90
99
|
# preload these so they're in SCHEMA
|
data/lib/graphql/call.rb
CHANGED
data/lib/graphql/connection.rb
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
+
# {Connection}s wrap collections of objects.
|
2
|
+
#
|
3
|
+
# Out of the box, the only field it has is `edges`, which provides access to the members of the collection.
|
4
|
+
#
|
5
|
+
# You can define a custom {Connection} to use. This allows you to define fields at the collection level (rather than the item level)
|
6
|
+
#
|
7
|
+
# Custom fields can access the collection as {Field#items}.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# class UpvotesConnection < GraphQL::Collection
|
11
|
+
# field.number(:count)
|
12
|
+
# field.boolean(:any)
|
13
|
+
#
|
14
|
+
# def count
|
15
|
+
# items.count
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# def any
|
19
|
+
# items.any?
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # Then, this connection will be used for connections whose names match:
|
24
|
+
# class PostNode < GraphQL::Node
|
25
|
+
# field.connection(:upvotes)
|
26
|
+
# # ^^ uses `UpvotesConnection` based on naming convention
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # And you can use the fields in a query:
|
30
|
+
# <<QUERY
|
31
|
+
# find_post(10) {
|
32
|
+
# title,
|
33
|
+
# upvotes {
|
34
|
+
# count,
|
35
|
+
# any,
|
36
|
+
# edges {
|
37
|
+
# node { created_at }
|
38
|
+
# }
|
39
|
+
# }
|
40
|
+
# }
|
41
|
+
# QUERY
|
1
42
|
class GraphQL::Connection < GraphQL::Node
|
2
43
|
exposes "Array"
|
3
44
|
field.any(:edges)
|
@@ -10,6 +51,7 @@ class GraphQL::Connection < GraphQL::Node
|
|
10
51
|
@query = query
|
11
52
|
end
|
12
53
|
|
54
|
+
# Returns the members of the collection, after any calls on the corresponding {Field} have been applied
|
13
55
|
def items
|
14
56
|
@target
|
15
57
|
end
|
@@ -34,6 +76,8 @@ class GraphQL::Connection < GraphQL::Node
|
|
34
76
|
end
|
35
77
|
|
36
78
|
attr_accessor :default_connection
|
79
|
+
# Call this to make a the class the default connection
|
80
|
+
# when one isn't found by name.
|
37
81
|
def default_connection!
|
38
82
|
GraphQL::Connection.default_connection = self
|
39
83
|
end
|
data/lib/graphql/field.rb
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
# {Field}s are used to safely lookup values on {Node}s. When you define a custom field, you can access it from {Node.field}
|
2
|
+
#
|
3
|
+
# `graphql` has built-in fields for some Ruby data types:
|
4
|
+
# - `boolean`: {Types::BooleanField}
|
5
|
+
# - `number`: {Types::NumberField}
|
6
|
+
# - `string`: {Types::StringField}
|
7
|
+
#
|
8
|
+
# You can define custom fields that allow you to control how values are exposed.
|
9
|
+
# - {Field.type} defines how it can be used inside {Node.field} calls.
|
10
|
+
# - {Field.call} defines calls that can mutate the value before it is added to the response.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # For example, an `AddressField` which wraps a string but exposes address-specific information
|
14
|
+
# class AddressField < GraphQL::Field
|
15
|
+
# type :address
|
16
|
+
# # ^^ now you can use it with `field.address` in node definitions
|
17
|
+
#
|
18
|
+
# # calls can modify the value:
|
19
|
+
# # eg, get the numbers at the beginning:
|
20
|
+
# call :house_number, -> (prev_value) { prev_value[/^\d*/]}
|
21
|
+
# # get everything after a space:
|
22
|
+
# call :street_name, -> (prev_value) { prev_value[/\s.*$/].strip }
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# # Then, use it in a node definition:
|
26
|
+
# class HouseNode < GraphQL::Node
|
27
|
+
# exposes("House")
|
28
|
+
# # create an `AddressField` for this node called `street_address`:
|
29
|
+
# field.address(:street_address)
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # Then, use the field in queries:
|
33
|
+
# <<QUERY
|
34
|
+
# find_house(1) {
|
35
|
+
# street_address,
|
36
|
+
# street_address.house_number() as number,
|
37
|
+
# street_address.street_name() as street,
|
38
|
+
# }
|
39
|
+
# QUERY
|
1
40
|
class GraphQL::Field
|
2
41
|
attr_reader :query, :owner, :calls, :fields
|
3
42
|
def initialize(query: nil, owner: nil, calls: [], fields: [])
|
@@ -8,7 +47,7 @@ class GraphQL::Field
|
|
8
47
|
end
|
9
48
|
|
10
49
|
def raw_value
|
11
|
-
owner.send(
|
50
|
+
owner.send(name)
|
12
51
|
end
|
13
52
|
|
14
53
|
def as_result
|
@@ -43,8 +82,6 @@ class GraphQL::Field
|
|
43
82
|
end
|
44
83
|
end
|
45
84
|
|
46
|
-
def method; name; end
|
47
|
-
|
48
85
|
class << self
|
49
86
|
def inherited(child_class)
|
50
87
|
GraphQL::SCHEMA.add_field(child_class)
|
@@ -72,7 +109,18 @@ class GraphQL::Field
|
|
72
109
|
super
|
73
110
|
end
|
74
111
|
end
|
75
|
-
|
112
|
+
# @param [Symbol] type_name the name used for getting this field from the {GraphQL::SCHEMA}.
|
113
|
+
# Defines the name used for getting fields of this type from the schema.
|
114
|
+
# @example
|
115
|
+
# # define the field with its type:
|
116
|
+
# class IPAddressField < GraphQL::Field
|
117
|
+
# type :ip_address
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# # then, attach fields of this type to your nodes:
|
121
|
+
# class ServerNode < GraphQL::Field
|
122
|
+
# field.ip_address(:static_ip_address)
|
123
|
+
# end
|
76
124
|
def type(value_type_name)
|
77
125
|
@value_type = value_type_name.to_s
|
78
126
|
GraphQL::SCHEMA.add_field(self)
|
@@ -103,14 +151,31 @@ class GraphQL::Field
|
|
103
151
|
rescue NoMethodError
|
104
152
|
{}
|
105
153
|
end
|
154
|
+
# @param [String] name the identifier for this call
|
155
|
+
# @param [lambda] operation the transformation this call makes
|
156
|
+
#
|
157
|
+
# Define a call that can be made on this field.
|
158
|
+
# The `lambda` receives arguments:
|
159
|
+
# - 1: `previous_value` -- the value of this field
|
160
|
+
# - *: arguments passed in the query (as strings)
|
161
|
+
#
|
162
|
+
# @example
|
163
|
+
# # upcase a string field:
|
164
|
+
# call :upcase, -> (prev_value) { prev_value.upcase }
|
165
|
+
# @example
|
166
|
+
# # tests a number field:
|
167
|
+
# call :greater_than, -> (prev_value, test_value) { prev_value > test_value.to_f }
|
168
|
+
# # (`test_value` is passed in as a string)
|
169
|
+
def call(name, lambda)
|
170
|
+
_calls[name.to_s] = GraphQL::Call.new(name: name.to_s, lambda: lambda)
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
106
174
|
|
107
175
|
def _calls
|
108
176
|
@calls ||= {}
|
109
177
|
end
|
110
178
|
|
111
|
-
def call(name, lambda)
|
112
|
-
_calls[name.to_s] = GraphQL::Call.new(name: name.to_s, lambda: lambda)
|
113
|
-
end
|
114
179
|
end
|
115
180
|
|
116
181
|
type :any
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# Every {Node} class has a {FieldDefiner} instance that
|
2
|
+
# enables the `field.{something}` API.
|
1
3
|
class GraphQL::FieldDefiner
|
2
4
|
attr_reader :owner_class
|
3
5
|
def initialize(owner_class)
|
4
6
|
@owner_class = owner_class
|
5
7
|
end
|
6
8
|
|
9
|
+
# `method_name` is used as a field type and looked up against {GraphQL::SCHEMA}.
|
10
|
+
# `args[0]` is the name for the field of that type.
|
7
11
|
def method_missing(method_name, *args, &block)
|
8
12
|
type = GraphQL::SCHEMA.get_field(method_name)
|
9
13
|
if type.present?
|
@@ -13,6 +17,8 @@ class GraphQL::FieldDefiner
|
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
20
|
+
private
|
21
|
+
|
16
22
|
def create_field(field_name, type: nil, description: nil)
|
17
23
|
field_name = field_name.to_s
|
18
24
|
field_class = GraphQL::Field.create_class({
|
data/lib/graphql/parser.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# Parser is a [parslet](http://kschiess.github.io/parslet/) parser for parsing queries.
|
2
|
+
#
|
3
|
+
# If it failes to parse, a {SyntaxError} is raised.
|
1
4
|
class GraphQL::Parser < Parslet::Parser
|
2
5
|
root(:query)
|
3
6
|
rule(:query) { node.repeat.as(:nodes) >> variable.repeat.as(:variables) }
|
data/lib/graphql/query.rb
CHANGED
@@ -7,7 +7,9 @@
|
|
7
7
|
# result = query.as_result
|
8
8
|
|
9
9
|
class GraphQL::Query
|
10
|
-
|
10
|
+
# This is the object passed to {#initialize} as `context:`
|
11
|
+
attr_reader :context
|
12
|
+
attr_reader :query_string, :root
|
11
13
|
|
12
14
|
# @param [String] query_string the string to be parsed
|
13
15
|
# @param [Object] context an object which will be available to all nodes and fields in the schema
|
data/lib/graphql/root_call.rb
CHANGED
@@ -34,6 +34,8 @@
|
|
34
34
|
#
|
35
35
|
class GraphQL::RootCall
|
36
36
|
attr_reader :query, :arguments
|
37
|
+
|
38
|
+
# Validates arguments against declared {.argument}s
|
37
39
|
def initialize(query:, syntax_arguments:)
|
38
40
|
@query = query
|
39
41
|
|
@@ -46,18 +48,23 @@ class GraphQL::RootCall
|
|
46
48
|
syntax_arg
|
47
49
|
end
|
48
50
|
|
49
|
-
|
51
|
+
typecast(idx, value)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
55
|
+
# @param [Array] args (splat) all args provided in query string (as strings)
|
56
|
+
# This method is invoked with the arguments provided to the query.
|
57
|
+
# It should do work and return values matching the {.returns} declarations
|
53
58
|
def execute!(*args)
|
54
59
|
raise NotImplementedError, "Do work in this method"
|
55
60
|
end
|
56
61
|
|
62
|
+
# The object passed to {Query#initialize} as `context`
|
57
63
|
def context
|
58
64
|
query.context
|
59
65
|
end
|
60
66
|
|
67
|
+
# Executes the call, validates the return values against declared {.returns}, then returns the return values.
|
61
68
|
def as_result
|
62
69
|
return_declarations = self.class.return_declarations
|
63
70
|
raise "#{self.class.name} must declare returns" unless return_declarations.present?
|
@@ -123,7 +130,10 @@ class GraphQL::RootCall
|
|
123
130
|
end
|
124
131
|
|
125
132
|
# @return [GraphQL::RootCallArgumentDefiner] definer
|
126
|
-
# Use this object to declare arguments.
|
133
|
+
# Use this object to declare arguments. They must be declared in order
|
134
|
+
# @example
|
135
|
+
# argument.string("post_title")
|
136
|
+
# argument.object("comment_data") # allows a JSON object
|
127
137
|
def argument
|
128
138
|
@argument ||= GraphQL::RootCallArgumentDefiner.new(self)
|
129
139
|
end
|
@@ -138,39 +148,42 @@ class GraphQL::RootCall
|
|
138
148
|
rescue NoMethodError
|
139
149
|
own
|
140
150
|
end
|
151
|
+
end
|
141
152
|
|
142
|
-
|
143
|
-
if arguments.first.any_number
|
144
|
-
arguments.first
|
145
|
-
else
|
146
|
-
arguments[idx]
|
147
|
-
end
|
148
|
-
end
|
153
|
+
private
|
149
154
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
+
TYPE_CHECKS = {
|
156
|
+
"object" => Hash,
|
157
|
+
"number" => Numeric,
|
158
|
+
"string" => String,
|
159
|
+
}
|
155
160
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
161
|
+
def argument_for_index(idx)
|
162
|
+
if self.class.arguments.first.any_number
|
163
|
+
self.class.arguments.first
|
164
|
+
else
|
165
|
+
self.class.arguments[idx]
|
166
|
+
end
|
167
|
+
end
|
160
168
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
end
|
169
|
+
def typecast(idx, value)
|
170
|
+
arg_dec = argument_for_index(idx)
|
171
|
+
expected_type = arg_dec.type
|
172
|
+
expected_type_class = TYPE_CHECKS[expected_type]
|
166
173
|
|
167
|
-
|
168
|
-
|
169
|
-
|
174
|
+
if expected_type == "string"
|
175
|
+
parsed_value = value
|
176
|
+
else
|
177
|
+
parsed_value = JSON.parse('{ "value" : ' + value + '}')["value"]
|
178
|
+
end
|
170
179
|
|
171
|
-
|
172
|
-
rescue JSON::ParserError
|
180
|
+
if !parsed_value.is_a?(expected_type_class)
|
173
181
|
raise GraphQL::RootCallArgumentError.new(arg_dec, value)
|
174
182
|
end
|
183
|
+
|
184
|
+
parsed_value
|
185
|
+
rescue JSON::ParserError
|
186
|
+
raise GraphQL::RootCallArgumentError.new(arg_dec, value)
|
175
187
|
end
|
188
|
+
|
176
189
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# {GraphQL::SCHEMA} keeps track of defined nodes, fields and calls.
|
2
|
+
#
|
2
3
|
# Although you don't interact with it directly, it responds to queries for `schema()` and `__type__` info.
|
3
|
-
|
4
4
|
class GraphQL::Schema
|
5
5
|
include Singleton
|
6
6
|
attr_reader :types, :calls, :fields, :class_names, :connections
|
data/lib/graphql/transform.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# {Transform} is a [parslet](http://kschiess.github.io/parslet/) transform for for turning the AST into objects in {GraphQL::Syntax}.
|
1
2
|
class GraphQL::Transform < Parslet::Transform
|
2
3
|
# query
|
3
4
|
rule(nodes: sequence(:n), variables: sequence(:v)) { GraphQL::Syntax::Query.new(nodes: n, variables: v)}
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -3,30 +3,31 @@
|
|
3
3
|
[![Build Status](https://travis-ci.org/rmosolgo/graphql-ruby.svg?branch=master)](https://travis-ci.org/rmosolgo/graphql-ruby)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/graphql.svg)](https://rubygems.org/gems/graphql)
|
5
5
|
[![Dependency Status](https://gemnasium.com/rmosolgo/graphql-ruby.svg)](https://gemnasium.com/rmosolgo/graphql-ruby)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/rmosolgo/graphql-ruby/badges/gpa.svg)](https://codeclimate.com/github/rmosolgo/graphql-ruby)
|
7
|
+
[![Test Coverage](https://codeclimate.com/github/rmosolgo/graphql-ruby/badges/coverage.svg)](https://codeclimate.com/github/rmosolgo/graphql-ruby)
|
8
|
+
![image](https://cloud.githubusercontent.com/assets/2231765/6424458/d5fd3896-beae-11e4-892a-77e135e6bf37.png)
|
6
9
|
|
10
|
+
Create a GraphQL interface by implementing [__nodes__](#nodes) and [__calls__](#calls), then running [__queries__](#queries).
|
7
11
|
|
8
|
-
|
12
|
+
API Docs: <http://rubydoc.info/gems/graphql>
|
9
13
|
|
10
14
|
## To do:
|
11
15
|
|
12
|
-
|
13
16
|
- Allow a default connection class, or some way to infer connection from name
|
14
17
|
- right now, `Introspection::Connection` isn't getting used, only `ApplicationConnection` is.
|
15
|
-
|
16
18
|
- How do you express failure? HTTP response? `errors` key?
|
17
|
-
- Handle blank objects in nested calls
|
19
|
+
- Handle blank objects in nested calls (how? wait for spec)
|
18
20
|
- Implement calls as arguments
|
19
21
|
- double-check how to handle `pals.first(3) { count }`
|
20
22
|
- Implement call argument introspection (wait for spec)
|
21
23
|
- For fields that return objects, can they be queried _without_ other fields? Or must they always have fields?
|
22
|
-
- __document__ (wait for spec)
|
23
24
|
|
24
25
|
## Example Implementation
|
25
26
|
|
26
27
|
- See test implementation in [`/spec/support/dummy_app/nodes.rb`](https://github.com/rmosolgo/graphql/blob/master/spec/support/nodes.rb)
|
27
28
|
- See `graphql-ruby-demo` with Rails on [github](https://github.com/rmosolgo/graphql-ruby-demo) or [heroku](http://graphql-ruby-demo.herokuapp.com/)
|
28
29
|
|
29
|
-
|
30
|
+
<a href="http://graphql-ruby-demo.herokuapp.com/" target="_blank"><img src="https://cloud.githubusercontent.com/assets/2231765/6217972/5d24edda-b5ce-11e4-9e07-3548304af862.png" style="max-width: 800px;"/></a>
|
30
31
|
|
31
32
|
|
32
33
|
## Usage
|
@@ -147,4 +148,3 @@ result
|
|
147
148
|
```
|
148
149
|
|
149
150
|
You could do something like this [inside a Rails controller](https://github.com/rmosolgo/graphql-ruby-demo/blob/master/app/controllers/queries_controller.rb#L5).
|
150
|
-
|
data/spec/graphql/field_spec.rb
CHANGED
@@ -9,11 +9,8 @@ describe GraphQL::Field do
|
|
9
9
|
it 'is present' do
|
10
10
|
assert_equal field.name, "high_fives"
|
11
11
|
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#method' do
|
15
12
|
it 'defaults to name' do
|
16
|
-
assert_equal "high_fives", field.
|
13
|
+
assert_equal "high_fives", field.name
|
17
14
|
end
|
18
15
|
end
|
19
16
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.6.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: codeclimate-test-reporter
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.4'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: pry
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,7 +218,7 @@ files:
|
|
204
218
|
- spec/spec_helper.rb
|
205
219
|
- spec/support/dummy_app.rb
|
206
220
|
- spec/support/nodes.rb
|
207
|
-
homepage: http://github.com/rmosolgo/graphql
|
221
|
+
homepage: http://github.com/rmosolgo/graphql-ruby
|
208
222
|
licenses:
|
209
223
|
- MIT
|
210
224
|
metadata: {}
|