def pagination(filtered_instances, path, type_, API_NAME, search_params, paginate, page_size): """Add pagination to the response and return the response :param filtered_instances: instances after filtered from the database query :param path: endpoint :param type_: type of object to be updated :param API_NAME: api name specified while starting server :param search_params: Query parameters :param paginate: Enable/disable pagination :param page_size: Number maximum elements showed in a page :return: response containing a page of the objects of that particular type_ """ collection_template = { "@id": f"{get_host_domain()}/{API_NAME}/{path}/", "@context": None, "@type": f"{path}", "members": [] } # type: Dict[str, Any] result_length = len(filtered_instances) try: # To paginate, calculate offset and page_limit values for pagination of search results page, page_size, offset = pre_process_pagination_parameters(search_params=search_params, paginate=paginate, page_size=page_size, result_length=result_length) except (IncompatibleParameters, PageNotFound, OffsetOutOfRange): raise current_page_size = page_size if result_length - offset < page_size: current_page_size = result_length - offset for i in range(offset, offset+current_page_size): object_template = { "@id": f"{get_host_domain()}/{API_NAME}/{type_}/{filtered_instances[i].id}", "@type": type_ } collection_template["members"].append(object_template) # If pagination is disabled then stop and return the collection template collection_template["hydra:totalItems"] = result_length if paginate is False: return collection_template # Calculate last page number if result_length != 0 and result_length % page_size == 0: last = result_length // page_size else: last = result_length // page_size + 1 if page < 1 or page > last: raise PageNotFound(str(page)) recreated_iri = recreate_iri(API_NAME, path, search_params=search_params) # Decide which parameter to use to provide navigation if "offset" in search_params: paginate_param = "offset" elif "pageIndex" in search_params: paginate_param = "pageIndex" else: paginate_param = "page" attach_hydra_view(collection_template=collection_template, paginate_param=paginate_param, result_length=result_length, iri=recreated_iri, page_size=page_size, offset=offset, page=page, last=last) return collection_template
def pre_process_pagination_parameters( search_params: Dict[str, Any], paginate: bool, page_size: int, result_length: int) -> Tuple[int, int, int]: """Pre-process pagination related query parameters passed by client. :param search_params: Dict of all search parameters. :param paginate: Indicates if pagination is enabled/disabled. :param page_size: Maximum element a page can contain. :param result_length: Length of the list of containing desired items. :return: returns page number, page limit and offset. """ incompatible_parameters = ["page", "pageIndex", "offset"] incompatible_parameters_len = len(incompatible_parameters) # Find any pair of incompatible parameters for i in range(incompatible_parameters_len): if incompatible_parameters[i] not in search_params: continue if i != incompatible_parameters_len - 1: for j in range(i + 1, incompatible_parameters_len): if incompatible_parameters[j] in search_params: raise IncompatibleParameters([ incompatible_parameters[i], incompatible_parameters[j] ]) try: # Extract page number from query arguments if "pageIndex" in search_params: page = int(search_params.get("pageIndex")) offset = None elif "offset" in search_params: offset = int(search_params.get("offset")) page = offset // page_size + 1 if offset > result_length: raise OffsetOutOfRange(str(offset)) else: page = int(search_params.get("page", 1)) offset = None if "limit" in search_params: limit = int(search_params.get("limit")) else: limit = None except ValueError: raise PageNotFound(page) page_limit, offset = calculate_page_limit_and_offset( paginate=paginate, page_size=page_size, page=page, result_length=result_length, offset=offset, limit=limit) return page, page_limit, offset