. (utf8) 2:- module( 3 pagination, 4 [ 5 pagination/3, % +Template, :Goal_0, -Page 6 pagination/4, % +Template, :Goal_0, +Options, -Page 7 pagination/5, % +Template, :Goal_0, :Estimate_1, +Options, -Page 8 pagination_bulk/3, % :Goal_1, +Options, -Page 9 pagination_bulk/4, % +Template, :Goal_0, +Options, -Page 10 pagination_is_at_end/1, % +Result 11 pagination_is_empty/1, % +Result 12 pagination_page/3, % +Page, ?Relation, -PageNumber 13 pagination_range/2 % +Page, -Range 14 ] 15).
30:- use_module(library(aggregate)). 31:- use_module(library(error)). 32:- use_module(library(settings)). 33 34:- use_module(library(dict)). 35:- use_module(library(list_ext)). 36 37:- meta_predicate 38 pagination( , , ), 39 pagination( , , , ), 40 pagination( , , , , ), 41 pagination_bulk( , , ), 42 pagination_bulk( , , , ). 43 44:- setting(default_page_size, positive_integer, 10, 45 "The default number of triples that is retreived in one request."). 46:- setting(maximum_page_size, positive_integer, 100, 47 "The maximum number of triples that can be retrieved in one request.").
57empty_pagination(Options, Page) :-
58 pagination(_, fail, Options, Page).
108pagination(Templ, Goal_0, Page) :- 109 pagination(Templ, Goal_0, options{}, Page). 110 111 112pagination(Templ, Goal_0, Options1, Page2) :- 113 pagination_options(Options1, PageNumber, PageSize, Options2), 114 Offset is PageSize * (PageNumber - 1), 115 findall(Templ, limit(PageSize, offset(Offset, Goal_0)), Results), 116 length(Results, NumResults), 117 Page1 = options{ 118 number_of_results: NumResults, 119 page_number: PageNumber, 120 page_size: PageSize, 121 results: Results, 122 single_page: false 123 }, 124 merge_dicts(Options2, Page1, Page2). 125pagination(_, _, Options, Page) :- 126 empty_pagination(Options, Page). 127 128 129pagination(Templ, Goal_0, Estimate_1, Options1, Page2) :- 130 pagination(Templ, Goal_0, Options1, Page1), 131 call(Estimate_1, TotalNumResults), 132 dict_put(total_number_of_results, Page1, TotalNumResults, Page2).
139pagination_bulk(Goal_1, Options, Page) :- 140 call(Goal_1, AllResults), 141 pagination_bulk_(AllResults, Options, Page). 142 143 144pagination_bulk(Templ, Goal_0, Options, Page) :- 145 aggregate_all(set(Templ), Goal_0, AllResults), 146 pagination_bulk_(AllResults, Options, Page). 147 148pagination_bulk_(AllResults, Options1, Page2) :- 149 pagination_options(Options1, StartPageNumber, PageSize, Options2), 150 length(AllResults, TotalNumberOfResults), 151 NumberOfPages is max(1, ceil(TotalNumberOfResults / PageSize)), 152 must_be(between(1, NumberOfPages), StartPageNumber), 153 between(StartPageNumber, NumberOfPages, PageNumber), 154 SkipLength is PageSize * (PageNumber - 1), 155 length(Skip, SkipLength), 156 append(Skip, Rest, AllResults), 157 list_truncate(Rest, PageSize, Results), 158 length(Results, NumberOfResults), 159 Page1 = options{ 160 number_of_results: NumberOfResults, 161 page_number: PageNumber, 162 page_size: PageSize, 163 results: Results, 164 single_page: false, 165 total_number_of_results: TotalNumberOfResults 166 }, 167 merge_dicts(Options2, Page1, Page2).
Since we do not know the total number of results, the last page may be empty.
178pagination_is_at_end(Page) :- 179 options{single_page: true} :< Page, !. 180pagination_is_at_end(Page) :- 181 dict_get(total_number_of_results, Page, TotalNumResults), 182 Page.page_number >= ceil(TotalNumResults / Page.page_size), !. 183pagination_is_at_end(Page) :- 184 Page.number_of_results < Page.page_size.
190pagination_is_empty(Page) :-
191 Page.number_of_results =:= 0.
200pagination_options(Options1, StartPageNumber, PageSize, Options3) :-
201 dict_delete(page_number, Options1, 1, StartPageNumber, Options2),
202 ( dict_delete(page_size, Options2, PageSize, Options3)
203 -> true
204 ; setting(default_page_size, PageSize),
205 Options3 = Options2
206 ).
Fails silently when there is no page with relation Relation.
222pagination_page(Page, first, 1) :- 223 Page.number_of_results > 0. 224pagination_page(Page, last, PageNumber) :- 225 dict_get(total_number_of_results, Page, TotalNumResults), 226 PageNumber is ceil(TotalNumResults / Page.page_size). 227pagination_page(Page, next, PageNumber) :- 228 \+ pagination_is_at_end(Page), 229 PageNumber is Page.page_number + 1. 230pagination_page(Page, prev, PageNumber) :- 231 PageNumber is Page.page_number - 1, 232 PageNumber > 0.
240pagination_range(Page, 0-0) :- 241 Page.number_of_results =:= 0, !. 242pagination_range(Page, Low-High) :- 243 Low is (Page.page_number - 1) * Page.page_size + 1, 244 High is Low + Page.number_of_results - 1
Pagination support
This module creates pages that group results.
*/