jsonapi-utils 0.4.6 → 0.4.7

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: c328df382d804f5ae2d625216ac2febd26b952ac
4
- data.tar.gz: b13829c6b72e5d4a8fb76fcafcac900916c5d8f6
3
+ metadata.gz: 5c64468130b16c1b4247c925d9fc25a583d6134d
4
+ data.tar.gz: 8d90c469c22ed667afb6b72dc02b2fcd31997e4b
5
5
  SHA512:
6
- metadata.gz: 60a974e53b5e40f500bc8a99cba456d21ca7c9c960ff040e91622f35bf40dcae9d6101fa38e93491d79fa96f7ca6e362d0d3857329c1841a06b541903bea2f27
7
- data.tar.gz: fc039cfdecd100db6b4d316e5b232734e9b96ec9e77ad8578398e9a542a17828a233a58ee39ea28fbfe673f50f43de783b3fec5fe350145022749662d7c408bf
6
+ metadata.gz: 9ef5754a5dbe043c4bfeb30f40532c9a893c98ce65c15b2ca0d46196386b5eaa8e77b80a59f8e4350fdaafb867cdb7fef357a342ea1a322813a09341f5af0403
7
+ data.tar.gz: da448b2469e853c89e027960810325eaf90e66191b93769ac30cb41d8e565455b37a2a23f5e923581ab8ce74abddd8065dc9b4d85539439dd97718b465ed3ebd
data/lib/jsonapi/utils.rb CHANGED
@@ -1,8 +1,12 @@
1
+
1
2
  require 'jsonapi-resources'
2
3
  require 'jsonapi/utils/version'
3
4
  require 'jsonapi/utils/exceptions'
4
5
  require 'jsonapi/utils/request'
5
6
  require 'jsonapi/utils/response'
7
+ require 'jsonapi/utils/support/filter/custom'
8
+
9
+ JSONAPI::Resource.extend JSONAPI::Utils::Support::Filter::Custom
6
10
 
7
11
  module JSONAPI
8
12
  module Utils
@@ -10,6 +14,8 @@ module JSONAPI
10
14
  include Response
11
15
 
12
16
  def self.included(base)
17
+ base.include ActsAsResourceController
18
+
13
19
  if base.respond_to?(:before_action)
14
20
  base.before_action :jsonapi_request_handling
15
21
  end
@@ -23,20 +23,24 @@ module JSONAPI
23
23
  end
24
24
 
25
25
  class BadRequest < ::JSONAPI::Exceptions::Error
26
- def code; '400' end
26
+ def code
27
+ '400'
28
+ end
27
29
 
28
30
  def errors
29
31
  [JSONAPI::Error.new(
30
- code: code,
31
- status: :bad_request,
32
- title: 'Bad Request',
33
- detail: 'This request is not supported.'
34
- )]
32
+ code: code,
33
+ status: :bad_request,
34
+ title: 'Bad Request',
35
+ detail: 'This request is not supported.'
36
+ )]
35
37
  end
36
38
  end
37
39
 
38
40
  class InternalServerError < ::JSONAPI::Exceptions::Error
39
- def code; '500' end
41
+ def code
42
+ '500'
43
+ end
40
44
 
41
45
  def errors
42
46
  [JSONAPI::Error.new(
@@ -1,21 +1,21 @@
1
- require 'jsonapi/utils/support/filter'
1
+ require 'jsonapi/utils/support/error'
2
+ require 'jsonapi/utils/support/filter/default'
2
3
  require 'jsonapi/utils/support/pagination'
3
4
  require 'jsonapi/utils/support/sort'
4
- require 'jsonapi/utils/support/error'
5
5
 
6
6
  module JSONAPI
7
7
  module Utils
8
8
  module Response
9
9
  module Support
10
10
  include ::JSONAPI::Utils::Support::Error
11
- include ::JSONAPI::Utils::Support::Filter
11
+ include ::JSONAPI::Utils::Support::Filter::Default
12
12
  include ::JSONAPI::Utils::Support::Pagination
13
13
  include ::JSONAPI::Utils::Support::Sort
14
14
 
15
15
  private
16
16
 
17
17
  def correct_media_type
18
- if response.body.size > 0
18
+ unless response.body.empty?
19
19
  response.headers['Content-Type'] = JSONAPI::MEDIA_TYPE
20
20
  end
21
21
  end
@@ -2,7 +2,7 @@ module JSONAPI
2
2
  module Utils
3
3
  module Support
4
4
  module Error
5
- MEMBERS = %i(title detail id code source links status meta)
5
+ MEMBERS = %i(title detail id code source links status meta).freeze
6
6
 
7
7
  module_function
8
8
 
@@ -17,9 +17,11 @@ module JSONAPI
17
17
 
18
18
  def filter_params
19
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]
20
+ case params[:filter]
21
+ when Hash, ActionController::Parameters
22
+ default_filters.each_with_object({}) do |field, hash|
23
+ unformatted_field = @request.unformat_key(field)
24
+ hash[unformatted_field] = params[:filter][field]
23
25
  end
24
26
  end
25
27
  end
@@ -0,0 +1,22 @@
1
+ module JSONAPI::Utils::Support::Filter
2
+ module Custom
3
+ def _custom_filters
4
+ @_allowed_custom_filters || []
5
+ end
6
+
7
+ def custom_filters(*attrs)
8
+ attrs.each { |attr| custom_filter(attr) }
9
+ end
10
+
11
+ def custom_filter(attr)
12
+ attr = attr.to_sym
13
+ @_allowed_filters[attr] = {}
14
+
15
+ if !@_allowed_custom_filters.is_a?(Array)
16
+ @_allowed_custom_filters = Array(attr)
17
+ elsif @_allowed_custom_filters.include?(attr)
18
+ @_allowed_custom_filters.push(attr)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ module JSONAPI::Utils::Support::Filter
2
+ module Default
3
+ # Apply default equality filters.
4
+ # e.g.: User.where(name: 'Foobar')
5
+ #
6
+ # @param records [ActiveRecord::Relation, Array] collection of records
7
+ # e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
8
+ #
9
+ # @param options [Hash] JU's options
10
+ # e.g.: { filter: false, paginate: false }
11
+ #
12
+ # @return [ActiveRecord::Relation, Array]
13
+ #
14
+ # @api public
15
+ def apply_filter(records, options = {})
16
+ if apply_filter?(records, options)
17
+ records.where(filter_params)
18
+ else
19
+ records
20
+ end
21
+ end
22
+
23
+ # Check whether default filters should be applied.
24
+ #
25
+ # @param records [ActiveRecord::Relation, Array] collection of records
26
+ # e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
27
+ #
28
+ # @param options [Hash] JU's options
29
+ # e.g.: { filter: false, paginate: false }
30
+ #
31
+ # @return [Boolean]
32
+ #
33
+ # @api public
34
+ def apply_filter?(records, options = {})
35
+ params[:filter].present? && records.respond_to?(:where) &&
36
+ (options[:filter].nil? || options[:filter])
37
+ end
38
+
39
+ # Build a Hash with the default filters.
40
+ #
41
+ # @return [Hash, NilClass]
42
+ #
43
+ # @api public
44
+ def filter_params
45
+ @_filter_params ||=
46
+ case params[:filter]
47
+ when Hash, ActionController::Parameters
48
+ default_filters.each_with_object({}) do |field, hash|
49
+ unformatted_field = @request.unformat_key(field)
50
+ hash[unformatted_field] = params[:filter][field]
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ # Take all allowed filters and remove the custom ones.
58
+ #
59
+ # @return [Array]
60
+ #
61
+ # @api private
62
+ def default_filters
63
+ params[:filter].keys.map(&:to_sym) - @request.resource_klass._custom_filters
64
+ end
65
+ end
66
+ end
@@ -2,63 +2,133 @@ module JSONAPI
2
2
  module Utils
3
3
  module Support
4
4
  module Pagination
5
+ # Apply proper pagination to the records.
6
+ #
7
+ # @param records [ActiveRecord::Relation, Array] collection of records
8
+ # e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
9
+ #
10
+ # @param options [Hash] JU's options
11
+ # e.g.: { resource: V2::UserResource, count: 100 }
12
+ #
13
+ # @return [ActiveRecord::Relation, Array]
14
+ #
15
+ # @api public
5
16
  def apply_pagination(records, options = {})
6
17
  return records unless apply_pagination?(options)
7
- pagination = set_pagination(options)
18
+ records.is_a?(Array) ? records[paginate_with(:range)] : paginate_with(:paginator).apply(records, nil)
19
+ end
8
20
 
9
- records =
10
- if records.is_a?(Array)
11
- records[pagination[:range]]
12
- else
13
- pagination[:paginator].apply(records, nil)
14
- end
21
+ # Mount pagination params for JSONAPI::ResourcesOperationResult.
22
+ # It can also be used anywhere else as a helper method.
23
+ #
24
+ # @param records [ActiveRecord::Relation, Array] collection of records
25
+ # e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
26
+ #
27
+ # @param options [Hash] JU's options
28
+ # e.g.: { resource: V2::UserResource, count: 100 }
29
+ #
30
+ # @return [Hash]
31
+ # e.g.: {"first"=>{"number"=>1, "size"=>2}, "next"=>{"number"=>2, "size"=>2}, "last"=>{"number"=>2, "size"=>2}}
32
+ #
33
+ # @api public
34
+ def pagination_params(records, options)
35
+ return {} unless JSONAPI.configuration.top_level_links_include_pagination
36
+ paginator.links_page_params(record_count: count_records(records, options))
37
+ end
38
+
39
+ private
40
+
41
+ # Define the paginator object to be used in the response's pagination.
42
+ #
43
+ # @return [PagedPaginator, OffsetPaginator]
44
+ #
45
+ # @api private
46
+ def paginator
47
+ @paginator ||= paginator_klass.new(page_params)
15
48
  end
16
49
 
50
+ # Returns the paginator class to be used in the response's pagination.
51
+ #
52
+ # @return [Paginator]
53
+ #
54
+ # @api private
55
+ def paginator_klass
56
+ "#{JSONAPI.configuration.default_paginator}_paginator".classify.constantize
57
+ end
58
+
59
+ # Check whether pagination should be applied to the response.
60
+ #
61
+ # @return [Boolean]
62
+ #
63
+ # @api private
17
64
  def apply_pagination?(options)
18
65
  JSONAPI.configuration.default_paginator != :none &&
19
66
  (options[:paginate].nil? || options[:paginate])
20
67
  end
21
68
 
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
- {}
69
+ # Creates an instance of ActionController::Parameters for page params.
70
+ #
71
+ # @return [ActionController::Parameters]
72
+ #
73
+ # @api private
74
+ def page_params
75
+ @page_params ||= begin
76
+ page = @request.params.to_unsafe_hash['page'] || {}
77
+ ActionController::Parameters.new(page)
31
78
  end
32
79
  end
33
80
 
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)
81
+ # Define the paginator or range according to the pagination strategy.
82
+ #
83
+ # @param kind [Symbol] pagination object's kind
84
+ # e.g.: :paginator or :range
85
+ #
86
+ # @return [PagedPaginator, OffsetPaginator, Range]
87
+ # e.g.: #<PagedPaginator:0x00561ed06dc5a0 @number=1, @size=2>
88
+ # 0..9
89
+ #
90
+ # @api private
91
+ def paginate_with(kind)
92
+ @pagination ||=
93
+ case kind
94
+ when :paginator then paginator
95
+ when :range then pagination_range
42
96
  end
43
97
  end
44
98
 
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)
99
+ # Define a pagination range for objects which quack like Arrays.
100
+ #
101
+ # @return [Range]
102
+ # e.g.: 0..9
103
+ #
104
+ # @api private
105
+ def pagination_range
106
+ case JSONAPI.configuration.default_paginator
107
+ when :paged
49
108
  number = page_params['number'].to_i.nonzero? || 1
50
109
  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)
110
+ (number - 1) * size..number * size - 1
111
+ when :offset
54
112
  offset = page_params['offset'].to_i.nonzero? || 0
55
113
  limit = page_params['limit'].to_i.nonzero? || JSONAPI.configuration.default_page_size
56
- { paginator: @_paginator, range: offset..offset + limit - 1 }
114
+ offset..offset + limit - 1
57
115
  else
58
- {}
116
+ paginator.pagination_range(page_params)
59
117
  end
60
118
  end
61
119
 
120
+ # Count records in order to build a proper pagination and to fill up the "record_count" response's member.
121
+ #
122
+ # @param records [ActiveRecord::Relation, Array] collection of records
123
+ # e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
124
+ #
125
+ # @param options [Hash] JU's options
126
+ # e.g.: { resource: V2::UserResource, count: 100 }
127
+ #
128
+ # @return [Integer]
129
+ # e.g.: 42
130
+ #
131
+ # @api private
62
132
  def count_records(records, options)
63
133
  if options[:count].present?
64
134
  options[:count]
@@ -1,35 +1,53 @@
1
- module JSONAPI
2
- module Utils
3
- module Support
4
- module Sort
5
- def apply_sort(records)
6
- return records unless params[:sort].present?
1
+ module JSONAPI::Utils::Support
2
+ module Sort
3
+ # Apply sort on result set (ascending by default).
4
+ # e.g.: User.order(:first_name)
5
+ #
6
+ # @param records [ActiveRecord::Relation, Array] collection of records
7
+ # e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
8
+ #
9
+ # @return [ActiveRecord::Relation, Array]
10
+ #
11
+ # @api public
12
+ def apply_sort(records)
13
+ return records unless params[:sort].present?
7
14
 
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
15
+ if records.is_a?(Array)
16
+ records.sort { |a, b| comp = 0; eval(sort_criteria) }
17
+ elsif records.respond_to?(:order)
18
+ records.order(sort_params)
19
+ end
20
+ end
14
21
 
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
22
+ # Build the criteria to be evaluated wthen applying sort
23
+ # on Array of Hashes (ascending by default).
24
+ #
25
+ # @return [String]
26
+ #
27
+ # @api public
28
+ def sort_criteria
29
+ @sort_criteria ||=
30
+ sort_params.reduce('') do |sum, (key, value)|
31
+ comparables = ["a[:#{key}]", "b[:#{key}]"]
32
+ comparables.reverse! if value == :desc
33
+ sum + "comp = comp == 0 ? #{comparables.join(' <=> ')} : comp; "
21
34
  end
35
+ end
22
36
 
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
37
+ # Build a Hash with the sort criteria.
38
+ #
39
+ # @return [Hash, NilClass]
40
+ #
41
+ # @api public
42
+ def sort_params
43
+ @_sort_params ||=
44
+ if params[:sort].present?
45
+ params[:sort].split(',').each_with_object({}) do |field, hash|
46
+ unformatted_field = @request.unformat_key(field)
47
+ desc, field = unformatted_field.to_s.match(/^([-_])?(\w+)$/i)[1..2]
48
+ hash[field] = desc.present? ? :desc : :asc
49
+ end
31
50
  end
32
- end
33
51
  end
34
52
  end
35
53
  end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Utils
3
- VERSION = '0.4.6'
3
+ VERSION = '0.4.7'
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.6
4
+ version: 0.4.7
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-07-04 00:00:00.000000000 Z
12
+ date: 2016-10-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jsonapi-resources
@@ -123,6 +123,34 @@ dependencies:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
125
  version: 0.1.4
126
+ - !ruby/object:Gem::Dependency
127
+ name: pry
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: 0.10.3
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: 0.10.3
140
+ - !ruby/object:Gem::Dependency
141
+ name: pry-byebug
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
126
154
  description: A Rails way to get your API's data serialized through JSON API's specs
127
155
  (http://jsosapi.org)
128
156
  email:
@@ -146,6 +174,8 @@ files:
146
174
  - lib/jsonapi/utils/response/support.rb
147
175
  - lib/jsonapi/utils/support/error.rb
148
176
  - lib/jsonapi/utils/support/filter.rb
177
+ - lib/jsonapi/utils/support/filter/custom.rb
178
+ - lib/jsonapi/utils/support/filter/default.rb
149
179
  - lib/jsonapi/utils/support/pagination.rb
150
180
  - lib/jsonapi/utils/support/sort.rb
151
181
  - lib/jsonapi/utils/version.rb
@@ -169,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
199
  version: '0'
170
200
  requirements: []
171
201
  rubyforge_project:
172
- rubygems_version: 2.6.2
202
+ rubygems_version: 2.5.1
173
203
  signing_key:
174
204
  specification_version: 4
175
205
  summary: JSON::Utils is a simple way to get a full-featured JSON API serialization