graphql-rails 0.0.2 → 0.0.3
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.
- checksums.yaml +4 -4
- data/lib/graphql/rails/dsl.rb +2 -0
- data/lib/graphql/rails/extensions/cancan.rb +1 -1
- data/lib/graphql/rails/extensions/mongoid.rb +13 -2
- data/lib/graphql/rails/node_identification.rb +1 -0
- data/lib/graphql/rails/operations.rb +121 -5
- data/lib/graphql/rails/schema.rb +1 -0
- data/lib/graphql/rails/types.rb +4 -6
- data/lib/graphql/rails/version.rb +1 -1
- data/spec/graphql/rails/config_spec.rb +20 -0
- data/spec/graphql/rails/dsl_spec.rb +42 -0
- data/spec/graphql/rails/types_spec.rb +12 -0
- data/spec/spec_helper.rb +7 -0
- metadata +38 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2982060c7ec7314e4c7daf5b37e708c4df649e7f
|
4
|
+
data.tar.gz: e9d139a3bb0eac9b9dfd228bbbb6b7f5c11f5bbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45ad67d595721cf99425f8bea6cfa6845a01132b943f6c374da92e1c21597581482703f05a8150aa49e8b88c75def2d031efe5f698031003513465ffa788c66c
|
7
|
+
data.tar.gz: 8ed5ba12d1b161031c39dfb6a61646aecd994834a5c589b745dcce44b3c067eef7f76625f7deb4ece6efe8fa1d4216aad9fa3791eaa99188085bff89b29261cd
|
data/lib/graphql/rails/dsl.rb
CHANGED
@@ -48,6 +48,7 @@ module GraphQL
|
|
48
48
|
# mappings for common built-in scalar types.
|
49
49
|
def types
|
50
50
|
@types ||= {
|
51
|
+
Boolean => GraphQL::BOOLEAN_TYPE,
|
51
52
|
::Mongoid::Boolean => GraphQL::BOOLEAN_TYPE,
|
52
53
|
BSON::ObjectId => GraphQL::STRING_TYPE,
|
53
54
|
}
|
@@ -91,13 +92,23 @@ module GraphQL
|
|
91
92
|
next
|
92
93
|
end
|
93
94
|
|
95
|
+
# Check that relationship has a valid type.
|
96
|
+
begin
|
97
|
+
klass = relationship.klass
|
98
|
+
rescue
|
99
|
+
Rails.logger.warn(
|
100
|
+
"Skipping relationship with invalid class: #{relationship.name}"
|
101
|
+
)
|
102
|
+
next
|
103
|
+
end
|
104
|
+
|
94
105
|
if relationship.many?
|
95
106
|
connection Types.to_field_name(relationship.name) do
|
96
|
-
type -> { Types.resolve(
|
107
|
+
type -> { Types.resolve(klass).connection_type }
|
97
108
|
end
|
98
109
|
else
|
99
110
|
field Types.to_field_name(relationship.name) do
|
100
|
-
type -> { Types.resolve(
|
111
|
+
type -> { Types.resolve(klass) }
|
101
112
|
end
|
102
113
|
end
|
103
114
|
end
|
@@ -2,6 +2,7 @@ module GraphQL
|
|
2
2
|
module Rails
|
3
3
|
# Implements globally-unique object IDs for Relay compatibility.
|
4
4
|
NodeIdentification = GraphQL::Relay::GlobalNodeIdentification.define do
|
5
|
+
# TODO: Add security checks.
|
5
6
|
object_from_id -> (id, ctx) do
|
6
7
|
Types.lookup(*NodeIdentification.from_global_id(id))
|
7
8
|
end
|
@@ -43,11 +43,44 @@ module GraphQL
|
|
43
43
|
Schema.add_query definition.field
|
44
44
|
end
|
45
45
|
|
46
|
-
#
|
46
|
+
# Define a mutation operation.
|
47
|
+
# Definitions should have the following form:
|
48
|
+
#
|
49
|
+
# mutation :feed_cat => {appetite: Integer, last_meal: DateTime} do
|
50
|
+
# description 'This mutation feeds the cat and returns its appetite'
|
51
|
+
# argument :cat_id, Integer, :required
|
52
|
+
# argument :mouse_id, Integer, :required
|
53
|
+
# resolve do
|
54
|
+
# cat = Cat.find(args[:cat_id])
|
55
|
+
# mouse = Mouse.find(args[:mouse_id])
|
56
|
+
# raise 'Cannot find cat or mouse' if cat.nil? || mouse.nil?
|
57
|
+
#
|
58
|
+
# cat.feed(mouse)
|
59
|
+
# {appetite: cat.appetite, last_meal: DateTime.now}
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
def self.mutation(hash, &block)
|
63
|
+
hash = extract_pair(hash)
|
64
|
+
unless hash[:type].is_a?(Hash)
|
65
|
+
raise 'Mutations must be specified with Hash results'
|
66
|
+
end
|
67
|
+
Rails.logger.debug "Adding mutation: #{Types.to_field_name(hash[:name])}"
|
68
|
+
|
69
|
+
definition = MutationDefinition.new(self)
|
70
|
+
definition.run(&block)
|
71
|
+
definition.run do
|
72
|
+
name hash[:name]
|
73
|
+
type hash[:type]
|
74
|
+
end
|
75
|
+
Schema.add_mutation definition.field
|
76
|
+
end
|
77
|
+
|
78
|
+
# TODO: Implement subscriptions.
|
47
79
|
|
48
80
|
private
|
49
81
|
|
50
82
|
# DSL for query definition.
|
83
|
+
# TODO: Support resolve-only blocks.
|
51
84
|
class QueryDefinition < DSL
|
52
85
|
attr_reader :field
|
53
86
|
|
@@ -71,9 +104,10 @@ module GraphQL
|
|
71
104
|
end
|
72
105
|
|
73
106
|
def argument(name, type, required = false)
|
74
|
-
argument = ::GraphQL::Argument.
|
75
|
-
|
76
|
-
|
107
|
+
argument = ::GraphQL::Argument.define do
|
108
|
+
name Types.to_field_name(name)
|
109
|
+
type Types.resolve(type, required == :required)
|
110
|
+
end
|
77
111
|
@field.arguments[argument.name] = argument
|
78
112
|
end
|
79
113
|
|
@@ -104,10 +138,92 @@ module GraphQL
|
|
104
138
|
end
|
105
139
|
end
|
106
140
|
|
141
|
+
# DSL for mutation definition.
|
142
|
+
class MutationDefinition < QueryDefinition
|
143
|
+
def initialize(klass)
|
144
|
+
super
|
145
|
+
@input = ::GraphQL::InputObjectType.new
|
146
|
+
@output = ::GraphQL::ObjectType.new
|
147
|
+
end
|
148
|
+
|
149
|
+
def type(hash)
|
150
|
+
hash.each do |name, type|
|
151
|
+
field = ::GraphQL::Field.define do
|
152
|
+
name Types.to_field_name(name)
|
153
|
+
type Types.resolve(type)
|
154
|
+
end
|
155
|
+
@output.fields[field.name] = field
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def argument(name, type, required = false)
|
160
|
+
argument = ::GraphQL::Argument.define do
|
161
|
+
name Types.to_field_name(name)
|
162
|
+
type Types.resolve(type, required == :required)
|
163
|
+
end
|
164
|
+
@input.arguments[argument.name] = argument
|
165
|
+
end
|
166
|
+
|
167
|
+
def field
|
168
|
+
input = @input
|
169
|
+
input.name = "#{@field.name}Input"
|
170
|
+
input.description = "Generated input type for #{@field.name}"
|
171
|
+
input.arguments['clientMutationId'] = ::GraphQL::Argument.define do
|
172
|
+
name 'clientMutationId'
|
173
|
+
type Types.resolve(::String)
|
174
|
+
description 'Unique identifier for client performing mutation'
|
175
|
+
end
|
176
|
+
|
177
|
+
output = @output
|
178
|
+
output.name = "#{@field.name}Output"
|
179
|
+
output.description = "Generated output type for #{@field.name}"
|
180
|
+
output.fields['clientMutationId'] = ::GraphQL::Field.define do
|
181
|
+
name 'clientMutationId'
|
182
|
+
type Types.resolve(::String)
|
183
|
+
description 'Unique identifier for client performing mutation'
|
184
|
+
end
|
185
|
+
|
186
|
+
@field.type = output
|
187
|
+
@field.arguments['input'] = ::GraphQL::Argument.define do
|
188
|
+
name 'input'
|
189
|
+
type Types.resolve(input, true)
|
190
|
+
end
|
191
|
+
@field
|
192
|
+
end
|
193
|
+
|
194
|
+
def resolve(&block)
|
195
|
+
field.resolve = -> (obj, args, ctx) do
|
196
|
+
# Instantiate the Operations class with state on this query.
|
197
|
+
instance = @klass.new({
|
198
|
+
op: :mutation, name: @name, type: @type,
|
199
|
+
obj: obj, args: args[:input], ctx: ctx, context: ctx
|
200
|
+
})
|
201
|
+
|
202
|
+
begin
|
203
|
+
# Run callbacks for this Operations class.
|
204
|
+
instance.run_callbacks(:perform_operation) do
|
205
|
+
# Call out to the app-defined resolver.
|
206
|
+
result = instance.instance_eval(&block)
|
207
|
+
result[:clientMutationId] = args[:clientMutationId]
|
208
|
+
::OpenStruct.new(result)
|
209
|
+
end
|
210
|
+
rescue => e
|
211
|
+
# Surface messages from standard errors in GraphQL response.
|
212
|
+
::GraphQL::ExecutionError.new(e.message)
|
213
|
+
rescue ::Exception => e
|
214
|
+
# Log and genericize other runtime errors.
|
215
|
+
Rails.logger.error "Unexpected exception during mutation: #{@name}"
|
216
|
+
Rails.logger.exception e
|
217
|
+
::GraphQL::ExecutionError.new('Internal error')
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
107
223
|
# Extract parts from a hash passed to the operation definition DSL.
|
108
224
|
def self.extract_pair(hash)
|
109
225
|
unless hash.length == 1
|
110
|
-
raise 'Hash must contain a single :name => Type pair
|
226
|
+
raise 'Hash must contain a single :name => Type pair'
|
111
227
|
end
|
112
228
|
{name: hash.keys.first, type: hash.values.first}
|
113
229
|
end
|
data/lib/graphql/rails/schema.rb
CHANGED
data/lib/graphql/rails/types.rb
CHANGED
@@ -61,11 +61,10 @@ module GraphQL
|
|
61
61
|
# applying an optional namespace.
|
62
62
|
def to_type_name(name, namespace = '')
|
63
63
|
return namespace + to_type_name(name) unless namespace.blank?
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
64
|
+
name = name.to_s
|
65
|
+
name = name.camelize(:upper) if Rails.config.camel_case
|
66
|
+
name = name.gsub(/\W/, '_')
|
67
|
+
name
|
69
68
|
end
|
70
69
|
|
71
70
|
# Convert a field name to a string with the correct convention.
|
@@ -86,7 +85,6 @@ module GraphQL
|
|
86
85
|
def types
|
87
86
|
@types ||= {
|
88
87
|
String => GraphQL::STRING_TYPE,
|
89
|
-
Boolean => GraphQL::BOOLEAN_TYPE,
|
90
88
|
|
91
89
|
Fixnum => GraphQL::INT_TYPE,
|
92
90
|
Integer => GraphQL::INT_TYPE,
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GraphQL::Rails do
|
4
|
+
describe '.configure' do
|
5
|
+
it 'yields the configuration object' do
|
6
|
+
config = nil
|
7
|
+
GraphQL::Rails.configure do |c|
|
8
|
+
config = c
|
9
|
+
end
|
10
|
+
expect(config).to eq GraphQL::Rails.config
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.config' do
|
15
|
+
it 'has attribute accessors' do
|
16
|
+
GraphQL::Rails.config.debug = false
|
17
|
+
expect(GraphQL::Rails.config.debug).to be false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestDSL < GraphQL::Rails::DSL
|
4
|
+
attr_reader :value
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(value)
|
11
|
+
@value += value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe GraphQL::Rails::DSL do
|
16
|
+
let(:dsl) { TestDSL.new(0) }
|
17
|
+
|
18
|
+
it 'resolves DSL instance variables' do
|
19
|
+
dsl.run do
|
20
|
+
expect(@value).to be 0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'resolves DSL instance methods' do
|
25
|
+
dsl.run do
|
26
|
+
add 2
|
27
|
+
add 4
|
28
|
+
end
|
29
|
+
expect(dsl.value).to be 6
|
30
|
+
end
|
31
|
+
|
32
|
+
def meaning_of_life
|
33
|
+
42
|
34
|
+
end
|
35
|
+
|
36
|
+
it "resolves methods from the block's context" do
|
37
|
+
dsl.run do
|
38
|
+
add meaning_of_life
|
39
|
+
end
|
40
|
+
expect(dsl.value).to be meaning_of_life
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestType; end
|
4
|
+
TestGraphQLType = GraphQL::BaseType.new
|
5
|
+
|
6
|
+
describe GraphQL::Rails::Types do
|
7
|
+
describe '.resolve' do
|
8
|
+
context 'when type is nil' do
|
9
|
+
it { expect(GraphQL::Rails::Types.resolve(nil)).to raise_error }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,71 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-rails
|
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
|
- James Reggio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '4'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: graphql
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0.13'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.13'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: graphql-relay
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0.9'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.9'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: graphiql-rails
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '1.2'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.6'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.6'
|
69
83
|
description: |
|
70
84
|
Zero-configuration GraphQL + Relay support for Rails. Adds a route to process
|
71
85
|
GraphQL operations and provides a visual editor (GraphiQL) during development.
|
@@ -78,9 +92,11 @@ executables: []
|
|
78
92
|
extensions: []
|
79
93
|
extra_rdoc_files: []
|
80
94
|
files:
|
95
|
+
- LICENSE
|
81
96
|
- app/controllers/graphql/rails/schema_controller.rb
|
82
97
|
- config/initializers/graphiql.rb
|
83
98
|
- config/routes.rb
|
99
|
+
- lib/graphql/rails.rb
|
84
100
|
- lib/graphql/rails/callbacks.rb
|
85
101
|
- lib/graphql/rails/config.rb
|
86
102
|
- lib/graphql/rails/controller_extensions.rb
|
@@ -93,9 +109,11 @@ files:
|
|
93
109
|
- lib/graphql/rails/schema.rb
|
94
110
|
- lib/graphql/rails/types.rb
|
95
111
|
- lib/graphql/rails/version.rb
|
96
|
-
- lib/graphql/rails.rb
|
97
112
|
- lib/tasks/graphql_rails_tasks.rake
|
98
|
-
-
|
113
|
+
- spec/graphql/rails/config_spec.rb
|
114
|
+
- spec/graphql/rails/dsl_spec.rb
|
115
|
+
- spec/graphql/rails/types_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
99
117
|
homepage: https://github.com/jamesreggio/graphql-rails
|
100
118
|
licenses:
|
101
119
|
- MIT
|
@@ -106,18 +124,22 @@ require_paths:
|
|
106
124
|
- lib
|
107
125
|
required_ruby_version: !ruby/object:Gem::Requirement
|
108
126
|
requirements:
|
109
|
-
- -
|
127
|
+
- - ">="
|
110
128
|
- !ruby/object:Gem::Version
|
111
129
|
version: 2.1.0
|
112
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
131
|
requirements:
|
114
|
-
- -
|
132
|
+
- - ">="
|
115
133
|
- !ruby/object:Gem::Version
|
116
134
|
version: '0'
|
117
135
|
requirements: []
|
118
136
|
rubyforge_project:
|
119
|
-
rubygems_version: 2.
|
137
|
+
rubygems_version: 2.4.5.1
|
120
138
|
signing_key:
|
121
139
|
specification_version: 4
|
122
140
|
summary: Zero-configuration GraphQL + Relay support for Rails
|
123
|
-
test_files:
|
141
|
+
test_files:
|
142
|
+
- spec/graphql/rails/config_spec.rb
|
143
|
+
- spec/graphql/rails/dsl_spec.rb
|
144
|
+
- spec/graphql/rails/types_spec.rb
|
145
|
+
- spec/spec_helper.rb
|