graphqr 0.0.5 → 0.0.6

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: 876e07cf3e0eb24c8d8c71f23b23e18ae3d014bc
4
- data.tar.gz: bcd24faba39f7be1b3a07ca3629bf6f680f10c25
3
+ metadata.gz: b962a2340faac84b6f9369947841074c52c34afa
4
+ data.tar.gz: 36fdff3a030711d367bd9d585228bf6f40755053
5
5
  SHA512:
6
- metadata.gz: 51f5c95b0ba53fe528e7e275bf6e00063c4d2cbd6add26bdc16cf41b0f2f2e6f4884e776108e8e4f3a522121ad0419863e50d111f0dadd0ce577d3611c524cf8
7
- data.tar.gz: cf5ff9b77895930d9d7bc9d8aa6adb3bdd494c34c6310139055e4ebb57e3403903810a197cd6f0098855dcfad2b0c275ec715bf21ef212569c7b7beeb9290bfa
6
+ metadata.gz: 5c68aeedd464b35f796312a9be00e7a909f3d99dea883637affde7a6ff349e44483326d5d6f5a5461ba7d5a191b2813f24403eebb7840b80e3b12e7b4d1d3509
7
+ data.tar.gz: 77739403805caf9a8974f16248a1da4bf392d08044e3a682fccb38e7e29697c1cf22d78fb6fd17a43242c359f8811c0a41739b82063896ffbe5a80d2fa7f3f75
data/README.md CHANGED
@@ -31,7 +31,7 @@ Or install it yourself as:
31
31
  GraphQR uses `pagy` and `pundit` by default and activates both `Authorization` and `Pagination` modules.
32
32
  If you'd like to create a specific configuration, create `config/initializers/graphql.rb` with
33
33
 
34
- ```
34
+ ```ruby
35
35
  GraphQR.configure do |config|
36
36
  config.use_pagination = true # or false to disable
37
37
  config.use_authorization = true # or false to disable
@@ -44,12 +44,20 @@ end
44
44
  ## Modules
45
45
 
46
46
  To use the extensions correctly add
47
+ ```ruby
48
+ field_class GraphQR::Fields::BaseField
47
49
  ```
48
- field_class GraphQR::Fields::BaseField
49
- ```
50
-
51
- to your `BaseObject` class. This will add the `paginate` options to your fields and add the necessary extensions according to the modules you activated.
50
+ to your `BaseObject` class. This will add the custom options to your fields and add the necessary extensions according to the modules you activated.
52
51
 
52
+ ```ruby
53
+ module Types
54
+ class BaseObject < GraphQL::Schema::Object
55
+ ...
56
+ field_class GraphQR::Fields::BaseField
57
+ ...
58
+ end
59
+ end
60
+ ```
53
61
  ### Pagination
54
62
 
55
63
  The Pagination module consists in a easier way of dealing with pages. Instead of using `cursors` we implemented a more Rails way using `per` and `page`.
@@ -57,16 +65,33 @@ Our implementation is (for now) based on [Pagy](https://github.com/ddnexus/pagy)
57
65
 
58
66
  To use the Pagination module add
59
67
 
60
- ```
68
+ ```ruby
69
+
61
70
  extend GraphQR::Pagination
62
71
  ```
63
72
 
64
73
  to any `GraphQL::Schema::Object` you'd like, but we recommend adding it to your `BaseObject` class.
65
74
 
75
+ ```ruby
76
+ module Types
77
+ class BaseObject < GraphQL::Schema::Object
78
+ ...
79
+ extend GraphQR::Pagination
80
+ ...
81
+ end
82
+ end
83
+ ```
84
+
66
85
  #### Usage
67
86
 
68
- ```
69
- field :users, UserType.pagination_type, paginate: true
87
+ ```ruby
88
+ module Types
89
+ class QueryType < Types::BaseObject
90
+ graphql_name 'Query'
91
+
92
+ field :users, UserType.pagination_type, paginate: true
93
+ end
94
+ end
70
95
  ```
71
96
 
72
97
  A `pagination_type` adds the `per` and `page` arguments and adds a `page_info` field to the response.
@@ -86,13 +111,23 @@ users(per: 10, page: 1) {
86
111
  The Authorization module in some wrappers around a `PolicyProvider` (only Pundit for now). And allows some basic behaviors.
87
112
  Everything on this module depends on a `policy_provider` passed to the GraphQL context. You can add it like this:
88
113
 
89
- ```
90
- context = {
91
- policy_provider: GraphQR::Policies::PunditProvider.new(policy_context: pundit_user)
114
+ ```ruby
115
+ class GraphqlController < ApplicationController
116
+
117
+ def execute
118
+ context = {
119
+ your_context,
120
+ policy_provider: policy_provider
121
+ }
122
+ result = YourSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
123
+ render json: result.to_json
124
+ rescue StandardError => e
125
+ raise e unless Rails.env.development?
126
+
127
+ handle_error_in_development(e)
128
+ end
92
129
  ...
93
- }
94
-
95
- Schema.execute(query, variables: variables, context: context, operation_name: operation_name)
130
+ end
96
131
  ```
97
132
 
98
133
  #### Authorized
@@ -101,11 +136,21 @@ This module adds a check on the object policy before resolving it. It always sea
101
136
  It works by extending the `authorized?` method.
102
137
 
103
138
  To add this behavior, add
104
- ```
139
+ ```ruby
105
140
  extend GraphQR::Authorized
106
141
  ```
107
142
  to any `GraphQL::Schema::Object` you'd like, but we recommend adding it to your `BaseObject` class.
108
143
 
144
+ ```ruby
145
+ module Types
146
+ class BaseObject < GraphQL::Schema::Object
147
+ ...
148
+ extend GraphQR::Authorized
149
+ ...
150
+ end
151
+ end
152
+ ```
153
+
109
154
  Example:
110
155
 
111
156
  ```
@@ -125,11 +170,21 @@ If any policy returns falsy, the object is returned as `null`.
125
170
  This module adds the PolicyProvider scope to the fields that represent an `ActiveRecord::Relation`. It works by implementing the `self.scope_items` method.
126
171
 
127
172
  To add this behavior, add
128
- ```
173
+ ```ruby
129
174
  extend GraphQR::ScopeItems
130
175
  ```
131
176
  to any `GraphQL::Schema::Object` you'd like, but we recommend adding it to your `BaseObject` class.
132
177
 
178
+ ```ruby
179
+ module Types
180
+ class BaseObject < GraphQL::Schema::Object
181
+ ...
182
+ extend GraphQR::ScopeItems
183
+ ...
184
+ end
185
+ end
186
+ ```
187
+
133
188
  Example:
134
189
 
135
190
  ```
@@ -146,14 +201,22 @@ This module is a wrapper around the PolicyProvider authorization.
146
201
  It adds the `authorize_graphql` method, similar to Pundit's `authorize`, but it returns an `GraphQL::ExecutionError` instead of a `Pundit::NotAuthorizedError`
147
202
 
148
203
  To add this behavior, add
149
- ```
150
- include GraphQR::AuthorizeGraphQL
204
+ ```ruby
205
+ include GraphQR::Policies::AuthorizeGraphQL
151
206
  ```
152
207
  where you want to use this methos, but we recommend adding it to your `Mutations` and `Resolvers` classes.
153
208
 
209
+ ```ruby
210
+ class BaseResolver < GraphQL::Schema::Resolver
211
+ ...
212
+ include GraphQR::Policies::AuthorizeGraphQL
213
+ ...
214
+ end
215
+ ```
216
+
154
217
  Example:
155
218
 
156
- ```
219
+ ```ruby
157
220
  authorize_graphql User, :index?
158
221
  ```
159
222
 
@@ -167,14 +230,22 @@ This modules is based on the [has_scope](https://github.com/plataformatec/has_sc
167
230
  It provides an `apply_scopes` method that can search for model scopes and use them on a collection
168
231
 
169
232
  To add this method, add
170
- ```
233
+ ```ruby
171
234
  include GraphQR::ApplyScopes
172
235
  ```
173
236
  where you'd like to use it, but we recommend adding it to your `Resolvers`.
174
237
 
238
+ ```ruby
239
+ class BaseResolver < GraphQL::Schema::Resolver
240
+ ...
241
+ include GraphQR::ApplyScopes
242
+ ...
243
+ end
244
+ ```
245
+
175
246
  Example:
176
247
 
177
- ```
248
+ ```ruby
178
249
  apply_scopes(User, { order_by_name: true, with_id: [1,2,3] })
179
250
  ```
180
251
 
@@ -184,11 +255,21 @@ This module adds the `query_field` helper.
184
255
  It adds an easy way of creating simple fields with resolvers.
185
256
 
186
257
  To add this method, add
187
- ```
258
+ ```ruby
188
259
  extend GraphQR::QueryField
189
260
  ```
190
261
  to your `BaseObject`.
191
262
 
263
+ ```ruby
264
+ module Types
265
+ class BaseObject < GraphQL::Schema::Object
266
+ ...
267
+ extend GraphQR::QueryField
268
+ ...
269
+ end
270
+ end
271
+ ```
272
+
192
273
  Read more about its use in the [documentation](https://qulturerocks.github.io/graphqr/GraphQR/QueryField.html)
193
274
 
194
275
 
@@ -57,6 +57,9 @@ require 'graphqr/apply_scopes'
57
57
  require 'graphqr/authorized'
58
58
  require 'graphqr/pagination'
59
59
  require 'graphqr/permitted_fields_extension'
60
+ require 'graphqr/base_resolver'
61
+ require 'graphqr/base_resolvers'
60
62
  require 'graphqr/query_field'
63
+ require 'graphqr/relation_fields'
61
64
  require 'graphqr/scope_items'
62
65
  require 'graphqr/version'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQR
4
+ ##
5
+ # @TODO doc
6
+ class BaseResolver < GraphQL::Schema::Resolver
7
+ ##
8
+ # @TODO doc
9
+ include GraphQR::ApplyScopes
10
+ include GraphQR::Policies::AuthorizeGraphQL
11
+ end
12
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQR
4
+ ##
5
+ # @TODO doc
6
+ module BaseResolvers
7
+ ##
8
+ # @TODO doc
9
+ def base_collection_resolver(type_class, scope_class)
10
+ Class.new(GraphQR::BaseResolver) do
11
+ type type_class.pagination_type, null: false
12
+
13
+ argument :filter, scope_class, required: false if scope_class.present?
14
+
15
+ def resolve(filter: {})
16
+ authorize_graphql unscoped_collection, :index?
17
+
18
+ collection = apply_scopes(unscoped_collection, filter)
19
+ context[:policy_provider].authorized_records(records: collection)
20
+ end
21
+
22
+ def unscoped_collection
23
+ raise NotImplementedError
24
+ end
25
+ end
26
+ end
27
+
28
+ def base_resource_resolver(type_class)
29
+ Class.new(GraphQR::BaseResolver) do
30
+ type type_class, null: false
31
+
32
+ def resolve
33
+ context[:policy_provider].allowed?(action: :show?, record: record)
34
+
35
+ record
36
+ end
37
+
38
+ def record
39
+ raise NotImplementedError
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -6,9 +6,9 @@ module GraphQR
6
6
  # A helper to create simple queries faster and easier
7
7
  #
8
8
  # To use this extension, add `extend Graphql::QueryField` on your `QueryType`
9
+ #
9
10
  module QueryField
10
- # rubocop:disable Metrics/ParameterLists
11
-
11
+ include BaseResolvers
12
12
  ##
13
13
  # The `query_field` method is a helper to create fields and resolver without effort.
14
14
  #
@@ -41,13 +41,15 @@ module GraphQR
41
41
  #
42
42
  # Single fields have the required `id` argument to find the exact record searched.
43
43
  # Its resolver will look for the `show?` method on the model Policy.
44
+ #
45
+ # rubocop:disable Metrics/ParameterLists
44
46
  def query_field(field_name, active_record_class, type_class:, scope_class: nil, **kwargs, &block)
45
47
  is_collection = active_record_class.is_a? Array
46
48
  if is_collection
47
49
  active_record_class = active_record_class.first
48
- resolver = collection(active_record_class, type_class, scope_class)
50
+ resolver = collection_resolver(active_record_class, type_class, scope_class)
49
51
  else
50
- resolver = resource(active_record_class, type_class)
52
+ resolver = resource_resolver(active_record_class, type_class)
51
53
  end
52
54
 
53
55
  field(field_name, paginate: is_collection, resolver: resolver, **kwargs, &block)
@@ -56,39 +58,26 @@ module GraphQR
56
58
 
57
59
  private
58
60
 
59
- def collection(active_record_class, type_class, scope_class)
60
- Class.new(::BaseResolver) do
61
- class_attribute :active_record_class
62
- self.active_record_class = active_record_class
63
-
64
- type type_class.pagination_type, null: false
65
-
66
- argument :filter, scope_class, required: false
67
-
68
- def resolve(filter: {})
69
- authorize_graphql active_record_class, :index?
70
-
71
- collection = apply_scopes(active_record_class, filter)
72
- context[:policy_provider].authorized_records(records: collection)
73
- end
74
- end
61
+ def collection_resolver(active_record_class, type_class, scope_class)
62
+ resolver = base_collection_resolver(type_class, scope_class)
63
+ resolver.define_method(:unscoped_collection) { @unscoped_collection ||= active_record_class }
64
+ resolver
75
65
  end
76
66
 
77
- def resource(active_record_class, type_class)
78
- Class.new(::BaseResolver) do
67
+ def resource_resolver(active_record_class, type_class)
68
+ Class.new(base_resource_resolver(type_class)) do
79
69
  class_attribute :active_record_class
80
70
  self.active_record_class = active_record_class
81
71
 
82
- type type_class, null: false
83
-
84
72
  argument :id, 'ID', required: true
85
73
 
86
74
  def resolve(id:)
87
- record = self.class.active_record_class.find(id)
88
-
89
- context[:policy_provider].allowed?(action: :show?, record: record)
75
+ @id = id
76
+ super()
77
+ end
90
78
 
91
- record
79
+ def record
80
+ @record ||= active_record_class.find(@id)
92
81
  end
93
82
  end
94
83
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQR
4
+ ##
5
+ # @TODO doc
6
+ module RelationFields
7
+ ##
8
+ # @TODO doc
9
+ # rubocop:disable Naming/PredicateName
10
+ include GraphQR::BaseResolvers
11
+
12
+ def has_many(field_name, type_class, scope_class: nil, **kwargs, &block)
13
+ type_class = type_class.first
14
+
15
+ resolver = has_many_resolver(field_name, type_class, scope_class)
16
+
17
+ field(field_name, paginate: true, resolver: resolver, **kwargs, &block)
18
+ end
19
+
20
+ def has_one(field_name, type_class, **kwargs, &block)
21
+ resolver = has_one_resolver(field_name, type_class)
22
+
23
+ field(field_name, resolver: resolver, **kwargs, &block)
24
+ end
25
+
26
+ private
27
+
28
+ def has_many_resolver(collection_name, type_class, scope_class)
29
+ resolver = base_collection_resolver(type_class, scope_class)
30
+ resolver.define_method(:unscoped_collection) { @unscoped_collection ||= object.send(collection_name) }
31
+ resolver
32
+ end
33
+
34
+ def has_one_resolver(resource_name, type_class)
35
+ resolver = base_resource_resolver(type_class)
36
+ resolver.define_method(:record) { @record ||= object.send(resource_name) }
37
+ resolver
38
+ end
39
+ # rubocop:enable Naming/PredicateName
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphQR
4
- VERSION = '0.0.5'
4
+ VERSION = '0.0.6'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphqr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manuel Puyol
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-05-29 00:00:00.000000000 Z
13
+ date: 2019-07-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: graphql
@@ -144,6 +144,8 @@ files:
144
144
  - lib/graphqr.rb
145
145
  - lib/graphqr/apply_scopes.rb
146
146
  - lib/graphqr/authorized.rb
147
+ - lib/graphqr/base_resolver.rb
148
+ - lib/graphqr/base_resolvers.rb
147
149
  - lib/graphqr/configuration.rb
148
150
  - lib/graphqr/fields/base_field.rb
149
151
  - lib/graphqr/hooks.rb
@@ -155,6 +157,7 @@ files:
155
157
  - lib/graphqr/policies/authorize_graphql.rb
156
158
  - lib/graphqr/policies/pundit_provider.rb
157
159
  - lib/graphqr/query_field.rb
160
+ - lib/graphqr/relation_fields.rb
158
161
  - lib/graphqr/scope_items.rb
159
162
  - lib/graphqr/version.rb
160
163
  - spec/graphqr_spec.rb