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 ResourceHistoryPredicateBuilder extends BaseJoiningPredicateBuilder implements ISourcePredicateBuilder { 044 045 private final DbColumn myColumnSourceUri; 046 private final DbColumn myColumnRequestId; 047 private final DbColumn myResourceIdColumn; 048 049 /** 050 * Constructor 051 */ 052 public ResourceHistoryPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) { 053 super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_RES_VER")); 054 055 myResourceIdColumn = getTable().addColumn("RES_ID"); 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 @Override 066 public Condition createPredicateSourceUri(String theSourceUri) { 067 return BinaryCondition.equalTo(myColumnSourceUri, generatePlaceholder(theSourceUri)); 068 } 069 070 @Override 071 public Condition createPredicateMissingSourceUri() { 072 return UnaryCondition.isNull(myColumnSourceUri); 073 } 074 075 @Override 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 @Override 124 public Condition createPredicateRequestId(String theRequestId) { 125 return BinaryCondition.equalTo(myColumnRequestId, generatePlaceholder(theRequestId)); 126 } 127}