001/*-
002 * #%L
003 * HAPI FHIR - Master Data Management
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.mdm.api.paging;
021
022import ca.uhn.fhir.i18n.Msg;
023import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
024import jakarta.annotation.Nullable;
025import org.apache.commons.lang3.StringUtils;
026import org.hl7.fhir.instance.model.api.IPrimitiveType;
027import org.springframework.data.domain.PageRequest;
028
029import static ca.uhn.fhir.rest.api.Constants.PARAM_COUNT;
030import static ca.uhn.fhir.rest.api.Constants.PARAM_OFFSET;
031
032/**
033 * This class is essentially just a data clump of offset + count, as well as the ability to convert itself into a standard
034 * {@link PageRequest} for spring data to use. The reason we don't use PageRequest natively is because it is concerned with `pages` and `counts`,
035 * but we are using `offset` and `count` which requires some minor translation.
036 */
037public class MdmPageRequest {
038
039        private final int myPage;
040        private final int myOffset;
041        private final int myCount;
042
043        public MdmPageRequest(
044                        @Nullable IPrimitiveType<Integer> theOffset,
045                        @Nullable IPrimitiveType<Integer> theCount,
046                        int theDefaultPageSize,
047                        int theMaximumPageSize) {
048                myOffset = theOffset == null ? 0 : theOffset.getValue();
049                myCount = theCount == null ? theDefaultPageSize : Math.min(theCount.getValue(), theMaximumPageSize);
050                validatePagingParameters(myOffset, myCount);
051
052                this.myPage = myOffset / myCount;
053        }
054
055        public MdmPageRequest(
056                        @Nullable Integer theOffset, @Nullable Integer theCount, int theDefaultPageSize, int theMaximumPageSize) {
057                myOffset = theOffset == null ? 0 : theOffset;
058                myCount = theCount == null ? theDefaultPageSize : Math.min(theCount, theMaximumPageSize);
059                validatePagingParameters(myOffset, myCount);
060
061                this.myPage = myOffset / myCount;
062        }
063
064        private void validatePagingParameters(int theOffset, int theCount) {
065                String errorMessage = "";
066
067                if (theOffset < 0) {
068                        errorMessage += PARAM_OFFSET + " must be greater than or equal to 0. ";
069                }
070                if (theCount <= 0) {
071                        errorMessage += PARAM_COUNT + " must be greater than 0.";
072                }
073                if (StringUtils.isNotEmpty(errorMessage)) {
074                        throw new InvalidRequestException(Msg.code(1524) + errorMessage);
075                }
076        }
077
078        public int getOffset() {
079                return myOffset;
080        }
081
082        public int getPage() {
083                return myPage;
084        }
085
086        public int getCount() {
087                return myCount;
088        }
089
090        public int getNextOffset() {
091                return myOffset + myCount;
092        }
093
094        public int getPreviousOffset() {
095                return myOffset - myCount;
096        }
097
098        public PageRequest toPageRequest() {
099                return PageRequest.of(this.myPage, this.myCount);
100        }
101}