jsonapi-utils 0.4.6 → 0.4.7

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