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