graphql-rails 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3a7c5384076b014463594f7ff514f7575c158d7e
4
- data.tar.gz: ffc42b92d06723a1ea3605d1c11f2ccb2fd1f880
3
+ metadata.gz: 2982060c7ec7314e4c7daf5b37e708c4df649e7f
4
+ data.tar.gz: e9d139a3bb0eac9b9dfd228bbbb6b7f5c11f5bbd
5
5
  SHA512:
6
- metadata.gz: ba44e7314732609e798b8bff7bbf931f26673af2aa835c5af3e65be9fa35a230c66f79c2ce2e0a2b2d854e7892029268ac15ead3ebb78bbb8a475ff1d4903068
7
- data.tar.gz: 25341849de64f37b1691a3735749a695a8769eaf6c3076aa1249fe7797d7939dda2e10d36c1d0a9229484627f3483de58cdab6a3f3a78cc12b8a45014577cd9b
6
+ metadata.gz: 45ad67d595721cf99425f8bea6cfa6845a01132b943f6c374da92e1c21597581482703f05a8150aa49e8b88c75def2d031efe5f698031003513465ffa788c66c
7
+ data.tar.gz: 8ed5ba12d1b161031c39dfb6a61646aecd994834a5c589b745dcce44b3c067eef7f76625f7deb4ece6efe8fa1d4216aad9fa3791eaa99188085bff89b29261cd
@@ -13,6 +13,8 @@ module GraphQL
13
13
  instance_eval(&block)
14
14
  end
15
15
 
16
+ private
17
+
16
18
  def method_missing(method, *args, &block)
17
19
  begin
18
20
  @self.send(method, *args, &block)
@@ -18,7 +18,7 @@ module GraphQL
18
18
  end
19
19
  end
20
20
 
21
- def skip_authorization_check(*args)
21
+ def self.skip_authorization_check(*args)
22
22
  self.before_filter(*args) do |instance|
23
23
  instance.instance_variable_set(:@authorized, true)
24
24
  end
@@ -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(relationship.klass).connection_type }
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(relationship.klass) }
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
- # TODO: Implement mutations and subscriptions.
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.new
75
- argument.name = Types.to_field_name(name)
76
- argument.type = Types.resolve(type, required == :required)
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
@@ -26,6 +26,7 @@ module GraphQL
26
26
  @schema ||= GraphQL::Schema.new begin
27
27
  TYPES.reduce({
28
28
  max_depth: Rails.config.max_depth,
29
+ types: [ExerciseTaskType]
29
30
  }) do |schema, type|
30
31
  fields = @fields[type]
31
32
  unless fields.empty?
@@ -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
- if Rails.config.camel_case
65
- name.to_s.camelize(:upper)
66
- else
67
- name.to_s
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,
@@ -1,5 +1,5 @@
1
1
  module GraphQL
2
2
  module Rails
3
- VERSION = '0.0.2'
3
+ VERSION = '0.0.3'
4
4
  end
5
5
  end
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'graphql/rails'
2
+
3
+ class Array
4
+ def second
5
+ self[1]
6
+ end
7
+ end
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.2
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-06-08 00:00:00.000000000 Z
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
- - LICENSE
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.0.14.1
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