fetcheable_on_api 0.1.5 → 0.1.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 +92 -5
- data/lib/fetcheable_on_api/filtreable.rb +11 -5
- data/lib/fetcheable_on_api/pagineable.rb +2 -3
- data/lib/fetcheable_on_api/sortable.rb +1 -3
- data/lib/fetcheable_on_api/version.rb +1 -1
- data/lib/fetcheable_on_api.rb +18 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '03812339432d5b98fc4b5c21a591fa89f6d4682e04ffbafca240e24c45bfa9fe'
|
4
|
+
data.tar.gz: 4156ce0dd1ab15dfc3c84b28b3caeb6bc45c8aec203ffd9d35b2995a16d78512
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b1e81ab96273f468b159de0fb3bcf366762c63e5743dcb6098b127ed7daa5e63a548f943a1de461022a757a930517f0cacd7dc88bd03e83e90f837393ceb6d5
|
7
|
+
data.tar.gz: c41a76a9bd81d7450e3b8c236b375aaa78359474d435f927de89a3a2109723e4570b1d212285a29e06f7f22528cb3eed78b93b99c5ad2ac74c50189dcd8c1d68
|
data/README.md
CHANGED
@@ -46,17 +46,23 @@ class Question < ApplicationRecord
|
|
46
46
|
foreign_key: 'question_id',
|
47
47
|
dependent: :destroy,
|
48
48
|
inverse_of: :question
|
49
|
+
|
50
|
+
belongs_to :category,
|
51
|
+
class_name: 'Category',
|
52
|
+
inverse_of: :questions,
|
53
|
+
optional: true
|
49
54
|
end
|
50
55
|
|
51
56
|
# == Schema Information
|
52
57
|
#
|
53
58
|
# Table name: questions
|
54
59
|
#
|
55
|
-
# id
|
56
|
-
# content
|
57
|
-
# position
|
58
|
-
#
|
59
|
-
#
|
60
|
+
# id :bigint(8) not null, primary key
|
61
|
+
# content :text not null
|
62
|
+
# position :integer
|
63
|
+
# category_id :bigint(8)
|
64
|
+
# created_at :datetime not null
|
65
|
+
# updated_at :datetime not null
|
60
66
|
#
|
61
67
|
```
|
62
68
|
|
@@ -88,6 +94,34 @@ end
|
|
88
94
|
# updated_at :datetime not null
|
89
95
|
#
|
90
96
|
```
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class Category < ApplicationRecord
|
100
|
+
#
|
101
|
+
# Validations
|
102
|
+
#
|
103
|
+
validates :name,
|
104
|
+
presence: true
|
105
|
+
|
106
|
+
#
|
107
|
+
# Associations
|
108
|
+
#
|
109
|
+
has_many :questions,
|
110
|
+
class_name: 'Question',
|
111
|
+
inverse_of: :category
|
112
|
+
end
|
113
|
+
|
114
|
+
# == Schema Information
|
115
|
+
#
|
116
|
+
# Table name: categories
|
117
|
+
#
|
118
|
+
# id :bigint(8) not null, primary key
|
119
|
+
# name :text not null
|
120
|
+
# created_at :datetime not null
|
121
|
+
# updated_at :datetime not null
|
122
|
+
#
|
123
|
+
```
|
124
|
+
|
91
125
|
And controller:
|
92
126
|
|
93
127
|
```ruby
|
@@ -128,18 +162,21 @@ $ curl -X GET \
|
|
128
162
|
{
|
129
163
|
"id": 3,
|
130
164
|
"position": 1,
|
165
|
+
"category_id": 1,
|
131
166
|
"content": "How to simply sort a collection with this gem ?",
|
132
167
|
"answer": "Just add sort_by in your controller and call the apply_fetcheable method"
|
133
168
|
},
|
134
169
|
{
|
135
170
|
"id": 4,
|
136
171
|
"position": 2,
|
172
|
+
"category_id": 2,
|
137
173
|
"content": "Is it so simple?",
|
138
174
|
"answer": "Yes"
|
139
175
|
},
|
140
176
|
{
|
141
177
|
"id": 5,
|
142
178
|
"position": 3,
|
179
|
+
"category_id": 2,
|
143
180
|
"content": "Is this real life?",
|
144
181
|
"answer": "Yes this is real life"
|
145
182
|
}
|
@@ -170,18 +207,21 @@ $ curl -X GET \
|
|
170
207
|
{
|
171
208
|
"id": 3,
|
172
209
|
"position": 1,
|
210
|
+
"category_id": 1,
|
173
211
|
"content": "How to simply sort a collection with this gem ?",
|
174
212
|
"answer": "Just add sort_by in your controller and call the apply_fetcheable method"
|
175
213
|
},
|
176
214
|
{
|
177
215
|
"id": 4,
|
178
216
|
"position": 2,
|
217
|
+
"category_id": 2,
|
179
218
|
"content": "Is it so simple?",
|
180
219
|
"answer": "Yes"
|
181
220
|
},
|
182
221
|
{
|
183
222
|
"id": 5,
|
184
223
|
"position": 3,
|
224
|
+
"category_id": 2,
|
185
225
|
"content": "Is this real life?",
|
186
226
|
"answer": "Yes this is real life"
|
187
227
|
}
|
@@ -198,18 +238,21 @@ $ curl -X GET \
|
|
198
238
|
{
|
199
239
|
"id": 5,
|
200
240
|
"position": 3,
|
241
|
+
"category_id": 2,
|
201
242
|
"content": "Is this real life?",
|
202
243
|
"answer": "Yes this is real life"
|
203
244
|
},
|
204
245
|
{
|
205
246
|
"id": 4,
|
206
247
|
"position": 2,
|
248
|
+
"category_id": 2,
|
207
249
|
"content": "Is it so simple?",
|
208
250
|
"answer": "Yes"
|
209
251
|
},
|
210
252
|
{
|
211
253
|
"id": 3,
|
212
254
|
"position": 1,
|
255
|
+
"category_id": 1,
|
213
256
|
"content": "How to simply sort a collection with this gem ?",
|
214
257
|
"answer": "Just add sort_by in your controller and call the apply_fetcheable method"
|
215
258
|
}
|
@@ -229,12 +272,14 @@ $ curl -X GET \
|
|
229
272
|
{
|
230
273
|
"id": 3,
|
231
274
|
"position": 1,
|
275
|
+
"category_id": 1,
|
232
276
|
"content": "How to simply sort a collection with this gem ?",
|
233
277
|
"answer": "Just add sort_by in your controller and call the apply_fetcheable method"
|
234
278
|
},
|
235
279
|
{
|
236
280
|
"id": 4,
|
237
281
|
"position": 2,
|
282
|
+
"category_id": 2,
|
238
283
|
"content": "Is it so simple?",
|
239
284
|
"answer": "Yes"
|
240
285
|
}
|
@@ -247,6 +292,7 @@ $ curl -X GET \
|
|
247
292
|
{
|
248
293
|
"id": 5,
|
249
294
|
"position": 3,
|
295
|
+
"category_id": 2,
|
250
296
|
"content": "Is this real life?",
|
251
297
|
"answer": "Yes this is real life"
|
252
298
|
}
|
@@ -288,6 +334,7 @@ $ curl -X GET \
|
|
288
334
|
{
|
289
335
|
"id": 3,
|
290
336
|
"position": 1,
|
337
|
+
"category_id": 1,
|
291
338
|
"content": "How to simply sort a collection with this gem ?",
|
292
339
|
"answer": "Just add sort_by in your controller and call the apply_fetcheable method"
|
293
340
|
}
|
@@ -304,12 +351,14 @@ $ curl -X GET \
|
|
304
351
|
{
|
305
352
|
"id": 4,
|
306
353
|
"position": 2,
|
354
|
+
"category_id": 2,
|
307
355
|
"content": "Is it so simple?",
|
308
356
|
"answer": "Yes"
|
309
357
|
},
|
310
358
|
{
|
311
359
|
"id": 5,
|
312
360
|
"position": 3,
|
361
|
+
"category_id": 2,
|
313
362
|
"content": "Is this real life?",
|
314
363
|
"answer": "Yes this is real life"
|
315
364
|
}
|
@@ -345,12 +394,50 @@ $ curl -X GET \
|
|
345
394
|
{
|
346
395
|
"id": 3,
|
347
396
|
"position": 1,
|
397
|
+
"category_id": 1,
|
348
398
|
"content": "How to simply sort a collection with this gem ?",
|
349
399
|
"answer": "Just add sort_by in your controller and call the apply_fetcheable method"
|
350
400
|
}
|
351
401
|
]
|
352
402
|
```
|
353
403
|
|
404
|
+
Furthermore you can specify one of the supported `Arel` predicate.
|
405
|
+
|
406
|
+
```ruby
|
407
|
+
class QuestionsController < ActionController::Base
|
408
|
+
#
|
409
|
+
# FetcheableOnApi
|
410
|
+
#
|
411
|
+
filter_by :category_id, with: :eq
|
412
|
+
|
413
|
+
# GET /questions
|
414
|
+
def index
|
415
|
+
questions = apply_fetcheable(Question.includes(:answer).all)
|
416
|
+
render json: questions
|
417
|
+
end
|
418
|
+
end
|
419
|
+
```
|
420
|
+
|
421
|
+
```bash
|
422
|
+
$ curl -X GET \
|
423
|
+
'http://localhost:3000/questions?filter[category_id]=1'
|
424
|
+
|
425
|
+
[
|
426
|
+
{
|
427
|
+
"id": 3,
|
428
|
+
"position": 1,
|
429
|
+
"category_id": 1,
|
430
|
+
"content": "How to simply sort a collection with this gem ?",
|
431
|
+
"answer": "Just add sort_by in your controller and call the apply_fetcheable method"
|
432
|
+
}
|
433
|
+
]
|
434
|
+
```
|
435
|
+
|
436
|
+
Currently two kind of predicates are supported:
|
437
|
+
|
438
|
+
+ `:ilike` which is the default behaviour and will match the parameter with the SQL fragment `ILIKE '%foo%'`.
|
439
|
+
+ `:eq` which matches the parameter with the SQL fragment `= 'foo'`.
|
440
|
+
|
354
441
|
And that's all !
|
355
442
|
|
356
443
|
## Development
|
@@ -21,7 +21,7 @@ module FetcheableOnApi
|
|
21
21
|
def filter_by(*attrs)
|
22
22
|
options = attrs.extract_options!
|
23
23
|
options.symbolize_keys!
|
24
|
-
options.assert_valid_keys(:as, :class_name)
|
24
|
+
options.assert_valid_keys(:as, :class_name, :with)
|
25
25
|
|
26
26
|
self.filters_configuration = filters_configuration.dup
|
27
27
|
|
@@ -45,10 +45,8 @@ module FetcheableOnApi
|
|
45
45
|
protected
|
46
46
|
|
47
47
|
def apply_filters(collection)
|
48
|
-
return collection unless valid_parameters?(params)
|
49
|
-
return collection unless valid_parameters?(params[:filter])
|
50
|
-
|
51
48
|
return collection if params[:filter].blank?
|
49
|
+
valid_parameters!(:filter)
|
52
50
|
|
53
51
|
filter_params = params.require(:filter)
|
54
52
|
.permit(filters_configuration.keys)
|
@@ -58,8 +56,16 @@ module FetcheableOnApi
|
|
58
56
|
values.split(',').map do |value|
|
59
57
|
column_name = filters_configuration[column.to_sym].fetch(:as, column)
|
60
58
|
klass = filters_configuration[column.to_sym].fetch(:class_name, collection.klass)
|
59
|
+
predicate = filters_configuration[column.to_sym].fetch(:with, :ilike)
|
61
60
|
|
62
|
-
|
61
|
+
case predicate
|
62
|
+
when :ilike
|
63
|
+
klass.arel_table[column_name].matches("%#{value}%")
|
64
|
+
when :eq
|
65
|
+
klass.arel_table[column_name].eq(value)
|
66
|
+
else
|
67
|
+
raise ArgumentError, "unsupported predicate `#{predicate}`"
|
68
|
+
end
|
63
69
|
end.inject(:or)
|
64
70
|
end
|
65
71
|
|
@@ -20,9 +20,8 @@ module FetcheableOnApi
|
|
20
20
|
protected
|
21
21
|
|
22
22
|
def apply_pagination(collection)
|
23
|
-
return collection
|
24
|
-
|
25
|
-
return collection unless params[:page].present?
|
23
|
+
return collection if params[:page].blank?
|
24
|
+
valid_parameters!(:page)
|
26
25
|
|
27
26
|
limit = params[:page].fetch(
|
28
27
|
:size,
|
@@ -48,10 +48,8 @@ module FetcheableOnApi
|
|
48
48
|
protected
|
49
49
|
|
50
50
|
def apply_sort(collection)
|
51
|
-
return collection unless valid_parameters?(params)
|
52
|
-
return collection unless valid_parameters?(params[:sort])
|
53
|
-
|
54
51
|
return collection if params[:sort].blank?
|
52
|
+
valid_parameters!(:sort, permitted_types: [String])
|
55
53
|
|
56
54
|
ordering = {}
|
57
55
|
sorted_params = params[:sort].split(',')
|
data/lib/fetcheable_on_api.rb
CHANGED
@@ -54,9 +54,24 @@ module FetcheableOnApi
|
|
54
54
|
apply_pagination(collection)
|
55
55
|
end
|
56
56
|
|
57
|
-
def valid_parameters
|
58
|
-
|
59
|
-
|
57
|
+
def valid_parameters!(*keys, permitted_types: default_permitted_types)
|
58
|
+
raise ArgumentError.new(
|
59
|
+
"Incorrect type #{params.dig(*keys).class} for params #{keys}"
|
60
|
+
) unless valid_params_types(*keys, permitted_types: permitted_types)
|
61
|
+
end
|
62
|
+
|
63
|
+
def valid_params_types(*keys, permitted_types: default_permitted_types)
|
64
|
+
permitted_types.inject(false) do |res, type|
|
65
|
+
res || valid_params_type(params.dig(*keys), type)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def valid_params_type(value, type)
|
70
|
+
value.is_a?(type)
|
71
|
+
end
|
72
|
+
|
73
|
+
def default_permitted_types
|
74
|
+
[ActionController::Parameters, Hash]
|
60
75
|
end
|
61
76
|
end
|
62
77
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fetcheable_on_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabien
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|