001package ca.uhn.fhir.jpa.search.builder.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.interceptor.model.RequestPartitionId;
024import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
025import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
026import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
027import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
028import com.google.common.collect.Lists;
029import com.healthmarketscience.sqlbuilder.BinaryCondition;
030import com.healthmarketscience.sqlbuilder.ComboCondition;
031import com.healthmarketscience.sqlbuilder.Condition;
032import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
033import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
034import org.apache.commons.lang3.tuple.Triple;
035
036import java.util.List;
037import java.util.Objects;
038
039import static ca.uhn.fhir.jpa.search.builder.predicate.StringPredicateBuilder.createLeftMatchLikeExpression;
040import static org.apache.commons.lang3.StringUtils.isNotBlank;
041
042public class TagPredicateBuilder extends BaseJoiningPredicateBuilder {
043
044        private final DbColumn myColumnResId;
045        private final DbTable myTagDefinitionTable;
046        private final DbColumn myTagDefinitionColumnTagId;
047        private final DbColumn myTagDefinitionColumnTagSystem;
048        private final DbColumn myTagDefinitionColumnTagCode;
049        private final DbColumn myColumnTagId;
050        private final DbColumn myTagDefinitionColumnTagType;
051
052        public TagPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
053                super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_RES_TAG"));
054
055                myColumnResId = getTable().addColumn("RES_ID");
056                myColumnTagId = getTable().addColumn("TAG_ID");
057
058                myTagDefinitionTable = theSearchSqlBuilder.addTable("HFJ_TAG_DEF");
059                myTagDefinitionColumnTagId = myTagDefinitionTable.addColumn("TAG_ID");
060                myTagDefinitionColumnTagSystem = myTagDefinitionTable.addColumn("TAG_SYSTEM");
061                myTagDefinitionColumnTagCode = myTagDefinitionTable.addColumn("TAG_CODE");
062                myTagDefinitionColumnTagType = myTagDefinitionTable.addColumn("TAG_TYPE");
063        }
064
065
066        public Condition createPredicateTag(TagTypeEnum theTagType, List<Triple<String, String, String>> theTokens, String theParamName, RequestPartitionId theRequestPartitionId) {
067                addJoin(getTable(), myTagDefinitionTable, myColumnTagId, myTagDefinitionColumnTagId);
068                return createPredicateTagList(theTagType, theTokens);
069        }
070
071        private Condition createPredicateTagList(TagTypeEnum theTagType, List<Triple<String, String, String>> theTokens) {
072                Condition typePredicate = BinaryCondition.equalTo(myTagDefinitionColumnTagType, generatePlaceholder(theTagType.ordinal()));
073
074                List<Condition> orPredicates = Lists.newArrayList();
075                for (Triple<String, String, String> next : theTokens) {
076                        String system = next.getLeft();
077                        String code = next.getRight();
078                        String qualifier = next.getMiddle();
079
080                        if (theTagType == TagTypeEnum.PROFILE) {
081                                system = BaseHapiFhirDao.NS_JPA_PROFILE;
082                        }
083
084                        Condition codePredicate = Objects.equals(qualifier, UriParamQualifierEnum.BELOW.getValue())
085                                ? BinaryCondition.like(myTagDefinitionColumnTagCode, generatePlaceholder(createLeftMatchLikeExpression(code)))
086                                : BinaryCondition.equalTo(myTagDefinitionColumnTagCode, generatePlaceholder(code));
087
088                        if (isNotBlank(system)) {
089                                Condition systemPredicate = BinaryCondition.equalTo(myTagDefinitionColumnTagSystem, generatePlaceholder(system));
090                                orPredicates.add(ComboCondition.and(typePredicate, systemPredicate, codePredicate));
091                        } else {
092                                // Note: We don't have an index for this combo, which means that this may not perform
093                                // well on MySQL (and maybe others) without an added index
094                                orPredicates.add(ComboCondition.and(typePredicate, codePredicate));
095                        }
096                }
097
098                return ComboCondition.or(orPredicates.toArray(new Condition[0]));
099        }
100
101        @Override
102        public DbColumn getResourceIdColumn() {
103                return myColumnResId;
104        }
105}