jsonapi-utils 0.4.4 → 0.4.5

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: 8e4f9e4f00521de390580aa6cc15c92f785ae0a5
4
- data.tar.gz: 42c4dc5facd04f531fe5e19790463785e45962d2
3
+ metadata.gz: ec04f95554ca59d1117ffa0452646252a5a156c5
4
+ data.tar.gz: 897fd3e12eceed6338421e6e5b7166afd8279947
5
5
  SHA512:
6
- metadata.gz: ea64cf3d3f5900d25b194047f045ccc0450315108223250cbfab943e89f8ccd25ecff1aca8d056bb1454aa2e9e933abc08177688f110f02f4b91095f99ffdcae
7
- data.tar.gz: 249e6f9b09eb464091f0c4aa38fb19920f42a3b62ad3d0d547d7274d2cdb2712230a5493711ec83e5efcea0efd5efe52bdc3b040339c5cf51d73c60bfb75381e
6
+ metadata.gz: 2aa0e5fc2e3c030898bd2287804bb62752523f6f9e6aad6a01c14954d9d8a09dee587117a54cd7463cb9cefedeb5ca2d91bb00548e703b5a99f57eb15e91a97b
7
+ data.tar.gz: 1136e92931251cce1ad8f652d56ee7555d0da2cbb93c3c4b44b7d33053b9460357b23bf84a9b178cb702e73942d92d9688e61d10ad0cd5e4e4bd80994e2d0a35
data/README.md CHANGED
@@ -13,7 +13,7 @@ JSONAPI::Utils (JU) was built on top of [JSONAPI::Resources](https://github.com/
13
13
  Add these lines to your application's Gemfile:
14
14
 
15
15
  ```ruby
16
- gem 'jsonapi-utils', '~> 0.4.3'
16
+ gem 'jsonapi-utils', '~> 0.4.4'
17
17
  ```
18
18
 
19
19
  And then execute:
@@ -22,11 +22,23 @@ And then execute:
22
22
  $ bundle
23
23
  ```
24
24
 
25
- ## Macros
25
+ ## Response Macros
26
26
 
27
27
  ### jsonapi_render
28
28
 
29
- Validates the request and renders ActiveRecord/Hash objects into JSON API-compliant responses.
29
+ Takes ActiveRecord/Hash objects and generates JSON API-compliant responses.
30
+
31
+ ```ruby
32
+ # GET /users
33
+ def index
34
+ jsonapi_render json: User.all
35
+ end
36
+
37
+ # GET /users/:id
38
+ def show
39
+ jsonapi_render json: User.find(params[:id])
40
+ end
41
+ ```
30
42
 
31
43
  Arguments:
32
44
 
@@ -37,13 +49,9 @@ Arguments:
37
49
  - `count`: explicitly points the total count of records for the request in order to build a proper pagination. By default, JU will count the total number of records.
38
50
  - `model`: sets the model reference in cases when `json` is a Hash or a collection of Hashes.
39
51
 
40
- ```ruby
41
- # Single resource rendering
42
- jsonapi_render json: User.find(params[:id])
43
-
44
- # Collection rendering
45
- jsonapi_render json: User.all
52
+ Examples:
46
53
 
54
+ ```ruby
47
55
  # Specify a particular HTTP status code
48
56
  jsonapi_render json: new_user, status: :created
49
57
 
@@ -60,17 +68,21 @@ jsonapi_render json: { data: { id: 1, first_name: 'Tiago' } }, options: { model:
60
68
  jsonapi_render json: { data: [{ id: 1, first_name: 'Tiago' }, { id: 2, first_name: 'Doug' }] }, options: { model: User }
61
69
  ```
62
70
 
63
- ### jsonapi_serialize
71
+ ### jsonapi_format
64
72
 
65
- In the backstage that's the method that actually parsers ActiveRecord/Hash objects and builds a new Hash compliant with JSON API. It can be called anywhere in controllers, concerns etc.
73
+ In the backstage this is the method that actually parses ActiveRecord/Hash objects and builds a new Hash compliant with JSON API. It can be called anywhere in your controllers being very useful whenever you need to work with a JSON API "serialized" version of your object before rendering it.
74
+
75
+ Note: because of semantic reasons `JSONAPI::Utils#jsonapi_serialize` was renamed being now just an alias to `JSONAPI::Utils#jsonapi_format`.
66
76
 
67
77
  ```ruby
68
- collection = jsonapi_serialize(User.all)
69
- render json: do_some_magic_with(collection)
78
+ def index
79
+ result = do_some_magic(jsonapi_format(User.all))
80
+ render json: result
81
+ end
70
82
  ```
71
83
 
72
84
  Arguments:
73
- - It receives a second optional argument with the same options for `jsonapi_render`.
85
+ - It receives the same options as `jsonapi_render`.
74
86
 
75
87
  ## Usage
76
88
 
@@ -218,12 +230,8 @@ Content-Type: application/vnd.api+json
218
230
  {
219
231
  "title": "Record not found",
220
232
  "detail": "The record identified by 3 could not be found.",
221
- "id": null,
222
- "href": null,
223
- "code": 404,
224
- "source": null,
225
- "links": null,
226
- "status": "not_found"
233
+ "code": "404",
234
+ "status": "404"
227
235
  }
228
236
  ]
229
237
  }
data/lib/jsonapi/utils.rb CHANGED
@@ -1,260 +1,18 @@
1
1
  require 'jsonapi-resources'
2
2
  require 'jsonapi/utils/version'
3
3
  require 'jsonapi/utils/exceptions'
4
+ require 'jsonapi/utils/request'
5
+ require 'jsonapi/utils/response'
4
6
 
5
7
  module JSONAPI
6
8
  module Utils
9
+ include JSONAPI::Utils::Request
10
+ include JSONAPI::Utils::Response
11
+
7
12
  def self.included(base)
8
- if base.respond_to?(:helper_method)
13
+ if base.respond_to?(:before_action)
9
14
  base.before_action :setup_request, :check_request
10
- base.helper_method :jsonapi_render, :jsonapi_serialize
11
- end
12
- end
13
-
14
- def jsonapi_render(json:, status: nil, options: {})
15
- body = jsonapi_serialize(json, options)
16
- render json: body, status: status || @_response_document.status
17
- rescue => e
18
- handle_exceptions(e)
19
- ensure
20
- if response.body.size > 0
21
- response.headers['Content-Type'] = JSONAPI::MEDIA_TYPE
22
- end
23
- end
24
-
25
- def jsonapi_render_errors(exception)
26
- result = jsonapi_format_errors(exception)
27
- errors = result.errors
28
- render json: { errors: errors }, status: errors.first.status
29
- end
30
-
31
- def jsonapi_format_errors(exception)
32
- JSONAPI::ErrorsOperationResult.new(exception.errors[0].code, exception.errors)
33
- end
34
-
35
- def jsonapi_render_internal_server_error
36
- jsonapi_render_errors(::JSONAPI::Utils::Exceptions::InternalServerError.new)
37
- end
38
-
39
- def jsonapi_render_bad_request
40
- jsonapi_render_errors(::JSONAPI::Utils::Exceptions::BadRequest.new)
41
- end
42
-
43
- def jsonapi_render_not_found(exception)
44
- id = exception.message.match(/=([\w-]+)/).try(:[], 1) || '(no identifier)'
45
- jsonapi_render_errors(JSONAPI::Exceptions::RecordNotFound.new(id))
46
- end
47
-
48
- def jsonapi_render_not_found_with_null
49
- render json: { data: nil }, status: 200
50
- end
51
-
52
- def jsonapi_serialize(records, options = {})
53
- if records.is_a?(Hash)
54
- hash = records.with_indifferent_access
55
- records = hash_to_active_record(hash[:data], options[:model])
56
- end
57
-
58
- fix_request_options(params, records)
59
- build_response_document(records, options).contents
60
- end
61
-
62
- def filter_params
63
- @_filter_params ||=
64
- if params[:filter].is_a?(Hash)
65
- params[:filter].keys.each_with_object({}) do |resource, hash|
66
- hash[resource] = params[:filter][resource]
67
- end
68
- end
69
- end
70
-
71
- def sort_params
72
- @_sort_params ||=
73
- if params[:sort].present?
74
- params[:sort].split(',').each_with_object({}) do |criteria, hash|
75
- order, field = criteria.match(/(\-?)(\w+)/i)[1..2]
76
- hash[field] = order == '-' ? :desc : :asc
77
- end
78
- end
79
- end
80
-
81
- private
82
-
83
- def build_response_document(records, options)
84
- results = JSONAPI::OperationResults.new
85
-
86
- if records.respond_to?(:to_ary)
87
- @_records = build_collection(records, options)
88
- results.add_result(JSONAPI::ResourcesOperationResult.new(:ok, @_records, result_options(records, options)))
89
- else
90
- @_record = turn_into_resource(records, options)
91
- results.add_result(JSONAPI::ResourceOperationResult.new(:ok, @_record))
92
- end
93
-
94
- @_response_document = create_response_document(results)
95
- end
96
-
97
-
98
- def fix_request_options(params, records)
99
- return if request.method !~ /get/i ||
100
- params.nil? ||
101
- %w(index show create update destroy).include?(params[:action])
102
- action = records.respond_to?(:to_ary) ? 'index' : 'show'
103
- @request.send("setup_#{action}_action", params)
104
- end
105
-
106
- def result_options(records, options)
107
- {}.tap do |data|
108
- if JSONAPI.configuration.default_paginator != :none &&
109
- JSONAPI.configuration.top_level_links_include_pagination
110
- data[:pagination_params] = pagination_params(records, options)
111
- end
112
-
113
- if JSONAPI.configuration.top_level_meta_include_record_count
114
- data[:record_count] = count_records(records, options)
115
- end
116
- end
117
- end
118
-
119
- def pagination_params(records, options)
120
- @paginator ||= paginator(params)
121
- if @paginator && JSONAPI.configuration.top_level_links_include_pagination
122
- options = {}
123
- @paginator.class.requires_record_count &&
124
- options[:record_count] = count_records(records, options)
125
- @paginator.links_page_params(options)
126
- else
127
- {}
128
- end
129
- end
130
-
131
- def paginator(params)
132
- page_params = ActionController::Parameters.new(params[:page])
133
-
134
- @paginator ||=
135
- if JSONAPI.configuration.default_paginator == :paged
136
- PagedPaginator.new(page_params)
137
- elsif JSONAPI.configuration.default_paginator == :offset
138
- OffsetPaginator.new(page_params)
139
- end
140
- end
141
-
142
- def build_collection(records, options = {})
143
- records = apply_filter(records, options)
144
- records = apply_pagination(records, options)
145
- records = apply_sort(records)
146
- records.respond_to?(:to_ary) ? records.map { |record| turn_into_resource(record, options) } : []
147
- end
148
-
149
- def turn_into_resource(record, options = {})
150
- if options[:resource]
151
- options[:resource].to_s.constantize.new(record, context)
152
- else
153
- @request.resource_klass.new(record, context)
154
- end
155
- end
156
-
157
- def apply_filter(records, options = {})
158
- if apply_filter?(records, options)
159
- records.where(filter_params)
160
- else
161
- records
162
15
  end
163
16
  end
164
-
165
- def apply_filter?(records, options = {})
166
- params[:filter].present? && records.respond_to?(:where) &&
167
- (options[:filter].nil? || options[:filter])
168
- end
169
-
170
- def apply_pagination(records, options = {})
171
- return records unless apply_pagination?(options)
172
- pagination = set_pagination(options)
173
-
174
- records =
175
- if records.is_a?(Array)
176
- records[pagination[:range]]
177
- else
178
- pagination[:paginator].apply(records, nil)
179
- end
180
- end
181
-
182
- def apply_sort(records)
183
- return records unless params[:sort].present?
184
-
185
- if records.is_a?(Array)
186
- records.sort { |a, b| comp = 0; eval(sort_criteria) }
187
- elsif records.respond_to?(:order)
188
- records.order(sort_params)
189
- end
190
- end
191
-
192
- def sort_criteria
193
- sort_params.reduce('') do |sum, hash|
194
- foo = ["a[:#{hash[0]}]", "b[:#{hash[0]}]"]
195
- foo.reverse! if hash[1] == :desc
196
- sum + "comp = comp == 0 ? #{foo.join(' <=> ')} : comp; "
197
- end
198
- end
199
-
200
- def set_pagination(options)
201
- page_params = ActionController::Parameters.new(@request.params[:page])
202
- if JSONAPI.configuration.default_paginator == :paged
203
- @_paginator ||= PagedPaginator.new(page_params)
204
- number = page_params['number'].to_i.nonzero? || 1
205
- size = page_params['size'].to_i.nonzero? || JSONAPI.configuration.default_page_size
206
- { paginator: @_paginator, range: (number - 1) * size..number * size - 1 }
207
- elsif JSONAPI.configuration.default_paginator == :offset
208
- @_paginator ||= OffsetPaginator.new(page_params)
209
- offset = page_params['offset'].to_i.nonzero? || 0
210
- limit = page_params['limit'].to_i.nonzero? || JSONAPI.configuration.default_page_size
211
- { paginator: @_paginator, range: offset..offset + limit - 1 }
212
- else
213
- {}
214
- end
215
- end
216
-
217
- def apply_pagination?(options)
218
- JSONAPI.configuration.default_paginator != :none &&
219
- (options[:paginate].nil? || options[:paginate])
220
- end
221
-
222
- def hash_to_active_record(data, model)
223
- return data if model.nil?
224
- coerced = [data].flatten.map { |hash| model.new(hash) }
225
- data.is_a?(Array) ? coerced : coerced.first
226
- rescue ActiveRecord::UnknownAttributeError
227
- if data.is_a?(Array)
228
- ids = data.map { |e| e[:id] }
229
- model.where(id: ids)
230
- else
231
- model.find_by(id: data[:id])
232
- end
233
- end
234
-
235
- def count_records(records, options)
236
- if options[:count].present?
237
- options[:count]
238
- elsif records.is_a?(Array)
239
- records.length
240
- else
241
- records = apply_filter(records, options) if params[:filter].present?
242
- records.except(:group, :order).count("DISTINCT #{records.table.name}.id")
243
- end
244
- end
245
-
246
- def setup_request
247
- @request ||=
248
- JSONAPI::Request.new(
249
- params,
250
- context: context,
251
- key_formatter: key_formatter,
252
- server_error_callbacks: (self.class.server_error_callbacks || [])
253
- )
254
- end
255
-
256
- def check_request
257
- @request.errors.blank? || render_errors(@request.errors)
258
- end
259
17
  end
260
18
  end
@@ -1,25 +1,52 @@
1
1
  require 'jsonapi/utils/version'
2
2
 
3
- module JSONAPI::Utils::Exceptions
4
- class BadRequest < ::JSONAPI::Exceptions::Error
5
- def code; 400 end
3
+ module JSONAPI
4
+ module Utils
5
+ module Exceptions
6
+ class ActiveRecord < ::JSONAPI::Exceptions::Error
7
+ attr_accessor :object
6
8
 
7
- def errors
8
- [JSONAPI::Error.new(code: 400,
9
- status: :bad_request,
10
- title: 'Bad Request',
11
- detail: 'This request is not supported.')]
12
- end
13
- end
9
+ def initialize(object)
10
+ @object = object
11
+ end
12
+
13
+ def errors
14
+ object.errors.keys.map do |key|
15
+ JSONAPI::Error.new(
16
+ code: JSONAPI::VALIDATION_ERROR,
17
+ status: :unprocessable_entity,
18
+ id: key,
19
+ title: object.errors.full_messages_for(key).first
20
+ )
21
+ end
22
+ end
23
+ end
24
+
25
+ class BadRequest < ::JSONAPI::Exceptions::Error
26
+ def code; '400' end
27
+
28
+ def errors
29
+ [JSONAPI::Error.new(
30
+ code: code,
31
+ status: :bad_request,
32
+ title: 'Bad Request',
33
+ detail: 'This request is not supported.'
34
+ )]
35
+ end
36
+ end
14
37
 
15
- class InternalServerError < ::JSONAPI::Exceptions::Error
16
- def code; 500 end
38
+ class InternalServerError < ::JSONAPI::Exceptions::Error
39
+ def code; '500' end
17
40
 
18
- def errors
19
- [JSONAPI::Error.new(code: 500,
20
- status: :internal_server_error,
21
- title: 'Internal Server Error',
22
- detail: 'An internal error ocurred while processing the request.')]
41
+ def errors
42
+ [JSONAPI::Error.new(
43
+ code: code,
44
+ status: :internal_server_error,
45
+ title: 'Internal Server Error',
46
+ detail: 'An internal error ocurred while processing the request.'
47
+ )]
48
+ end
49
+ end
23
50
  end
24
51
  end
25
52
  end
@@ -0,0 +1,19 @@
1
+ module JSONAPI
2
+ module Utils
3
+ module Request
4
+ def setup_request
5
+ @request ||=
6
+ JSONAPI::Request.new(
7
+ params,
8
+ context: context,
9
+ key_formatter: key_formatter,
10
+ server_error_callbacks: (self.class.server_error_callbacks || [])
11
+ )
12
+ end
13
+
14
+ def check_request
15
+ @request.errors.blank? || jsonapi_render_errors(json: @request)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ require 'jsonapi/utils/response/formatters'
2
+ require 'jsonapi/utils/response/renders'
3
+ require 'jsonapi/utils/response/support'
4
+
5
+ module JSONAPI
6
+ module Utils
7
+ module Response
8
+ include Renders
9
+ include Formatters
10
+ include Support
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,89 @@
1
+ module JSONAPI
2
+ module Utils
3
+ module Response
4
+ module Formatters
5
+ def jsonapi_format(records, options = {})
6
+ if records.is_a?(Hash)
7
+ hash = records.with_indifferent_access
8
+ records = hash_to_active_record(hash[:data], options[:model])
9
+ end
10
+ fix_request_options(params, records)
11
+ build_response_document(records, options).contents
12
+ end
13
+
14
+ alias_method :jsonapi_serialize, :jsonapi_format
15
+
16
+ def jsonapi_format_errors(data)
17
+ data = JSONAPI::Utils::Exceptions::ActiveRecord.new(data) if data.is_a?(ActiveRecord::Base)
18
+ errors = data.respond_to?(:errors) ? data.errors : data
19
+ JSONAPI::Utils::Support::Error.sanitize(errors).uniq
20
+ end
21
+
22
+ protected
23
+
24
+ def build_response_document(records, options)
25
+ results = JSONAPI::OperationResults.new
26
+
27
+ if records.respond_to?(:to_ary)
28
+ @_records = build_collection(records, options)
29
+ results.add_result(JSONAPI::ResourcesOperationResult.new(:ok, @_records, result_options(records, options)))
30
+ else
31
+ @_record = turn_into_resource(records, options)
32
+ results.add_result(JSONAPI::ResourceOperationResult.new(:ok, @_record))
33
+ end
34
+
35
+ @_response_document = create_response_document(results)
36
+ end
37
+
38
+ def fix_request_options(params, records)
39
+ return if request.method !~ /get/i ||
40
+ params.nil? ||
41
+ %w(index show create update destroy).include?(params[:action])
42
+ action = records.respond_to?(:to_ary) ? 'index' : 'show'
43
+ @request.send("setup_#{action}_action", params)
44
+ end
45
+
46
+ def result_options(records, options)
47
+ {}.tap do |data|
48
+ if JSONAPI.configuration.default_paginator != :none &&
49
+ JSONAPI.configuration.top_level_links_include_pagination
50
+ data[:pagination_params] = pagination_params(records, options)
51
+ end
52
+
53
+ if JSONAPI.configuration.top_level_meta_include_record_count
54
+ data[:record_count] = count_records(records, options)
55
+ end
56
+ end
57
+ end
58
+
59
+ def build_collection(records, options = {})
60
+ records = apply_filter(records, options)
61
+ records = apply_pagination(records, options)
62
+ records = apply_sort(records)
63
+ records.respond_to?(:to_ary) ? records.map { |record| turn_into_resource(record, options) } : []
64
+ end
65
+
66
+ def turn_into_resource(record, options = {})
67
+ if options[:resource]
68
+ options[:resource].to_s.constantize.new(record, context)
69
+ else
70
+ @request.resource_klass.new(record, context)
71
+ end
72
+ end
73
+
74
+ def hash_to_active_record(data, model)
75
+ return data if model.nil?
76
+ coerced = [data].flatten.map { |hash| model.new(hash) }
77
+ data.is_a?(Array) ? coerced : coerced.first
78
+ rescue ActiveRecord::UnknownAttributeError
79
+ if data.is_a?(Array)
80
+ ids = data.map { |e| e[:id] }
81
+ model.where(id: ids)
82
+ else
83
+ model.find_by(id: data[:id])
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,41 @@
1
+ module JSONAPI
2
+ module Utils
3
+ module Response
4
+ module Renders
5
+ def jsonapi_render(json:, status: nil, options: {})
6
+ body = jsonapi_format(json, options)
7
+ render json: body, status: status || @_response_document.status
8
+ rescue => e
9
+ handle_exceptions(e)
10
+ ensure
11
+ correct_media_type
12
+ end
13
+
14
+ def jsonapi_render_errors(exception = nil, json: nil, status: nil)
15
+ body = jsonapi_format_errors(exception || json)
16
+ status = status || body.try(:first).try(:[], :status)
17
+ render json: { errors: body }, status: status
18
+ ensure
19
+ correct_media_type
20
+ end
21
+
22
+ def jsonapi_render_internal_server_error
23
+ jsonapi_render_errors(::JSONAPI::Utils::Exceptions::InternalServerError.new)
24
+ end
25
+
26
+ def jsonapi_render_bad_request
27
+ jsonapi_render_errors(::JSONAPI::Utils::Exceptions::BadRequest.new)
28
+ end
29
+
30
+ def jsonapi_render_not_found(exception)
31
+ id = exception.message.match(/=([\w-]+)/).try(:[], 1) || '(no identifier)'
32
+ jsonapi_render_errors(JSONAPI::Exceptions::RecordNotFound.new(id))
33
+ end
34
+
35
+ def jsonapi_render_not_found_with_null
36
+ render json: { data: nil }, status: 200
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ require 'jsonapi/utils/support/filter'
2
+ require 'jsonapi/utils/support/pagination'
3
+ require 'jsonapi/utils/support/sort'
4
+ require 'jsonapi/utils/support/error'
5
+
6
+ module JSONAPI
7
+ module Utils
8
+ module Response
9
+ module Support
10
+ include ::JSONAPI::Utils::Support::Error
11
+ include ::JSONAPI::Utils::Support::Filter
12
+ include ::JSONAPI::Utils::Support::Pagination
13
+ include ::JSONAPI::Utils::Support::Sort
14
+
15
+ protected
16
+
17
+ def correct_media_type
18
+ if response.body.size > 0
19
+ response.headers['Content-Type'] = JSONAPI::MEDIA_TYPE
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module JSONAPI
2
+ module Utils
3
+ module Support
4
+ module Error
5
+ MEMBERS = %i(title detail id code source links status meta)
6
+
7
+ module_function
8
+
9
+ def sanitize(errors)
10
+ Array(errors).map do |error|
11
+ MEMBERS.reduce({}) do |sum, key|
12
+ value = error.try(key) || error.try(:[], key)
13
+ if value.nil?
14
+ sum
15
+ else
16
+ value = value.to_s if key == :code
17
+ sum.merge(key => value)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ module JSONAPI
2
+ module Utils
3
+ module Support
4
+ module Filter
5
+ def apply_filter(records, options = {})
6
+ if apply_filter?(records, options)
7
+ records.where(filter_params)
8
+ else
9
+ records
10
+ end
11
+ end
12
+
13
+ def apply_filter?(records, options = {})
14
+ params[:filter].present? && records.respond_to?(:where) &&
15
+ (options[:filter].nil? || options[:filter])
16
+ end
17
+
18
+ def filter_params
19
+ @_filter_params ||=
20
+ if params[:filter].is_a?(Hash)
21
+ params[:filter].keys.each_with_object({}) do |resource, hash|
22
+ hash[resource] = params[:filter][resource]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,75 @@
1
+ module JSONAPI
2
+ module Utils
3
+ module Support
4
+ module Pagination
5
+ def apply_pagination(records, options = {})
6
+ return records unless apply_pagination?(options)
7
+ pagination = set_pagination(options)
8
+
9
+ records =
10
+ if records.is_a?(Array)
11
+ records[pagination[:range]]
12
+ else
13
+ pagination[:paginator].apply(records, nil)
14
+ end
15
+ end
16
+
17
+ def apply_pagination?(options)
18
+ JSONAPI.configuration.default_paginator != :none &&
19
+ (options[:paginate].nil? || options[:paginate])
20
+ end
21
+
22
+ def pagination_params(records, options)
23
+ @paginator ||= paginator(params)
24
+ if @paginator && JSONAPI.configuration.top_level_links_include_pagination
25
+ options = {}
26
+ @paginator.class.requires_record_count &&
27
+ options[:record_count] = count_records(records, options)
28
+ @paginator.links_page_params(options)
29
+ else
30
+ {}
31
+ end
32
+ end
33
+
34
+ def paginator(params)
35
+ page_params = ActionController::Parameters.new(params[:page])
36
+
37
+ @paginator ||=
38
+ if JSONAPI.configuration.default_paginator == :paged
39
+ PagedPaginator.new(page_params)
40
+ elsif JSONAPI.configuration.default_paginator == :offset
41
+ OffsetPaginator.new(page_params)
42
+ end
43
+ end
44
+
45
+ def set_pagination(options)
46
+ page_params = ActionController::Parameters.new(@request.params[:page])
47
+ if JSONAPI.configuration.default_paginator == :paged
48
+ @_paginator ||= PagedPaginator.new(page_params)
49
+ number = page_params['number'].to_i.nonzero? || 1
50
+ size = page_params['size'].to_i.nonzero? || JSONAPI.configuration.default_page_size
51
+ { paginator: @_paginator, range: (number - 1) * size..number * size - 1 }
52
+ elsif JSONAPI.configuration.default_paginator == :offset
53
+ @_paginator ||= OffsetPaginator.new(page_params)
54
+ offset = page_params['offset'].to_i.nonzero? || 0
55
+ limit = page_params['limit'].to_i.nonzero? || JSONAPI.configuration.default_page_size
56
+ { paginator: @_paginator, range: offset..offset + limit - 1 }
57
+ else
58
+ {}
59
+ end
60
+ end
61
+
62
+ def count_records(records, options)
63
+ if options[:count].present?
64
+ options[:count]
65
+ elsif records.is_a?(Array)
66
+ records.length
67
+ else
68
+ records = apply_filter(records, options) if params[:filter].present?
69
+ records.except(:group, :order).count("DISTINCT #{records.table.name}.id")
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,35 @@
1
+ module JSONAPI
2
+ module Utils
3
+ module Support
4
+ module Sort
5
+ def apply_sort(records)
6
+ return records unless params[:sort].present?
7
+
8
+ if records.is_a?(Array)
9
+ records.sort { |a, b| comp = 0; eval(sort_criteria) }
10
+ elsif records.respond_to?(:order)
11
+ records.order(sort_params)
12
+ end
13
+ end
14
+
15
+ def sort_criteria
16
+ sort_params.reduce('') do |sum, hash|
17
+ foo = ["a[:#{hash[0]}]", "b[:#{hash[0]}]"]
18
+ foo.reverse! if hash[1] == :desc
19
+ sum + "comp = comp == 0 ? #{foo.join(' <=> ')} : comp; "
20
+ end
21
+ end
22
+
23
+ def sort_params
24
+ @_sort_params ||=
25
+ if params[:sort].present?
26
+ params[:sort].split(',').each_with_object({}) do |criteria, hash|
27
+ order, field = criteria.match(/(\-?)(\w+)/i)[1..2]
28
+ hash[field] = order == '-' ? :desc : :asc
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Utils
3
- VERSION = '0.4.4'
3
+ VERSION = '0.4.5'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Guedes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-05-24 00:00:00.000000000 Z
12
+ date: 2016-06-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jsonapi-resources
@@ -139,6 +139,15 @@ files:
139
139
  - bin/setup
140
140
  - lib/jsonapi/utils.rb
141
141
  - lib/jsonapi/utils/exceptions.rb
142
+ - lib/jsonapi/utils/request.rb
143
+ - lib/jsonapi/utils/response.rb
144
+ - lib/jsonapi/utils/response/formatters.rb
145
+ - lib/jsonapi/utils/response/renders.rb
146
+ - lib/jsonapi/utils/response/support.rb
147
+ - lib/jsonapi/utils/support/error.rb
148
+ - lib/jsonapi/utils/support/filter.rb
149
+ - lib/jsonapi/utils/support/pagination.rb
150
+ - lib/jsonapi/utils/support/sort.rb
142
151
  - lib/jsonapi/utils/version.rb
143
152
  homepage: https://github.com/b2beauty/jsonapi-utils
144
153
  licenses: