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 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