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 +4 -4
- data/README.md +103 -22
- data/lib/graphqr.rb +3 -0
- data/lib/graphqr/base_resolver.rb +12 -0
- data/lib/graphqr/base_resolvers.rb +44 -0
- data/lib/graphqr/query_field.rb +17 -28
- data/lib/graphqr/relation_fields.rb +41 -0
- data/lib/graphqr/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b962a2340faac84b6f9369947841074c52c34afa
|
4
|
+
data.tar.gz: 36fdff3a030711d367bd9d585228bf6f40755053
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
|
-
|
91
|
-
|
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
|
|
data/lib/graphqr.rb
CHANGED
@@ -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,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
|
data/lib/graphqr/query_field.rb
CHANGED
@@ -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
|
-
|
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 =
|
50
|
+
resolver = collection_resolver(active_record_class, type_class, scope_class)
|
49
51
|
else
|
50
|
-
resolver =
|
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
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
78
|
-
Class.new(
|
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
|
-
|
88
|
-
|
89
|
-
|
75
|
+
@id = id
|
76
|
+
super()
|
77
|
+
end
|
90
78
|
|
91
|
-
|
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
|
data/lib/graphqr/version.rb
CHANGED
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.
|
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-
|
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
|