graphql-sugar 0.1.1

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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +601 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/graphql-sugar.gemspec +26 -0
  13. data/lib/generators/graphql/mutator/USAGE +8 -0
  14. data/lib/generators/graphql/mutator/mutator_generator.rb +9 -0
  15. data/lib/generators/graphql/mutator/templates/mutator.erb +15 -0
  16. data/lib/generators/graphql/resolver/USAGE +8 -0
  17. data/lib/generators/graphql/resolver/resolver_generator.rb +9 -0
  18. data/lib/generators/graphql/resolver/templates/resolver.erb +4 -0
  19. data/lib/generators/graphql/sugar/USAGE +10 -0
  20. data/lib/generators/graphql/sugar/sugar_generator.rb +17 -0
  21. data/lib/generators/graphql/sugar/templates/application_function.erb +3 -0
  22. data/lib/generators/graphql/sugar/templates/application_mutator.erb +3 -0
  23. data/lib/generators/graphql/sugar/templates/application_resolver.erb +3 -0
  24. data/lib/graphql/sugar/boot.rb +18 -0
  25. data/lib/graphql/sugar/define/attribute.rb +19 -0
  26. data/lib/graphql/sugar/define/attributes.rb +16 -0
  27. data/lib/graphql/sugar/define/model_class.rb +21 -0
  28. data/lib/graphql/sugar/define/mutator.rb +16 -0
  29. data/lib/graphql/sugar/define/parameter.rb +26 -0
  30. data/lib/graphql/sugar/define/relationship.rb +57 -0
  31. data/lib/graphql/sugar/define/relationships.rb +23 -0
  32. data/lib/graphql/sugar/define/resolver.rb +25 -0
  33. data/lib/graphql/sugar/function.rb +31 -0
  34. data/lib/graphql/sugar/mutator.rb +11 -0
  35. data/lib/graphql/sugar/resolver.rb +11 -0
  36. data/lib/graphql/sugar/version.rb +5 -0
  37. data/lib/graphql/sugar.rb +99 -0
  38. metadata +122 -0
data/README.md ADDED
@@ -0,0 +1,601 @@
1
+ # GraphQL::Sugar
2
+
3
+ A sweet, extended DSL written on top of the [graphql-ruby](https://github.com/rmosolgo/graphql-ruby) gem.
4
+
5
+ **Looking for a quick overview of this gem in action?** Head over to the [Usage](#usage) section.
6
+
7
+ This gem allows you to:
8
+
9
+ * Easily write [object types](#object-types) and [input types](#input-types) that are backed by ActiveRecord models.
10
+ * Automatically convert field names to snake_case.
11
+ * Automatically add `id`, `createdAt` and `updatedAt` fields if these columns exist in your database schema.
12
+ * Automatically determine the type of the field, based on your database schema and model validation rules, keeping things DRY.
13
+ * Easily write [resolvers](#resolvers) and [mutators](#mutators) to encapsulate query and mutation logic.
14
+ * Provide an object-oriented layer, allowing easy refactoring of common code across queries and mutations.
15
+ * Look like (and function very similar to) Rails controllers, so that writing them is a breeze.
16
+
17
+ ## Installation
18
+
19
+ ```ruby
20
+ gem 'graphql'
21
+ gem 'graphql-sugar'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ And finally, do some initial setup:
29
+
30
+ $ rails g graphql:sugar
31
+
32
+ ## Usage
33
+
34
+ This section provides a quick overview of the how simple the DSL can be, as well as a general workflow to follow:
35
+
36
+ ### Writing Queries
37
+
38
+ Create the ObjectType:
39
+
40
+ ```ruby
41
+ Types::PostType = GraphQL::ObjectType.define do
42
+ model_class Post
43
+
44
+ attribute :title
45
+ attribute :content
46
+ attribute :isPublic
47
+
48
+ relationship :user
49
+ relationship :comments
50
+ end
51
+ ```
52
+
53
+ Create a [Resolver](#resolvers):
54
+
55
+ ```ruby
56
+ class PostResolver < ApplicationResolver
57
+ parameter :id, !types.ID
58
+
59
+ def resolve
60
+ Post.find(params[:id])
61
+ end
62
+ end
63
+ ```
64
+
65
+ Expose the Resolver:
66
+
67
+ ```ruby
68
+ Types::QueryType = GraphQL::ObjectType.define do
69
+ name 'Query'
70
+
71
+ resolver :post
72
+ end
73
+ ```
74
+
75
+ ### Writing Mutations
76
+
77
+ Create the InputObjectType:
78
+
79
+ ```ruby
80
+ Inputs::PostInputType = GraphQL::InputObjectType.define do
81
+ name 'PostInput'
82
+
83
+ model_class Post
84
+
85
+ parameter :title
86
+ parameter :content
87
+ end
88
+ ```
89
+
90
+ Create a [Mutator](#mutators):
91
+
92
+ ```ruby
93
+ class CreatePostMutator < ApplicationMutator
94
+ parameter :input, !Inputs::PostInputType
95
+
96
+ type !Types::PostType
97
+
98
+ def mutate
99
+ Post.create!(params[:input])
100
+ end
101
+ end
102
+ ```
103
+
104
+ Expose the Mutator:
105
+
106
+ ```ruby
107
+ Types::MutationType = GraphQL::ObjectType.define do
108
+ name 'Mutation'
109
+
110
+ mutator :createPost
111
+ end
112
+ ```
113
+
114
+ ## Usage
115
+
116
+ ### Object Types
117
+
118
+ Start by generating an ObjectType as you normally would:
119
+
120
+ $ rails g graphql:object Post
121
+
122
+ This would create the following under `app/graphql/types/post_type.rb`:
123
+
124
+ ```ruby
125
+ Types::PostType = GraphQL::ObjectType.define do
126
+ name "Post"
127
+ end
128
+ ```
129
+
130
+ Replace the `name` line with a `model_class` declaration:
131
+
132
+ ```ruby
133
+ Types::PostType = GraphQL::ObjectType.define do
134
+ model_class Post
135
+ end
136
+ ```
137
+
138
+ This automatically sets the name as `PostType`. If you wish to overwrite the name, you can pass a second argument:
139
+
140
+ ```ruby
141
+ Types::PostType = GraphQL::ObjectType.define do
142
+ model_class Post, 'PostObject'
143
+ end
144
+ ```
145
+
146
+ The `model_class` declaration is **required** to use rest of the extended ObjectType DSL (like `attributes`, `attribute`, `relationships`, `relationship`, etc). If you forget to declare it however, a helpful exception is raised. :smile:
147
+
148
+ #### Defining attributes
149
+
150
+ *Normally*, this is how you would add a couple of fields to your ObjectType:
151
+
152
+ ```ruby
153
+ Types::PostType = GraphQL::ObjectType.define do
154
+ model_class Post
155
+
156
+ field :id, !types.ID
157
+ field :title, !types.String
158
+ field :content, types.String
159
+ field :isPublic, !types.Boolean, property: :is_public
160
+ field :createdAt
161
+ field :updatedAt
162
+ end
163
+ ```
164
+
165
+ However, using GraphQL::Sugar, you can now shorten this to:
166
+
167
+ ```ruby
168
+ Types::PostType = GraphQL::ObjectType.define do
169
+ model_class Post
170
+
171
+ attribute :title
172
+ attribute :content
173
+ attribute :isPublic
174
+ end
175
+ ```
176
+
177
+ Under the hood:
178
+
179
+ * The `id`, `createdAt` and `updatedAt` fields are automatically added if your model has those attributes.
180
+ * The type for the rest of the fields are automatically determined based on your `schema.rb` and model validations. (Read more about [automatic type resolution](#automatic-type-resolution).)
181
+ * The fields automatically resolve to the snake_cased method names of the attribute name provided (eg. `isPublic` => `is_public`).
182
+
183
+ You can shorten this further [active_model_serializers](https://github.com/rails-api/active_model_serializers)-style:
184
+
185
+ ```ruby
186
+ Types::PostType = GraphQL::ObjectType.define do
187
+ model_class Post
188
+
189
+ attributes :title, :content, :isPublic
190
+ end
191
+ ```
192
+
193
+ Or even more simply:
194
+
195
+ ```ruby
196
+ Types::PostType = GraphQL::ObjectType.define do
197
+ model_class Post
198
+
199
+ attributes
200
+ end
201
+ ```
202
+
203
+ ... which automatically includes *all* the attributes of a model based on your schema. While NOT recommended for production, this provides easy scaffolding of model-backed object types during development.
204
+
205
+ Internally `attribute` just defines a `field`, but automatically determines the type and resolves to the model's snake_cased attribute. For simplicity, it follows the *exact same syntax* as `field`, so you can override type or specify a `resolve:` function:
206
+
207
+ ```ruby
208
+ Types::PostType = GraphQL::ObjectType.define do
209
+ model_class Post
210
+
211
+ attribute :thumbnail, types.String, resolve: ->(obj, args, ctx) { obj.picture_url(:thumb) }
212
+ end
213
+ ```
214
+
215
+ This is useful (and necessary) if you wish to expose `attr_accessor`s defined in your model. (Read more about [automatic type resolution](#automatic-type-resolution).)
216
+
217
+ **Side Note:** You _can_ always mix in good ol' `field`s along with `attribute`s if you really need to access the old DSL:
218
+
219
+ ```ruby
220
+ Types::PostType = GraphQL::ObjectType.define do
221
+ model_class Post
222
+
223
+ attribute :title
224
+ field :isArchived, types.Boolean, resolve: ->(obj, args, ctx) { obj.is_archived? }
225
+ end
226
+ ```
227
+
228
+ However, since the syntax is pretty much the same, it is preferable to use either `field` or `attribute` throughout the type definition for the sake of uniformity. You may have a non-model backed ObjectType for example, which can use `field`s.
229
+
230
+ #### Defining relationships
231
+
232
+ Assume the Post model has the following associations:
233
+
234
+ ```ruby
235
+ class Post < ApplicationRecord
236
+ belongs_to :user
237
+ has_many :comments
238
+ end
239
+ ```
240
+
241
+ *Normally*, this is how you would define the relationship in your ObjectType:
242
+
243
+ ```ruby
244
+ Types::PostType = GraphQL::ObjectType.define do
245
+ model_class Post
246
+
247
+ field :userId, !types.ID, property: :user_id
248
+ field :user, Types::UserType
249
+
250
+ field :comments, !types[Types::CommentType]
251
+ end
252
+ ```
253
+
254
+ However, using GraphQL::Sugar, you can now shorten this to:
255
+
256
+ ```ruby
257
+ Types::PostType = GraphQL::ObjectType.define do
258
+ model_class Post
259
+
260
+ relationship :user
261
+ relationship :comments
262
+ end
263
+ ```
264
+
265
+ Under the hood:
266
+
267
+ * If the relationship is **belongs_to**, it automatically defines a field for the corresponding foreign key. It also determines the type and marks the association as non-null using [automatic type resolution](#automatic-type-resolution).
268
+ * If the relationship is **has_one** or **has_many**, it first looks for a corresponding [Resolver](#resolvers) (eg. in this case, `CommentsResolver`). If it doesn't find one, it defaults to calling method of the underlying association on the object (eg. `obj.comments`)
269
+
270
+ You can shorten the above code to:
271
+
272
+ ```ruby
273
+ Types::PostType = GraphQL::ObjectType.define do
274
+ model_class Post
275
+
276
+ relationships :user, :comments
277
+ end
278
+ ```
279
+
280
+ Or even more simply:
281
+
282
+ ```ruby
283
+ Types::PostType = GraphQL::ObjectType.define do
284
+ model_class Post
285
+
286
+ relationships
287
+ end
288
+ ```
289
+
290
+ ... which automatically reflects on *all* your model associations and includes them. While NOT recommended for production, this provides easy scaffolding of model-backed object types during development.
291
+
292
+ **Side Note:** Unlike `attribute`, `relationship` is not just syntactic sugar for `field` and it does much more. It is recommended that you revert to using `field`s (rather than `attribute`) if you need to achieve a specific behavior involving associations. For example:
293
+
294
+ ```ruby
295
+ Types::PostType = GraphQL::ObjectType.define do
296
+ model_class Post
297
+
298
+ relationship :user
299
+
300
+ field :recentComments, !types[Types::CommentType], resolve: ->(obj, args, ctx) {
301
+ obj.comments.not_flagged.recent.limit(3)
302
+ }
303
+ end
304
+ end
305
+ ```
306
+
307
+ #### Automatic Type Resolution
308
+
309
+ Your model attribute's type is automatically determined using Rails' reflection methods, as follows:
310
+
311
+ * First, we look at the column type:
312
+ * `:integer` gets mapped to `types.Int` (`GraphQL::INT_TYPE`),
313
+ * `:float` and `:decimal` get mapped to `types.Float` (`GraphQL::FLOAT_TYPE`),
314
+ * `:boolean` gets mapped to `types.Boolean` (`GraphQL::BOOLEAN_TYPE`),
315
+ * and the rest get mapped to `types.String` (`GraphQL::STRING_TYPE`).
316
+ * Then, we determine the non-nullability based on whether:
317
+ * You have specified `null: false` for the column in your schema, or
318
+ * You have specified `presence: true` validation for the attribute in your model.
319
+
320
+ In instances where a type cannot be automatically determined, you must provide the type yourself. For example, `attr_accessor`s are not persisted and don't have a corresponding column in your database schema.
321
+
322
+ ### Input Types
323
+
324
+ *Normally*, this is how you would define your InputObjectType:
325
+
326
+ ```ruby
327
+ Inputs::PostInputType = GraphQL::InputObjectType.define do
328
+ name 'PostInput'
329
+
330
+ argument :title, types.String
331
+ argument :content, types.String
332
+ argument :isPublic, types.Boolean, as: :is_public
333
+ end
334
+ ```
335
+
336
+ However, using GraphQL::Sugar, you can now shorten this to:
337
+
338
+ ```ruby
339
+ Inputs::PostInputType = GraphQL::InputObjectType.define do
340
+ name 'PostInput'
341
+
342
+ model_class 'Post'
343
+
344
+ parameter :title
345
+ parameter :content
346
+ parameter :isPublic
347
+ end
348
+ ```
349
+
350
+ Under the hood,
351
+ * `parameter` uses the same [automatic type resolution](#automatic-type-resolution) as `attribute`, but creates arguments that are not-null by default. The default behavior passes all values to be validated in the model instead, in order to return proper error messages in the response. (**TODO:** Allow this behavior to be configured via an initializer.)
352
+ * It allows sets the `:as` value to the snake_cased form of the provided name. (eg. `:isPublic` => `:is_public`). This allows us to easily pass them into ActiveRecord's `create` and `update_attributes` methods.
353
+
354
+ You can override the type to make a field non-null as follows:
355
+
356
+ ```ruby
357
+ Inputs::PostInputType = GraphQL::InputObjectType.define do
358
+ name 'PostInput'
359
+
360
+ model_class 'Post'
361
+
362
+ parameter :title, !types.String
363
+ parameter :content
364
+ end
365
+ ```
366
+
367
+ ### Resolvers
368
+
369
+ In its simplest form, a Resolver simply inherits from `ApplicationResolver` and contains a `#resolve` method.
370
+
371
+ ```ruby
372
+ class PostsResolver < ApplicationResolver
373
+ def resolve
374
+ Post.all
375
+ end
376
+ end
377
+ ```
378
+
379
+ To expose the resolver as a field, declare it in your root QueryType:
380
+
381
+ ```ruby
382
+ Types::QueryType = GraphQL::ObjectType.define do
383
+ name 'Query'
384
+
385
+ resolver :posts
386
+ end
387
+ ```
388
+
389
+ To declare arguments, you can use the `parameter` keyword which follows the same syntax:
390
+
391
+ ```ruby
392
+ class PostResolver < ApplicationResolver
393
+ parameter :id, !types.ID
394
+
395
+ def resolve
396
+ Post.find(params[:id])
397
+ end
398
+ end
399
+ ```
400
+
401
+ The benefit is that all `parameter`s (read: arguments) are loaded into a `params` object, with all keys transformed into snake_case. This allows them to be easily used with ActiveRecord methods like `where` and `find_by`.
402
+
403
+ You also have `object` and `context` available in your resolve method:
404
+
405
+ ```ruby
406
+ class PostsResolver < ApplicationResolver
407
+ def resolve
408
+ (object || context[:current_user]).posts
409
+ end
410
+ end
411
+ ```
412
+
413
+ #### Thinking in Graphs *using Resolvers*
414
+
415
+ Assume the following GraphQL query ("fetch 10 posts, along with the authors and 2 of their highest rated posts."):
416
+
417
+ ```
418
+ query {
419
+ posts(limit: 10) {
420
+ title
421
+ content
422
+
423
+ user {
424
+ name
425
+
426
+ posts(limit: 2, sort: "rating_desc") {
427
+ title
428
+ rating
429
+ }
430
+ }
431
+ }
432
+ }
433
+ ```
434
+
435
+ When executed, we resolve both the first and second `posts` using `PostsResolver`. This means:
436
+
437
+ 1. All the `argument`s (or `parameter`s) available to your top level `posts` are available to all your nested `posts`s through relationships without any extra work.
438
+
439
+ 2. The `object` value passed to your `PostsResolver#resolve` function is *very* important. This would be a good place to perform an authorization check to see if the current user has access to this relationship on the `object`.
440
+
441
+ **A quick detour:** At the top of your graph, you have your **root_value** ([read more](http://graphql-ruby.org/queries/executing_queries.html#root-value)), which the [graphql-ruby](https://github.com/rmosolgo/graphql-ruby) library allows you to set for your schema. By default, this is `null`. You can either *explicitly* set this root_value, or *implicitly* consider to be the current user (or current organization, or whatever your application deems it to be).
442
+
443
+ For example,
444
+
445
+ ```ruby
446
+ class PostsResolver < ApplicationResolver
447
+ def resolve
448
+ parent_object = (object || context[:current_user])
449
+ authorize! :view_posts, parent_object
450
+
451
+ parent_object.posts
452
+ end
453
+ end
454
+ ```
455
+
456
+ ### Mutators
457
+
458
+ In its simplest form, a Mutator simply inherits from `ApplicationMutator` and contains a `#mutate` method:
459
+
460
+ ```ruby
461
+ class CreatePostMutator < ApplicationMutator
462
+ parameter :input, !Inputs::PostInputType
463
+
464
+ type !Types::PostType
465
+
466
+ def mutate
467
+ Post.create!(params[:input])
468
+ end
469
+ end
470
+ ```
471
+
472
+ To expose the mutator as a field, declare it in your root MutationType:
473
+
474
+ ```ruby
475
+ Types::MutationType = GraphQL::ObjectType.define do
476
+ name 'Mutation'
477
+
478
+ mutator :createPost
479
+ end
480
+ ```
481
+
482
+ Just like resolvers, you have access to `object`, `params` and `context`:
483
+
484
+ ```ruby
485
+ class UpdatePostMutator < ApplicationMutator
486
+ parameter :id, !types.ID
487
+ parameter :input, !Inputs::PostInputType
488
+
489
+ type !Types::PostType
490
+
491
+ def mutate
492
+ post = context[:current_user].posts.find(params[:id])
493
+ post.update_attributes!(params[:input])
494
+ post
495
+ end
496
+ end
497
+ ```
498
+
499
+ ### Organizing Your Code
500
+
501
+ When you install the gem using `rails g graphql:sugar`, it creates the following files:
502
+
503
+ ```
504
+ app/graphql/functions/application_function.rb
505
+ app/graphql/resolvers/application_resolver.rb
506
+ app/graphql/mutators/application_mutator.rb
507
+ ```
508
+
509
+ All your resolvers inherit from `ApplicationResolver` and all your mutators inherit from `ApplicationMutator`, both of which in turn inherit from `ApplicationFunction`. You can use these classes to write shared code common to multiple queries, mutations, or both.
510
+
511
+ #### Applying OO principles
512
+
513
+ *Pagination and Sorting:* You can easily create methods that enable common features.
514
+
515
+ ```ruby
516
+ class ApplicationResolver < ApplicationFunction
517
+ include GraphQL::Sugar::Resolver
518
+
519
+ def self.sortable
520
+ parameter :sort, types.String
521
+ parameter :sortDir, types.String
522
+ end
523
+ end
524
+ ```
525
+
526
+ Use in your other resolvers:
527
+
528
+ ```ruby
529
+ class PostsResolver < ApplicationResolver
530
+ sortable
531
+
532
+ def resolve
533
+ # ...
534
+ end
535
+ end
536
+ ```
537
+
538
+ *Shared Code:* You can also easily share common code across a specific set of mutators. For example, your `CreatePostMutator` and `UpdatePostMutator` could inherit from `PostMutator`, which inherits from `ApplicationMutator`.
539
+
540
+ #### Tips for Large Applications
541
+
542
+ In a large app, you can quite easily end up with tons of mutations. During setup, GraphQL::Sugar adds a few lines to your eager_load_paths so you can group them in folders, while maintaining mutations at the root level. For example,
543
+
544
+ ```
545
+ # Folder Structure
546
+ app/graphql/mutators/
547
+ - posts
548
+ - create_post_mutator.rb
549
+ - update_post_mutator.rb
550
+ - users
551
+ - create_user_mutator.rb
552
+ - update_user_mutator.rb
553
+ - application_mutator.rb
554
+ ```
555
+
556
+ ```ruby
557
+ Types::MutationType = GraphQL::ObjectType.define do
558
+ name 'Mutation'
559
+
560
+ mutator :createPost
561
+ mutator :updatePost
562
+
563
+ mutator :createUser
564
+ mutator :updateUser
565
+ end
566
+ ```
567
+
568
+ ### Generators
569
+
570
+ A few basic generators have been written to quickly create some of the boilerplate code. They may not work perfectly, and the generated code may require further editing.
571
+
572
+ $ rails g graphql:resolver BlogPosts
573
+
574
+ Creates a `BlogPostsResolver` class at `app/graphql/resolvers/blog_posts_resolver.rb`.
575
+
576
+ $ rails g graphql:mutator CreateBlogPost
577
+
578
+ Creates a `CreateBlogPostMutator` class under `app/graphql/mutators/create_blog_post_mutator.rb`.
579
+
580
+ ## Credits
581
+
582
+ Many thanks to the work done by the authors of the following gems, which this gem uses as a foundation and/or inspiration:
583
+
584
+ - [graphql-ruby](https://github.com/rmosolgo/graphql-ruby)
585
+ - [graphql-activerecord](https://github.com/goco-inc/graphql-activerecord)
586
+ - [graphql-rails-resolver](https://github.com/colepatrickturner/graphql-rails-resolver)
587
+ - [active_model_serializers](https://github.com/rails-api/active_model_serializers)
588
+
589
+ ---
590
+
591
+ Maintained and sponsored by [KeepWorks](http://www.keepworks.com).
592
+
593
+ ![KeepWorks](http://www.keepworks.com/assets/logo-800bbf55fabb3427537cf669dc8cd018.png "KeepWorks")
594
+
595
+ ## Contributing
596
+
597
+ Bug reports and pull requests are welcome on GitHub at https://github.com/keepworks/graphql-sugar. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
598
+
599
+ ## License
600
+
601
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "graphql/sugar"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'graphql/sugar/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "graphql-sugar"
8
+ spec.version = GraphQL::Sugar::VERSION
9
+ spec.authors = ["Pradeep Kumar"]
10
+ spec.email = ["pradeep@keepworks.com"]
11
+
12
+ spec.summary = "A sweet, extended DSL written on top of the graphql-ruby gem."
13
+ spec.homepage = "https://github.com/keepworks/graphql-sugar"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.14"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Creates a GraphQL::Sugar Mutator.
3
+
4
+ Example:
5
+ rails generate graphql:mutator Thing
6
+
7
+ This will create:
8
+ app/graphql/mutators/thing_mutator.rb
@@ -0,0 +1,9 @@
1
+ module Graphql
2
+ class MutatorGenerator < Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def create_mutator
6
+ template 'mutator.erb', File.join('app/graphql/mutators', class_path, "#{file_name}_mutator.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ class <%= class_name %>Mutator < ApplicationMutator
2
+ <%= class_name %>InputType = GraphQL::InputObjectType.define do
3
+ name '<%= class_name %>Input'
4
+
5
+ parameter :id, !types.ID
6
+ end
7
+
8
+ parameter :input, !<%= class_name %>InputType
9
+
10
+ <%- type_name = file_name.split('_').drop(1).join('_').camelize -%>
11
+ type !Types::<%= type_name %>Type
12
+
13
+ def mutate
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Creates a GraphQL::Sugar Resolver.
3
+
4
+ Example:
5
+ rails generate graphql:resolver Thing
6
+
7
+ This will create:
8
+ app/graphql/resolvers/thing_resolver.rb