hq-graphql 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,374 @@
1
+ require 'rails_helper'
2
+
3
+ describe ::HQ::GraphQL::Resource do
4
+ let(:organization_type) do
5
+ Class.new do
6
+ include ::HQ::GraphQL::Resource
7
+ self.model_name = "Organization"
8
+ end
9
+ end
10
+
11
+ let(:advisor_type) do
12
+ Class.new do
13
+ include ::HQ::GraphQL::Resource
14
+ self.model_name = "Advisor"
15
+
16
+ root_query
17
+ end
18
+ end
19
+
20
+ let(:root_query) do
21
+ Class.new(::HQ::GraphQL::RootQuery)
22
+ end
23
+
24
+ let(:root_mutation) do
25
+ Class.new(::HQ::GraphQL::RootMutation)
26
+ end
27
+
28
+ let(:schema) do
29
+ Class.new(GraphQL::Schema) do
30
+ query(RootQuery)
31
+ mutation(RootMutation)
32
+ end
33
+ end
34
+
35
+ before(:each) do
36
+ advisor_type
37
+ stub_const("RootQuery", root_query)
38
+ stub_const("RootMutation", root_mutation)
39
+ end
40
+
41
+ context "defaults" do
42
+ it "builds the query klass" do
43
+ expect(::HQ::GraphQL::Types[Advisor]).to eql(advisor_type.query_klass)
44
+ end
45
+
46
+ it "builds the input klass" do
47
+ expect(::HQ::GraphQL::Inputs[Advisor]).to eql(advisor_type.input_klass)
48
+ end
49
+
50
+ it "creates query fields" do
51
+ ::HQ::GraphQL::Types[Advisor].graphql_definition
52
+ expected = ["id", "organizationId", "name", "createdAt", "updatedAt"]
53
+ expect(::HQ::GraphQL::Types[Advisor].fields.keys).to contain_exactly(*expected)
54
+ end
55
+
56
+ it "creates query graphql name" do
57
+ ::HQ::GraphQL::Types[Advisor].graphql_definition
58
+ expect(::HQ::GraphQL::Types[Advisor].graphql_name).to eql("Advisor")
59
+ end
60
+
61
+ it "creates input arguments" do
62
+ ::HQ::GraphQL::Inputs[Advisor].graphql_definition
63
+ expected = ["id", "organizationId", "name", "createdAt", "updatedAt"]
64
+ expect(::HQ::GraphQL::Inputs[Advisor].arguments.keys).to contain_exactly(*expected)
65
+ end
66
+
67
+ it "creates input graphql name" do
68
+ ::HQ::GraphQL::Inputs[Advisor].graphql_definition
69
+ expect(::HQ::GraphQL::Inputs[Advisor].graphql_name).to eql("AdvisorInput")
70
+ end
71
+
72
+ it "doesn't create mutations" do
73
+ expect(advisor_type.mutation_klasses).to be_empty
74
+ end
75
+
76
+ context "with an association" do
77
+ before(:each) do
78
+ organization_type
79
+ end
80
+
81
+ it "adds organization type" do
82
+ ::HQ::GraphQL::Types[Advisor].graphql_definition
83
+ expected = ["id", "organization", "organizationId", "name", "createdAt", "updatedAt"]
84
+ expect(::HQ::GraphQL::Types[Advisor].fields.keys).to contain_exactly(*expected)
85
+ end
86
+
87
+ it "doesn't add organization type" do
88
+ ::HQ::GraphQL::Inputs[Advisor].graphql_definition
89
+ expected = ["id", "organizationId", "name", "createdAt", "updatedAt"]
90
+ expect(::HQ::GraphQL::Inputs[Advisor].arguments.keys).to contain_exactly(*expected)
91
+ end
92
+ end
93
+ end
94
+
95
+ context ".query" do
96
+ let(:advisor_type) do
97
+ Class.new do
98
+ include ::HQ::GraphQL::Resource
99
+ self.model_name = "Advisor"
100
+
101
+ query associations: false do
102
+ graphql_name "CustomAdvisorName"
103
+ remove_attr :name
104
+ end
105
+ end
106
+ end
107
+
108
+ before(:each) do
109
+ organization_type
110
+ advisor_type
111
+ end
112
+
113
+ it "removes name" do
114
+ ::HQ::GraphQL::Types[Advisor].graphql_definition
115
+ expected = ["id", "organizationId", "createdAt", "updatedAt"]
116
+ expect(::HQ::GraphQL::Types[Advisor].fields.keys).to contain_exactly(*expected)
117
+ end
118
+
119
+ it "customizes graphql name" do
120
+ ::HQ::GraphQL::Types[Advisor].graphql_definition
121
+ expect(::HQ::GraphQL::Types[Advisor].graphql_name).to eql("CustomAdvisorName")
122
+ end
123
+ end
124
+
125
+ context ".input" do
126
+ let(:advisor_type) do
127
+ Class.new do
128
+ include ::HQ::GraphQL::Resource
129
+ self.model_name = "Advisor"
130
+
131
+ input do
132
+ graphql_name "CustomAdvisorInput"
133
+ remove_attr :name
134
+ end
135
+ end
136
+ end
137
+
138
+ before(:each) do
139
+ organization_type
140
+ advisor_type
141
+ end
142
+
143
+ it "removes name" do
144
+ ::HQ::GraphQL::Inputs[Advisor].graphql_definition
145
+ expected = ["id", "organizationId", "createdAt", "updatedAt"]
146
+ expect(::HQ::GraphQL::Inputs[Advisor].arguments.keys).to contain_exactly(*expected)
147
+ end
148
+
149
+ it "customizes graphql name" do
150
+ ::HQ::GraphQL::Inputs[Advisor].graphql_definition
151
+ expect(::HQ::GraphQL::Inputs[Advisor].graphql_name).to eql("CustomAdvisorInput")
152
+ end
153
+ end
154
+
155
+ context ".mutations" do
156
+ let(:advisor_type) do
157
+ Class.new do
158
+ include ::HQ::GraphQL::Resource
159
+ self.model_name = "Advisor"
160
+
161
+ mutations
162
+
163
+ input do
164
+ remove_attr :name
165
+ add_association :organization
166
+ end
167
+ end
168
+ end
169
+
170
+ before(:each) do
171
+ organization_type
172
+ end
173
+
174
+ it "generates the create, update, and destroy mutations by default" do
175
+ expect(advisor_type.mutation_klasses.keys).to contain_exactly("create_advisor", "update_advisor", "destroy_advisor")
176
+ end
177
+
178
+ it "removes name on update" do
179
+ update_mutation = advisor_type.mutation_klasses[:update_advisor]
180
+ update_mutation.payload_type
181
+
182
+ aggregate_failures do
183
+ expected_arguments = ["id", "organizationId", "organizationAttributes", "createdAt", "updatedAt"]
184
+ expect(update_mutation.arguments.keys).to contain_exactly(*expected_arguments)
185
+
186
+ expected_fields = ["errors", "resource"]
187
+ expect(update_mutation.fields.keys).to contain_exactly(*expected_fields)
188
+ end
189
+ end
190
+ end
191
+
192
+ context "execution" do
193
+ let(:find_advisor) {
194
+ <<-gql
195
+ query findAdvisor($id: UUID!){
196
+ advisor(id: $id) {
197
+ name
198
+ organizationId
199
+
200
+ organization {
201
+ name
202
+ }
203
+ }
204
+ }
205
+ gql
206
+ }
207
+
208
+ let(:create_mutation) {
209
+ <<-gql
210
+ mutation createAdvisor($name: String!, $organizationId: UUID!){
211
+ createAdvisor(name: $name, organizationId: $organizationId) {
212
+ errors
213
+ resource {
214
+ id
215
+ name
216
+ }
217
+ }
218
+ }
219
+ gql
220
+ }
221
+
222
+ let(:update_mutation) {
223
+ <<-gql
224
+ mutation updateAdvisor($id: UUID!, $name: String!, $organizationAttributes: OrganizationInput){
225
+ updateAdvisor(id: $id, name: $name, organizationAttributes: $organizationAttributes) {
226
+ errors
227
+ resource {
228
+ name
229
+ organization {
230
+ name
231
+ }
232
+ }
233
+ }
234
+ }
235
+ gql
236
+ }
237
+
238
+ let(:destroy_mutation) {
239
+ <<-gql
240
+ mutation destroyAdvisor($id: UUID!){
241
+ destroyAdvisor(id: $id) {
242
+ errors
243
+ resource {
244
+ name
245
+ }
246
+ }
247
+ }
248
+ gql
249
+ }
250
+
251
+ before(:each) do
252
+ organization_type
253
+
254
+ advisor_type.class_eval do
255
+ mutations
256
+
257
+ input do
258
+ add_association :organization
259
+ end
260
+ end
261
+ end
262
+
263
+ it "fetches results" do
264
+ advisor = FactoryBot.create(:advisor)
265
+ results = schema.execute(find_advisor, variables: { id: advisor.id })
266
+ data = results["data"]["advisor"]
267
+
268
+ aggregate_failures do
269
+ expect(data["name"]).to eql(advisor.name)
270
+ expect(data["organizationId"]).to eql(advisor.organization_id)
271
+ expect(data["organization"]["name"]).to eql(advisor.organization.name)
272
+ end
273
+ end
274
+
275
+ it "creates" do
276
+ organization = FactoryBot.create(:organization)
277
+ name = "Bob"
278
+ results = schema.execute(create_mutation, variables: { name: name, organizationId: organization.id })
279
+
280
+ data = results["data"]
281
+ aggregate_failures do
282
+ expect(data["errors"]).to be_nil
283
+ expect(data["createAdvisor"]["resource"]["name"]).to eql name
284
+ expect(Advisor.where(id: data["createAdvisor"]["resource"]["id"]).exists?).to eql true
285
+ end
286
+ end
287
+
288
+ it "updates" do
289
+ advisor = FactoryBot.create(:advisor)
290
+ name = "Bob"
291
+ organization_name = "Foo"
292
+
293
+ results = schema.execute(update_mutation, variables: {
294
+ id: advisor.id,
295
+ name: name,
296
+ organizationAttributes: { id: advisor.organization_id, name: organization_name }
297
+ })
298
+
299
+ data = results["data"]
300
+ aggregate_failures do
301
+ expect(data["errors"]).to be_nil
302
+ expect(data["updateAdvisor"]["resource"]["name"]).to eql name
303
+ expect(data["updateAdvisor"]["resource"]["organization"]["name"]).to eql organization_name
304
+ expect(Advisor.find(advisor.id).name).to eql name
305
+ expect(Organization.find(advisor.organization_id).name).to eql organization_name
306
+ end
307
+ end
308
+
309
+ it "destroys" do
310
+ advisor = FactoryBot.create(:advisor)
311
+ results = schema.execute(destroy_mutation, variables: { id: advisor.id })
312
+
313
+ data = results["data"]
314
+ aggregate_failures do
315
+ expect(data["errors"]).to be_nil
316
+ expect(data["destroyAdvisor"]["resource"]["name"]).to eql advisor.name
317
+ expect(Advisor.where(id: advisor.id).exists?).to eql false
318
+ end
319
+ end
320
+
321
+ context "with a global scope" do
322
+ before(:each) do
323
+ allow(::HQ::GraphQL).to receive(:default_scope) { Advisor.none }
324
+ end
325
+
326
+ it "returns nothing" do
327
+ advisor = FactoryBot.create(:advisor)
328
+ results = schema.execute(find_advisor, variables: { id: advisor.id })
329
+
330
+ expect(results["data"]["advisor"]).to be_nil
331
+ end
332
+
333
+ it "returns an error on a mutation" do
334
+ advisor = FactoryBot.create(:advisor)
335
+ results = schema.execute(update_mutation, variables: { id: advisor.id, name: "Bob" })
336
+
337
+ data = results["data"]
338
+ aggregate_failures do
339
+ expect(data["updateAdvisor"]["errors"]).to be_present
340
+ expect(data["updateAdvisor"]["resource"]).to be_nil
341
+ end
342
+ end
343
+ end
344
+
345
+ context "with a local scope" do
346
+ before(:each) do
347
+ advisor_type.class_eval do
348
+ default_scope do
349
+ Advisor.none
350
+ end
351
+ end
352
+ end
353
+
354
+ it "returns nothing" do
355
+ advisor = FactoryBot.create(:advisor)
356
+ results = schema.execute(find_advisor, variables: { id: advisor.id })
357
+
358
+ expect(results["data"]["advisor"]).to be_nil
359
+ end
360
+
361
+ it "returns an error on a mutation" do
362
+ advisor = FactoryBot.create(:advisor)
363
+ results = schema.execute(update_mutation, variables: { id: advisor.id, name: "Bob" })
364
+
365
+ data = results["data"]
366
+ aggregate_failures do
367
+ expect(data["updateAdvisor"]["errors"]).to be_present
368
+ expect(data["updateAdvisor"]["resource"]).to be_nil
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ end
@@ -0,0 +1,65 @@
1
+ require 'rails_helper'
2
+
3
+ describe ::HQ::GraphQL::Types::UUID do
4
+ let(:hql_object_klass) do
5
+ Class.new(::HQ::GraphQL::Object) do
6
+ graphql_name "TestQuery"
7
+
8
+ field :name, ::HQ::GraphQL::Types::UUID, null: false
9
+ end
10
+ end
11
+
12
+ let(:query) do
13
+ Class.new(::HQ::GraphQL::Object) do
14
+ graphql_name "Query"
15
+
16
+ field :advisor, AdvisorType, null: false do
17
+ argument :id, ::HQ::GraphQL::Types::UUID, required: true
18
+ end
19
+
20
+ def advisor(id:)
21
+ Advisor.find(id)
22
+ end
23
+ end
24
+ end
25
+
26
+ let(:schema) do
27
+ Class.new(GraphQL::Schema) do
28
+ query(Query)
29
+ end
30
+ end
31
+
32
+ let(:query_str) do
33
+ <<-gql
34
+ query findAdvisor($id: UUID!){
35
+ advisor(id: $id) {
36
+ name
37
+ }
38
+ }
39
+ gql
40
+ end
41
+
42
+ before(:each) do
43
+ stub_const("AdvisorType", hql_object_klass)
44
+ stub_const("Query", query)
45
+ end
46
+
47
+ describe ".coerce_result" do
48
+ it "raises an error on incorrect type" do
49
+ advisor = FactoryBot.create(:advisor)
50
+ expect { schema.execute(query_str, variables: { id: advisor.id }) }.to raise_error(
51
+ ::GraphQL::CoercionError, "\"#{advisor.name}\" is not a valid UUID"
52
+ )
53
+ end
54
+ end
55
+
56
+ describe ".coerce_input" do
57
+ it "displays an error message" do
58
+ result = schema.execute(query_str, variables: { id: "1" })
59
+ aggregate_failures do
60
+ expect(result["errors"].length).to eql(1)
61
+ expect(result["errors"][0]["message"]).to eql("Variable id of type UUID! was provided invalid value")
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,40 @@
1
+ require 'rails_helper'
2
+
3
+ describe ::HQ::GraphQL::Types do
4
+
5
+ describe ".[]" do
6
+ let(:graphql_klass) do
7
+ Class.new do
8
+ include ::HQ::GraphQL::Resource
9
+
10
+ self.model_name = "Advisor"
11
+
12
+ query(attributes: false, associations: false) do
13
+ field :custom_field, String, null: false
14
+ end
15
+ end
16
+ end
17
+
18
+ it "finds the type" do
19
+ type_object = graphql_klass.query_klass
20
+
21
+ aggregate_failures do
22
+ expect(type_object.superclass).to eql(::HQ::GraphQL::Object)
23
+ expect(type_object).to eql(described_class[Advisor])
24
+ expect(type_object.fields.keys).to contain_exactly("customField")
25
+ type_object.to_graphql
26
+ expect(type_object.fields.keys).to contain_exactly("customField")
27
+ end
28
+ end
29
+
30
+ it "finds the type when lookup is a string" do
31
+ type_object = graphql_klass.query_klass
32
+ expect(type_object).to eql(described_class["Advisor"])
33
+ end
34
+
35
+ it "raises an exception for unknown types" do
36
+ expect { described_class[Advisor] }.to raise_error(described_class::Error)
37
+ end
38
+ end
39
+
40
+ end
data/spec/rails_helper.rb CHANGED
@@ -32,10 +32,12 @@ RSpec.configure do |config|
32
32
  end
33
33
 
34
34
  config.before(:each) do
35
+ ::HQ::GraphQL.reset!
35
36
  DatabaseCleaner.start
36
37
  end
37
38
 
38
39
  config.after(:each) do
39
40
  DatabaseCleaner.clean
41
+ ::HQ::GraphQL.reset!
40
42
  end
41
43
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hq-graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Jones
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-23 00:00:00.000000000 Z
11
+ date: 2018-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -33,7 +33,7 @@ dependencies:
33
33
  version: '1.0'
34
34
  - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: 1.8.7
36
+ version: 1.8.10
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '1.0'
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 1.8.7
46
+ version: 1.8.10
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec_junit_formatter
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -96,25 +96,37 @@ files:
96
96
  - Rakefile
97
97
  - lib/hq-graphql.rb
98
98
  - lib/hq/graphql.rb
99
+ - lib/hq/graphql/active_record_extensions.rb
99
100
  - lib/hq/graphql/engine.rb
101
+ - lib/hq/graphql/input_extensions.rb
102
+ - lib/hq/graphql/input_object.rb
103
+ - lib/hq/graphql/inputs.rb
104
+ - lib/hq/graphql/mutation.rb
100
105
  - lib/hq/graphql/object.rb
106
+ - lib/hq/graphql/resource.rb
107
+ - lib/hq/graphql/resource/mutation.rb
108
+ - lib/hq/graphql/root_mutation.rb
109
+ - lib/hq/graphql/root_query.rb
110
+ - lib/hq/graphql/scalars.rb
101
111
  - lib/hq/graphql/types.rb
102
112
  - lib/hq/graphql/types/uuid.rb
103
113
  - lib/hq/graphql/version.rb
104
114
  - spec/factories/advisors.rb
105
115
  - spec/factories/organizations.rb
106
116
  - spec/factories/users.rb
107
- - spec/internal/app/graphql/query.rb
108
- - spec/internal/app/graphql/schema.rb
109
- - spec/internal/app/graphql/user_type.rb
110
117
  - spec/internal/app/models/advisor.rb
111
118
  - spec/internal/app/models/organization.rb
112
119
  - spec/internal/app/models/user.rb
113
120
  - spec/internal/config/database.circleci.yml
114
121
  - spec/internal/config/database.yml
115
122
  - spec/internal/db/schema.rb
116
- - spec/lib/object_spec.rb
117
- - spec/lib/types_spec.rb
123
+ - spec/lib/graphql/active_record_extensions_spec.rb
124
+ - spec/lib/graphql/inputs_spec.rb
125
+ - spec/lib/graphql/mutation_spec.rb
126
+ - spec/lib/graphql/object_spec.rb
127
+ - spec/lib/graphql/resource_spec.rb
128
+ - spec/lib/graphql/types/uuid_spec.rb
129
+ - spec/lib/graphql/types_spec.rb
118
130
  - spec/rails_helper.rb
119
131
  - spec/spec_helper.rb
120
132
  homepage: https://github.com/OneHQ/hq-graphql
@@ -146,15 +158,17 @@ test_files:
146
158
  - spec/internal/app/models/advisor.rb
147
159
  - spec/internal/app/models/organization.rb
148
160
  - spec/internal/app/models/user.rb
149
- - spec/internal/app/graphql/schema.rb
150
- - spec/internal/app/graphql/query.rb
151
- - spec/internal/app/graphql/user_type.rb
152
161
  - spec/internal/config/database.circleci.yml
153
162
  - spec/internal/config/database.yml
154
163
  - spec/internal/db/schema.rb
155
164
  - spec/factories/organizations.rb
156
165
  - spec/factories/advisors.rb
157
166
  - spec/factories/users.rb
158
- - spec/lib/object_spec.rb
159
- - spec/lib/types_spec.rb
167
+ - spec/lib/graphql/types/uuid_spec.rb
168
+ - spec/lib/graphql/active_record_extensions_spec.rb
169
+ - spec/lib/graphql/object_spec.rb
170
+ - spec/lib/graphql/inputs_spec.rb
171
+ - spec/lib/graphql/resource_spec.rb
172
+ - spec/lib/graphql/types_spec.rb
173
+ - spec/lib/graphql/mutation_spec.rb
160
174
  - spec/rails_helper.rb
@@ -1,18 +0,0 @@
1
- class Query < GraphQL::Schema::Object
2
- graphql_name "Query"
3
-
4
- field :users, [HQ::GraphQL::Types[User]], null: false
5
- field :advisors, [HQ::GraphQL::Types[Advisor]], null: false
6
-
7
- def users
8
- User.all
9
- end
10
-
11
- def users_custom
12
- users
13
- end
14
-
15
- def advisors
16
- Advisor.all
17
- end
18
- end
@@ -1,3 +0,0 @@
1
- class Schema < GraphQL::Schema
2
- query(Query)
3
- end
@@ -1,3 +0,0 @@
1
- class UserType < HQ::GraphQL::Object
2
- with_model "User"
3
- end