graphql-rails-resolver 0.1.2 → 0.1.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: eac8d006df6f747647df533f2606819a2b6e304a
4
- data.tar.gz: c2d7486872ecc83c143fd1654f369ab8fc58045e
3
+ metadata.gz: daaae82f72286352c8b15b9c04ebe0f29cdb5c7d
4
+ data.tar.gz: 8d6d288781cbe6643e005a7d618f174f96324833
5
5
  SHA512:
6
- metadata.gz: de1cd692a89ecf230ede5977aecf4e36a6ad5be227354643228d139c620f6e281547a8d259560a80e6016c3a3cbb6db8b3bf0bd691963d3ae71cb997eff14d91
7
- data.tar.gz: a5de48a5fb24727abd8f92f39fb3946f9e913aa8ca2116d6ecff9bc107e3110f1568f4d07398d550f5a7fa5e211e9ebb7d4c829ccb2ba4068b2dc0a667753f4f
6
+ metadata.gz: a1d3162e913409721fb111794ec0cc2d325957852d126513123945683d97ab220fc16475ae391feea818014d02604f9e91a35fda4c8b12025f01e9c99adc4e78
7
+ data.tar.gz: 2388a47c80fcfd9440322c14355587d6dd546866b95b9ff3402e3761c47faf459a517086c56470c3a850353f116736154bd75e22ce325cdff59f009021c9f152
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # GraphQL::Rails::Resolver
2
+ ## CHANGELOG
3
+
4
+ ### Version 0.1.3
5
+ Added `resolve_scope` for resolving model scopes.
6
+ Fixed `resolve_where` not being called and reworked class inheritance.
7
+
8
+
9
+ ### Version 0.1.2
10
+ Initial release. Took a couple tries to figure out how to import to a new namespace on an existing gem.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Cole Turner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # ActiveResolver (graphql-rails-resolver)
2
- A utility for ease graphql-ruby integration into a Rails project. ActiveResolver offers a declarative approach to resolving Field arguments in a Rails environment.
1
+ # GraphQL::Rails::Resolver (graphql-rails-resolver)
2
+ A utility to ease graphql-ruby integration into a Rails project. This resolver offers a declarative approach to resolving Field arguments in a Rails environment.
3
3
 
4
- # How it works:
5
- `ActiveResolver.rb` serves as a base class for your GraphQL Ruby schema. When a resolver inherits from this base class, you can easily map arguments in a GraphQL Field to an attribute on an ActiveRecord model or a custom method.
4
+ # How it works
5
+ `GraphQL::Rails::Resolver` serves as a base class for your GraphQL Ruby schema. When a resolver inherits from this base class, you can easily map arguments in a GraphQL Field to an attribute on an ActiveRecord model or a custom method.
6
6
 
7
7
  ## Why?
8
- **tl;dr; Active Resolvers achieves three goals: maintainable query type, code re-use, and a declarative integration with Ruby on Rails.**
8
+ **tl;dr; To achieves three goals: maintainable query type, code re-use, and a declarative integration with Ruby on Rails.**
9
9
 
10
10
  Take for example the following Rails model:
11
11
 
@@ -16,6 +16,7 @@ class Post < ApplicationRecord
16
16
 
17
17
  scope :is_public, -> { where(is_public: true) }
18
18
  scope :is_private, -> { where(is_public: false) }
19
+ scope :featured, -> (value) { where(created_at: value) }
19
20
 
20
21
  def tags
21
22
  ["hello", "world"]
@@ -28,11 +29,11 @@ The standard implementation for resolving a `Post` is as follows:
28
29
 
29
30
  ```
30
31
  field :post, PostType do
31
- argument :is_public, types.Boolean, default_value: true
32
- resolve -> (obj, args, ctx) {
33
- post.is_public if args[:is_public]
34
- post.is_private unless args[:is_public]
35
- }
32
+ argument :is_public, types.Boolean, default_value: true
33
+ resolve -> (obj, args, ctx) {
34
+ post.is_public if args[:is_public]
35
+ post.is_private unless args[:is_public]
36
+ }
36
37
  end
37
38
  ```
38
39
 
@@ -43,8 +44,8 @@ Using the pattern from this article, our Field becomes much simpler:
43
44
  **/app/graph/types/query_type.rb**
44
45
  ```
45
46
  field :post, PostType do
46
- argument :is_public, types.Boolean, default_value: true
47
- resolve Resolvers::Post.new
47
+ argument :is_public, types.Boolean, default_value: true
48
+ resolve Resolvers::Post.new
48
49
  end
49
50
  ```
50
51
 
@@ -65,19 +66,27 @@ module Resolvers
65
66
  end
66
67
  end
67
68
  ```
68
- This solution addresses code re-use, however this series of conditionals do not allow you to resolve more than one argument, and it may become difficult to maintain this imperative approach.
69
+ This solution addresses code re-use, but these series of conditionals do not allow you to resolve more than one argument, and it may become difficult to maintain this imperative approach.
69
70
 
70
71
 
71
- ## Hello Active Resolver:
72
+ ## Hello "Active" Resolver
72
73
  **Out with imperative, in with declarative.**
73
74
 
74
- Take the Resolver from the previous example. Using `ActiveResolver`, we inherit and use declarations for arguments and how they will be resolved. These declarations will be mapped to the attributes on the resolved model.
75
+ To begin, we install the gem by adding it to our `Gemfile`:
76
+
77
+ `
78
+ gem 'graphql-rails-resolver'
79
+ `
80
+
81
+ This will load a class by the name of `GraphQL::Rails::Resolver`
82
+
83
+ Take the Resolver from the previous example. Using `GraphQL::Rails::Resolver`, we inherit and use declarations for arguments and how they will be resolved. These declarations will be mapped to the attributes on the resolved model.
75
84
 
76
85
  ```
77
86
  # Class name must match the Rails model name exactly.
78
87
 
79
- class Post < GraphQL::Rails::ActiveResolver
80
- # ID argument is resolved within ActiveResolver
88
+ class Post < GraphQL::Rails::Resolver
89
+ # ID argument is resolved in base class
81
90
 
82
91
  # Resolve :is_public to a class method
83
92
  resolve_method :is_public
@@ -87,6 +96,18 @@ class Post < GraphQL::Rails::ActiveResolver
87
96
  resolve_where :created_at
88
97
  resolve_where :updated_at
89
98
 
99
+ # Resolve :featured argument with default test: if argument `featured` is present
100
+ resolve_scope :featured
101
+
102
+ # Same resolution as the line above, but send the value to the scope function
103
+ resolve_scope :featured, :with_value => true
104
+
105
+ # Resolve :featured scope if it passes custom argument test
106
+ resolve_scope :featured, -> (value) { value == :today }
107
+
108
+ # Resolve :is_public argument with a different scope name
109
+ resolve_scope :is_public, -> (value) { value != true }, :scope_name => :is_private
110
+
90
111
  def is_public(value)
91
112
  @result.is_public if value
92
113
  @result.is_private unless value
@@ -95,13 +116,15 @@ class Post < GraphQL::Rails::ActiveResolver
95
116
  end
96
117
  ```
97
118
 
98
- In the example above, there are two declarations:
119
+ In the example above, there are three declarations:
99
120
 
100
121
  `resolve_where` is a declarative approach using `ActiveRecord.where` to resolve arguments.
101
122
 
102
- `resolve_method` is an imperative approach that's useful for using Model scopes or custom resolution.
123
+ `resolve_scope` is an declarative way to call scopes on a model where a custom test for the argument can be specified with a closure.
124
+ - Use `with_value` to send the argument value to the scope closure.
125
+ - Use `scope_name` to map an argument to a scope by another name.
103
126
 
104
- [Help make scopes declarative!](#making-scopes-declarative)
127
+ `resolve_method` is an imperative approach that allows completely custom resolution.
105
128
 
106
129
 
107
130
 
@@ -115,7 +138,7 @@ end
115
138
  ```
116
139
 
117
140
  ### Find Model by ID
118
- Every Active Resolver includes the ability to resolve a model by ID. Using the following method, by default the resolver will find a model by **NodeIdentification.from_global_id(value)** or **Model.where(:id => value)**. This means a model can be resolved by Global ID or Integer ID.
141
+ `GraphQL::Rails::Resolver` includes the ability to resolve a model by ID. Using the following method, by default the resolver will find a model by **NodeIdentification.from_global_id(value)** or **Model.where(:id => value)**. This means a model can be resolved by Global ID or Integer ID.
119
142
  ```
120
143
  def lookup_id(value)
121
144
  ...
@@ -123,8 +146,8 @@ end
123
146
  ```
124
147
 
125
148
 
126
- ### Override Default Resolution
127
- The default behavior is to use `Model.all` to seed the resolution. This seed can be changed by providing a block or lambda to the class instance:
149
+ ### Override Default Scope
150
+ The default behavior is to use `Model.all` to scope the resolution. This scope can be changed by providing a block or lambda to the class instance:
128
151
  ```
129
152
  Resolvers::Post.new(Proc.new {
130
153
  ::Post.where(:created_at => ...)
@@ -133,22 +156,8 @@ Resolvers::Post.new(Proc.new {
133
156
 
134
157
 
135
158
  # Needs Help
136
- I wanted to release this utility for the hopes of sparking interest in Rails integration with `graphql-ruby`.
137
-
138
- If you wish to contribute to this project, any pull request is warmly welcomed. If time permits, I will continue to update this project to achieve the following:
139
-
140
- ### [Making Scopes Declarative](#making-scopes-declarative):
141
- For first release, scopes can only be resolved using `resolve_method`. The goal for further development is to stop using `resolve_method` and adapt other methods to facilitate resolution.
142
-
143
- The current syntax planned for scope resolution is as follows, where the argument is passed to the scope:
144
-
145
- ```
146
- resolve_scope :is_public, -> (args) { args[:is_public] == true }
147
- resolve_scope :is_private, -> (args) { args[:is_public] == false }
148
- ```
149
-
150
-
159
+ I wanted to release this utility for the hopes of sparking interest in Rails integration with `graphql-ruby`. If you wish to contribute to this project, any pull request is warmly welcomed.
151
160
 
152
161
  # Credits
153
- - Cole Turner ([@colepatrickturner](/colepatrickturner))
154
- - Peter Salanki ([@salanki](/salanki))
162
+ - Cole Turner ([@colepatrickturner](https://github.com/colepatrickturner))
163
+ - Peter Salanki ([@salanki](https://github.com/salanki))
@@ -1,7 +1,9 @@
1
1
  module GraphQL
2
2
  module Rails
3
3
  class Resolver
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.3'
5
+
6
+ attr_accessor :resolvers
5
7
 
6
8
  def initialize(callable=nil)
7
9
  unless callable.nil?
@@ -12,7 +14,7 @@ module GraphQL
12
14
  @obj = nil
13
15
  @args = nil
14
16
  @ctx = nil
15
- @resolvers = {}
17
+ @resolvers = self.class.resolvers
16
18
  end
17
19
 
18
20
  def call(obj, args, ctx)
@@ -29,7 +31,7 @@ module GraphQL
29
31
 
30
32
  @resolvers.each do |field,method|
31
33
  if args.key? field
32
- method
34
+ @result = method.call(@result, args[field])
33
35
  end
34
36
  end
35
37
 
@@ -75,28 +77,6 @@ module GraphQL
75
77
  "::#{self.class.name.demodulize}".constantize
76
78
  end
77
79
 
78
- def self.resolve(field, method)
79
- self.class_eval do
80
- @resolvers[field] = method
81
- end
82
- end
83
-
84
- def self.resolve_where(field)
85
- self.class_eval do
86
- resolve(field, Proc.new {
87
- @result = @result.where(field, @args[field])
88
- })
89
- end
90
- end
91
-
92
- def self.resolve_method(field)
93
- self.class_eval do
94
- resolve(field, Proc.new {
95
- send(field, @args[field])
96
- })
97
- end
98
- end
99
-
100
80
  def lookup_id(value)
101
81
  if is_global_id(value)
102
82
  type_name, id = NodeIdentification.from_global_id(value)
@@ -112,7 +92,49 @@ module GraphQL
112
92
  end
113
93
  end
114
94
 
95
+ class << self
96
+
97
+ def resolvers
98
+ @resolvers ||= {}
99
+ @resolvers
100
+ end
101
+
102
+ def resolve(field, method)
103
+ @resolvers ||= {}
104
+ @resolvers[field] = method
105
+ end
106
+
107
+ def resolve_where(field)
108
+ resolve(field, lambda { |obj, value|
109
+ where = {}
110
+ where[field] = value
111
+
112
+ obj.where(where)
113
+ })
114
+ end
115
+
116
+ def resolve_scope(field, test=nil, scope_name: nil, with_value: false)
117
+ test = lambda { |value| value.present? } if test.nil?
118
+ scope_name = field if scope_name.nil?
115
119
 
120
+ resolve(field, lambda { |obj, value|
121
+ args = []
122
+ args.push(value) if with_value
123
+
124
+ if test.call(value)
125
+ obj.send(scope_name, *args)
126
+ else
127
+ obj
128
+ end
129
+ })
130
+ end
131
+
132
+ def resolve_method(field)
133
+ resolve(field, lambda { |obj, value|
134
+ obj.send(field, value)
135
+ })
136
+ end
137
+ end
116
138
  end
117
139
  end
118
140
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-rails-resolver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cole Turner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-22 00:00:00.000000000 Z
11
+ date: 2016-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -44,6 +44,8 @@ executables: []
44
44
  extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
+ - CHANGELOG.md
48
+ - LICENSE
47
49
  - README.md
48
50
  - lib/graphql/rails.rb
49
51
  - lib/graphql/rails/resolver.rb