@@ -2,63 +2,133 @@ module JSONAPI
22 module Utils
33 module Support
44 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
516 def apply_pagination ( records , options = { } )
617 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
820
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 )
1548 end
1649
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
1764 def apply_pagination? ( options )
1865 JSONAPI . configuration . default_paginator != :none &&
1966 ( options [ :paginate ] . nil? || options [ :paginate ] )
2067 end
2168
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 )
3178 end
3279 end
3380
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
4296 end
4397 end
4498
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
49108 number = page_params [ 'number' ] . to_i . nonzero? || 1
50109 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
54112 offset = page_params [ 'offset' ] . to_i . nonzero? || 0
55113 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
57115 else
58- { }
116+ paginator . pagination_range ( page_params )
59117 end
60118 end
61119
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
62132 def count_records ( records , options )
63133 if options [ :count ] . present?
64134 options [ :count ]
0 commit comments