1414
1515
1616class CursorPaginatedResultPresenter :
17- @staticmethod
17+ @classmethod
1818 def build_result (
19+ cls ,
1920 result_items : List [MODEL ],
2021 total_items_count : int ,
2122 items_per_page : int ,
2223 cursor_reference : Union [CursorReference , None ],
23- is_end_cursor : bool ,
24+ is_before_cursor : bool ,
2425 ) -> CursorPaginatedResult :
2526 """
2627 Produces a structured paginated result identifying previous/next pages
@@ -30,72 +31,153 @@ def build_result(
3031 :param total_items_count:
3132 :param items_per_page:
3233 :param cursor_reference:
33- :param is_end_cursor :
34+ :param is_before_cursor :
3435 :return:
3536 """
36- result_structure : CursorPaginatedResult = CursorPaginatedResult (
37+ if not result_items :
38+ return cls ._build_empty_items_result (total_items_count , items_per_page )
39+
40+ if not cursor_reference :
41+ return cls ._build_no_cursor_result (
42+ result_items , total_items_count , items_per_page
43+ )
44+
45+ if is_before_cursor :
46+ return cls ._build_before_cursor_result (
47+ result_items , total_items_count , items_per_page , cursor_reference
48+ )
49+
50+ return cls ._build_after_cursor_result (
51+ result_items , total_items_count , items_per_page , cursor_reference
52+ )
53+
54+ @staticmethod
55+ def _build_empty_items_result (
56+ total_items_count : int ,
57+ items_per_page : int ,
58+ ) -> CursorPaginatedResult :
59+ return CursorPaginatedResult (
60+ items = [],
61+ page_info = CursorPageInfo (
62+ items_per_page = items_per_page ,
63+ total_items = total_items_count ,
64+ ),
65+ )
66+
67+ @staticmethod
68+ def _build_no_cursor_result (
69+ result_items : List [MODEL ],
70+ total_items_count : int ,
71+ items_per_page : int ,
72+ ) -> CursorPaginatedResult :
73+ has_next_page = len (result_items ) > items_per_page
74+ if has_next_page :
75+ result_items = result_items [0 :items_per_page ]
76+ reference_column = _pk_from_result_object (result_items [0 ])
77+
78+ return CursorPaginatedResult (
3779 items = result_items ,
3880 page_info = CursorPageInfo (
3981 items_per_page = items_per_page ,
4082 total_items = total_items_count ,
83+ has_previous_page = False ,
84+ has_next_page = has_next_page ,
85+ start_cursor = CursorReference (
86+ column = reference_column ,
87+ value = getattr (result_items [0 ], reference_column ),
88+ ),
89+ end_cursor = CursorReference (
90+ column = reference_column ,
91+ value = getattr (result_items [- 1 ], reference_column ),
92+ ),
4193 ),
4294 )
43- if not result_items :
44- return result_structure
4595
46- if not cursor_reference :
47- has_previous_page = False
48- has_next_page = len (result_items ) > items_per_page
49- if has_next_page :
50- result_items = result_items [0 :items_per_page ]
51- result_structure .page_info .has_next_page = has_next_page
52- result_structure .page_info .has_previous_page = has_previous_page
53- reference_column = _pk_from_result_object (result_items [0 ])
54-
55- elif is_end_cursor :
56- index = - 1
57- reference_column = cursor_reference .column
58- last_found_cursor_value = getattr (result_items [index ], reference_column )
59- if not isinstance (last_found_cursor_value , type (cursor_reference .value )):
60- raise TypeError (
61- "Values from CursorReference and results must be of the same type"
96+ @staticmethod
97+ def _build_before_cursor_result (
98+ result_items : List [MODEL ],
99+ total_items_count : int ,
100+ items_per_page : int ,
101+ cursor_reference : CursorReference ,
102+ ) -> CursorPaginatedResult :
103+ index = - 1
104+ reference_column = cursor_reference .column
105+ last_found_cursor_value = getattr (result_items [index ], reference_column )
106+ if not isinstance (last_found_cursor_value , type (cursor_reference .value )):
107+ raise TypeError (
108+ "Values from CursorReference and results must be of the same type"
109+ )
110+ has_next_page = last_found_cursor_value >= cursor_reference .value
111+ if has_next_page :
112+ result_items .pop (index )
113+ has_previous_page = len (result_items ) > items_per_page
114+ if has_previous_page :
115+ result_items = result_items [- items_per_page :]
116+
117+ return CursorPaginatedResult (
118+ items = result_items ,
119+ page_info = CursorPageInfo (
120+ items_per_page = items_per_page ,
121+ total_items = total_items_count ,
122+ has_previous_page = has_previous_page ,
123+ has_next_page = has_next_page ,
124+ start_cursor = CursorReference (
125+ column = reference_column ,
126+ value = getattr (result_items [0 ], reference_column ),
62127 )
63- has_next_page = last_found_cursor_value >= cursor_reference .value
64- if has_next_page :
65- result_items .pop (index )
66- has_previous_page = len (result_items ) > items_per_page
67- if has_previous_page :
68- result_items = result_items [- items_per_page :]
69- else :
70- index = 0
71- reference_column = cursor_reference .column
72- first_found_cursor_value = getattr (result_items [index ], reference_column )
73- if not isinstance (first_found_cursor_value , type (cursor_reference .value )):
74- raise TypeError (
75- "Values from CursorReference and results must be of the same type"
128+ if result_items
129+ else None ,
130+ end_cursor = CursorReference (
131+ column = reference_column ,
132+ value = getattr (result_items [- 1 ], reference_column ),
76133 )
77- has_previous_page = first_found_cursor_value <= cursor_reference .value
78- if has_previous_page :
79- result_items .pop (index )
80- has_next_page = len (result_items ) > items_per_page
81- if has_next_page :
82- result_items = result_items [0 :items_per_page ]
83-
84- result_structure .items = result_items
85- result_structure .page_info .has_next_page = has_next_page
86- result_structure .page_info .has_previous_page = has_previous_page
87-
88- if result_items :
89- result_structure .page_info .start_cursor = CursorReference (
90- column = reference_column ,
91- value = getattr (result_items [0 ], reference_column ),
92- )
93- result_structure .page_info .end_cursor = CursorReference (
94- column = reference_column ,
95- value = getattr (result_items [- 1 ], reference_column ),
96- )
134+ if result_items
135+ else None ,
136+ ),
137+ )
97138
98- return result_structure
139+ @staticmethod
140+ def _build_after_cursor_result (
141+ result_items : List [MODEL ],
142+ total_items_count : int ,
143+ items_per_page : int ,
144+ cursor_reference : CursorReference ,
145+ ) -> CursorPaginatedResult :
146+ index = 0
147+ reference_column = cursor_reference .column
148+ first_found_cursor_value = getattr (result_items [index ], reference_column )
149+ if not isinstance (first_found_cursor_value , type (cursor_reference .value )):
150+ raise TypeError (
151+ "Values from CursorReference and results must be of the same type"
152+ )
153+ has_previous_page = first_found_cursor_value <= cursor_reference .value
154+ if has_previous_page :
155+ result_items .pop (index )
156+ has_next_page = len (result_items ) > items_per_page
157+ if has_next_page :
158+ result_items = result_items [0 :items_per_page ]
159+
160+ return CursorPaginatedResult (
161+ items = result_items ,
162+ page_info = CursorPageInfo (
163+ items_per_page = items_per_page ,
164+ total_items = total_items_count ,
165+ has_previous_page = has_previous_page ,
166+ has_next_page = has_next_page ,
167+ start_cursor = CursorReference (
168+ column = reference_column ,
169+ value = getattr (result_items [0 ], reference_column ),
170+ )
171+ if result_items
172+ else None ,
173+ end_cursor = CursorReference (
174+ column = reference_column ,
175+ value = getattr (result_items [- 1 ], reference_column ),
176+ )
177+ if result_items
178+ else None ,
179+ ),
180+ )
99181
100182
101183class PaginatedResultPresenter :
0 commit comments