001package ca.uhn.fhir.jpa.dao.predicate;
002
003/*-
004 * #%L
005 * HAPI FHIR JPA Server
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.i18n.Msg;
024import ca.uhn.fhir.context.RuntimeSearchParam;
025import ca.uhn.fhir.interceptor.model.RequestPartitionId;
026import ca.uhn.fhir.jpa.dao.LegacySearchBuilder;
027import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
028import ca.uhn.fhir.model.api.IQueryParameterType;
029import ca.uhn.fhir.rest.param.NumberParam;
030import ca.uhn.fhir.rest.param.ParamPrefixEnum;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033import org.springframework.context.annotation.Scope;
034import org.springframework.stereotype.Component;
035
036import javax.persistence.criteria.Expression;
037import javax.persistence.criteria.From;
038import javax.persistence.criteria.Predicate;
039import java.math.BigDecimal;
040import java.util.ArrayList;
041import java.util.List;
042
043import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
044
045@Component
046@Scope("prototype")
047public class PredicateBuilderNumber extends BasePredicateBuilder implements IPredicateBuilder {
048        private static final Logger ourLog = LoggerFactory.getLogger(PredicateBuilderNumber.class);
049
050        public PredicateBuilderNumber(LegacySearchBuilder theSearchBuilder) {
051                super(theSearchBuilder);
052        }
053
054        @Override
055        public Predicate addPredicate(String theResourceName,
056                                                                                        RuntimeSearchParam theSearchParam,
057                                                                                        List<? extends IQueryParameterType> theList,
058                                                                                        SearchFilterParser.CompareOperation operation,
059                                                                                        RequestPartitionId theRequestPartitionId) {
060
061                From<?, ResourceIndexedSearchParamNumber> join = myQueryStack.createJoin(SearchBuilderJoinEnum.NUMBER, theSearchParam.getName());
062
063                if (theList.get(0).getMissing() != null) {
064                        addPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), join, theRequestPartitionId);
065                        return null;
066                }
067
068                List<Predicate> codePredicates = new ArrayList<>();
069                addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
070
071                for (IQueryParameterType nextOr : theList) {
072
073                        if (nextOr instanceof NumberParam) {
074                                NumberParam param = (NumberParam) nextOr;
075
076                                BigDecimal value = param.getValue();
077                                if (value == null) {
078                                        continue;
079                                }
080
081                                final Expression<BigDecimal> fromObj = join.get("myValue");
082                                ParamPrefixEnum prefix = defaultIfNull(param.getPrefix(), ParamPrefixEnum.EQUAL);
083                                if (operation == SearchFilterParser.CompareOperation.ne) {
084                                        prefix = ParamPrefixEnum.NOT_EQUAL;
085                                } else if (operation == SearchFilterParser.CompareOperation.lt) {
086                                        prefix = ParamPrefixEnum.LESSTHAN;
087                                } else if (operation == SearchFilterParser.CompareOperation.le) {
088                                        prefix = ParamPrefixEnum.LESSTHAN_OR_EQUALS;
089                                } else if (operation == SearchFilterParser.CompareOperation.gt) {
090                                        prefix = ParamPrefixEnum.GREATERTHAN;
091                                } else if (operation == SearchFilterParser.CompareOperation.ge) {
092                                        prefix = ParamPrefixEnum.GREATERTHAN_OR_EQUALS;
093                                } else if (operation == SearchFilterParser.CompareOperation.eq) {
094                                        prefix = ParamPrefixEnum.EQUAL;
095                                } else if (operation != null) {
096                                        throw new IllegalArgumentException(Msg.code(999) + "Invalid operator specified for number type");
097                                }
098
099
100                                String invalidMessageName = "invalidNumberPrefix";
101
102                                Predicate predicateNumeric = createPredicateNumeric(theResourceName, theSearchParam.getName(), join, myCriteriaBuilder, nextOr, prefix, value, fromObj, invalidMessageName, theRequestPartitionId);
103                                Predicate predicateOuter = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theSearchParam.getName(), join, predicateNumeric, theRequestPartitionId);
104                                codePredicates.add(predicateOuter);
105
106                        } else {
107                                throw new IllegalArgumentException(Msg.code(1000) + "Invalid token type: " + nextOr.getClass());
108                        }
109
110                }
111
112                Predicate predicate = myCriteriaBuilder.or(toArray(codePredicates));
113                myQueryStack.addPredicateWithImplicitTypeSelection(predicate);
114                return predicate;
115        }
116}