merging in masters

This commit is contained in:
leif stawnyczy 2024-04-08 15:46:33 -04:00
commit 8d84ed0b94
166 changed files with 2831 additions and 2097 deletions

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -155,6 +155,7 @@ ca.uhn.fhir.jpa.search.builder.predicate.TokenPredicateBuilder.invalidCodeMissin
ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl.matchesFound=Matches found ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl.matchesFound=Matches found
ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl.noMatchesFound=No Matches found ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl.noMatchesFound=No Matches found
ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl.onlyNegativeMatchesFound=Only negative matches found
ca.uhn.fhir.jpa.dao.JpaResourceDaoSearchParameter.invalidSearchParamExpression=The expression "{0}" can not be evaluated and may be invalid: {1} ca.uhn.fhir.jpa.dao.JpaResourceDaoSearchParameter.invalidSearchParamExpression=The expression "{0}" can not be evaluated and may be invalid: {1}

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId> <artifactId>hapi-fhir-bom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>HAPI FHIR BOM</name> <name>HAPI FHIR BOM</name>
@ -12,7 +12,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -93,7 +93,8 @@ public class ExportConceptMapToCsvCommandR4Test {
"\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2a\",\"Display 2a\",\"Code 3a\",\"Display 3a\",\"equal\",\"3a This is a comment.\"\n" + "\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2a\",\"Display 2a\",\"Code 3a\",\"Display 3a\",\"equal\",\"3a This is a comment.\"\n" +
"\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2b\",\"Display 2b\",\"Code 3b\",\"Display 3b\",\"equal\",\"3b This is a comment.\"\n" + "\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2b\",\"Display 2b\",\"Code 3b\",\"Display 3b\",\"equal\",\"3b This is a comment.\"\n" +
"\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2c\",\"Display 2c\",\"Code 3c\",\"Display 3c\",\"equal\",\"3c This is a comment.\"\n" + "\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2c\",\"Display 2c\",\"Code 3c\",\"Display 3c\",\"equal\",\"3c This is a comment.\"\n" +
"\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2d\",\"Display 2d\",\"Code 3d\",\"Display 3d\",\"equal\",\"3d This is a comment.\"\n"; "\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2d\",\"Display 2d\",\"Code 3d\",\"Display 3d\",\"equal\",\"3d This is a comment.\"\n" +
"\"http://example.com/codesystem/2\",\"Version 2s\",\"http://example.com/codesystem/3\",\"Version 3t\",\"Code 2e\",\"Display 2e\",\"\",\"\",\"unmatched\",\"3e This is a comment.\"\n";
String result = IOUtils.toString(new FileInputStream(FILE), Charsets.UTF_8); String result = IOUtils.toString(new FileInputStream(FILE), Charsets.UTF_8);
assertEquals(expected, result); assertEquals(expected, result);
@ -272,6 +273,16 @@ public class ExportConceptMapToCsvCommandR4Test {
.setEquivalence(ConceptMapEquivalence.EQUAL) .setEquivalence(ConceptMapEquivalence.EQUAL)
.setComment("3d This is a comment."); .setComment("3d This is a comment.");
element = group.addElement();
element
.setCode("Code 2e")
.setDisplay("Display 2e");
target = element.addTarget();
target
.setEquivalence(ConceptMapEquivalence.UNMATCHED)
.setComment("3e This is a comment.");
return conceptMap; return conceptMap;
} }
} }

View File

@ -273,7 +273,7 @@ public class ImportCsvToConceptMapCommandDstu3Test {
assertEquals(CS_URL_3, group.getTarget()); assertEquals(CS_URL_3, group.getTarget());
assertEquals("Version 3t", group.getTargetVersion()); assertEquals("Version 3t", group.getTargetVersion());
assertEquals(4, group.getElement().size()); assertEquals(5, group.getElement().size());
source = group.getElement().get(0); source = group.getElement().get(0);
assertEquals("Code 2a", source.getCode()); assertEquals("Code 2a", source.getCode());
@ -323,6 +323,19 @@ public class ImportCsvToConceptMapCommandDstu3Test {
assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence());
assertEquals("3d This is a comment.", target.getComment()); assertEquals("3d This is a comment.", target.getComment());
// ensure unmatched codes are handled correctly
source = group.getElement().get(4);
assertEquals("Code 2e", source.getCode());
assertEquals("Display 2e", source.getDisplay());
assertEquals(1, source.getTarget().size());
target = source.getTarget().get(0);
assertNull(target.getCode());
assertNull(target.getDisplay());
assertEquals(ConceptMapEquivalence.UNMATCHED, target.getEquivalence());
assertEquals("3e This is a comment.", target.getComment());
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs( App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
new String[]{ new String[]{
ImportCsvToConceptMapCommand.COMMAND, ImportCsvToConceptMapCommand.COMMAND,

View File

@ -284,7 +284,7 @@ public class ImportCsvToConceptMapCommandR4Test {
assertEquals(CS_URL_3, group.getTarget()); assertEquals(CS_URL_3, group.getTarget());
assertEquals("Version 3t", group.getTargetVersion()); assertEquals("Version 3t", group.getTargetVersion());
assertEquals(4, group.getElement().size()); assertEquals(5, group.getElement().size());
source = group.getElement().get(0); source = group.getElement().get(0);
assertEquals("Code 2a", source.getCode()); assertEquals("Code 2a", source.getCode());
@ -334,6 +334,19 @@ public class ImportCsvToConceptMapCommandR4Test {
assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence());
assertEquals("3d This is a comment.", target.getComment()); assertEquals("3d This is a comment.", target.getComment());
// ensure unmatched codes are handled correctly
source = group.getElement().get(4);
assertEquals("Code 2e", source.getCode());
assertEquals("Display 2e", source.getDisplay());
assertEquals(1, source.getTarget().size());
target = source.getTarget().get(0);
assertNull(target.getCode());
assertNull(target.getDisplay());
assertEquals(ConceptMapEquivalence.UNMATCHED, target.getEquivalence());
assertEquals("3e This is a comment.", target.getComment());
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs( App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
new String[]{ new String[]{
ImportCsvToConceptMapCommand.COMMAND, ImportCsvToConceptMapCommand.COMMAND,

View File

@ -11,3 +11,4 @@
"http://example.com/codesystem/2","Version 2s","http://example.com/codesystem/3","Version 3t","Code 2b","Display 2b","Code 3b","Display 3b","equal","3b This is a comment." "http://example.com/codesystem/2","Version 2s","http://example.com/codesystem/3","Version 3t","Code 2b","Display 2b","Code 3b","Display 3b","equal","3b This is a comment."
"http://example.com/codesystem/2","Version 2s","http://example.com/codesystem/3","Version 3t","Code 2c","Display 2c","Code 3c","Display 3c","equal","3c This is a comment." "http://example.com/codesystem/2","Version 2s","http://example.com/codesystem/3","Version 3t","Code 2c","Display 2c","Code 3c","Display 3c","equal","3c This is a comment."
"http://example.com/codesystem/2","Version 2s","http://example.com/codesystem/3","Version 3t","Code 2d","Display 2d","Code 3d","Display 3d","equal","3d This is a comment." "http://example.com/codesystem/2","Version 2s","http://example.com/codesystem/3","Version 3t","Code 2d","Display 2d","Code 3d","Display 3d","equal","3d This is a comment."
"http://example.com/codesystem/2","Version 2s","http://example.com/codesystem/3","Version 3t","Code 2e","Display 2e","","","unmatched","3e This is a comment."

1 SOURCE_CODE_SYSTEM SOURCE_CODE_SYSTEM_VERSION TARGET_CODE_SYSTEM TARGET_CODE_SYSTEM_VERSION SOURCE_CODE SOURCE_DISPLAY TARGET_CODE TARGET_DISPLAY EQUIVALENCE COMMENT
11 http://example.com/codesystem/2 Version 2s http://example.com/codesystem/3 Version 3t Code 2b Display 2b Code 3b Display 3b equal 3b This is a comment.
12 http://example.com/codesystem/2 Version 2s http://example.com/codesystem/3 Version 3t Code 2c Display 2c Code 3c Display 3c equal 3c This is a comment.
13 http://example.com/codesystem/2 Version 2s http://example.com/codesystem/3 Version 3t Code 2d Display 2d Code 3d Display 3d equal 3d This is a comment.
14 http://example.com/codesystem/2 Version 2s http://example.com/codesystem/3 Version 3t Code 2e Display 2e unmatched 3e This is a comment.

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId> <artifactId>hapi-fhir-cli</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -0,0 +1,7 @@
---
type: fix
issue: 5801
title: "Support for the _language parameter was added but it was not able to be used by clients of a JPA server
because the _language parameter was not added to the resource providers. Additionally, no error message
was returned when language support was disabled and a search with _language was performed. This has
been fixed."

View File

@ -0,0 +1,5 @@
---
type: change
issue: 5814
title: "Extracted methods out of ResourceProviderFactory into ObservableSupplierSet so that functionality can be used by
other services. Unit tests revealed a cleanup bug in MdmProviderLoader that is fixed in this MR."

View File

@ -0,0 +1,5 @@
---
type: add
issue: 5816
title: "The ConceptMap/$translate operation will include targets with an equivalence code of `unmatched` in the response
regardless of whether the target has a code."

View File

@ -0,0 +1,4 @@
---
type: change
issue: 5817
title: "The HFJ_FORCED_ID table is no longer used."

View File

@ -0,0 +1,7 @@
---
type: fix
issue: 5820
title: "Unifying the code paths for Patient type export and Patient instance export.
These paths should be the same, since type is defined by spec, but instance
is just 'syntactic sugar' on top of that spec (and so should be the same).
"

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 5824
jira: SMILE-7999
title: "We now avoid a query during reindex and transaction processing that was very slow on Sql Server."

View File

@ -0,0 +1,8 @@
---
type: fix
issue: 5828
title: "When batch 2 jobs with Reduction steps fail in the final part
of the reduction step, this would often leave the job
stuck in the FINALIZE state.
This has been fixed; the job will now FAIL.
"

View File

@ -0,0 +1,4 @@
## HFJ_FORCED_ID Table
The HFJ_FORCED_ID table is no longer used.
Users may delete it after upgrading to 7.2 to free database storage space.

View File

@ -84,6 +84,15 @@ The HFJ_RESOURCE table indicates a single resource of any type in the database.
Contains the resource type (e.g. <code>Patient</code>) Contains the resource type (e.g. <code>Patient</code>)
</td> </td>
</tr> </tr>
<tr>
<td>FHIR_ID</td>
<td></td>
<td>String</td>
<td></td>
<td>
Contains the FHIR Resource id element. Either the PID, or the client-assigned id.
</td>
</tr>
<tr> <tr>
<td>HASH_SHA256</td> <td>HASH_SHA256</td>
<td></td> <td></td>
@ -243,30 +252,6 @@ The complete raw contents of the resource is stored in either the `RES_TEXT` or
</tbody> </tbody>
</table> </table>
<a name="HFJ_FORCED_ID"/>
# HFJ_FORCED_ID: Client Assigned/Visible Resource IDs
By default, the **HFJ_RESOURCE.RES_ID** column is used as the resource ID for all server-assigned IDs. For example, if a Patient resource is created in a completely empty database, it will be assigned the ID `Patient/1` by the server and RES_ID will have a value of 1.
However, when client-assigned IDs are used, these may contain text values to allow a client to create an ID such
as `Patient/ABC`. When a client-assigned ID is given to a resource, a row is created in the **HFJ_RESOURCE** table. When
an **HFJ_FORCED_ID** row exists corresponding to the equivalent **HFJ_RESOURCE** row, the RES_ID value is no longer
visible or usable by FHIR clients and it becomes purely an internal ID to the JPA server.
If the server has been configured with
a [Resource Server ID Strategy](/apidocs/hapi-fhir-storage/undefined/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.html#setResourceServerIdStrategy(ca.uhn.fhir.jpa.api.config.JpaStorageSettings.IdStrategyEnum))
of [UUID](/apidocs/hapi-fhir-storage/undefined/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.IdStrategyEnum.html#UUID), or the
server has been configured with
a [Resource Client ID Strategy](/apidocs/hapi-fhir-storage/undefined/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.html#setResourceClientIdStrategy(ca.uhn.fhir.jpa.api.config.JpaStorageSettings.ClientIdStrategyEnum))
of [ANY](/apidocs/hapi-fhir-storage/undefined/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.ClientIdStrategyEnum.html#ANY)
the server will create a Forced ID for all resources (not only resources having textual IDs).
The **HFJ_RESOURCE** table now has a FHIR_ID column.
This column is always populated; both for server-assigned ids and for client-assigned ids.
As of Hapi release 6.10, this column is used in place of the **HFJ_FORCED_ID** table for id search and sort.
A future version of Hapi will stop populating the **HFJ_FORCED_ID** table.
## Columns ## Columns
<table class="table table-striped table-condensed"> <table class="table table-striped table-condensed">

View File

@ -11,7 +11,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -37,7 +37,6 @@ import ca.uhn.fhir.jpa.api.dao.IJpaDao;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService; import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc; import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao; import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
@ -195,9 +194,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
@Autowired @Autowired
protected IIdHelperService<JpaPid> myIdHelperService; protected IIdHelperService<JpaPid> myIdHelperService;
@Autowired
protected IForcedIdDao myForcedIdDao;
@Autowired @Autowired
protected ISearchCoordinatorSvc<JpaPid> mySearchCoordinatorSvc; protected ISearchCoordinatorSvc<JpaPid> mySearchCoordinatorSvc;
@ -1204,10 +1200,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
if (entity.getId() == null) { if (entity.getId() == null) {
myEntityManager.persist(entity); myEntityManager.persist(entity);
if (entity.getForcedId() != null) {
myEntityManager.persist(entity.getForcedId());
}
postPersist(entity, (T) theResource, theRequest); postPersist(entity, (T) theResource, theRequest);
} else if (entity.getDeleted() != null) { } else if (entity.getDeleted() != null) {

View File

@ -44,14 +44,12 @@ import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
import ca.uhn.fhir.jpa.api.model.ExpungeOutcome; import ca.uhn.fhir.jpa.api.model.ExpungeOutcome;
import ca.uhn.fhir.jpa.api.model.LazyDaoMethodOutcome; import ca.uhn.fhir.jpa.api.model.LazyDaoMethodOutcome;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService; import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService; import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
import ca.uhn.fhir.jpa.delete.DeleteConflictUtil; import ca.uhn.fhir.jpa.delete.DeleteConflictUtil;
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
import ca.uhn.fhir.jpa.model.dao.JpaPid; import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.BaseHasResource; import ca.uhn.fhir.jpa.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.model.entity.BaseTag; import ca.uhn.fhir.jpa.model.entity.BaseTag;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId; import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum; import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
@ -517,18 +515,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
} }
} }
String resourceIdBeforeStorage = theResource.getIdElement().getIdPart(); boolean isClientAssignedId = storeNonPidResourceId(theResource, entity);
boolean resourceHadIdBeforeStorage = isNotBlank(resourceIdBeforeStorage);
boolean resourceIdWasServerAssigned =
theResource.getUserData(JpaConstants.RESOURCE_ID_SERVER_ASSIGNED) == Boolean.TRUE;
if (resourceHadIdBeforeStorage) {
entity.setFhirId(resourceIdBeforeStorage);
}
HookParams hookParams; HookParams hookParams;
// Notify interceptor for accepting/rejecting client assigned ids // Notify interceptor for accepting/rejecting client assigned ids
if (!resourceIdWasServerAssigned && resourceHadIdBeforeStorage) { if (isClientAssignedId) {
hookParams = new HookParams().add(IBaseResource.class, theResource).add(RequestDetails.class, theRequest); hookParams = new HookParams().add(IBaseResource.class, theResource).add(RequestDetails.class, theRequest);
doCallHooks(theTransactionDetails, theRequest, Pointcut.STORAGE_PRESTORAGE_CLIENT_ASSIGNED_ID, hookParams); doCallHooks(theTransactionDetails, theRequest, Pointcut.STORAGE_PRESTORAGE_CLIENT_ASSIGNED_ID, hookParams);
} }
@ -542,7 +534,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
.add(TransactionDetails.class, theTransactionDetails); .add(TransactionDetails.class, theTransactionDetails);
doCallHooks(theTransactionDetails, theRequest, Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, hookParams); doCallHooks(theTransactionDetails, theRequest, Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, hookParams);
if (resourceHadIdBeforeStorage && !resourceIdWasServerAssigned) { if (isClientAssignedId) {
validateResourceIdCreation(theResource, theRequest); validateResourceIdCreation(theResource, theRequest);
} }
@ -569,31 +561,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
// Store the resource forced ID if necessary // Store the resource forced ID if necessary
JpaPid jpaPid = JpaPid.fromId(updatedEntity.getResourceId()); JpaPid jpaPid = JpaPid.fromId(updatedEntity.getResourceId());
if (resourceHadIdBeforeStorage) {
if (resourceIdWasServerAssigned) {
boolean createForPureNumericIds = true;
createForcedIdIfNeeded(entity, resourceIdBeforeStorage, createForPureNumericIds);
} else {
boolean createForPureNumericIds = getStorageSettings().getResourceClientIdStrategy()
!= JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC;
createForcedIdIfNeeded(entity, resourceIdBeforeStorage, createForPureNumericIds);
}
} else {
switch (getStorageSettings().getResourceClientIdStrategy()) {
case NOT_ALLOWED:
case ALPHANUMERIC:
break;
case ANY:
boolean createForPureNumericIds = true;
createForcedIdIfNeeded(
updatedEntity, theResource.getIdElement().getIdPart(), createForPureNumericIds);
// for client ID mode ANY, we will always have a forced ID. If we ever
// stop populating the transient forced ID be warned that we use it
// (and expect it to be set correctly) farther below.
assert updatedEntity.getTransientForcedId() != null;
break;
}
}
// Populate the resource with its actual final stored ID from the entity // Populate the resource with its actual final stored ID from the entity
theResource.setId(entity.getIdDt()); theResource.setId(entity.getIdDt());
@ -601,7 +568,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
// Pre-cache the resource ID // Pre-cache the resource ID
jpaPid.setAssociatedResourceId(entity.getIdType(myFhirContext)); jpaPid.setAssociatedResourceId(entity.getIdType(myFhirContext));
myIdHelperService.addResolvedPidToForcedId( myIdHelperService.addResolvedPidToForcedId(
jpaPid, theRequestPartitionId, getResourceName(), entity.getTransientForcedId(), null); jpaPid, theRequestPartitionId, getResourceName(), entity.getFhirId(), null);
theTransactionDetails.addResolvedResourceId(jpaPid.getAssociatedResourceId(), jpaPid); theTransactionDetails.addResolvedResourceId(jpaPid.getAssociatedResourceId(), jpaPid);
theTransactionDetails.addResolvedResource(jpaPid.getAssociatedResourceId(), theResource); theTransactionDetails.addResolvedResource(jpaPid.getAssociatedResourceId(), theResource);
@ -646,40 +613,34 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
return outcome; return outcome;
} }
private void createForcedIdIfNeeded( /**
ResourceTable theEntity, String theResourceId, boolean theCreateForPureNumericIds) { * Check for an id on the resource and if so,
// TODO MB delete this in step 3 * store it in ResourceTable.
if (isNotBlank(theResourceId) && theEntity.getForcedId() == null) { *
if (theCreateForPureNumericIds || !IdHelperService.isValidPid(theResourceId)) { * The fhirId property is either set here with the resource id
ForcedId forcedId = new ForcedId(); * OR by hibernate once the PK is generated for a server-assigned id.
forcedId.setResourceType(theEntity.getResourceType()); *
forcedId.setForcedId(theResourceId); * Used for both client-assigned id and for server-assigned UUIDs.
forcedId.setResource(theEntity); *
forcedId.setPartitionId(theEntity.getPartitionId()); * @return true if this is a client-assigned id
*
* @see ca.uhn.fhir.jpa.model.entity.ResourceTable.FhirIdGenerator
*/
private boolean storeNonPidResourceId(T theResource, ResourceTable entity) {
String resourceIdBeforeStorage = theResource.getIdElement().getIdPart();
boolean resourceHadIdBeforeStorage = isNotBlank(resourceIdBeforeStorage);
boolean resourceIdWasServerAssigned =
theResource.getUserData(JpaConstants.RESOURCE_ID_SERVER_ASSIGNED) == Boolean.TRUE;
/* // We distinguish actual client-assigned ids from UUIDs which the server assigned.
* As of Hibernate 5.6.2, assigning the forced ID to the boolean isClientAssigned = resourceHadIdBeforeStorage && !resourceIdWasServerAssigned;
* resource table causes an extra update to happen, even
* though the ResourceTable entity isn't actually changed // But both need to be set on the entity fhirId field.
* (there is a @OneToOne reference on ResourceTable to the if (resourceHadIdBeforeStorage) {
* ForcedId table, but the actual column is on the ForcedId entity.setFhirId(resourceIdBeforeStorage);
* table so it doesn't actually make sense to update the table
* when this is set). But to work around that we avoid
* actually assigning ResourceTable#myForcedId here.
*
* It's conceivable they may fix this in the future, or
* they may not.
*
* If you want to try assigning the forced it to the resource
* entity (by calling ResourceTable#setForcedId) try running
* the tests FhirResourceDaoR4QueryCountTest to verify that
* nothing has broken as a result.
* JA 20220121
*/
theEntity.setTransientForcedId(forcedId.getForcedId());
myForcedIdDao.save(forcedId);
}
} }
return isClientAssigned;
} }
void validateResourceIdCreation(T theResource, RequestDetails theRequest) { void validateResourceIdCreation(T theResource, RequestDetails theRequest) {
@ -1891,7 +1852,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
throw new ResourceNotFoundException(Msg.code(1998) + theId); throw new ResourceNotFoundException(Msg.code(1998) + theId);
} }
validateGivenIdIsAppropriateToRetrieveResource(theId, entity); validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
entity.setTransientForcedId(theId.getIdPart());
return entity; return entity;
} }
@ -2634,18 +2594,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
} }
private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) { private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) {
if (entity.getForcedId() != null) { if (!entity.getIdDt().getIdPart().equals(theId.getIdPart())) {
if (getStorageSettings().getResourceClientIdStrategy() != JpaStorageSettings.ClientIdStrategyEnum.ANY) { // This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning
if (theId.isIdPartValidLong()) { // that
// This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning // as far as the outside world is concerned, the given ID doesn't exist (it's just an internal
// that // pointer
// as far as the outside world is concerned, the given ID doesn't exist (it's just an internal // to the
// pointer // forced ID)
// to the throw new ResourceNotFoundException(Msg.code(2000) + theId);
// forced ID)
throw new ResourceNotFoundException(Msg.code(2000) + theId);
}
}
} }
} }

View File

@ -28,7 +28,6 @@ import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.api.model.ExpungeOptions; import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
import ca.uhn.fhir.jpa.api.model.ExpungeOutcome; import ca.uhn.fhir.jpa.api.model.ExpungeOutcome;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
import ca.uhn.fhir.jpa.dao.expunge.ExpungeService; import ca.uhn.fhir.jpa.dao.expunge.ExpungeService;
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService; import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService;
@ -38,7 +37,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProviderFactory; import ca.uhn.fhir.jpa.search.PersistedJpaBundleProviderFactory;
import ca.uhn.fhir.jpa.search.builder.SearchBuilder; import ca.uhn.fhir.jpa.search.SearchConstants;
import ca.uhn.fhir.jpa.util.QueryChunker; import ca.uhn.fhir.jpa.util.QueryChunker;
import ca.uhn.fhir.jpa.util.ResourceCountCache; import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
@ -47,34 +46,31 @@ import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.util.StopWatch;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.persistence.PersistenceContextType; import jakarta.persistence.PersistenceContextType;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery; import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends BaseStorageDao public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends BaseStorageDao
implements IFhirSystemDao<T, MT> { implements IFhirSystemDao<T, MT> {
public static final Predicate[] EMPTY_PREDICATE_ARRAY = new Predicate[0];
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirSystemDao.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirSystemDao.class);
public ResourceCountCache myResourceCountsCache; public ResourceCountCache myResourceCountsCache;
@PersistenceContext(type = PersistenceContextType.TRANSACTION) @PersistenceContext(type = PersistenceContextType.TRANSACTION)
@ -95,9 +91,6 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
@Autowired @Autowired
private PersistedJpaBundleProviderFactory myPersistedJpaBundleProviderFactory; private PersistedJpaBundleProviderFactory myPersistedJpaBundleProviderFactory;
@Autowired
private IResourceTagDao myResourceTagDao;
@Autowired @Autowired
private IInterceptorBroadcaster myInterceptorBroadcaster; private IInterceptorBroadcaster myInterceptorBroadcaster;
@ -181,13 +174,25 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
return myTransactionProcessor.transaction(theRequestDetails, theRequest, true); return myTransactionProcessor.transaction(theRequestDetails, theRequest, true);
} }
/**
* Prefetch entities into the Hibernate session.
*
* When processing several resources (e.g. transaction bundle, $reindex chunk, etc.)
* it would be slow to fetch each piece of a resource (e.g. all token index rows)
* one resource at a time.
* Instead, we fetch all the linked resources for the entire batch and populate the Hibernate Session.
*
* @param theResolvedIds the pids
* @param thePreFetchIndexes Should resource indexes be loaded
*/
@SuppressWarnings("rawtypes")
@Override @Override
public <P extends IResourcePersistentId> void preFetchResources( public <P extends IResourcePersistentId> void preFetchResources(
List<P> theResolvedIds, boolean thePreFetchIndexes) { List<P> theResolvedIds, boolean thePreFetchIndexes) {
HapiTransactionService.requireTransaction(); HapiTransactionService.requireTransaction();
List<Long> pids = theResolvedIds.stream().map(t -> ((JpaPid) t).getId()).collect(Collectors.toList()); List<Long> pids = theResolvedIds.stream().map(t -> ((JpaPid) t).getId()).collect(Collectors.toList());
new QueryChunker<Long>().chunk(pids, ids -> { new QueryChunker<Long>().chunk(pids, idChunk -> {
/* /*
* Pre-fetch the resources we're touching in this transaction in mass - this reduced the * Pre-fetch the resources we're touching in this transaction in mass - this reduced the
@ -200,117 +205,110 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
* *
* However, for realistic average workloads, this should reduce the number of round trips. * However, for realistic average workloads, this should reduce the number of round trips.
*/ */
if (ids.size() >= 2) { if (idChunk.size() >= 2) {
List<ResourceTable> loadedResourceTableEntries = new ArrayList<>(); List<ResourceTable> entityChunk = prefetchResourceTableHistoryAndProvenance(idChunk);
preFetchIndexes(ids, "forcedId", "myForcedId", loadedResourceTableEntries);
List<Long> entityIds;
if (thePreFetchIndexes) { if (thePreFetchIndexes) {
entityIds = loadedResourceTableEntries.stream()
.filter(ResourceTable::isParamsStringPopulated)
.map(ResourceTable::getId)
.collect(Collectors.toList());
if (entityIds.size() > 0) {
preFetchIndexes(entityIds, "string", "myParamsString", null);
}
entityIds = loadedResourceTableEntries.stream() prefetchByField("string", "myParamsString", ResourceTable::isParamsStringPopulated, entityChunk);
.filter(ResourceTable::isParamsTokenPopulated) prefetchByField("token", "myParamsToken", ResourceTable::isParamsTokenPopulated, entityChunk);
.map(ResourceTable::getId) prefetchByField("date", "myParamsDate", ResourceTable::isParamsDatePopulated, entityChunk);
.collect(Collectors.toList()); prefetchByField(
if (entityIds.size() > 0) { "quantity", "myParamsQuantity", ResourceTable::isParamsQuantityPopulated, entityChunk);
preFetchIndexes(entityIds, "token", "myParamsToken", null); prefetchByField("resourceLinks", "myResourceLinks", ResourceTable::isHasLinks, entityChunk);
}
entityIds = loadedResourceTableEntries.stream() prefetchByJoinClause(
.filter(ResourceTable::isParamsDatePopulated) "tags",
.map(ResourceTable::getId) // fetch the TagResources and the actual TagDefinitions
.collect(Collectors.toList()); "LEFT JOIN FETCH r.myTags t LEFT JOIN FETCH t.myTag",
if (entityIds.size() > 0) { BaseHasResource::isHasTags,
preFetchIndexes(entityIds, "date", "myParamsDate", null); entityChunk);
}
entityIds = loadedResourceTableEntries.stream()
.filter(ResourceTable::isParamsQuantityPopulated)
.map(ResourceTable::getId)
.collect(Collectors.toList());
if (entityIds.size() > 0) {
preFetchIndexes(entityIds, "quantity", "myParamsQuantity", null);
}
entityIds = loadedResourceTableEntries.stream()
.filter(ResourceTable::isHasLinks)
.map(ResourceTable::getId)
.collect(Collectors.toList());
if (entityIds.size() > 0) {
preFetchIndexes(entityIds, "resourceLinks", "myResourceLinks", null);
}
entityIds = loadedResourceTableEntries.stream()
.filter(BaseHasResource::isHasTags)
.map(ResourceTable::getId)
.collect(Collectors.toList());
if (entityIds.size() > 0) {
myResourceTagDao.findByResourceIds(entityIds);
preFetchIndexes(entityIds, "tags", "myTags", null);
}
entityIds = loadedResourceTableEntries.stream()
.map(ResourceTable::getId)
.collect(Collectors.toList());
if (myStorageSettings.getIndexMissingFields() == JpaStorageSettings.IndexEnabledEnum.ENABLED) { if (myStorageSettings.getIndexMissingFields() == JpaStorageSettings.IndexEnabledEnum.ENABLED) {
preFetchIndexes(entityIds, "searchParamPresence", "mySearchParamPresents", null); prefetchByField("searchParamPresence", "mySearchParamPresents", r -> true, entityChunk);
} }
} }
new QueryChunker<ResourceTable>()
.chunk(loadedResourceTableEntries, SearchBuilder.getMaximumPageSize() / 2, entries -> {
Map<Long, ResourceTable> entities =
entries.stream().collect(Collectors.toMap(ResourceTable::getId, t -> t));
CriteriaBuilder b = myEntityManager.getCriteriaBuilder();
CriteriaQuery<ResourceHistoryTable> q = b.createQuery(ResourceHistoryTable.class);
Root<ResourceHistoryTable> from = q.from(ResourceHistoryTable.class);
from.fetch("myProvenance", JoinType.LEFT);
List<Predicate> orPredicates = new ArrayList<>();
for (ResourceTable next : entries) {
Predicate resId = b.equal(from.get("myResourceId"), next.getId());
Predicate resVer = b.equal(from.get("myResourceVersion"), next.getVersion());
orPredicates.add(b.and(resId, resVer));
}
q.where(b.or(orPredicates.toArray(EMPTY_PREDICATE_ARRAY)));
List<ResourceHistoryTable> resultList =
myEntityManager.createQuery(q).getResultList();
for (ResourceHistoryTable next : resultList) {
ResourceTable nextEntity = entities.get(next.getResourceId());
if (nextEntity != null) {
nextEntity.setCurrentVersionEntity(next);
}
}
});
} }
}); });
} }
private void preFetchIndexes( @Nonnull
List<Long> theIds, private List<ResourceTable> prefetchResourceTableHistoryAndProvenance(List<Long> idChunk) {
String typeDesc, assert idChunk.size() < SearchConstants.MAX_PAGE_SIZE : "assume pre-chunked";
String fieldName,
@Nullable List<ResourceTable> theEntityListToPopulate) { Query query = myEntityManager.createQuery("select r, h "
new QueryChunker<Long>().chunk(theIds, ids -> { + " FROM ResourceTable r "
TypedQuery<ResourceTable> query = myEntityManager.createQuery( + " LEFT JOIN fetch ResourceHistoryTable h "
"FROM ResourceTable r LEFT JOIN FETCH r." + fieldName + " WHERE r.myId IN ( :IDS )", + " on r.myVersion = h.myResourceVersion and r.id = h.myResourceId "
ResourceTable.class); + " left join fetch h.myProvenance "
query.setParameter("IDS", ids); + " WHERE r.myId IN ( :IDS ) ");
List<ResourceTable> indexFetchOutcome = query.getResultList(); query.setParameter("IDS", idChunk);
ourLog.debug("Pre-fetched {} {}} indexes", indexFetchOutcome.size(), typeDesc);
if (theEntityListToPopulate != null) { @SuppressWarnings("unchecked")
theEntityListToPopulate.addAll(indexFetchOutcome); Stream<Object[]> queryResultStream = query.getResultStream();
} return queryResultStream
}); .map(nextPair -> {
// Store the matching ResourceHistoryTable in the transient slot on ResourceTable
ResourceTable result = (ResourceTable) nextPair[0];
ResourceHistoryTable currentVersion = (ResourceHistoryTable) nextPair[1];
result.setCurrentVersionEntity(currentVersion);
return result;
})
.collect(Collectors.toList());
}
/**
* Prefetch a join field for the active subset of some ResourceTable entities.
* Convenience wrapper around prefetchByJoinClause() for simple fields.
*
* @param theDescription for logging
* @param theJpaFieldName the join field from ResourceTable
* @param theEntityPredicate select which ResourceTable entities need this join
* @param theEntities the ResourceTable entities to consider
*/
private void prefetchByField(
String theDescription,
String theJpaFieldName,
Predicate<ResourceTable> theEntityPredicate,
List<ResourceTable> theEntities) {
String joinClause = "LEFT JOIN FETCH r." + theJpaFieldName;
prefetchByJoinClause(theDescription, joinClause, theEntityPredicate, theEntities);
}
/**
* Prefetch a join field for the active subset of some ResourceTable entities.
*
* @param theDescription for logging
* @param theJoinClause the JPA join expression to add to `ResourceTable r`
* @param theEntityPredicate selects which entities need this prefetch
* @param theEntities the ResourceTable entities to consider
*/
private void prefetchByJoinClause(
String theDescription,
String theJoinClause,
Predicate<ResourceTable> theEntityPredicate,
List<ResourceTable> theEntities) {
// Which entities need this prefetch?
List<Long> idSubset = theEntities.stream()
.filter(theEntityPredicate)
.map(ResourceTable::getId)
.collect(Collectors.toList());
if (idSubset.isEmpty()) {
// nothing to do
return;
}
String jqlQuery = "FROM ResourceTable r " + theJoinClause + " WHERE r.myId IN ( :IDS )";
TypedQuery<ResourceTable> query = myEntityManager.createQuery(jqlQuery, ResourceTable.class);
query.setParameter("IDS", idSubset);
List<ResourceTable> indexFetchOutcome = query.getResultList();
ourLog.debug("Pre-fetched {} {} indexes", indexFetchOutcome.size(), theDescription);
} }
@Nullable @Nullable

View File

@ -1,43 +0,0 @@
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2024 Smile CDR, Inc.
* %%
* 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%
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/**
* Legacy forced_id implementation.
*
* @deprecated we now have a fhir_id column directly on HFJ_RESOURCE.
* No runtime code should query this table except for deletions by PK.
* To be deleted in 2024 (zero-downtime).
*/
@Deprecated(since = "6.10")
@Repository
public interface IForcedIdDao extends JpaRepository<ForcedId, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM ForcedId t WHERE t.myId = :pid")
void deleteByPid(@Param("pid") Long theId);
}

View File

@ -43,7 +43,6 @@ public interface IResourceLinkDao extends JpaRepository<ResourceLink, Long>, IHa
* Loads a collection of ResourceLink entities by PID, but also eagerly fetches * Loads a collection of ResourceLink entities by PID, but also eagerly fetches
* the target resources and their forced IDs * the target resources and their forced IDs
*/ */
@Query( @Query("SELECT t FROM ResourceLink t LEFT JOIN FETCH t.myTargetResource tr WHERE t.myId in :pids")
"SELECT t FROM ResourceLink t LEFT JOIN FETCH t.myTargetResource tr LEFT JOIN FETCH tr.myForcedId WHERE t.myId in :pids")
List<ResourceLink> findByPidAndFetchTargetDetails(@Param("pids") List<Long> thePids); List<ResourceLink> findByPidAndFetchTargetDetails(@Param("pids") List<Long> thePids);
} }

View File

@ -177,25 +177,26 @@ public interface IResourceTableDao
@Query("SELECT t.myId, t.myResourceType, t.myVersion FROM ResourceTable t WHERE t.myId IN ( :pid )") @Query("SELECT t.myId, t.myResourceType, t.myVersion FROM ResourceTable t WHERE t.myId IN ( :pid )")
Collection<Object[]> getResourceVersionsForPid(@Param("pid") List<Long> pid); Collection<Object[]> getResourceVersionsForPid(@Param("pid") List<Long> pid);
@Query( @Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId IS NULL AND t.myId = :pid")
"SELECT t FROM ResourceTable t LEFT JOIN FETCH t.myForcedId WHERE t.myPartitionId.myPartitionId IS NULL AND t.myId = :pid")
Optional<ResourceTable> readByPartitionIdNull(@Param("pid") Long theResourceId); Optional<ResourceTable> readByPartitionIdNull(@Param("pid") Long theResourceId);
@Query( @Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId = :partitionId AND t.myId = :pid")
"SELECT t FROM ResourceTable t LEFT JOIN FETCH t.myForcedId WHERE t.myPartitionId.myPartitionId = :partitionId AND t.myId = :pid")
Optional<ResourceTable> readByPartitionId( Optional<ResourceTable> readByPartitionId(
@Param("partitionId") int thePartitionId, @Param("pid") Long theResourceId); @Param("partitionId") int thePartitionId, @Param("pid") Long theResourceId);
@Query( @Query(
"SELECT t FROM ResourceTable t LEFT JOIN FETCH t.myForcedId WHERE (t.myPartitionId.myPartitionId IS NULL OR t.myPartitionId.myPartitionId IN (:partitionIds)) AND t.myId = :pid") "SELECT t FROM ResourceTable t WHERE (t.myPartitionId.myPartitionId IS NULL OR t.myPartitionId.myPartitionId IN (:partitionIds)) AND t.myId = :pid")
Optional<ResourceTable> readByPartitionIdsOrNull( Optional<ResourceTable> readByPartitionIdsOrNull(
@Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId); @Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId);
@Query( @Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId IN (:partitionIds) AND t.myId = :pid")
"SELECT t FROM ResourceTable t LEFT JOIN FETCH t.myForcedId WHERE t.myPartitionId.myPartitionId IN (:partitionIds) AND t.myId = :pid")
Optional<ResourceTable> readByPartitionIds( Optional<ResourceTable> readByPartitionIds(
@Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId); @Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId);
@Query("SELECT t FROM ResourceTable t LEFT JOIN FETCH t.myForcedId WHERE t.myId IN :pids") @Query("SELECT t FROM ResourceTable t WHERE t.myId IN :pids")
List<ResourceTable> findAllByIdAndLoadForcedIds(@Param("pids") List<Long> thePids); List<ResourceTable> findAllByIdAndLoadForcedIds(@Param("pids") List<Long> thePids);
@Query("SELECT t FROM ResourceTable t where t.myResourceType = :restype and t.myFhirId = :fhirId")
Optional<ResourceTable> findByTypeAndFhirId(
@Param("restype") String theResourceName, @Param("fhirId") String theFhirId);
} }

View File

@ -53,9 +53,7 @@ public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long>, IHa
* The current TermValueSet is not necessarily the last uploaded anymore, but the current VS resource * The current TermValueSet is not necessarily the last uploaded anymore, but the current VS resource
* is pointed by a specific ForcedId, so we locate current ValueSet as the one pointing to current VS resource * is pointed by a specific ForcedId, so we locate current ValueSet as the one pointing to current VS resource
*/ */
@Query( @Query(value = "SELECT vs FROM TermValueSet vs where vs.myResource.myFhirId = :forcedId ")
value =
"SELECT vs FROM ForcedId f, TermValueSet vs where f.myForcedId = :forcedId and vs.myResource = f.myResource")
Optional<TermValueSet> findTermValueSetByForcedId(@Param("forcedId") String theForcedId); Optional<TermValueSet> findTermValueSetByForcedId(@Param("forcedId") String theForcedId);
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url AND vs.myVersion IS NULL") @Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url AND vs.myVersion IS NULL")

View File

@ -47,7 +47,6 @@ import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept; import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation; import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.NpmPackageEntity; import ca.uhn.fhir.jpa.model.entity.NpmPackageEntity;
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity; import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity;
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionResourceEntity; import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionResourceEntity;
@ -174,7 +173,6 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobFileEntity.class, requestPartitionId)); expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobFileEntity.class, requestPartitionId));
counter.addAndGet( counter.addAndGet(
expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobEntity.class, requestPartitionId)); expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobEntity.class, requestPartitionId));
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ForcedId.class, requestPartitionId));
counter.addAndGet(expungeEverythingByTypeWithoutPurging( counter.addAndGet(expungeEverythingByTypeWithoutPurging(
theRequest, ResourceIndexedSearchParamDate.class, requestPartitionId)); theRequest, ResourceIndexedSearchParamDate.class, requestPartitionId));
counter.addAndGet(expungeEverythingByTypeWithoutPurging( counter.addAndGet(expungeEverythingByTypeWithoutPurging(

View File

@ -27,7 +27,6 @@ import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService; import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.IJpaStorageResourceParser; import ca.uhn.fhir.jpa.dao.IJpaStorageResourceParser;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryProvenanceDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryProvenanceDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao;
@ -46,7 +45,6 @@ import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTagDao; import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao; import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
import ca.uhn.fhir.jpa.model.dao.JpaPid; import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.MemoryCacheService; import ca.uhn.fhir.jpa.util.MemoryCacheService;
@ -79,9 +77,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid> { public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid> {
private static final Logger ourLog = LoggerFactory.getLogger(JpaResourceExpungeService.class); private static final Logger ourLog = LoggerFactory.getLogger(JpaResourceExpungeService.class);
@Autowired
private IForcedIdDao myForcedIdDao;
@Autowired @Autowired
private IResourceTableDao myResourceTableDao; private IResourceTableDao myResourceTableDao;
@ -323,11 +318,6 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
myResourceTagDao.deleteByResourceId(resource.getId()); myResourceTagDao.deleteByResourceId(resource.getId());
} }
if (resource.getForcedId() != null) {
ForcedId forcedId = resource.getForcedId();
myForcedIdDao.deleteByPid(forcedId.getId());
}
myResourceTableDao.deleteByPid(resource.getId()); myResourceTableDao.deleteByPid(resource.getId());
} catch (DataIntegrityViolationException e) { } catch (DataIntegrityViolationException e) {
throw new PreconditionFailedException(Msg.code(2415) throw new PreconditionFailedException(Msg.code(2415)

View File

@ -44,7 +44,6 @@ public class ResourceTableFKProvider {
retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", "RES_PID")); retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", "RES_PID"));
// These have the possibility of touching all resource types. // These have the possibility of touching all resource types.
retval.add(new ResourceForeignKey("HFJ_FORCED_ID", "RESOURCE_PID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID")); retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", "RES_ID")); retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID")); retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID"));
@ -83,7 +82,6 @@ public class ResourceTableFKProvider {
// These have the possibility of touching all resource types. // These have the possibility of touching all resource types.
retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", "RES_ID")); retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", "RES_PID")); retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", "RES_PID"));
retval.add(new ResourceForeignKey("HFJ_FORCED_ID", "RESOURCE_PID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID")); retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", "RES_ID")); retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID")); retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID"));

View File

@ -58,7 +58,7 @@ public class TermConceptMapGroupElementTarget implements Serializable {
foreignKey = @ForeignKey(name = "FK_TCMGETARGET_ELEMENT")) foreignKey = @ForeignKey(name = "FK_TCMGETARGET_ELEMENT"))
private TermConceptMapGroupElement myConceptMapGroupElement; private TermConceptMapGroupElement myConceptMapGroupElement;
@Column(name = "TARGET_CODE", nullable = false, length = TermConcept.MAX_CODE_LENGTH) @Column(name = "TARGET_CODE", nullable = true, length = TermConcept.MAX_CODE_LENGTH)
private String myCode; private String myCode;
@Column(name = "TARGET_DISPLAY", nullable = true, length = TermConcept.MAX_DISP_LENGTH) @Column(name = "TARGET_DISPLAY", nullable = true, length = TermConcept.MAX_DISP_LENGTH)

View File

@ -119,6 +119,26 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
init680(); init680();
init680_Part2(); init680_Part2();
init700(); init700();
init720();
}
protected void init720() {
// Start of migrations from 7.0 to 7.2
Builder version = forVersion(VersionEnum.V7_2_0);
// allow null codes in concept map targets
version.onTable("TRM_CONCEPT_MAP_GRP_ELM_TGT")
.modifyColumn("20240327.1", "TARGET_CODE")
.nullable()
.withType(ColumnTypeEnum.STRING, 500);
// Stop writing to hfj_forced_id https://github.com/hapifhir/hapi-fhir/pull/5817
Builder.BuilderWithTableName forcedId = version.onTable("HFJ_FORCED_ID");
forcedId.dropForeignKey("20240402.1", "FK_FORCEDID_RESOURCE", "HFJ_RESOURCE");
forcedId.dropIndex("20240402.2", "IDX_FORCEDID_RESID");
forcedId.dropIndex("20240402.3", "IDX_FORCEDID_TYPE_FID");
forcedId.dropIndex("20240402.4", "IDX_FORCEID_FID");
} }
protected void init700() { protected void init700() {
@ -1398,9 +1418,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
.addIndex("20211210.4", "FK_FORCEDID_RESOURCE") .addIndex("20211210.4", "FK_FORCEDID_RESOURCE")
.unique(true) .unique(true)
.withColumns("RESOURCE_PID") .withColumns("RESOURCE_PID")
.doNothing() // This migration was added in error, as this table already has a unique constraint on
// RESOURCE_PID and every database creates an index on anything that is unique. // RESOURCE_PID and every database creates an index on anything that is unique.
.onlyAppliesToPlatforms(NON_AUTOMATIC_FK_INDEX_PLATFORMS); .onlyAppliesToPlatforms(NON_AUTOMATIC_FK_INDEX_PLATFORMS)
.doNothing(); // This migration was added in error, as this table already has a unique constraint on
} }
private void init570() { private void init570() {

View File

@ -51,6 +51,7 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Enumerations;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -416,6 +417,10 @@ public class TermConceptClientMappingSvcImpl implements ITermConceptClientMappin
theTranslationResult.setResult(false); theTranslationResult.setResult(false);
msg = myContext.getLocalizer().getMessage(TermConceptMappingSvcImpl.class, "noMatchesFound"); msg = myContext.getLocalizer().getMessage(TermConceptMappingSvcImpl.class, "noMatchesFound");
theTranslationResult.setMessage(msg); theTranslationResult.setMessage(msg);
} else if (isOnlyNegativeMatches(theTranslationResult)) {
theTranslationResult.setResult(false);
msg = myContext.getLocalizer().getMessage(TermConceptMappingSvcImpl.class, "onlyNegativeMatchesFound");
theTranslationResult.setMessage(msg);
} else { } else {
theTranslationResult.setResult(true); theTranslationResult.setResult(true);
msg = myContext.getLocalizer().getMessage(TermConceptMappingSvcImpl.class, "matchesFound"); msg = myContext.getLocalizer().getMessage(TermConceptMappingSvcImpl.class, "matchesFound");
@ -423,6 +428,21 @@ public class TermConceptClientMappingSvcImpl implements ITermConceptClientMappin
} }
} }
/**
* Evaluates whether a translation result contains any positive matches or only negative ones. This is required
* because the <a href="https://hl7.org/fhir/R4/conceptmap-operation-translate.html">FHIR specification</a> states
* that the result field "can only be true if at least one returned match has an equivalence which is not unmatched
* or disjoint".
* @param theTranslationResult the translation result to be evaluated
* @return true if all the potential matches in the result have a negative valence (i.e., "unmatched" and "disjoint")
*/
private boolean isOnlyNegativeMatches(TranslateConceptResults theTranslationResult) {
return theTranslationResult.getResults().stream()
.map(TranslateConceptResult::getEquivalence)
.allMatch(t -> StringUtils.equals(Enumerations.ConceptMapEquivalence.UNMATCHED.toCode(), t)
|| StringUtils.equals(Enumerations.ConceptMapEquivalence.DISJOINT.toCode(), t));
}
private boolean alreadyContainsMapping( private boolean alreadyContainsMapping(
List<TranslateConceptResult> elements, TranslateConceptResult translationMatch) { List<TranslateConceptResult> elements, TranslateConceptResult translationMatch) {
for (TranslateConceptResult nextExistingElement : elements) { for (TranslateConceptResult nextExistingElement : elements) {

View File

@ -41,6 +41,7 @@ import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.StringType;
@ -218,13 +219,17 @@ public class TermConceptMappingSvcImpl extends TermConceptClientMappingSvcImpl i
if (element.hasTarget()) { if (element.hasTarget()) {
TermConceptMapGroupElementTarget termConceptMapGroupElementTarget; TermConceptMapGroupElementTarget termConceptMapGroupElementTarget;
for (ConceptMap.TargetElementComponent elementTarget : element.getTarget()) { for (ConceptMap.TargetElementComponent elementTarget : element.getTarget()) {
if (isBlank(elementTarget.getCode())) { if (isBlank(elementTarget.getCode())
&& elementTarget.getEquivalence()
!= Enumerations.ConceptMapEquivalence.UNMATCHED) {
continue; continue;
} }
termConceptMapGroupElementTarget = new TermConceptMapGroupElementTarget(); termConceptMapGroupElementTarget = new TermConceptMapGroupElementTarget();
termConceptMapGroupElementTarget.setConceptMapGroupElement(termConceptMapGroupElement); termConceptMapGroupElementTarget.setConceptMapGroupElement(termConceptMapGroupElement);
termConceptMapGroupElementTarget.setCode(elementTarget.getCode()); if (isNotBlank(elementTarget.getCode())) {
termConceptMapGroupElementTarget.setDisplay(elementTarget.getDisplay()); termConceptMapGroupElementTarget.setCode(elementTarget.getCode());
termConceptMapGroupElementTarget.setDisplay(elementTarget.getDisplay());
}
termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence()); termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence());
termConceptMapGroupElement termConceptMapGroupElement
.getConceptMapGroupElementTargets() .getConceptMapGroupElementTargets()

View File

@ -1,5 +1,5 @@
-- we can't use convering index until the autovacuum runs for those rows, which kills index performance -- we can't use covering index until the autovacuum runs for those rows, which kills index performance
ALTER TABLE hfj_resource SET (autovacuum_vacuum_scale_factor = 0.01); ALTER TABLE hfj_resource SET (autovacuum_vacuum_scale_factor = 0.01);
ALTER TABLE hfj_forced_id SET (autovacuum_vacuum_scale_factor = 0.01); ALTER TABLE hfj_forced_id SET (autovacuum_vacuum_scale_factor = 0.01);
ALTER TABLE hfj_res_link SET (autovacuum_vacuum_scale_factor = 0.01); ALTER TABLE hfj_res_link SET (autovacuum_vacuum_scale_factor = 0.01);

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -29,7 +29,6 @@ import jakarta.persistence.Enumerated;
import jakarta.persistence.MappedSuperclass; import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Temporal; import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import jakarta.persistence.Transient;
import org.hibernate.annotations.OptimisticLock; import org.hibernate.annotations.OptimisticLock;
import java.util.Collection; import java.util.Collection;
@ -65,22 +64,6 @@ public abstract class BaseHasResource extends BasePartitionable
@OptimisticLock(excluded = true) @OptimisticLock(excluded = true)
private Date myUpdated; private Date myUpdated;
/**
* This is stored as an optimization to avoid needing to query for this
* after an update
*/
@Transient
// TODO MB forced_id delete this in step 3
private transient String myTransientForcedId;
public String getTransientForcedId() {
return myTransientForcedId;
}
public void setTransientForcedId(String theTransientForcedId) {
myTransientForcedId = theTransientForcedId;
}
public abstract BaseTag addTag(TagDefinition theDef); public abstract BaseTag addTag(TagDefinition theDef);
@Override @Override
@ -97,13 +80,6 @@ public abstract class BaseHasResource extends BasePartitionable
myFhirVersion = theFhirVersion; myFhirVersion = theFhirVersion;
} }
public abstract ForcedId getForcedId();
public abstract void setForcedId(ForcedId theForcedId);
@Override
public abstract Long getId();
public void setDeleted(Date theDate) { public void setDeleted(Date theDate) {
myDeleted = theDate; myDeleted = theDate;
} }
@ -129,12 +105,6 @@ public abstract class BaseHasResource extends BasePartitionable
myPublished = thePublished.getValue(); myPublished = thePublished.getValue();
} }
@Override
public abstract Long getResourceId();
@Override
public abstract String getResourceType();
public abstract Collection<? extends BaseTag> getTags(); public abstract Collection<? extends BaseTag> getTags();
@Override @Override
@ -151,9 +121,6 @@ public abstract class BaseHasResource extends BasePartitionable
myUpdated = theUpdated; myUpdated = theUpdated;
} }
@Override
public abstract long getVersion();
@Override @Override
public boolean isHasTags() { public boolean isHasTags() {
return myHasTags; return myHasTags;

View File

@ -21,51 +21,24 @@ package ca.uhn.fhir.jpa.model.entity;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType; import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator; import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
/**
* The old way we handled client-assigned resource ids.
* Replaced by {@link ResourceTable#myFhirId}.
* @deprecated This is unused, and only kept for history and upgrade migration testing.
*/
@Entity() @Entity()
@Table( @Table(name = ForcedId.HFJ_FORCED_ID)
name = ForcedId.HFJ_FORCED_ID, @Deprecated(since = "7.1", forRemoval = true)
uniqueConstraints = { class ForcedId extends BasePartitionable {
@UniqueConstraint(
name = "IDX_FORCEDID_RESID",
columnNames = {"RESOURCE_PID"}),
/*
* This index is called IDX_FORCEDID_TYPE_FID and guarantees
* uniqueness of RESOURCE_TYPE,FORCED_ID. This doesn't make sense
* for partitioned servers, so we replace it on those servers
* with IDX_FORCEDID_TYPE_PFID covering
* PARTITION_ID,RESOURCE_TYPE,FORCED_ID
*/
@UniqueConstraint(
name = ForcedId.IDX_FORCEDID_TYPE_FID,
columnNames = {"RESOURCE_TYPE", "FORCED_ID"})
},
indexes = {
/*
* NB: We previously had indexes named
* - IDX_FORCEDID_TYPE_FORCEDID
* - IDX_FORCEDID_TYPE_RESID
* so don't reuse these names
*/
@Index(name = "IDX_FORCEID_FID", columnList = "FORCED_ID"),
// @Index(name = "IDX_FORCEID_RESID", columnList = "RESOURCE_PID"),
})
public class ForcedId extends BasePartitionable {
public static final int MAX_FORCED_ID_LENGTH = 100; public static final int MAX_FORCED_ID_LENGTH = 100;
public static final String IDX_FORCEDID_TYPE_FID = "IDX_FORCEDID_TYPE_FID"; public static final String IDX_FORCEDID_TYPE_FID = "IDX_FORCEDID_TYPE_FID";
@ -80,14 +53,6 @@ public class ForcedId extends BasePartitionable {
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;
@JoinColumn(
name = "RESOURCE_PID",
nullable = false,
updatable = false,
foreignKey = @ForeignKey(name = "FK_FORCEDID_RESOURCE"))
@OneToOne(fetch = FetchType.LAZY)
private ResourceTable myResource;
@Column(name = "RESOURCE_PID", nullable = false, updatable = false, insertable = false) @Column(name = "RESOURCE_PID", nullable = false, updatable = false, insertable = false)
private Long myResourcePid; private Long myResourcePid;
@ -112,10 +77,6 @@ public class ForcedId extends BasePartitionable {
myForcedId = theForcedId; myForcedId = theForcedId;
} }
public void setResource(ResourceTable theResource) {
myResource = theResource;
}
public String getResourceType() { public String getResourceType() {
return myResourceType; return myResourceType;
} }

View File

@ -22,7 +22,26 @@ package ca.uhn.fhir.jpa.model.entity;
import ca.uhn.fhir.jpa.model.dao.JpaPid; import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import jakarta.persistence.*; import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.Lob;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import jakarta.persistence.UniqueConstraint;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.Length; import org.hibernate.Length;
@ -111,6 +130,12 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
@Transient @Transient
private transient ResourceHistoryProvenanceEntity myNewHistoryProvenanceEntity; private transient ResourceHistoryProvenanceEntity myNewHistoryProvenanceEntity;
/**
* This is stored as an optimization to avoid needing to fetch ResourceTable
* to access the resource id.
*/
@Transient
private transient String myTransientForcedId;
/** /**
* Constructor * Constructor
@ -280,16 +305,6 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
return new IdDt(getResourceType() + '/' + resourceIdPart + '/' + Constants.PARAM_HISTORY + '/' + getVersion()); return new IdDt(getResourceType() + '/' + resourceIdPart + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
} }
@Override
public ForcedId getForcedId() {
return getResourceTable().getForcedId();
}
@Override
public void setForcedId(ForcedId theForcedId) {
getResourceTable().setForcedId(theForcedId);
}
/** /**
* Returns <code>true</code> if there is a populated resource text (i.e. * Returns <code>true</code> if there is a populated resource text (i.e.
* either {@link #getResource()} or {@link #getResourceTextVc()} return a non null * either {@link #getResource()} or {@link #getResourceTextVc()} return a non null
@ -311,4 +326,12 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
} }
return myNewHistoryProvenanceEntity; return myNewHistoryProvenanceEntity;
} }
public String getTransientForcedId() {
return myTransientForcedId;
}
public void setTransientForcedId(String theTransientForcedId) {
myTransientForcedId = theTransientForcedId;
}
} }

View File

@ -38,7 +38,6 @@ import jakarta.persistence.Id;
import jakarta.persistence.Index; import jakarta.persistence.Index;
import jakarta.persistence.NamedEntityGraph; import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.PostPersist; import jakarta.persistence.PostPersist;
import jakarta.persistence.PrePersist; import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate; import jakarta.persistence.PreUpdate;
@ -420,15 +419,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
@Transient @Transient
private transient boolean myVersionUpdatedInCurrentTransaction; private transient boolean myVersionUpdatedInCurrentTransaction;
@OneToOne(
optional = true,
fetch = FetchType.EAGER,
cascade = {},
orphanRemoval = false,
mappedBy = "myResource")
@OptimisticLock(excluded = true)
private ForcedId myForcedId;
@Transient @Transient
private volatile String myCreatedByMatchUrl; private volatile String myCreatedByMatchUrl;
@ -889,10 +879,9 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
retVal.setResourceId(myId); retVal.setResourceId(myId);
retVal.setResourceType(myResourceType); retVal.setResourceType(myResourceType);
retVal.setTransientForcedId(getTransientForcedId()); retVal.setTransientForcedId(getFhirId());
retVal.setFhirVersion(getFhirVersion()); retVal.setFhirVersion(getFhirVersion());
retVal.setResourceTable(this); retVal.setResourceTable(this);
retVal.setForcedId(getForcedId());
retVal.setPartitionId(getPartitionId()); retVal.setPartitionId(getPartitionId());
retVal.setHasTags(isHasTags()); retVal.setHasTags(isHasTags());
@ -923,6 +912,7 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
public String toString() { public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("pid", myId); b.append("pid", myId);
b.append("fhirId", myFhirId);
b.append("resourceType", myResourceType); b.append("resourceType", myResourceType);
b.append("version", myVersion); b.append("version", myVersion);
if (getPartitionId() != null) { if (getPartitionId() != null) {
@ -970,16 +960,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
return JpaPid.fromId(getId()); return JpaPid.fromId(getId());
} }
@Override
public ForcedId getForcedId() {
return myForcedId;
}
@Override
public void setForcedId(ForcedId theForcedId) {
myForcedId = theForcedId;
}
@Override @Override
public IdDt getIdDt() { public IdDt getIdDt() {
IdDt retVal = new IdDt(); IdDt retVal = new IdDt();
@ -997,10 +977,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
String resourceId; String resourceId;
if (myFhirId != null && !myFhirId.isEmpty()) { if (myFhirId != null && !myFhirId.isEmpty()) {
resourceId = myFhirId; resourceId = myFhirId;
} else if (getTransientForcedId() != null) {
resourceId = getTransientForcedId();
} else if (myForcedId != null) {
resourceId = myForcedId.getForcedId();
} else { } else {
Long id = this.getResourceId(); Long id = this.getResourceId();
resourceId = Long.toString(id); resourceId = Long.toString(id);

View File

@ -25,17 +25,15 @@ public class ResourceTableTest {
@ParameterizedTest @ParameterizedTest
@CsvSource(value={ @CsvSource(value={
"123, null, Patient/123/_history/1",
"123, 123, Patient/123/_history/1", "123, 123, Patient/123/_history/1",
", 123, Patient/123/_history/1", "123, 456, Patient/456/_history/1"
"null, 456, Patient/456/_history/1"
},nullValues={"null"}) },nullValues={"null"})
public void testPopulateId(String theFhirId, String theForcedId, String theExpected) { public void testPopulateId(Long theResId, String theFhirId, String theExpected) {
// Given // Given
ResourceTable t = new ResourceTable(); ResourceTable t = new ResourceTable();
t.setId(theResId);
t.setFhirId(theFhirId); t.setFhirId(theFhirId);
ForcedId forcedId = new ForcedId();
forcedId.setForcedId(theForcedId);
t.setForcedId(forcedId);
t.setResourceType(new Patient().getResourceType().name()); t.setResourceType(new Patient().getResourceType().name());
t.setVersionForUnitTest(1); t.setVersionForUnitTest(1);

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -6,7 +6,6 @@ import ca.uhn.fhir.jpa.api.model.HistoryCountModeEnum;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.BaseStorageDao; import ca.uhn.fhir.jpa.dao.BaseStorageDao;
import ca.uhn.fhir.jpa.dao.DaoTestUtils; import ca.uhn.fhir.jpa.dao.DaoTestUtils;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.model.dao.JpaPid; import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
@ -82,7 +81,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -112,8 +110,6 @@ import static org.junit.jupiter.api.Assertions.fail;
public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test { public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2Test.class);
@Autowired
private IForcedIdDao myForcedIdDao;
@AfterEach @AfterEach
public final void after() { public final void after() {
@ -995,9 +991,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
idv2 = myPatientDao.update(patient, mySrd).getId(); idv2 = myPatientDao.update(patient, mySrd).getId();
} }
runInTransaction(() -> { logAllResources();
ourLog.info("Forced IDs:\n{}", myForcedIdDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n")));
});
List<Patient> patients = toList(myPatientDao.history(idv1.toVersionless(), null, null, null, mySrd)); List<Patient> patients = toList(myPatientDao.history(idv1.toVersionless(), null, null, null, mySrd));
assertTrue(patients.size() == 2); assertTrue(patients.size() == 2);

View File

@ -0,0 +1,67 @@
package ca.uhn.fhir.jpa.provider;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ResourceProviderLanguageParamDstu2Test extends BaseResourceProviderDstu2Test {
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamEnabled() {
myStorageSettings.setLanguageSearchParameterEnabled(true);
mySearchParamRegistry.forceRefresh();
Patient pat = new Patient();
pat.setLanguage(new CodeDt("en"));
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient();
pat.setLanguage(new CodeDt("fr"));
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
List<String> foundResources;
Bundle result;
result = myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
foundResources = toUnqualifiedVersionlessIdValues(result);
assertThat(foundResources, contains(patId.getValue()));
}
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamDisabled() {
myStorageSettings.setLanguageSearchParameterEnabled(new JpaStorageSettings().isLanguageSearchParameterEnabled());
mySearchParamRegistry.forceRefresh();
InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> {
myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
});
assertThat(exception.getMessage(), containsString(Msg.code(1223)));
}
}

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -626,16 +626,9 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
.getSingleResult(); .getSingleResult();
assertNotNull(readBackView, "found search view"); assertNotNull(readBackView, "found search view");
// verify the forced id join still works assertEquals(myExpectedId, readBackView.getFhirId(),
if (readBackResource.getForcedId() != null) { "fhir_id populated");
assertEquals(myExpectedId, readBackResource.getForcedId().getForcedId(), }
"legacy join populated");
assertEquals(myExpectedId, readBackView.getFhirId(),
"legacy join populated");
} else {
assertEquals(IdStrategyEnum.SEQUENTIAL_NUMERIC, theServerIdStrategy,
"hfj_forced_id join column is only empty when using server-assigned ids");
} }
} }
@Test @Test

View File

@ -0,0 +1,84 @@
package ca.uhn.fhir.jpa.provider.dstu3;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Patient;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ResourceProviderLanguageParamDstu3Test extends BaseResourceProviderDstu3Test {
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamEnabled() {
myStorageSettings.setLanguageSearchParameterEnabled(true);
mySearchParamRegistry.forceRefresh();
Patient pat = new Patient();
pat.setLanguage("en");
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient();
pat.setLanguage("fr");
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap map;
IBundleProvider results;
List<String> foundResources;
Bundle result;
result = myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
foundResources = toUnqualifiedVersionlessIdValues(result);
assertThat(foundResources, contains(patId.getValue()));
}
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamDisabled() {
myStorageSettings.setLanguageSearchParameterEnabled(new JpaStorageSettings().isLanguageSearchParameterEnabled());
mySearchParamRegistry.forceRefresh();
Patient pat = new Patient();
pat.setLanguage("en");
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient();
pat.setLanguage("fr");
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap map;
IBundleProvider results;
List<String> foundResources;
Bundle result;
InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> {
myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
});
assertThat(exception.getMessage(), containsString(Msg.code(1223)));
}
}

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -321,6 +321,61 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test {
} }
} }
@Test
public void reductionStepFailing_willFailJob() throws InterruptedException {
// setup
String jobId = new Exception().getStackTrace()[0].getMethodName();
int totalChunks = 3;
AtomicInteger chunkCounter = new AtomicInteger();
String error = "this is an error";
buildAndDefine3StepReductionJob(jobId, new IReductionStepHandler() {
@Override
public void firstStep(StepExecutionDetails<TestJobParameters, VoidModel> theStep, IJobDataSink<FirstStepOutput> theDataSink) {
for (int i = 0; i < totalChunks; i++) {
theDataSink.accept(new FirstStepOutput());
}
}
@Override
public void secondStep(StepExecutionDetails<TestJobParameters, FirstStepOutput> theStep, IJobDataSink<SecondStepOutput> theDataSink) {
SecondStepOutput output = new SecondStepOutput();
theDataSink.accept(output);
}
@Override
public void reductionStepConsume(ChunkExecutionDetails<TestJobParameters, SecondStepOutput> theChunkDetails, IJobDataSink<ReductionStepOutput> theDataSink) {
chunkCounter.getAndIncrement();
}
@Override
public void reductionStepRun(StepExecutionDetails<TestJobParameters, SecondStepOutput> theStepExecutionDetails, IJobDataSink<ReductionStepOutput> theDataSink) {
// always throw
throw new RuntimeException(error);
}
});
// test
JobInstanceStartRequest request = buildRequest(jobId);
myFirstStepLatch.setExpectedCount(1);
Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request);
String instanceId = startResponse.getInstanceId();
assertNotNull(instanceId);
// waiting for job to end (any status - but we'll verify failed later)
myBatch2JobHelper.awaitJobHasStatus(instanceId, StatusEnum.getEndedStatuses().toArray(new StatusEnum[0]));
// verify
Optional<JobInstance> instanceOp = myJobPersistence.fetchInstance(instanceId);
assertTrue(instanceOp.isPresent());
JobInstance jobInstance = instanceOp.get();
assertEquals(totalChunks, chunkCounter.get());
assertEquals(StatusEnum.FAILED, jobInstance.getStatus());
}
@Test @Test
public void testJobWithReductionStepFiresCompletionHandler() throws InterruptedException { public void testJobWithReductionStepFiresCompletionHandler() throws InterruptedException {
// setup // setup

View File

@ -3,7 +3,6 @@ package ca.uhn.fhir.jpa.bulk.imprt2;
import ca.uhn.fhir.batch2.api.JobExecutionFailedException; import ca.uhn.fhir.batch2.api.JobExecutionFailedException;
import ca.uhn.fhir.batch2.jobs.imprt.ConsumeFilesStep; import ca.uhn.fhir.batch2.jobs.imprt.ConsumeFilesStep;
import ca.uhn.fhir.interceptor.model.RequestPartitionId; import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.dao.r4.BasePartitioningR4Test; import ca.uhn.fhir.jpa.dao.r4.BasePartitioningR4Test;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
@ -84,7 +83,7 @@ public class ConsumeFilesStepR4Test extends BasePartitioningR4Test {
// Validate // Validate
assertEquals(7, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(6, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread(), myCaptureQueriesListener.getInsertQueriesForCurrentThread().stream().map(t->t.getSql(true, false)).collect(Collectors.joining("\n"))); assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread(), myCaptureQueriesListener.getInsertQueriesForCurrentThread().stream().map(t->t.getSql(true, false)).collect(Collectors.joining("\n")));
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
@ -145,9 +144,9 @@ public class ConsumeFilesStepR4Test extends BasePartitioningR4Test {
// Validate // Validate
if (partitionEnabled) { if (partitionEnabled) {
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
} else {
assertEquals(7, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(7, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
} else {
assertEquals(6, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
} }
assertEquals(2, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(2, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(4, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(4, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
@ -190,7 +189,7 @@ public class ConsumeFilesStepR4Test extends BasePartitioningR4Test {
assertThat(myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false), assertThat(myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false),
either(containsString("rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='B' and rt1_0.PARTITION_ID is null or rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='A' and rt1_0.PARTITION_ID is null")) either(containsString("rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='B' and rt1_0.PARTITION_ID is null or rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='A' and rt1_0.PARTITION_ID is null"))
.or(containsString("rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='A' and rt1_0.PARTITION_ID is null or rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='B' and rt1_0.PARTITION_ID is null"))); .or(containsString("rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='A' and rt1_0.PARTITION_ID is null or rt1_0.RES_TYPE='Patient' and rt1_0.FHIR_ID='B' and rt1_0.PARTITION_ID is null")));
assertEquals(52, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(50, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
assertEquals(1, myCaptureQueriesListener.countCommits()); assertEquals(1, myCaptureQueriesListener.countCommits());

View File

@ -19,7 +19,6 @@ import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService;
import ca.uhn.fhir.jpa.delete.DeleteConflictService; import ca.uhn.fhir.jpa.delete.DeleteConflictService;
import ca.uhn.fhir.jpa.model.dao.JpaPid; import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.jpa.search.ResourceSearchUrlSvc; import ca.uhn.fhir.jpa.search.ResourceSearchUrlSvc;
@ -227,7 +226,8 @@ class BaseHapiFhirResourceDaoTest {
RequestPartitionId partitionId = Mockito.mock(RequestPartitionId.class); RequestPartitionId partitionId = Mockito.mock(RequestPartitionId.class);
JpaPid jpaPid = JpaPid.fromIdAndVersion(123L, 1L); JpaPid jpaPid = JpaPid.fromIdAndVersion(123L, 1L);
ResourceTable entity = new ResourceTable(); ResourceTable entity = new ResourceTable();
entity.setForcedId(new ForcedId()); entity.setId(123L);
entity.setFhirId("456");
// mock // mock
when(myRequestPartitionHelperSvc.determineReadPartitionForRequestForRead( when(myRequestPartitionHelperSvc.determineReadPartitionForRequestForRead(

View File

@ -7,7 +7,6 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc; import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
@ -30,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import static ca.uhn.fhir.jpa.model.entity.ResourceTable.IDX_RES_TYPE_FHIR_ID;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -61,13 +61,6 @@ public abstract class BasePartitioningR4Test extends BaseJpaR4SystemTest {
mySrdInterceptorService.unregisterInterceptorsIf(t -> t instanceof MyReadWriteInterceptor); mySrdInterceptorService.unregisterInterceptorsIf(t -> t instanceof MyReadWriteInterceptor);
if (myHaveDroppedForcedIdUniqueConstraint) {
runInTransaction(() -> {
myEntityManager.createNativeQuery("delete from HFJ_FORCED_ID").executeUpdate();
myEntityManager.createNativeQuery("alter table HFJ_FORCED_ID add constraint IDX_FORCEDID_TYPE_FID unique (RESOURCE_TYPE, FORCED_ID)");
});
}
myStorageSettings.setIndexMissingFields(new JpaStorageSettings().getIndexMissingFields()); myStorageSettings.setIndexMissingFields(new JpaStorageSettings().getIndexMissingFields());
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(new JpaStorageSettings().isAutoCreatePlaceholderReferenceTargets()); myStorageSettings.setAutoCreatePlaceholderReferenceTargets(new JpaStorageSettings().isAutoCreatePlaceholderReferenceTargets());
myStorageSettings.setMassIngestionMode(new JpaStorageSettings().isMassIngestionMode()); myStorageSettings.setMassIngestionMode(new JpaStorageSettings().isMassIngestionMode());
@ -106,6 +99,18 @@ public abstract class BasePartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Override
public void afterPurgeDatabase() {
super.afterPurgeDatabase();
if (myHaveDroppedForcedIdUniqueConstraint) {
runInTransaction(() -> {
myEntityManager.createNativeQuery("delete from HFJ_RESOURCE").executeUpdate();
myEntityManager.createNativeQuery("alter table " + ResourceTable.HFJ_RESOURCE +
" add constraint " + IDX_RES_TYPE_FHIR_ID + " unique (RES_TYPE, FHIR_ID)").executeUpdate();
});
}
}
protected void createUniqueCompositeSp() { protected void createUniqueCompositeSp() {
addCreateDefaultPartition(); addCreateDefaultPartition();
addReadDefaultPartition(); // one for search param validation addReadDefaultPartition(); // one for search param validation
@ -137,8 +142,7 @@ public abstract class BasePartitioningR4Test extends BaseJpaR4SystemTest {
protected void dropForcedIdUniqueConstraint() { protected void dropForcedIdUniqueConstraint() {
runInTransaction(() -> { runInTransaction(() -> {
myEntityManager.createNativeQuery("alter table " + ForcedId.HFJ_FORCED_ID + " drop constraint " + ForcedId.IDX_FORCEDID_TYPE_FID).executeUpdate(); myEntityManager.createNativeQuery("alter table " + ResourceTable.HFJ_RESOURCE + " drop constraint " + IDX_RES_TYPE_FHIR_ID).executeUpdate();
myEntityManager.createNativeQuery("alter table " + ResourceTable.HFJ_RESOURCE + " drop constraint " + ResourceTable.IDX_RES_TYPE_FHIR_ID).executeUpdate();
}); });
myHaveDroppedForcedIdUniqueConstraint = true; myHaveDroppedForcedIdUniqueConstraint = true;
} }

View File

@ -20,7 +20,6 @@ import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum; import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.interceptor.ForceOffsetSearchModeInterceptor; import ca.uhn.fhir.jpa.interceptor.ForceOffsetSearchModeInterceptor;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
@ -47,6 +46,7 @@ import ca.uhn.fhir.test.utilities.ProxyUtil;
import ca.uhn.fhir.test.utilities.server.HashMapResourceProviderExtension; import ca.uhn.fhir.test.utilities.server.HashMapResourceProviderExtension;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
import ca.uhn.fhir.util.BundleBuilder; import ca.uhn.fhir.util.BundleBuilder;
import jakarta.annotation.Nonnull;
import org.hamcrest.CoreMatchers; import org.hamcrest.CoreMatchers;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -90,7 +90,6 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.util.comparator.ComparableComparator; import org.springframework.util.comparator.ComparableComparator;
import jakarta.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -150,7 +149,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
@Autowired @Autowired
private ISubscriptionTriggeringSvc mySubscriptionTriggeringSvc; private ISubscriptionTriggeringSvc mySubscriptionTriggeringSvc;
@Autowired @Autowired
private ResourceModifiedSubmitterSvc myResourceModifiedSubmitterSvc;; private ResourceModifiedSubmitterSvc myResourceModifiedSubmitterSvc;
@Autowired @Autowired
private ReindexStep myReindexStep; private ReindexStep myReindexStep;
@Autowired @Autowired
@ -221,7 +220,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty()))); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty())));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty()))); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty())));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), not(empty())));
logAllResources(); logAllResources();
@ -242,11 +240,10 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(47, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(47, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(85, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(80, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
} }
@ -328,7 +325,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
Group group = createGroup(patientList.subList(0, initialPatientsCount)); Group group = createGroup(patientList.subList(0, initialPatientsCount));
assertQueryCount(31, 0, 4, 0); assertQueryCount(31, 0, 3, 0);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
group = updateGroup(group, patientList.subList(initialPatientsCount, allPatientsCount)); group = updateGroup(group, patientList.subList(initialPatientsCount, allPatientsCount));
@ -350,7 +347,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
Group group = createGroup(patientList); Group group = createGroup(patientList);
assertQueryCount(31, 0, 4, 0); assertQueryCount(31, 0, 3, 0);
// Make a change to the group, but don't touch any references in it // Make a change to the group, but don't touch any references in it
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
@ -672,7 +669,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size()); assertEquals(3, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
myCaptureQueriesListener.logDeleteQueriesForCurrentThread(); myCaptureQueriesListener.logDeleteQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
@ -705,24 +702,20 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size()); assertEquals(3, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
myCaptureQueriesListener.logDeleteQueriesForCurrentThread(); myCaptureQueriesListener.logDeleteQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
runInTransaction(() -> { runInTransaction(() -> {
List<ForcedId> allForcedIds = myForcedIdDao.findAll();
for (ForcedId next : allForcedIds) {
assertNotNull(next.getResourceId());
assertNotNull(next.getForcedId());
}
List<ResourceTable> resources = myResourceTableDao.findAll(); List<ResourceTable> resources = myResourceTableDao.findAll();
String versions = "Resource Versions:\n * " + resources.stream().map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion()).collect(Collectors.joining("\n * ")); String versions = "Resource Versions:\n * " + resources.stream().map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion()).collect(Collectors.joining("\n * "));
for (ResourceTable next : resources) { for (ResourceTable next : resources) {
assertEquals(1, next.getVersion(), versions); assertEquals(1, next.getVersion(), versions);
assertNotNull(next.getResourceId());
assertNotNull(next.getFhirId());
} }
}); });
@ -771,22 +764,18 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size()); assertEquals(3, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
myCaptureQueriesListener.logDeleteQueriesForCurrentThread(); myCaptureQueriesListener.logDeleteQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
runInTransaction(() -> { runInTransaction(() -> {
List<ForcedId> allForcedIds = myForcedIdDao.findAll();
for (ForcedId next : allForcedIds) {
assertNotNull(next.getResourceId());
assertNotNull(next.getForcedId());
}
List<ResourceTable> resources = myResourceTableDao.findAll(); List<ResourceTable> resources = myResourceTableDao.findAll();
String versions = "Resource Versions:\n * " + resources.stream().map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion()).collect(Collectors.joining("\n * ")); String versions = "Resource Versions:\n * " + resources.stream().map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion()).collect(Collectors.joining("\n * "));
for (ResourceTable next : resources) { for (ResourceTable next : resources) {
assertEquals(1, next.getVersion(), versions); assertEquals(1, next.getVersion(), versions);
assertNotNull(next.getResourceId());
assertNotNull(next.getFhirId());
} }
}); });
@ -819,7 +808,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size()); assertEquals(3, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
myCaptureQueriesListener.logDeleteQueriesForCurrentThread(); myCaptureQueriesListener.logDeleteQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size()); assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
} }
@ -838,7 +827,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?active=true", new SystemRequestDetails()); DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?active=true", new SystemRequestDetails());
// Validate // Validate
assertEquals(13, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(12, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(10, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(10, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(10, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(10, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(30, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(30, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
@ -856,7 +845,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
withFamily("Family" + i), withFamily("Family" + i),
withTag("http://foo", "blah")); withTag("http://foo", "blah"));
} }
List<TypedPidJson> pids = runInTransaction(() -> myForcedIdDao List<TypedPidJson> pids = runInTransaction(() -> myResourceTableDao
.findAll() .findAll()
.stream() .stream()
.map(t -> new TypedPidJson(t.getResourceType(), Long.toString(t.getResourceId()))) .map(t -> new TypedPidJson(t.getResourceType(), Long.toString(t.getResourceId())))
@ -874,7 +863,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(29, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(28, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
assertEquals(10, outcome.getRecordsProcessed()); assertEquals(10, outcome.getRecordsProcessed());
runInTransaction(()-> assertEquals(0, myResourceTableDao.count())); runInTransaction(()-> assertEquals(0, myResourceTableDao.count()));
} }
@ -1037,10 +1026,10 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
@ParameterizedTest @ParameterizedTest
@CsvSource({ @CsvSource({
// OptimisticLock OptimizeMode ExpectedSelect ExpectedUpdate // OptimisticLock OptimizeMode ExpectedSelect ExpectedUpdate
" false, CURRENT_VERSION, 2, 0", " false, CURRENT_VERSION, 1, 0",
" true, CURRENT_VERSION, 12, 0", " true, CURRENT_VERSION, 11, 0",
" false, ALL_VERSIONS, 12, 0", " false, ALL_VERSIONS, 11, 0",
" true, ALL_VERSIONS, 22, 0", " true, ALL_VERSIONS, 21, 0",
}) })
public void testReindexJob_OptimizeStorage(boolean theOptimisticLock, ReindexParameters.OptimizeStorageModeEnum theOptimizeStorageModeEnum, int theExpectedSelectCount, int theExpectedUpdateCount) { public void testReindexJob_OptimizeStorage(boolean theOptimisticLock, ReindexParameters.OptimizeStorageModeEnum theOptimizeStorageModeEnum, int theExpectedSelectCount, int theExpectedUpdateCount) {
// Setup // Setup
@ -1839,7 +1828,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(1, myCaptureQueriesListener.countSelectQueries()); assertEquals(1, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(21, myCaptureQueriesListener.countInsertQueries()); assertEquals(18, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
assertEquals(0, myCaptureQueriesListener.countUpdateQueries()); assertEquals(0, myCaptureQueriesListener.countUpdateQueries());
assertEquals(0, myCaptureQueriesListener.countDeleteQueries()); assertEquals(0, myCaptureQueriesListener.countDeleteQueries());
@ -1852,7 +1841,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(5, myCaptureQueriesListener.countSelectQueries()); assertEquals(4, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(2, myCaptureQueriesListener.countInsertQueries()); assertEquals(2, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
@ -1868,7 +1857,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(5, myCaptureQueriesListener.countSelectQueries()); assertEquals(4, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(2, myCaptureQueriesListener.countInsertQueries()); assertEquals(2, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
@ -1925,7 +1914,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
// Search for IDs and Search for tag definition // Search for IDs and Search for tag definition
assertEquals(3, myCaptureQueriesListener.countSelectQueries()); assertEquals(3, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(29, myCaptureQueriesListener.countInsertQueries()); assertEquals(26, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
assertEquals(0, myCaptureQueriesListener.countUpdateQueries()); assertEquals(0, myCaptureQueriesListener.countUpdateQueries());
assertEquals(0, myCaptureQueriesListener.countDeleteQueries()); assertEquals(0, myCaptureQueriesListener.countDeleteQueries());
@ -1938,7 +1927,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(9, myCaptureQueriesListener.countSelectQueries()); assertEquals(7, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(7, myCaptureQueriesListener.countInsertQueries()); assertEquals(7, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
@ -1954,7 +1943,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(7, myCaptureQueriesListener.countSelectQueries()); assertEquals(5, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(5, myCaptureQueriesListener.countInsertQueries()); assertEquals(5, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
@ -2250,7 +2239,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(9, myCaptureQueriesListener.countSelectQueries()); assertEquals(8, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(4, myCaptureQueriesListener.countInsertQueries()); assertEquals(4, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
@ -2267,7 +2256,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(8, myCaptureQueriesListener.countSelectQueries()); assertEquals(7, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(4, myCaptureQueriesListener.countInsertQueries()); assertEquals(4, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
@ -2282,7 +2271,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(6, myCaptureQueriesListener.countSelectQueries()); assertEquals(5, myCaptureQueriesListener.countSelectQueries());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(4, myCaptureQueriesListener.countInsertQueries()); assertEquals(4, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
@ -2453,7 +2442,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(7, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(6, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
@ -3000,7 +2989,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(17, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(17, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(6607, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(6189, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(418, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(418, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
assertEquals(2, myCaptureQueriesListener.countCommits()); assertEquals(2, myCaptureQueriesListener.countCommits());
@ -3368,7 +3357,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
mySystemDao.transaction(new SystemRequestDetails(), supplier.get()); mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(30, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(29, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
@ -3376,7 +3365,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
Bundle outcome = mySystemDao.transaction(new SystemRequestDetails(), supplier.get()); Bundle outcome = mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(6, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(6, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(6, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
@ -3399,7 +3388,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
outcome = mySystemDao.transaction(new SystemRequestDetails(), supplier.get()); outcome = mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(6, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
myCaptureQueriesListener.logInsertQueries(); myCaptureQueriesListener.logInsertQueries();
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(6, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(6, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
@ -3451,7 +3440,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
mySystemDao.transaction(new SystemRequestDetails(), loadResourceFromClasspath(Bundle.class, "r4/transaction-perf-bundle.json")); mySystemDao.transaction(new SystemRequestDetails(), loadResourceFromClasspath(Bundle.class, "r4/transaction-perf-bundle.json"));
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(125, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(120, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
@ -3460,7 +3449,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
mySystemDao.transaction(new SystemRequestDetails(), loadResourceFromClasspath(Bundle.class, "r4/transaction-perf-bundle-smallchanges.json")); mySystemDao.transaction(new SystemRequestDetails(), loadResourceFromClasspath(Bundle.class, "r4/transaction-perf-bundle-smallchanges.json"));
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(6, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(2, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(2, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(5, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(5, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());

View File

@ -31,9 +31,7 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.test.utilities.ProxyUtil; import ca.uhn.fhir.test.utilities.ProxyUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.checkerframework.checker.units.qual.A;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.BodyStructure; import org.hl7.fhir.r4.model.BodyStructure;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
@ -1238,12 +1236,11 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
myPatientDao.update(p).getId().toUnqualifiedVersionless(); myPatientDao.update(p).getId().toUnqualifiedVersionless();
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(3, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
runInTransaction(() -> { runInTransaction(() -> {
assertEquals(1, myResourceTableDao.count()); assertEquals(1, myResourceTableDao.count());
assertEquals(1, myResourceHistoryTableDao.count()); assertEquals(1, myResourceHistoryTableDao.count());
assertEquals(1, myForcedIdDao.count());
assertEquals(1, myResourceIndexedSearchParamTokenDao.count()); assertEquals(1, myResourceIndexedSearchParamTokenDao.count());
}); });
@ -1264,7 +1261,6 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
runInTransaction(() -> { runInTransaction(() -> {
assertEquals(1, myResourceTableDao.count()); assertEquals(1, myResourceTableDao.count());
assertEquals(2, myResourceHistoryTableDao.count()); assertEquals(2, myResourceHistoryTableDao.count());
assertEquals(1, myForcedIdDao.count());
assertEquals(1, myResourceIndexedSearchParamTokenDao.count()); assertEquals(1, myResourceIndexedSearchParamTokenDao.count());
}); });

View File

@ -15,7 +15,6 @@ import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId; import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag;
@ -589,13 +588,13 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
myPatientDao.update(p, mySrd); myPatientDao.update(p, mySrd);
runInTransaction(() -> { runInTransaction(() -> {
// HFJ_FORCED_ID ResourceTable orgResourceTable = myResourceTableDao.findByTypeAndFhirId("Organization", "org").orElseThrow(IllegalArgumentException::new);
List<ForcedId> forcedIds = myForcedIdDao.findAll(); assertEquals(myPartitionId, orgResourceTable.getPartitionId().getPartitionId().intValue());
assertEquals(2, forcedIds.size()); assertLocalDateFromDbMatches(myPartitionDate, orgResourceTable.getPartitionId().getPartitionDate());
assertEquals(myPartitionId, forcedIds.get(0).getPartitionId().getPartitionId().intValue());
assertLocalDateFromDbMatches(myPartitionDate, forcedIds.get(0).getPartitionId().getPartitionDate()); ResourceTable patientResourceTable = myResourceTableDao.findByTypeAndFhirId("Patient", "pat").orElseThrow(IllegalArgumentException::new);
assertEquals(myPartitionId, forcedIds.get(1).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, patientResourceTable.getPartitionId().getPartitionId().intValue());
assertLocalDateFromDbMatches(myPartitionDate, forcedIds.get(1).getPartitionId().getPartitionDate()); assertLocalDateFromDbMatches(myPartitionDate, patientResourceTable.getPartitionId().getPartitionDate());
}); });
} }
@ -615,11 +614,11 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
myPatientDao.update(p, mySrd); myPatientDao.update(p, mySrd);
runInTransaction(() -> { runInTransaction(() -> {
// HFJ_FORCED_ID ResourceTable orgResourceTable = myResourceTableDao.findByTypeAndFhirId("Organization", "org").orElseThrow(IllegalArgumentException::new);
List<ForcedId> forcedIds = myForcedIdDao.findAll(); assertNull(orgResourceTable.getPartitionId());
assertEquals(2, forcedIds.size());
assertEquals(null, forcedIds.get(0).getPartitionId()); ResourceTable patientResourceTable = myResourceTableDao.findByTypeAndFhirId("Patient", "pat").orElseThrow(IllegalArgumentException::new);
assertEquals(null, forcedIds.get(1).getPartitionId()); assertNull(patientResourceTable.getPartitionId());
}); });
} }
@ -639,13 +638,13 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
myPatientDao.update(p, mySrd); myPatientDao.update(p, mySrd);
runInTransaction(() -> { runInTransaction(() -> {
// HFJ_FORCED_ID ResourceTable orgResourceTable = myResourceTableDao.findByTypeAndFhirId("Organization", "org").orElseThrow(IllegalArgumentException::new);
List<ForcedId> forcedIds = myForcedIdDao.findAll(); assertNull(orgResourceTable.getPartitionId().getPartitionId());
assertEquals(2, forcedIds.size()); assertLocalDateFromDbMatches(myPartitionDate, orgResourceTable.getPartitionId().getPartitionDate());
assertEquals(null, forcedIds.get(0).getPartitionId().getPartitionId());
assertLocalDateFromDbMatches(myPartitionDate, forcedIds.get(0).getPartitionId().getPartitionDate()); ResourceTable patientResourceTable = myResourceTableDao.findByTypeAndFhirId("Patient", "pat").orElseThrow(IllegalArgumentException::new);
assertEquals(null, forcedIds.get(1).getPartitionId().getPartitionId()); assertNull(patientResourceTable.getPartitionId().getPartitionId());
assertLocalDateFromDbMatches(myPartitionDate, forcedIds.get(1).getPartitionId().getPartitionDate()); assertLocalDateFromDbMatches(myPartitionDate, patientResourceTable.getPartitionId().getPartitionDate());
}); });
} }
@ -876,8 +875,8 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
ourLog.info("Search SQL:\n{}", searchSql); ourLog.info("Search SQL:\n{}", searchSql);
// Only the read columns should be used, no criteria use partition // Only the read columns should be used, no criteria use partition
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,")); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"));
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID")); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID"));
} }
{ {
addReadAllPartitions(); addReadAllPartitions();
@ -888,8 +887,8 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
ourLog.info("Search SQL:\n{}", searchSql); ourLog.info("Search SQL:\n{}", searchSql);
// Only the read columns should be used, no criteria use partition // Only the read columns should be used, no criteria use partition
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,")); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"));
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID")); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID"));
} }
} }
@ -910,7 +909,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
ourLog.info("Search SQL:\n{}", searchSql); ourLog.info("Search SQL:\n{}", searchSql);
// Only the read columns should be used, no criteria use partition // Only the read columns should be used, no criteria use partition
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql);
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID='1'"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID='1'"), searchSql);
} }
@ -954,7 +953,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
// Only the read columns should be used, but no selectors on partition ID // Only the read columns should be used, but no selectors on partition ID
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql);
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID in ("), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID in ("), searchSql);
} }
@ -967,7 +966,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
// Only the read columns should be used, but no selectors on partition ID // Only the read columns should be used, but no selectors on partition ID
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql);
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID is null"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID is null"), searchSql);
} }
@ -1008,7 +1007,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
// Only the read columns should be used, but no selectors on partition ID // Only the read columns should be used, but no selectors on partition ID
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql);
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID in ("), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID in ("), searchSql);
} }
@ -1022,7 +1021,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
// Only the read columns should be used, but no selectors on partition ID // Only the read columns should be used, but no selectors on partition ID
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"), searchSql);
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID is null"), searchSql); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID is null"), searchSql);
} }
@ -1064,7 +1063,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
ourLog.info("Search SQL:\n{}", searchSql); ourLog.info("Search SQL:\n{}", searchSql);
// Only the read columns should be used, no criteria use partition // Only the read columns should be used, no criteria use partition
assertEquals(2, StringUtils.countMatches(searchSql, "PARTITION_ID,")); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID,"));
assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID is null")); assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID is null"));
} }
@ -2843,7 +2842,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(9, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
@ -2860,7 +2859,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(7, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
@ -2875,7 +2874,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
outcome = mySystemDao.transaction(mySrd, input.get()); outcome = mySystemDao.transaction(mySrd, input.get());
ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); ourLog.debug("Resp: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(6, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(5, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
myCaptureQueriesListener.logInsertQueriesForCurrentThread(); myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread(); myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
@ -2899,7 +2898,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(18, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(18, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(6607, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(6189, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(418, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(418, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
assertEquals(2, myCaptureQueriesListener.countCommits()); assertEquals(2, myCaptureQueriesListener.countCommits());
@ -2925,7 +2924,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
output = mySystemDao.transaction(requestDetails, input); output = mySystemDao.transaction(requestDetails, input);
myCaptureQueriesListener.logSelectQueries(); myCaptureQueriesListener.logSelectQueries();
assertEquals(29, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(26, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());

View File

@ -27,8 +27,6 @@ import ca.uhn.fhir.util.MultimapCollector;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
@ -47,7 +45,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -64,8 +61,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
public class PatientIdPartitionInterceptorTest extends BaseResourceProviderR4Test { public class PatientIdPartitionInterceptorTest extends BaseResourceProviderR4Test {
public static final int ALTERNATE_DEFAULT_ID = -1; public static final int ALTERNATE_DEFAULT_ID = -1;
@ -355,7 +350,6 @@ public class PatientIdPartitionInterceptorTest extends BaseResourceProviderR4Tes
org.setName("name 2"); org.setName("name 2");
logAllResources(); logAllResources();
logAllForcedIds();
myOrganizationDao.update(org); myOrganizationDao.update(org);

View File

@ -18,16 +18,15 @@ import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil; import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
import ca.uhn.fhir.jpa.search.PersistedJpaSearchFirstPageBundleProvider; import ca.uhn.fhir.jpa.search.PersistedJpaSearchFirstPageBundleProvider;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
@ -379,7 +378,6 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty()))); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty())));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty()))); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty())));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), not(empty())));
myPatientDao.expunge(new ExpungeOptions() myPatientDao.expunge(new ExpungeOptions()
.setExpungeDeletedResources(true) .setExpungeDeletedResources(true)
@ -387,7 +385,6 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
} }
@ -409,7 +406,6 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty()))); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty())));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty()))); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty())));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), not(empty())));
// Test // Test
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
@ -421,11 +417,10 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(9, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(8, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
} }
@ -749,7 +744,6 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
.setExpungeOldVersions(true), null); .setExpungeOldVersions(true), null);
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
// Create again with the same forced ID // Create again with the same forced ID
p = new Patient(); p = new Patient();
@ -788,7 +782,6 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
.setExpungeOldVersions(true), null); .setExpungeOldVersions(true), null);
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty())); runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
} }
@ -1061,6 +1054,5 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
assertThat(myTermConceptDao.findAll(), empty()); assertThat(myTermConceptDao.findAll(), empty());
assertThat(myResourceTableDao.findAll(), empty()); assertThat(myResourceTableDao.findAll(), empty());
assertThat(myResourceHistoryTableDao.findAll(), empty()); assertThat(myResourceHistoryTableDao.findAll(), empty());
assertThat(myForcedIdDao.findAll(), empty());
} }
} }

View File

@ -0,0 +1,67 @@
package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ResourceProviderLanguageParamR4Test extends BaseResourceProviderR4Test {
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamEnabled() {
myStorageSettings.setLanguageSearchParameterEnabled(true);
mySearchParamRegistry.forceRefresh();
Patient pat = new Patient();
pat.setLanguage("en");
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient();
pat.setLanguage("fr");
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
List<String> foundResources;
Bundle result;
result = myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
foundResources = toUnqualifiedVersionlessIdValues(result);
assertThat(foundResources, contains(patId.getValue()));
}
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamDisabled() {
myStorageSettings.setLanguageSearchParameterEnabled(new JpaStorageSettings().isLanguageSearchParameterEnabled());
mySearchParamRegistry.forceRefresh();
InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> {
myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
});
assertThat(exception.getMessage(), containsString(Msg.code(1223)));
}
}

View File

@ -307,6 +307,86 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test
assertFalse(hasParameterByName(respParams, "match")); assertFalse(hasParameterByName(respParams, "match"));
} }
@Test
public void testTranslateByCodeSystemsAndSourceCodeMappedToCodelessTarget() {
// ensure that the current behaviour when a target does not have a code is preserved, and no matches returned
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId, mySrd);
ourLog.debug("ConceptMap:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
Parameters inParams = new Parameters();
inParams.addParameter().setName("system").setValue(new UriType(CS_URL_4));
inParams.addParameter().setName("targetsystem").setValue(new UriType(CS_URL_3));
inParams.addParameter().setName("code").setValue(new CodeType("89012"));
ourLog.debug("Request Parameters:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(inParams));
Parameters respParams = myClient
.operation()
.onType(ConceptMap.class)
.named("translate")
.withParameters(inParams)
.execute();
ourLog.debug("Response Parameters\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(respParams));
ParametersParameterComponent param = getParameterByName(respParams, "result");
assertFalse(((BooleanType) param.getValue()).booleanValue());
param = getParameterByName(respParams, "message");
assertEquals("No Matches found", ((StringType) param.getValue()).getValueAsString());
assertFalse(hasParameterByName(respParams, "match"));
}
@Test
public void testTranslateByCodeSystemsAndSourceCodeWithEquivalenceUnmatched() {
// the equivalence code 'unmatched' is an exception - it does not normally have a target code,
// so it will be included in the collection of matches even if there is no code present
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId, mySrd);
ourLog.debug("ConceptMap:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
Parameters inParams = new Parameters();
inParams.addParameter().setName("system").setValue(new UriType(CS_URL_4));
inParams.addParameter().setName("targetsystem").setValue(new UriType(CS_URL_3));
inParams.addParameter().setName("code").setValue(new CodeType("89123"));
ourLog.debug("Request Parameters:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(inParams));
Parameters respParams = myClient
.operation()
.onType(ConceptMap.class)
.named("translate")
.withParameters(inParams)
.execute();
ourLog.debug("Response Parameters\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(respParams));
ParametersParameterComponent param = getParameterByName(respParams, "result");
assertFalse(((BooleanType) param.getValue()).booleanValue());
param = getParameterByName(respParams, "message");
assertEquals("Only negative matches found", ((StringType) param.getValue()).getValueAsString());
assertEquals(1, getNumberOfParametersByName(respParams, "match"));
param = getParameterByName(respParams, "match");
assertEquals(3, param.getPart().size());
ParametersParameterComponent part = getPartByName(param, "equivalence");
assertEquals("unmatched", ((CodeType) part.getValue()).getCode());
part = getPartByName(param, "concept");
Coding coding = (Coding) part.getValue();
assertNull(coding.getCode());
assertNull(coding.getDisplay());
assertFalse(coding.getUserSelected());
assertEquals(CS_URL_3, coding.getSystem());
assertEquals("Version 1", coding.getVersion());
part = getPartByName(param, "source");
assertEquals(CM_URL, ((UriType) part.getValue()).getValueAsString());
}
@Test @Test
public void testTranslateUsingPredicatesWithCodeOnly() { public void testTranslateUsingPredicatesWithCodeOnly() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);

View File

@ -346,7 +346,7 @@ public class ServerCapabilityStatementProviderJpaR4Test extends BaseResourceProv
CapabilityStatement cs = myClient.capabilities().ofType(CapabilityStatement.class).execute(); CapabilityStatement cs = myClient.capabilities().ofType(CapabilityStatement.class).execute();
for (CapabilityStatement.CapabilityStatementRestResourceComponent nextResource : cs.getRestFirstRep().getResource()) { for (CapabilityStatement.CapabilityStatementRestResourceComponent nextResource : cs.getRestFirstRep().getResource()) {
for (CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent nextSp : nextResource.getSearchParam()) { for (CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent nextSp : nextResource.getSearchParam()) {
if (nextSp.getName().equals("_has") || nextSp.getName().equals("_list")) { if (nextSp.getName().equals("_has") || nextSp.getName().equals("_list") || nextSp.getName().equals("_language")) {
if (nextSp.getDefinition() == null) { if (nextSp.getDefinition() == null) {
continue; continue;
} }

View File

@ -64,7 +64,7 @@ public class ReindexStepTest extends BaseJpaR4Test {
// Verify // Verify
assertEquals(2, outcome.getRecordsProcessed()); assertEquals(2, outcome.getRecordsProcessed());
assertEquals(6, myCaptureQueriesListener.logSelectQueries().size()); assertEquals(5, myCaptureQueriesListener.logSelectQueries().size());
assertEquals(0, myCaptureQueriesListener.countInsertQueries()); assertEquals(0, myCaptureQueriesListener.countInsertQueries());
myCaptureQueriesListener.logUpdateQueries(); myCaptureQueriesListener.logUpdateQueries();
assertEquals(0, myCaptureQueriesListener.countUpdateQueries()); assertEquals(0, myCaptureQueriesListener.countUpdateQueries());
@ -95,7 +95,7 @@ public class ReindexStepTest extends BaseJpaR4Test {
// Verify // Verify
assertEquals(2, outcome.getRecordsProcessed()); assertEquals(2, outcome.getRecordsProcessed());
assertEquals(8, myCaptureQueriesListener.logSelectQueries().size()); assertEquals(7, myCaptureQueriesListener.logSelectQueries().size());
assertEquals(0, myCaptureQueriesListener.countInsertQueries()); assertEquals(0, myCaptureQueriesListener.countInsertQueries());
assertEquals(0, myCaptureQueriesListener.countUpdateQueries()); assertEquals(0, myCaptureQueriesListener.countUpdateQueries());
assertEquals(0, myCaptureQueriesListener.countDeleteQueries()); assertEquals(0, myCaptureQueriesListener.countDeleteQueries());
@ -128,7 +128,7 @@ public class ReindexStepTest extends BaseJpaR4Test {
// Verify // Verify
assertEquals(2, outcome.getRecordsProcessed()); assertEquals(2, outcome.getRecordsProcessed());
assertEquals(6, myCaptureQueriesListener.logSelectQueries().size()); assertEquals(5, myCaptureQueriesListener.logSelectQueries().size());
// name, family, phonetic, deceased, active // name, family, phonetic, deceased, active
assertEquals(5, myCaptureQueriesListener.countInsertQueries()); assertEquals(5, myCaptureQueriesListener.countInsertQueries());
assertEquals(0, myCaptureQueriesListener.countUpdateQueries()); assertEquals(0, myCaptureQueriesListener.countUpdateQueries());
@ -196,7 +196,7 @@ public class ReindexStepTest extends BaseJpaR4Test {
// Verify // Verify
assertEquals(2, outcome.getRecordsProcessed()); assertEquals(2, outcome.getRecordsProcessed());
assertEquals(10, myCaptureQueriesListener.logSelectQueries().size()); assertEquals(9, myCaptureQueriesListener.logSelectQueries().size());
assertEquals(0, myCaptureQueriesListener.countInsertQueries()); assertEquals(0, myCaptureQueriesListener.countInsertQueries());
assertEquals(4, myCaptureQueriesListener.countUpdateQueries()); assertEquals(4, myCaptureQueriesListener.countUpdateQueries());
assertEquals(0, myCaptureQueriesListener.countDeleteQueries()); assertEquals(0, myCaptureQueriesListener.countDeleteQueries());
@ -241,7 +241,7 @@ public class ReindexStepTest extends BaseJpaR4Test {
// Verify // Verify
assertEquals(4, outcome.getRecordsProcessed()); assertEquals(4, outcome.getRecordsProcessed());
assertEquals(9, myCaptureQueriesListener.logSelectQueries().size()); assertEquals(8, myCaptureQueriesListener.logSelectQueries().size());
assertEquals(5, myCaptureQueriesListener.countInsertQueries()); assertEquals(5, myCaptureQueriesListener.countInsertQueries());
assertEquals(2, myCaptureQueriesListener.countUpdateQueries()); assertEquals(2, myCaptureQueriesListener.countUpdateQueries());
assertEquals(0, myCaptureQueriesListener.countDeleteQueries()); assertEquals(0, myCaptureQueriesListener.countDeleteQueries());

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -18,7 +18,6 @@ import ca.uhn.fhir.jpa.binary.interceptor.BinaryStorageInterceptor;
import ca.uhn.fhir.jpa.binary.provider.BinaryAccessProvider; import ca.uhn.fhir.jpa.binary.provider.BinaryAccessProvider;
import ca.uhn.fhir.jpa.bulk.export.api.IBulkDataExportJobSchedulingHelper; import ca.uhn.fhir.jpa.bulk.export.api.IBulkDataExportJobSchedulingHelper;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboStringUniqueDao; import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboStringUniqueDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao; import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
@ -64,6 +63,7 @@ import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
import ca.uhn.fhir.test.utilities.ITestDataBuilder; import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import jakarta.persistence.EntityManager;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -124,7 +124,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.persistence.EntityManager;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -280,8 +279,6 @@ public abstract class BaseJpaR4BTest extends BaseJpaTest implements ITestDataBui
@Autowired @Autowired
protected IResourceHistoryTableDao myResourceHistoryTableDao; protected IResourceHistoryTableDao myResourceHistoryTableDao;
@Autowired @Autowired
protected IForcedIdDao myForcedIdDao;
@Autowired
@Qualifier("myCoverageDaoR4B") @Qualifier("myCoverageDaoR4B")
protected IFhirResourceDao<Coverage> myCoverageDao; protected IFhirResourceDao<Coverage> myCoverageDao;
@Autowired @Autowired

View File

@ -0,0 +1,66 @@
package ca.uhn.fhir.jpa.provider.r4b;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4b.model.Bundle;
import org.hl7.fhir.r4b.model.Patient;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ResourceProviderLanguageParamR4BTest extends BaseResourceProviderR4BTest {
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamEnabled() {
myStorageSettings.setLanguageSearchParameterEnabled(true);
mySearchParamRegistry.forceRefresh();
Patient pat = new Patient();
pat.setLanguage("en");
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient();
pat.setLanguage("fr");
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
List<String> foundResources;
Bundle result;
result = myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
foundResources = toUnqualifiedVersionlessIdValues(result);
assertThat(foundResources, contains(patId.getValue()));
}
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamDisabled() {
myStorageSettings.setLanguageSearchParameterEnabled(new JpaStorageSettings().isLanguageSearchParameterEnabled());
mySearchParamRegistry.forceRefresh();
InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> {
myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
});
assertThat(exception.getMessage(), containsString(Msg.code(1223)));
}
}

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -19,7 +19,6 @@ import ca.uhn.fhir.jpa.binary.interceptor.BinaryStorageInterceptor;
import ca.uhn.fhir.jpa.binary.provider.BinaryAccessProvider; import ca.uhn.fhir.jpa.binary.provider.BinaryAccessProvider;
import ca.uhn.fhir.jpa.bulk.export.api.IBulkDataExportJobSchedulingHelper; import ca.uhn.fhir.jpa.bulk.export.api.IBulkDataExportJobSchedulingHelper;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryProvenanceDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryProvenanceDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao;
@ -72,6 +71,7 @@ import ca.uhn.fhir.rest.server.BasePagingProvider;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
import ca.uhn.fhir.test.utilities.ITestDataBuilder; import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import jakarta.persistence.EntityManager;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r5.model.AllergyIntolerance; import org.hl7.fhir.r5.model.AllergyIntolerance;
@ -134,7 +134,6 @@ import org.springframework.test.util.AopTestUtils;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.persistence.EntityManager;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -303,8 +302,6 @@ public abstract class BaseJpaR5Test extends BaseJpaTest implements ITestDataBuil
@Autowired @Autowired
protected IResourceHistoryProvenanceDao myResourceHistoryProvenanceDao; protected IResourceHistoryProvenanceDao myResourceHistoryProvenanceDao;
@Autowired @Autowired
protected IForcedIdDao myForcedIdDao;
@Autowired
@Qualifier("myCoverageDaoR5") @Qualifier("myCoverageDaoR5")
protected IFhirResourceDao<Coverage> myCoverageDao; protected IFhirResourceDao<Coverage> myCoverageDao;
@Autowired @Autowired

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.util.BundleBuilder; import ca.uhn.fhir.util.BundleBuilder;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.r5.model.BooleanType; import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.CodeType; import org.hl7.fhir.r5.model.CodeType;
@ -20,7 +21,6 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import jakarta.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
@ -28,7 +28,6 @@ import static org.apache.commons.lang3.StringUtils.countMatches;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.Matchers.matchesPattern;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
@ -151,7 +150,7 @@ public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
// Verify // Verify
assertEquals(theMatchUrlCacheEnabled ? 4 : 5, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(theMatchUrlCacheEnabled ? 3 : 4, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
@ -203,7 +202,7 @@ public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
// Verify // Verify
assertEquals(theMatchUrlCacheEnabled ? 4 : 5, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(theMatchUrlCacheEnabled ? 3 : 4, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread()); assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());

View File

@ -401,7 +401,7 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test {
// 1- Resolve resource forced IDs, and 2- Resolve Practitioner/PR1 reference // 1- Resolve resource forced IDs, and 2- Resolve Practitioner/PR1 reference
myCaptureQueriesListener.logSelectQueriesForCurrentThread(); myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(10, myCaptureQueriesListener.countSelectQueriesForCurrentThread()); assertEquals(9, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
// Verify correct indexes are written // Verify correct indexes are written
@ -441,7 +441,7 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test {
bb.addTransactionUpdateEntry(newEncounter(ENCOUNTER_E2, p2Id)); bb.addTransactionUpdateEntry(newEncounter(ENCOUNTER_E2, p2Id));
bb.addTransactionCreateEntry(newPatientP1_HomerSimpson().setId(p1Id)).conditional("identifier=http://system|200"); bb.addTransactionCreateEntry(newPatientP1_HomerSimpson().setId(p1Id)).conditional("identifier=http://system|200");
bb.addTransactionCreateEntry(newPatientP2_MargeSimpson().setId(p2Id)).conditional("identifier=http://system|300"); bb.addTransactionCreateEntry(newPatientP2_MargeSimpson().setId(p2Id)).conditional("identifier=http://system|300");
;
Bundle requestBundle = bb.getBundleTyped(); Bundle requestBundle = bb.getBundleTyped();
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
@ -496,7 +496,7 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test {
bb.addTransactionUpdateEntry(newEncounter(ENCOUNTER_E2, p2Id)); bb.addTransactionUpdateEntry(newEncounter(ENCOUNTER_E2, p2Id));
bb.addTransactionCreateEntry(new Patient().addIdentifier(new Identifier().setSystem("http://system").setValue("200")).setId(p1Id)).conditional("identifier=http://system|200"); bb.addTransactionCreateEntry(new Patient().addIdentifier(new Identifier().setSystem("http://system").setValue("200")).setId(p1Id)).conditional("identifier=http://system|200");
bb.addTransactionCreateEntry(new Patient().addIdentifier(new Identifier().setSystem("http://system").setValue("300")).setId(p2Id)).conditional("identifier=http://system|300"); bb.addTransactionCreateEntry(new Patient().addIdentifier(new Identifier().setSystem("http://system").setValue("300")).setId(p2Id)).conditional("identifier=http://system|300");
;
Bundle requestBundle = bb.getBundleTyped(); Bundle requestBundle = bb.getBundleTyped();
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();

View File

@ -0,0 +1,66 @@
package ca.uhn.fhir.jpa.provider.r5;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Patient;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ResourceProviderLanguageParamR5Test extends BaseResourceProviderR5Test {
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamEnabled() {
myStorageSettings.setLanguageSearchParameterEnabled(true);
mySearchParamRegistry.forceRefresh();
Patient pat = new Patient();
pat.setLanguage("en");
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
Patient pat2 = new Patient();
pat.setLanguage("fr");
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
List<String> foundResources;
Bundle result;
result = myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
foundResources = toUnqualifiedVersionlessIdValues(result);
assertThat(foundResources, contains(patId.getValue()));
}
@SuppressWarnings("unused")
@Test
public void testSearchWithLanguageParamDisabled() {
myStorageSettings.setLanguageSearchParameterEnabled(new JpaStorageSettings().isLanguageSearchParameterEnabled());
mySearchParamRegistry.forceRefresh();
InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> {
myClient
.search()
.forResource(Patient.class)
.where(new TokenClientParam(Constants.PARAM_LANGUAGE).exactly().code("en"))
.returnBundle(Bundle.class)
.execute();
});
assertThat(exception.getMessage(), containsString(Msg.code(1223)));
}
}

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -20,8 +20,6 @@
package ca.uhn.fhir.jpa.test; package ca.uhn.fhir.jpa.test;
import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider; import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexAppCtx;
import ca.uhn.fhir.batch2.model.JobInstance;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.interceptor.api.IInterceptorService; import ca.uhn.fhir.interceptor.api.IInterceptorService;
@ -45,7 +43,6 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.TestDaoSearch; import ca.uhn.fhir.jpa.dao.TestDaoSearch;
import ca.uhn.fhir.jpa.dao.data.IBatch2JobInstanceRepository; import ca.uhn.fhir.jpa.dao.data.IBatch2JobInstanceRepository;
import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkRepository; import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkRepository;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkJpaRepository; import ca.uhn.fhir.jpa.dao.data.IMdmLinkJpaRepository;
import ca.uhn.fhir.jpa.dao.data.IPartitionDao; import ca.uhn.fhir.jpa.dao.data.IPartitionDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryProvenanceDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryProvenanceDao;
@ -116,6 +113,7 @@ import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import jakarta.persistence.EntityManager;
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport; import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -208,7 +206,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.util.AopTestUtils; import org.springframework.test.util.AopTestUtils;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import jakarta.persistence.EntityManager;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -935,6 +932,28 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
target.setDisplay("Target Code 34567"); target.setDisplay("Target Code 34567");
target.setEquivalence(ConceptMapEquivalence.NARROWER); target.setEquivalence(ConceptMapEquivalence.NARROWER);
group = conceptMap.addGroup();
group.setSource(CS_URL_4);
group.setSourceVersion("Version 1");
group.setTarget(CS_URL_3);
group.setTargetVersion("Version 1");
// This one should not show up in the results because it doesn't have a code
element = group.addElement();
element.setCode("89012");
element.setDisplay("Source Code 89012");
target = element.addTarget();
target.setEquivalence(ConceptMapEquivalence.DISJOINT);
// This one should show up in the results because unmatched targets are allowed to be codeless
element = group.addElement();
element.setCode("89123");
element.setDisplay("Source Code 89123");
target = element.addTarget();
target.setEquivalence(ConceptMapEquivalence.UNMATCHED);
return conceptMap; return conceptMap;
} }

View File

@ -36,7 +36,6 @@ import ca.uhn.fhir.jpa.config.JpaConfig;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.JpaPersistedResourceValidationSupport; import ca.uhn.fhir.jpa.dao.JpaPersistedResourceValidationSupport;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboTokensNonUniqueDao; import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboTokensNonUniqueDao;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao; import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
@ -61,7 +60,6 @@ import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept; import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation; import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
@ -99,6 +97,8 @@ import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.FhirVersionIndependentConcept; import ca.uhn.fhir.util.FhirVersionIndependentConcept;
import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import jakarta.annotation.Nonnull;
import jakarta.persistence.EntityManager;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
@ -129,8 +129,6 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import jakarta.annotation.Nonnull;
import jakarta.persistence.EntityManager;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -257,8 +255,6 @@ public abstract class BaseJpaTest extends BaseTest {
@Autowired @Autowired
private IResourceHistoryTableDao myResourceHistoryTableDao; private IResourceHistoryTableDao myResourceHistoryTableDao;
@Autowired @Autowired
protected IForcedIdDao myForcedIdDao;
@Autowired
private DaoRegistry myDaoRegistry; private DaoRegistry myDaoRegistry;
private final List<Object> myRegisteredInterceptors = new ArrayList<>(1); private final List<Object> myRegisteredInterceptors = new ArrayList<>(1);
@ -517,14 +513,6 @@ public abstract class BaseJpaTest extends BaseTest {
}); });
} }
protected int logAllForcedIds() {
return runInTransaction(() -> {
List<ForcedId> forcedIds = myForcedIdDao.findAll();
ourLog.info("Resources:\n * {}", forcedIds.stream().map(ForcedId::toString).collect(Collectors.joining("\n * ")));
return forcedIds.size();
});
}
protected void logAllDateIndexes() { protected void logAllDateIndexes() {
runInTransaction(() -> { runInTransaction(() -> {
ourLog.info("Date indexes:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(ResourceIndexedSearchParamDate::toString).collect(Collectors.joining("\n * "))); ourLog.info("Date indexes:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(ResourceIndexedSearchParamDate::toString).collect(Collectors.joining("\n * ")));

View File

@ -0,0 +1 @@
INSERT INTO TRM_CONCEPT_MAP_GRP_ELM_TGT (PID, TARGET_CODE, CONCEPT_MAP_URL, TARGET_DISPLAY, TARGET_EQUIVALENCE, SYSTEM_URL, SYSTEM_VERSION, VALUESET_URL, CONCEPT_MAP_GRP_ELM_PID) VALUES (61, NULL, NULL, 'PYRIDOXINE', 'UNMATCHED', NULL, NULL, NULL, 60);

View File

@ -0,0 +1 @@
INSERT INTO TRM_CONCEPT_MAP_GRP_ELM_TGT (PID, TARGET_CODE, CONCEPT_MAP_URL, TARGET_DISPLAY, TARGET_EQUIVALENCE, SYSTEM_URL, SYSTEM_VERSION, VALUESET_URL, CONCEPT_MAP_GRP_ELM_PID) VALUES (61, NULL, NULL, 'PYRIDOXINE', 'UNMATCHED', NULL, NULL, NULL, 60);

View File

@ -0,0 +1 @@
INSERT INTO TRM_CONCEPT_MAP_GRP_ELM_TGT (PID, TARGET_CODE, CONCEPT_MAP_URL, TARGET_DISPLAY, TARGET_EQUIVALENCE, SYSTEM_URL, SYSTEM_VERSION, VALUESET_URL, CONCEPT_MAP_GRP_ELM_PID) VALUES (61, NULL, NULL, 'PYRIDOXINE', 'UNMATCHED', NULL, NULL, NULL, 60);

View File

@ -0,0 +1 @@
INSERT INTO TRM_CONCEPT_MAP_GRP_ELM_TGT (PID, TARGET_CODE, CONCEPT_MAP_URL, TARGET_DISPLAY, TARGET_EQUIVALENCE, SYSTEM_URL, SYSTEM_VERSION, VALUESET_URL, CONCEPT_MAP_GRP_ELM_PID) VALUES (61, NULL, NULL, 'PYRIDOXINE', 'UNMATCHED', NULL, NULL, NULL, 60);

View File

@ -3,16 +3,17 @@ package ca.uhn.fhir.jpa.cache;
import ca.uhn.fhir.interceptor.model.RequestPartitionId; import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService; import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.cache.ResourcePersistentIdMap;
import ca.uhn.fhir.jpa.cache.ResourceVersionSvcDaoImpl;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.dao.index.IdHelperService; import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.dao.JpaPid; import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Root;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -23,11 +24,6 @@ import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Root;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -36,7 +32,6 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -85,8 +80,6 @@ public class ResourceVersionSvcTest {
CriteriaQuery<ResourceTable> criteriaQuery = Mockito.mock(CriteriaQuery.class); CriteriaQuery<ResourceTable> criteriaQuery = Mockito.mock(CriteriaQuery.class);
Root<ResourceTable> from = Mockito.mock(Root.class); Root<ResourceTable> from = Mockito.mock(Root.class);
Path path = Mockito.mock(Path.class); Path path = Mockito.mock(Path.class);
TypedQuery<ForcedId> queryMock = Mockito.mock(TypedQuery.class);
} }
/** /**

View File

@ -83,7 +83,8 @@ public class HapiSchemaMigrationTest {
VersionEnum.V5_4_0, VersionEnum.V5_4_0,
VersionEnum.V5_5_0, VersionEnum.V5_5_0,
VersionEnum.V6_0_0, VersionEnum.V6_0_0,
VersionEnum.V6_6_0 VersionEnum.V6_6_0,
VersionEnum.V7_2_0
); );
int fromVersion = 0; int fromVersion = 0;
@ -92,6 +93,7 @@ public class HapiSchemaMigrationTest {
for (int i = 0; i < allVersions.length; i++) { for (int i = 0; i < allVersions.length; i++) {
toVersion = allVersions[i]; toVersion = allVersions[i];
ourLog.info("Applying migrations for {}", toVersion);
migrate(theDriverType, dataSource, hapiMigrationStorageSvc, toVersion); migrate(theDriverType, dataSource, hapiMigrationStorageSvc, toVersion);
if (dataVersions.contains(toVersion)) { if (dataVersions.contains(toVersion)) {
myEmbeddedServersExtension.insertPersistenceTestData(theDriverType, toVersion); myEmbeddedServersExtension.insertPersistenceTestData(theDriverType, toVersion);

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <artifactId>hapi-deployable-pom</artifactId>
<version>7.1.7-SNAPSHOT</version> <version>7.1.8-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -32,6 +32,8 @@ import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.function.Supplier;
@Service @Service
public class MdmProviderLoader { public class MdmProviderLoader {
@Autowired @Autowired
@ -58,26 +60,28 @@ public class MdmProviderLoader {
@Autowired @Autowired
private IInterceptorBroadcaster myInterceptorBroadcaster; private IInterceptorBroadcaster myInterceptorBroadcaster;
private BaseMdmProvider myMdmProvider; private Supplier<Object> myMdmProviderSupplier;
private MdmLinkHistoryProviderDstu3Plus myMdmHistoryProvider; private Supplier<Object> myMdmHistoryProviderSupplier;
public void loadProvider() { public void loadProvider() {
switch (myFhirContext.getVersion().getVersion()) { switch (myFhirContext.getVersion().getVersion()) {
case DSTU3: case DSTU3:
case R4: case R4:
case R5: case R5:
myResourceProviderFactory.addSupplier(() -> new MdmProviderDstu3Plus( // We store the supplier so that removeSupplier works properly
myMdmProviderSupplier = () -> new MdmProviderDstu3Plus(
myFhirContext, myFhirContext,
myMdmControllerSvc, myMdmControllerSvc,
myMdmControllerHelper, myMdmControllerHelper,
myMdmSubmitSvc, myMdmSubmitSvc,
myInterceptorBroadcaster, myInterceptorBroadcaster,
myMdmSettings)); myMdmSettings);
// We store the supplier so that removeSupplier works properly
myResourceProviderFactory.addSupplier(myMdmProviderSupplier);
if (myStorageSettings.isNonResourceDbHistoryEnabled()) { if (myStorageSettings.isNonResourceDbHistoryEnabled()) {
myResourceProviderFactory.addSupplier(() -> { myMdmHistoryProviderSupplier = () -> new MdmLinkHistoryProviderDstu3Plus(
return new MdmLinkHistoryProviderDstu3Plus( myFhirContext, myMdmControllerSvc, myInterceptorBroadcaster);
myFhirContext, myMdmControllerSvc, myInterceptorBroadcaster); myResourceProviderFactory.addSupplier(myMdmHistoryProviderSupplier);
});
} }
break; break;
default: default:
@ -88,11 +92,11 @@ public class MdmProviderLoader {
@PreDestroy @PreDestroy
public void unloadProvider() { public void unloadProvider() {
if (myMdmProvider != null) { if (myMdmProviderSupplier != null) {
myResourceProviderFactory.removeSupplier(() -> myMdmProvider); myResourceProviderFactory.removeSupplier(myMdmProviderSupplier);
} }
if (myMdmHistoryProvider != null) { if (myMdmHistoryProviderSupplier != null) {
myResourceProviderFactory.removeSupplier(() -> myMdmHistoryProvider); myResourceProviderFactory.removeSupplier(myMdmHistoryProviderSupplier);
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More