hq-graphql 0.0.2 → 1.0.0

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