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