Avoid a crash on double date chains (#2097)
* Avoid a crash on double date chains * Add changelog * Address coverage warning
This commit is contained in:
parent
631556041c
commit
072e63be5a
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 2097
|
||||||
|
title: "A crash in the JPA server was fixed when performing a search containined two chained search parameters to
|
||||||
|
date target types."
|
|
@ -49,7 +49,6 @@ import java.util.Map;
|
||||||
public class PredicateBuilderDate extends BasePredicateBuilder implements IPredicateBuilder {
|
public class PredicateBuilderDate extends BasePredicateBuilder implements IPredicateBuilder {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(PredicateBuilderDate.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(PredicateBuilderDate.class);
|
||||||
|
|
||||||
private Map<String, From<?, ResourceIndexedSearchParamDate>> myJoinMap;
|
|
||||||
|
|
||||||
PredicateBuilderDate(SearchBuilder theSearchBuilder) {
|
PredicateBuilderDate(SearchBuilder theSearchBuilder) {
|
||||||
super(theSearchBuilder);
|
super(theSearchBuilder);
|
||||||
|
@ -64,15 +63,15 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi
|
||||||
|
|
||||||
String paramName = theSearchParam.getName();
|
String paramName = theSearchParam.getName();
|
||||||
boolean newJoin = false;
|
boolean newJoin = false;
|
||||||
if (myJoinMap == null) {
|
|
||||||
myJoinMap = new HashMap<>();
|
Map<String, From<?, ResourceIndexedSearchParamDate>> joinMap = myQueryStack.getJoinMap();
|
||||||
}
|
|
||||||
String key = theResourceName + " " + paramName;
|
String key = theResourceName + " " + paramName;
|
||||||
|
|
||||||
From<?, ResourceIndexedSearchParamDate> join = myJoinMap.get(key);
|
From<?, ResourceIndexedSearchParamDate> join = joinMap.get(key);
|
||||||
|
|
||||||
if (join == null) {
|
if (join == null) {
|
||||||
join = myQueryStack.createJoin(SearchBuilderJoinEnum.DATE, paramName);
|
join = myQueryStack.createJoin(SearchBuilderJoinEnum.DATE, paramName);
|
||||||
myJoinMap.put(key, join);
|
joinMap.put(key, join);
|
||||||
newJoin = true;
|
newJoin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.dao.predicate.querystack;
|
||||||
import ca.uhn.fhir.jpa.dao.predicate.IndexJoins;
|
import ca.uhn.fhir.jpa.dao.predicate.IndexJoins;
|
||||||
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinEnum;
|
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinEnum;
|
||||||
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinKey;
|
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinKey;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
|
|
||||||
import javax.persistence.criteria.AbstractQuery;
|
import javax.persistence.criteria.AbstractQuery;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
@ -37,7 +38,9 @@ import javax.persistence.criteria.Subquery;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
abstract class QueryRootEntry {
|
abstract class QueryRootEntry {
|
||||||
|
@ -45,6 +48,7 @@ abstract class QueryRootEntry {
|
||||||
private final IndexJoins myIndexJoins = new IndexJoins();
|
private final IndexJoins myIndexJoins = new IndexJoins();
|
||||||
private final CriteriaBuilder myCriteriaBuilder;
|
private final CriteriaBuilder myCriteriaBuilder;
|
||||||
private boolean myHasImplicitTypeSelection;
|
private boolean myHasImplicitTypeSelection;
|
||||||
|
private Map<String, From<?, ResourceIndexedSearchParamDate>> myJoinMap;
|
||||||
|
|
||||||
QueryRootEntry(CriteriaBuilder theCriteriaBuilder) {
|
QueryRootEntry(CriteriaBuilder theCriteriaBuilder) {
|
||||||
myCriteriaBuilder = theCriteriaBuilder;
|
myCriteriaBuilder = theCriteriaBuilder;
|
||||||
|
@ -108,6 +112,15 @@ abstract class QueryRootEntry {
|
||||||
return getQueryRoot();
|
return getQueryRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, From<?, ResourceIndexedSearchParamDate>> getJoinMap() {
|
||||||
|
Map<String, From<?, ResourceIndexedSearchParamDate>> retVal = myJoinMap;
|
||||||
|
if (retVal==null) {
|
||||||
|
retVal = new HashMap<>();
|
||||||
|
myJoinMap = retVal;
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
abstract void orderBy(List<Order> theOrders);
|
abstract void orderBy(List<Order> theOrders);
|
||||||
|
|
||||||
abstract Expression<Date> getLastUpdatedColumn();
|
abstract Expression<Date> getLastUpdatedColumn();
|
||||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.dao.predicate.querystack;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinEnum;
|
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinEnum;
|
||||||
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinKey;
|
import ca.uhn.fhir.jpa.dao.predicate.SearchBuilderJoinKey;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ import javax.persistence.criteria.Root;
|
||||||
import javax.persistence.criteria.Subquery;
|
import javax.persistence.criteria.Subquery;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
|
@ -281,4 +283,9 @@ public class QueryStack {
|
||||||
public Predicate addNeverMatchingPredicate() {
|
public Predicate addNeverMatchingPredicate() {
|
||||||
return top().addNeverMatchingPredicate();
|
return top().addNeverMatchingPredicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, From<?, ResourceIndexedSearchParamDate>> getJoinMap() {
|
||||||
|
return top().getJoinMap();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
import org.hl7.fhir.r4.model.CodeType;
|
import org.hl7.fhir.r4.model.CodeType;
|
||||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.Communication;
|
||||||
import org.hl7.fhir.r4.model.CommunicationRequest;
|
import org.hl7.fhir.r4.model.CommunicationRequest;
|
||||||
import org.hl7.fhir.r4.model.Condition;
|
import org.hl7.fhir.r4.model.Condition;
|
||||||
import org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem;
|
import org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem;
|
||||||
|
@ -5080,6 +5081,34 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(outcome), contains(crId));
|
assertThat(toUnqualifiedVersionlessIdValues(outcome), contains(crId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchWithTwoChainedDates() {
|
||||||
|
// Matches
|
||||||
|
Encounter e1 = new Encounter();
|
||||||
|
e1.setPeriod(new Period().setStartElement(new DateTimeType("2020-09-14T12:00:00Z")).setEndElement(new DateTimeType("2020-09-14T12:00:00Z")));
|
||||||
|
String e1Id = myEncounterDao.create(e1).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
Communication c1 = new Communication();
|
||||||
|
c1.getEncounter().setReference(e1Id);
|
||||||
|
myCommunicationDao.create(c1);
|
||||||
|
|
||||||
|
// Doesn't match
|
||||||
|
Encounter e2 = new Encounter();
|
||||||
|
e2.setPeriod(new Period().setStartElement(new DateTimeType("2020-02-14T12:00:00Z")).setEndElement(new DateTimeType("2020-02-14T12:00:00Z")));
|
||||||
|
String e2Id = myEncounterDao.create(e2).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
Communication c2 = new Communication();
|
||||||
|
c2.getEncounter().setReference(e2Id);
|
||||||
|
myCommunicationDao.create(c2);
|
||||||
|
|
||||||
|
SearchParameterMap map = SearchParameterMap.newSynchronous();
|
||||||
|
map.add(Communication.SP_ENCOUNTER, new ReferenceParam("ge2020-09-14").setChain("date"));
|
||||||
|
map.add(Communication.SP_ENCOUNTER, new ReferenceParam("le2020-09-15").setChain("date"));
|
||||||
|
|
||||||
|
IBundleProvider outcome = myCommunicationDao.search(map);
|
||||||
|
assertEquals(1, outcome.sizeOrThrowNpe());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCircularReferencesDontBreakRevIncludes() {
|
public void testCircularReferencesDontBreakRevIncludes() {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.server.messaging;
|
package ca.uhn.fhir.rest.server.messaging;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.IModelJson;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.server.messaging;
|
package ca.uhn.fhir.rest.server.messaging;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IModelJson;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.server.messaging;
|
package ca.uhn.fhir.rest.server.messaging;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface IResourceMessage {
|
public interface IResourceMessage {
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.server.messaging;
|
package ca.uhn.fhir.rest.server.messaging;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.server.messaging.json;
|
package ca.uhn.fhir.rest.server.messaging.json;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.IModelJson;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.server.messaging.json;
|
package ca.uhn.fhir.rest.server.messaging.json;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.IModelJson;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.server.messaging.json;
|
package ca.uhn.fhir.rest.server.messaging.json;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
|
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
|
Loading…
Reference in New Issue