jsonapi-utils 0.4.4 → 0.4.5

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: 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: