From 08a984406615ddded727d3fd0d2b71a109f974b4 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Wed, 17 Apr 2019 09:10:17 -0400 Subject: [PATCH] Work on #1280 --- .../ca/uhn/fhir/jpa/entity/SearchResult.java | 70 +++++++++---------- .../ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java | 3 + .../dao/r4/FhirResourceDaoR4CreateTest.java | 1 + .../r4/FhirResourceDaoR4SearchNoFtTest.java | 25 +++++++ .../fhir/jpa/provider/r4/ExpungeR4Test.java | 11 +-- .../extractor/SearchParamExtractorR4.java | 39 +++++++---- src/changes/changes.xml | 4 ++ 7 files changed, 98 insertions(+), 55 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchResult.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchResult.java index fb77ed87c47..62cb95309bb 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchResult.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SearchResult.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity; * 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. @@ -21,50 +21,35 @@ package ca.uhn.fhir.jpa.entity; */ import ca.uhn.fhir.jpa.model.entity.ResourceTable; +import org.apache.commons.lang3.builder.ToStringBuilder; +import javax.persistence.*; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.ForeignKey; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; - @Entity -@Table(name = "HFJ_SEARCH_RESULT", uniqueConstraints= { - @UniqueConstraint(name="IDX_SEARCHRES_ORDER", columnNames= {"SEARCH_PID", "SEARCH_ORDER"}) +@Table(name = "HFJ_SEARCH_RESULT", uniqueConstraints = { + @UniqueConstraint(name = "IDX_SEARCHRES_ORDER", columnNames = {"SEARCH_PID", "SEARCH_ORDER"}) }) public class SearchResult implements Serializable { private static final long serialVersionUID = 1L; - @GeneratedValue(strategy = GenerationType.AUTO, generator="SEQ_SEARCH_RES") - @SequenceGenerator(name="SEQ_SEARCH_RES", sequenceName="SEQ_SEARCH_RES") + @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SEARCH_RES") + @SequenceGenerator(name = "SEQ_SEARCH_RES", sequenceName = "SEQ_SEARCH_RES") @Id @Column(name = "PID") private Long myId; - - @Column(name="SEARCH_ORDER", nullable=false) + @Column(name = "SEARCH_ORDER", nullable = false) private int myOrder; - @ManyToOne - @JoinColumn(name="RESOURCE_PID", referencedColumnName="RES_ID", foreignKey=@ForeignKey(name="FK_SEARCHRES_RES"), insertable=false, updatable=false, nullable=false) + @JoinColumn(name = "RESOURCE_PID", referencedColumnName = "RES_ID", foreignKey = @ForeignKey(name = "FK_SEARCHRES_RES"), insertable = false, updatable = false, nullable = false) private ResourceTable myResource; - - @Column(name="RESOURCE_PID", insertable=true, updatable=false, nullable=false) + @Column(name = "RESOURCE_PID", insertable = true, updatable = false, nullable = false) private Long myResourcePid; - @ManyToOne - @JoinColumn(name="SEARCH_PID", referencedColumnName="PID", foreignKey=@ForeignKey(name="FK_SEARCHRES_SEARCH")) + @JoinColumn(name = "SEARCH_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_SEARCHRES_SEARCH")) private Search mySearch; - - @Column(name="SEARCH_PID", insertable=false, updatable=false, nullable=false) + @Column(name = "SEARCH_PID", insertable = false, updatable = false, nullable = false) private Long mySearchPid; /** @@ -81,33 +66,42 @@ public class SearchResult implements Serializable { mySearch = theSearch; } + @Override + public String toString() { + return new ToStringBuilder(this) + .append("search", mySearchPid) + .append("order", myOrder) + .append("resourcePid", myResourcePid) + .toString(); + } + @Override public boolean equals(Object theObj) { if (!(theObj instanceof SearchResult)) { return false; } - return myResourcePid.equals(((SearchResult)theObj).myResourcePid); + return myResourcePid.equals(((SearchResult) theObj).myResourcePid); } public int getOrder() { return myOrder; } - - public Long getResourcePid() { - return myResourcePid; - } - - @Override - public int hashCode() { - return myResourcePid.hashCode(); - } public void setOrder(int theOrder) { myOrder = theOrder; } + public Long getResourcePid() { + return myResourcePid; + } + public SearchResult setResourcePid(Long theResourcePid) { myResourcePid = theResourcePid; return this; } + + @Override + public int hashCode() { + return myResourcePid.hashCode(); + } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java index e15b11279c2..190b44a4087 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java @@ -178,6 +178,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest { @Qualifier("myNamingSystemDaoR4") protected IFhirResourceDao myNamingSystemDao; @Autowired + @Qualifier("myChargeItemDaoR4") + protected IFhirResourceDao myChargeItemDao; + @Autowired @Qualifier("myObservationDaoR4") protected IFhirResourceDao myObservationDao; @Autowired diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java index 90a41be1fbc..42a62bcac3e 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.r4; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; +import ca.uhn.fhir.rest.param.QuantityParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java index a8f8feb86d2..15a5ea9be0d 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java @@ -1725,6 +1725,31 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a)); } + @Test + public void testSearchByMoneyParam() { + ChargeItem ci = new ChargeItem(); + ci.getPriceOverride().setValue(123).setCurrency("$"); + + myChargeItemDao.create(ci); + + SearchParameterMap map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(ChargeItem.SP_PRICE_OVERRIDE, new QuantityParam().setValue(123)); + assertEquals(1, myChargeItemDao.search(map).size().intValue()); + + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(ChargeItem.SP_PRICE_OVERRIDE, new QuantityParam().setValue(123).setUnits("$")); + assertEquals(1, myChargeItemDao.search(map).size().intValue()); + + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(ChargeItem.SP_PRICE_OVERRIDE, new QuantityParam().setValue(123).setUnits("$").setSystem("urn:iso:std:iso:4217")); + assertEquals(1, myChargeItemDao.search(map).size().intValue()); + + } + + @Test public void testSearchNameParam() { IIdType id1; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java index ac34d6b68b1..0b911c5c3b6 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java @@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.provider.r4; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirResourceDao; -import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test; +import ca.uhn.fhir.jpa.search.PersistedJpaSearchFirstPageBundleProvider; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.util.ExpungeOptions; import ca.uhn.fhir.rest.api.server.IBundleProvider; @@ -19,6 +19,8 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; @@ -28,6 +30,7 @@ import static org.junit.Assert.*; public class ExpungeR4Test extends BaseResourceProviderR4Test { + private static final Logger ourLog = LoggerFactory.getLogger(ExpungeR4Test.class); private IIdType myOneVersionPatientId; private IIdType myTwoVersionPatientId; private IIdType myDeletedPatientId; @@ -67,7 +70,6 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test { getDao(theId).read(theId); } - public void createStandardPatients() { Patient p = new Patient(); p.setId("PT-ONEVERSION"); @@ -183,7 +185,6 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test { } - @Test public void testExpungeInstanceVersionCurrentVersion() { createStandardPatients(); @@ -338,11 +339,13 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test { createStandardPatients(); IBundleProvider search = myPatientDao.search(new SearchParameterMap()); + assertEquals(PersistedJpaSearchFirstPageBundleProvider.class, search.getClass()); assertEquals(2, search.size().intValue()); assertEquals(2, search.getResources(0, 2).size()); runInTransaction(() -> { - assertEquals(2, mySearchResultDao.count()); + ourLog.info("Search results: {}", mySearchResultDao.findAll().toString()); + assertEquals(mySearchResultDao.findAll().toString(), 2, mySearchResultDao.count()); }); mySystemDao.expunge(new ExpungeOptions() diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorR4.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorR4.java index 53d607717cf..1ad82174326 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorR4.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorR4.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.searchparam.extractor; * 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. @@ -86,6 +86,17 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements } } + private void addMoney(ResourceTable theEntity, HashSet retVal, String resourceName, Money nextValue) { + if (!nextValue.getValueElement().isEmpty()) { + BigDecimal nextValueValue = nextValue.getValueElement().getValue(); + String nextValueString = "urn:iso:std:iso:4217"; + String nextValueCode = nextValue.getCurrency(); + ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValueValue, nextValueString, nextValueCode); + nextEntity.setResource(theEntity); + retVal.add(nextEntity); + } + } + private void addSearchTerm(ResourceTable theEntity, Set retVal, String resourceName, String searchTerm) { if (isBlank(searchTerm)) { return; @@ -352,6 +363,9 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements if (nextObject instanceof Quantity) { Quantity nextValue = (Quantity) nextObject; addQuantity(theEntity, retVal, resourceName, nextValue); + } else if (nextObject instanceof Money) { + Money nextValue = (Money) nextObject; + addMoney(theEntity, retVal, resourceName, nextValue); } else if (nextObject instanceof Range) { Range nextValue = (Range) nextObject; addQuantity(theEntity, retVal, resourceName, nextValue.getLow()); @@ -747,16 +761,10 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements myValidationSupport = theValidationSupport; } - private static > String extractSystem(Enumeration theBoundCode) { - if (theBoundCode.getValue() != null) { - return theBoundCode.getEnumFactory().toSystem(theBoundCode.getValue()); - } - return null; - } - - private class SearchParamExtractorR4HostServices implements FHIRPathEngine.IEvaluationContext { + private Map myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>()); + @Override public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { return null; @@ -787,8 +795,6 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements return null; } - private Map myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>()); - @Override public Base resolveReference(Object theAppContext, String theUrl) throws FHIRException { @@ -810,7 +816,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements ResourceType resourceType = ResourceType.fromCode(url.getResourceType()); if (resourceType != null) { - retVal = new Resource(){ + retVal = new Resource() { @Override public Resource copy() { return this; @@ -839,4 +845,11 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements } } + private static > String extractSystem(Enumeration theBoundCode) { + if (theBoundCode.getValue() != null) { + return theBoundCode.getEnumFactory().toSystem(theBoundCode.getValue()); + } + return null; + } + } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f9f7ff63404..6862067c1df 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -147,6 +147,10 @@ The fetchValueSet method on IValidationSupport implementation was not visible and could not be overridden. Thanks to Patrick Werner for the pull reuqest! + + The JPA server failed to index R4 reources with search parameters pointing to the Money data type. + Thanks to GitHub user @navyflower for reporting! +