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.i18n.Msg; 023import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; 024import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder; 025import ca.uhn.fhir.jpa.util.QueryParameterUtils; 026import ca.uhn.fhir.model.api.IQueryParameterType; 027import ca.uhn.fhir.rest.param.UriParam; 028import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 029import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; 030import ca.uhn.fhir.util.StringUtil; 031import ca.uhn.fhir.util.UrlUtil; 032import com.healthmarketscience.sqlbuilder.BinaryCondition; 033import com.healthmarketscience.sqlbuilder.Condition; 034import com.healthmarketscience.sqlbuilder.FunctionCall; 035import com.healthmarketscience.sqlbuilder.UnaryCondition; 036import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040import java.util.List; 041 042import static ca.uhn.fhir.jpa.search.builder.predicate.StringPredicateBuilder.createLeftAndRightMatchLikeExpression; 043import static ca.uhn.fhir.jpa.search.builder.predicate.StringPredicateBuilder.createLeftMatchLikeExpression; 044 045public class SourcePredicateBuilder extends BaseJoiningPredicateBuilder { 046 047 private static final Logger ourLog = LoggerFactory.getLogger(SourcePredicateBuilder.class); 048 private final DbColumn myColumnSourceUri; 049 private final DbColumn myColumnRequestId; 050 private final DbColumn myResourceIdColumn; 051 052 /** 053 * Constructor 054 */ 055 public SourcePredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) { 056 super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_RES_VER_PROV")); 057 058 myResourceIdColumn = getTable().addColumn("RES_PID"); 059 myColumnSourceUri = getTable().addColumn("SOURCE_URI"); 060 myColumnRequestId = getTable().addColumn("REQUEST_ID"); 061 } 062 063 @Override 064 public DbColumn getResourceIdColumn() { 065 return myResourceIdColumn; 066 } 067 068 public Condition createPredicateSourceUri(String theSourceUri) { 069 return BinaryCondition.equalTo(myColumnSourceUri, generatePlaceholder(theSourceUri)); 070 } 071 072 public Condition createPredicateMissingSourceUri() { 073 return UnaryCondition.isNull(myColumnSourceUri); 074 } 075 076 public Condition createPredicateSourceUriWithModifiers( 077 IQueryParameterType theQueryParameter, JpaStorageSettings theStorageSetting, String theSourceUri) { 078 if (theQueryParameter.getMissing() != null && !theQueryParameter.getMissing()) { 079 return UnaryCondition.isNotNull(myColumnSourceUri); 080 } else if (theQueryParameter instanceof UriParam && theQueryParameter.getQueryParameterQualifier() != null) { 081 UriParam uriParam = (UriParam) theQueryParameter; 082 switch (uriParam.getQualifier()) { 083 case ABOVE: 084 return createPredicateSourceAbove(theSourceUri); 085 case BELOW: 086 return createPredicateSourceBelow(theSourceUri); 087 case CONTAINS: 088 return createPredicateSourceContains(theStorageSetting, theSourceUri); 089 default: 090 throw new InvalidRequestException(Msg.code(2418) 091 + String.format( 092 "Unsupported qualifier specified, qualifier=%s", 093 theQueryParameter.getQueryParameterQualifier())); 094 } 095 } else { 096 return createPredicateSourceUri(theSourceUri); 097 } 098 } 099 100 private Condition createPredicateSourceAbove(String theSourceUri) { 101 List<String> aboveUriCandidates = UrlUtil.getAboveUriCandidates(theSourceUri); 102 List<String> aboveUriPlaceholders = generatePlaceholders(aboveUriCandidates); 103 return QueryParameterUtils.toEqualToOrInPredicate(myColumnSourceUri, aboveUriPlaceholders); 104 } 105 106 private Condition createPredicateSourceBelow(String theSourceUri) { 107 String belowLikeExpression = createLeftMatchLikeExpression(theSourceUri); 108 return BinaryCondition.like(myColumnSourceUri, generatePlaceholder(belowLikeExpression)); 109 } 110 111 private Condition createPredicateSourceContains(JpaStorageSettings theStorageSetting, String theSourceUri) { 112 if (theStorageSetting.isAllowContainsSearches()) { 113 FunctionCall upperFunction = new FunctionCall("UPPER"); 114 upperFunction.addCustomParams(myColumnSourceUri); 115 String normalizedString = StringUtil.normalizeStringForSearchIndexing(theSourceUri); 116 String containsLikeExpression = createLeftAndRightMatchLikeExpression(normalizedString); 117 return BinaryCondition.like(upperFunction, generatePlaceholder(containsLikeExpression)); 118 } else { 119 throw new MethodNotAllowedException(Msg.code(2417) + ":contains modifier is disabled on this server"); 120 } 121 } 122 123 public Condition createPredicateRequestId(String theRequestId) { 124 return BinaryCondition.equalTo(myColumnRequestId, generatePlaceholder(theRequestId)); 125 } 126}