Merge pull request #190 from hapifhir/rel_5_3_0
Prerelase branch for 5.3.0-SNAPSHOT
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
[*.java]
|
[*.java]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = tab
|
||||||
indent_size = 2
|
indent_size = 3
|
||||||
|
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -316,9 +316,13 @@ The server may be configured with subscription support by enabling properties in
|
|||||||
|
|
||||||
- `hapi.fhir.subscription.websocket.enabled` - Enables websocket subscriptions. With this enabled, your server will accept incoming websocket connections on the following URL (this example uses the default context path and port, you may need to tweak depending on your deployment environment): [ws://localhost:8080/websocket](ws://localhost:8080/websocket)
|
- `hapi.fhir.subscription.websocket.enabled` - Enables websocket subscriptions. With this enabled, your server will accept incoming websocket connections on the following URL (this example uses the default context path and port, you may need to tweak depending on your deployment environment): [ws://localhost:8080/websocket](ws://localhost:8080/websocket)
|
||||||
|
|
||||||
## Enabling EMPI
|
## Enabling CQL
|
||||||
|
|
||||||
Set `hapi.fhir.empi_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable EMPI on this server. The EMPI matching rules are configured in [empi-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/empi-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. Note that EMPI relies on subscriptions, so for EMPI to work, subscriptions must be enabled.
|
Set `hapi.fhir.cql_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable [Clinical Quality Language](https://cql.hl7.org/) on this server.
|
||||||
|
|
||||||
|
## Enabling MDM (EMPI)
|
||||||
|
|
||||||
|
Set `hapi.fhir.mdm_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable MDM on this server. The MDM matching rules are configured in [mdm-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/mdm-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. Note that MDM relies on subscriptions, so for MDM to work, subscriptions must be enabled.
|
||||||
|
|
||||||
## Using Elasticsearch
|
## Using Elasticsearch
|
||||||
|
|
||||||
@@ -328,9 +332,10 @@ For example:
|
|||||||
|
|
||||||
```properties
|
```properties
|
||||||
elasticsearch.enabled=true
|
elasticsearch.enabled=true
|
||||||
elasticsearch.rest_url=http://localhost:9200
|
elasticsearch.rest_url=localhost:9200
|
||||||
elasticsearch.username=SomeUsername
|
elasticsearch.username=SomeUsername
|
||||||
elasticsearch.password=SomePassword
|
elasticsearch.password=SomePassword
|
||||||
|
elasticsearch.protocol=http
|
||||||
elasticsearch.required_index_status=YELLOW
|
elasticsearch.required_index_status=YELLOW
|
||||||
elasticsearch.schema_management_strategy=CREATE
|
elasticsearch.schema_management_strategy=CREATE
|
||||||
```
|
```
|
||||||
|
|||||||
34
pom.xml
34
pom.xml
@@ -14,14 +14,14 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>5.2.0</version>
|
<!-- FIMXME KBD Change this to 5.3.0 BEFORE merging this code to master ! -->
|
||||||
|
<version>5.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>hapi-fhir-jpaserver-starter</artifactId>
|
<artifactId>hapi-fhir-jpaserver-starter</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>8</java.version>
|
<java.version>8</java.version>
|
||||||
<spring_boot_version>2.3.4.RELEASE</spring_boot_version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<prerequisites>
|
<prerequisites>
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||||
@@ -100,10 +101,16 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- This dependency includes the JPA EMPI Server -->
|
<!-- This dependency includes the JPA CQL Server -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-jpaserver-empi</artifactId>
|
<artifactId>hapi-fhir-jpaserver-cql</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- This dependency includes the JPA MDM Server -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-jpaserver-mdm</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
|
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
|
||||||
@@ -234,6 +241,21 @@
|
|||||||
<artifactId>jetty-webapp</artifactId>
|
<artifactId>jetty-webapp</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>testcontainers</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>elasticsearch</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -265,7 +287,6 @@
|
|||||||
<version>${spring_boot_version}</version>
|
<version>${spring_boot_version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
@@ -358,7 +379,6 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>3.0.0-M5</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -386,7 +406,7 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
|
<failBuildInCaseOfConflict>false</failBuildInCaseOfConflict>
|
||||||
<checkTestClasspath>false</checkTestClasspath>
|
<checkTestClasspath>false</checkTestClasspath>
|
||||||
<!--
|
<!--
|
||||||
<printEqualFiles>false</printEqualFiles>
|
<printEqualFiles>false</printEqualFiles>
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
package ca.uhn.fhir.jpa.empi;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.empi.api.IEmpiSettings;
|
|
||||||
import ca.uhn.fhir.empi.rules.config.EmpiRuleValidator;
|
|
||||||
import ca.uhn.fhir.empi.rules.config.EmpiSettings;
|
|
||||||
import ca.uhn.fhir.jpa.empi.config.EmpiConsumerConfig;
|
|
||||||
import ca.uhn.fhir.jpa.empi.config.EmpiSubmitterConfig;
|
|
||||||
import ca.uhn.fhir.jpa.starter.AppProperties;
|
|
||||||
import ca.uhn.fhir.rest.server.util.ISearchParamRetriever;
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Conditional;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Move this to package "ca.uhn.fhir.jpa.starter" in HAPI FHIR 5.2.0+. The lousy component scan
|
|
||||||
* in 5.1.0 picks this up even if EMPI is disabled currently.
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@Conditional(EmpiConfigCondition.class)
|
|
||||||
@Import({EmpiConsumerConfig.class, EmpiSubmitterConfig.class})
|
|
||||||
public class EmpiConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
EmpiRuleValidator empiRuleValidator(FhirContext theFhirContext, ISearchParamRetriever theSearchParamRetriever) {
|
|
||||||
return new EmpiRuleValidator(theFhirContext, theSearchParamRetriever);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
IEmpiSettings empiSettings(@Autowired EmpiRuleValidator theEmpiRuleValidator, AppProperties appProperties) throws IOException {
|
|
||||||
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
|
||||||
Resource resource = resourceLoader.getResource("empi-rules.json");
|
|
||||||
String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8);
|
|
||||||
return new EmpiSettings(theEmpiRuleValidator).setEnabled(appProperties.getEmpi_enabled()).setScriptText(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
45
src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java
Normal file
45
src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package ca.uhn.fhir.jpa.mdm;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.mdm.config.MdmConsumerConfig;
|
||||||
|
import ca.uhn.fhir.jpa.mdm.config.MdmSubmitterConfig;
|
||||||
|
import ca.uhn.fhir.jpa.starter.AppProperties;
|
||||||
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
|
import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator;
|
||||||
|
import ca.uhn.fhir.mdm.rules.config.MdmSettings;
|
||||||
|
import ca.uhn.fhir.rest.server.util.ISearchParamRetriever;
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Move this to package "ca.uhn.fhir.jpa.starter" in HAPI FHIR 5.2.0+. The lousy component scan
|
||||||
|
* in 5.1.0 picks this up even if MDM is disabled currently.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Conditional(MdmConfigCondition.class)
|
||||||
|
@Import({MdmConsumerConfig.class, MdmSubmitterConfig.class})
|
||||||
|
public class MdmConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MdmRuleValidator mdmRuleValidator(FhirContext theFhirContext, ISearchParamRetriever theSearchParamRetriever) {
|
||||||
|
return new MdmRuleValidator(theFhirContext, theSearchParamRetriever);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
IMdmSettings mdmSettings(@Autowired MdmRuleValidator theMdmRuleValidator, AppProperties appProperties) throws IOException {
|
||||||
|
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
Resource resource = resourceLoader.getResource("mdm-rules.json");
|
||||||
|
String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8);
|
||||||
|
return new MdmSettings(theMdmRuleValidator).setEnabled(appProperties.getMdm_enabled()).setScriptText(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package ca.uhn.fhir.jpa.empi;
|
package ca.uhn.fhir.jpa.mdm;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Condition;
|
import org.springframework.context.annotation.Condition;
|
||||||
import org.springframework.context.annotation.ConditionContext;
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
|
||||||
public class EmpiConfigCondition implements Condition {
|
public class MdmConfigCondition implements Condition {
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
|
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
|
||||||
String property = conditionContext.getEnvironment().getProperty("hapi.fhir.empi_enabled");
|
String property = conditionContext.getEnvironment().getProperty("hapi.fhir.mdm_enabled");
|
||||||
return Boolean.parseBoolean(property);
|
return Boolean.parseBoolean(property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,27 +3,26 @@ package ca.uhn.fhir.jpa.starter;
|
|||||||
|
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig.ClientIdStrategyEnum;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig.ClientIdStrategyEnum;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import org.hl7.fhir.r4.model.Bundle;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "hapi.fhir")
|
@ConfigurationProperties(prefix = "hapi.fhir")
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties
|
@EnableConfigurationProperties
|
||||||
public class AppProperties {
|
public class AppProperties {
|
||||||
|
|
||||||
private Boolean empi_enabled = false;
|
private Boolean cql_enabled = false;
|
||||||
|
private Boolean mdm_enabled = false;
|
||||||
private Boolean allow_cascading_deletes = false;
|
private Boolean allow_cascading_deletes = false;
|
||||||
private Boolean allow_contains_searches = true;
|
private Boolean allow_contains_searches = true;
|
||||||
private Boolean allow_external_references = false;
|
private Boolean allow_external_references = false;
|
||||||
@@ -32,6 +31,7 @@ public class AppProperties {
|
|||||||
private Boolean allow_placeholder_references = true;
|
private Boolean allow_placeholder_references = true;
|
||||||
private Boolean auto_create_placeholder_reference_targets = false;
|
private Boolean auto_create_placeholder_reference_targets = false;
|
||||||
private Boolean enable_index_missing_fields = false;
|
private Boolean enable_index_missing_fields = false;
|
||||||
|
private Boolean enable_repository_validating_interceptor = false;
|
||||||
private Boolean enforce_referential_integrity_on_delete = true;
|
private Boolean enforce_referential_integrity_on_delete = true;
|
||||||
private Boolean enforce_referential_integrity_on_write = true;
|
private Boolean enforce_referential_integrity_on_write = true;
|
||||||
private Boolean etag_support_enabled = true;
|
private Boolean etag_support_enabled = true;
|
||||||
@@ -65,6 +65,7 @@ public class AppProperties {
|
|||||||
private Map<String, ImplementationGuide> implementationGuides = null;
|
private Map<String, ImplementationGuide> implementationGuides = null;
|
||||||
|
|
||||||
private Boolean lastn_enabled = false;
|
private Boolean lastn_enabled = false;
|
||||||
|
private NormalizedQuantitySearchLevel normalized_quantity_search_level = NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED;
|
||||||
|
|
||||||
public Integer getDefer_indexing_for_codesystems_of_size() {
|
public Integer getDefer_indexing_for_codesystems_of_size() {
|
||||||
return defer_indexing_for_codesystems_of_size;
|
return defer_indexing_for_codesystems_of_size;
|
||||||
@@ -90,14 +91,21 @@ public class AppProperties {
|
|||||||
this.partitioning = partitioning;
|
this.partitioning = partitioning;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getEmpi_enabled() {
|
public Boolean getCql_enabled() {
|
||||||
return empi_enabled;
|
return cql_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEmpi_enabled(Boolean empi_enabled) {
|
public void setCql_enabled(Boolean cql_enabled) {
|
||||||
this.empi_enabled = empi_enabled;
|
this.cql_enabled = cql_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getMdm_enabled() {
|
||||||
|
return mdm_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMdm_enabled(Boolean mdm_enabled) {
|
||||||
|
this.mdm_enabled = mdm_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
public Cors getCors() {
|
public Cors getCors() {
|
||||||
return cors;
|
return cors;
|
||||||
@@ -246,6 +254,14 @@ public class AppProperties {
|
|||||||
this.enable_index_missing_fields = enable_index_missing_fields;
|
this.enable_index_missing_fields = enable_index_missing_fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getEnable_repository_validating_interceptor() {
|
||||||
|
return enable_repository_validating_interceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnable_repository_validating_interceptor(Boolean theEnable_repository_validating_interceptor) {
|
||||||
|
enable_repository_validating_interceptor = theEnable_repository_validating_interceptor;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean getEnforce_referential_integrity_on_delete() {
|
public Boolean getEnforce_referential_integrity_on_delete() {
|
||||||
return enforce_referential_integrity_on_delete;
|
return enforce_referential_integrity_on_delete;
|
||||||
}
|
}
|
||||||
@@ -398,7 +414,16 @@ public class AppProperties {
|
|||||||
this.lastn_enabled = lastn_enabled;
|
this.lastn_enabled = lastn_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Cors {
|
public NormalizedQuantitySearchLevel getNormalized_quantity_search_level() {
|
||||||
|
return this.normalized_quantity_search_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNormalized_quantity_search_level(NormalizedQuantitySearchLevel normalized_quantity_search_level) {
|
||||||
|
this.normalized_quantity_search_level = normalized_quantity_search_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Cors {
|
||||||
private Boolean allow_Credentials = true;
|
private Boolean allow_Credentials = true;
|
||||||
private List<String> allowed_origin = ImmutableList.of("*");
|
private List<String> allowed_origin = ImmutableList.of("*");
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package ca.uhn.fhir.jpa.starter;
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.empi.EmpiConfig;
|
import ca.uhn.fhir.jpa.mdm.MdmConfig;
|
||||||
import ca.uhn.fhir.jpa.starter.annotations.OnEitherVersion;
|
import ca.uhn.fhir.jpa.starter.annotations.OnEitherVersion;
|
||||||
import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig;
|
import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
|
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
|
||||||
@@ -24,7 +24,7 @@ import org.springframework.web.servlet.DispatcherServlet;
|
|||||||
@ServletComponentScan(basePackageClasses = {
|
@ServletComponentScan(basePackageClasses = {
|
||||||
JpaRestfulServer.class})
|
JpaRestfulServer.class})
|
||||||
@SpringBootApplication(exclude = {ElasticsearchRestClientAutoConfiguration.class})
|
@SpringBootApplication(exclude = {ElasticsearchRestClientAutoConfiguration.class})
|
||||||
@Import({SubscriptionSubmitterConfig.class, SubscriptionProcessorConfig.class, SubscriptionChannelConfig.class, WebsocketDispatcherConfig.class, EmpiConfig.class})
|
@Import({SubscriptionSubmitterConfig.class, SubscriptionProcessorConfig.class, SubscriptionChannelConfig.class, WebsocketDispatcherConfig.class, MdmConfig.class})
|
||||||
public class Application extends SpringBootServletInitializer {
|
public class Application extends SpringBootServletInitializer {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@@ -32,8 +32,8 @@ public class Application extends SpringBootServletInitializer {
|
|||||||
System.setProperty("spring.batch.job.enabled", "false");
|
System.setProperty("spring.batch.job.enabled", "false");
|
||||||
SpringApplication.run(Application.class, args);
|
SpringApplication.run(Application.class, args);
|
||||||
|
|
||||||
//Server is now accessible at eg. http://localhost:8080/hapi-fhir-jpaserver/fhir/metadata
|
//Server is now accessible at eg. http://localhost:8080/fhir/metadata
|
||||||
//UI is now accessible at http://localhost:8080/hapi-fhir-jpaserver/
|
//UI is now accessible at http://localhost:8080/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.starter;
|
|||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
|
import ca.uhn.fhir.cql.common.provider.CqlProviderLoader;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
@@ -11,6 +12,7 @@ import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
|||||||
import ca.uhn.fhir.jpa.bulk.provider.BulkDataExportProvider;
|
import ca.uhn.fhir.jpa.bulk.provider.BulkDataExportProvider;
|
||||||
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||||
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
|
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
|
||||||
|
import ca.uhn.fhir.jpa.packages.PackageInstallOutcomeJson;
|
||||||
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
|
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
|
||||||
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
|
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
|
||||||
import ca.uhn.fhir.jpa.provider.*;
|
import ca.uhn.fhir.jpa.provider.*;
|
||||||
@@ -96,8 +98,13 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
|||||||
@Autowired
|
@Autowired
|
||||||
ApplicationContext myApplicationContext;
|
ApplicationContext myApplicationContext;
|
||||||
|
|
||||||
public BaseJpaRestfulServer() {
|
@Autowired(required = false)
|
||||||
|
IRepositoryValidationInterceptorFactory factory;
|
||||||
|
|
||||||
|
// These are set only if the features are enabled
|
||||||
|
private CqlProviderLoader cqlProviderLoader;
|
||||||
|
|
||||||
|
public BaseJpaRestfulServer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@@ -120,10 +127,10 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setFhirContext(fhirSystemDao.getContext());
|
setFhirContext(fhirSystemDao.getContext());
|
||||||
|
|
||||||
registerProviders(resourceProviders.createProviders());
|
registerProviders(resourceProviders.createProviders());
|
||||||
registerProvider(jpaSystemProvider);
|
registerProvider(jpaSystemProvider);
|
||||||
|
|
||||||
FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion();
|
|
||||||
/*
|
/*
|
||||||
* The conformance provider exports the supported resources, search parameters, etc for
|
* The conformance provider exports the supported resources, search parameters, etc for
|
||||||
* this server. The JPA version adds resourceProviders counts to the exported statement, so it
|
* this server. The JPA version adds resourceProviders counts to the exported statement, so it
|
||||||
@@ -133,7 +140,7 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
|||||||
* provide further customization of your server's CapabilityStatement
|
* provide further customization of your server's CapabilityStatement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion();
|
||||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||||
|
|
||||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, fhirSystemDao,
|
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, fhirSystemDao,
|
||||||
@@ -355,15 +362,19 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
|||||||
.setName(guide.getValue().getName())
|
.setName(guide.getValue().getName())
|
||||||
.setVersion(guide.getValue().getVersion())
|
.setVersion(guide.getValue().getVersion())
|
||||||
.setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL));
|
.setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(factory != null) {
|
||||||
|
interceptorService.registerInterceptor(factory.buildUsingStoredStructureDefinitions());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (appProperties.getLastn_enabled()) {
|
if (appProperties.getLastn_enabled()) {
|
||||||
daoConfig.setLastNEnabled(true);
|
daoConfig.setLastNEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
daoConfig.getModelConfig().setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
package ca.uhn.fhir.jpa.starter;
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||||
import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder;
|
import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder;
|
||||||
import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hibernate.search.elasticsearch.cfg.IndexSchemaManagementStrategy;
|
import org.elasticsearch.action.admin.indices.stats.IndexStats;
|
||||||
|
import org.hibernate.search.backend.elasticsearch.index.IndexStatus;
|
||||||
|
import org.hibernate.search.backend.lucene.cfg.LuceneBackendSettings;
|
||||||
|
import org.hibernate.search.backend.lucene.cfg.LuceneIndexSettings;
|
||||||
|
import org.hibernate.search.engine.cfg.BackendSettings;
|
||||||
|
import org.hibernate.search.mapper.orm.automaticindexing.session.AutomaticIndexingSynchronizationStrategyNames;
|
||||||
|
import org.hibernate.search.mapper.orm.cfg.HibernateOrmMapperSettings;
|
||||||
|
import org.hibernate.search.mapper.orm.schema.management.SchemaManagementStrategyName;
|
||||||
import org.springframework.core.env.CompositePropertySource;
|
import org.springframework.core.env.CompositePropertySource;
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
import org.springframework.core.env.EnumerablePropertySource;
|
import org.springframework.core.env.EnumerablePropertySource;
|
||||||
@@ -19,8 +27,6 @@ public class EnvironmentHelper {
|
|||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
|
|
||||||
Map<String, Object> jpaProps = getPropertiesStartingWith(environment, "spring.jpa.properties");
|
Map<String, Object> jpaProps = getPropertiesStartingWith(environment, "spring.jpa.properties");
|
||||||
|
|
||||||
properties.putIfAbsent("hibernate.search.model_mapping", "ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory");
|
|
||||||
properties.putIfAbsent("hibernate.format_sql", "false");
|
properties.putIfAbsent("hibernate.format_sql", "false");
|
||||||
properties.putIfAbsent("hibernate.show_sql", "false");
|
properties.putIfAbsent("hibernate.show_sql", "false");
|
||||||
properties.putIfAbsent("hibernate.hbm2ddl.auto", "update");
|
properties.putIfAbsent("hibernate.hbm2ddl.auto", "update");
|
||||||
@@ -29,9 +35,17 @@ public class EnvironmentHelper {
|
|||||||
properties.putIfAbsent("hibernate.cache.use_second_level_cache", "false");
|
properties.putIfAbsent("hibernate.cache.use_second_level_cache", "false");
|
||||||
properties.putIfAbsent("hibernate.cache.use_structured_entries", "false");
|
properties.putIfAbsent("hibernate.cache.use_structured_entries", "false");
|
||||||
properties.putIfAbsent("hibernate.cache.use_minimal_puts", "false");
|
properties.putIfAbsent("hibernate.cache.use_minimal_puts", "false");
|
||||||
properties.putIfAbsent("hibernate.search.default.directory_provider", "filesystem");
|
|
||||||
properties.putIfAbsent("hibernate.search.default.indexBase", "target/lucenefiles");
|
if (jpaProps.getOrDefault("spring.jpa.properties.hibernate.search.enabled", "false").toString() == "true") {
|
||||||
properties.putIfAbsent("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
properties.putIfAbsent(HibernateOrmMapperSettings.ENABLED, true);
|
||||||
|
properties.putIfAbsent(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_TYPE), "local-filesystem");
|
||||||
|
properties.putIfAbsent(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_ROOT), "target/lucenefiles");
|
||||||
|
properties.putIfAbsent(BackendSettings.backendKey(BackendSettings.TYPE), "lucene");
|
||||||
|
properties.putIfAbsent(BackendSettings.backendKey(LuceneBackendSettings.ANALYSIS_CONFIGURER), HapiLuceneAnalysisConfigurer.class.getName());
|
||||||
|
properties.putIfAbsent(BackendSettings.backendKey(LuceneBackendSettings.LUCENE_VERSION), "LUCENE_CURRENT");
|
||||||
|
} else {
|
||||||
|
properties.putIfAbsent(HibernateOrmMapperSettings.ENABLED, false);
|
||||||
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, Object> entry : jpaProps.entrySet()) {
|
for (Map.Entry<String, Object> entry : jpaProps.entrySet()) {
|
||||||
String strippedKey = entry.getKey().replace("spring.jpa.properties.", "");
|
String strippedKey = entry.getKey().replace("spring.jpa.properties.", "");
|
||||||
@@ -42,9 +56,9 @@ public class EnvironmentHelper {
|
|||||||
if (environment.getProperty("elasticsearch.enabled", Boolean.class) != null
|
if (environment.getProperty("elasticsearch.enabled", Boolean.class) != null
|
||||||
&& environment.getProperty("elasticsearch.enabled", Boolean.class) == true) {
|
&& environment.getProperty("elasticsearch.enabled", Boolean.class) == true) {
|
||||||
ElasticsearchHibernatePropertiesBuilder builder = new ElasticsearchHibernatePropertiesBuilder();
|
ElasticsearchHibernatePropertiesBuilder builder = new ElasticsearchHibernatePropertiesBuilder();
|
||||||
ElasticsearchIndexStatus requiredIndexStatus = environment.getProperty("elasticsearch.required_index_status", ElasticsearchIndexStatus.class);
|
IndexStatus requiredIndexStatus = environment.getProperty("elasticsearch.required_index_status", IndexStatus.class);
|
||||||
if (requiredIndexStatus == null) {
|
if (requiredIndexStatus == null) {
|
||||||
builder.setRequiredIndexStatus(ElasticsearchIndexStatus.YELLOW);
|
builder.setRequiredIndexStatus(IndexStatus.YELLOW);
|
||||||
} else {
|
} else {
|
||||||
builder.setRequiredIndexStatus(requiredIndexStatus);
|
builder.setRequiredIndexStatus(requiredIndexStatus);
|
||||||
}
|
}
|
||||||
@@ -52,18 +66,19 @@ public class EnvironmentHelper {
|
|||||||
builder.setRestUrl(getElasticsearchServerUrl(environment));
|
builder.setRestUrl(getElasticsearchServerUrl(environment));
|
||||||
builder.setUsername(getElasticsearchServerUsername(environment));
|
builder.setUsername(getElasticsearchServerUsername(environment));
|
||||||
builder.setPassword(getElasticsearchServerPassword(environment));
|
builder.setPassword(getElasticsearchServerPassword(environment));
|
||||||
IndexSchemaManagementStrategy indexSchemaManagementStrategy = environment.getProperty("elasticsearch.schema_management_strategy", IndexSchemaManagementStrategy.class);
|
builder.setProtocol(getElasticsearchServerProtocol(environment));
|
||||||
|
SchemaManagementStrategyName indexSchemaManagementStrategy = environment.getProperty("elasticsearch.schema_management_strategy", SchemaManagementStrategyName.class);
|
||||||
if (indexSchemaManagementStrategy == null) {
|
if (indexSchemaManagementStrategy == null) {
|
||||||
builder.setIndexSchemaManagementStrategy(IndexSchemaManagementStrategy.CREATE);
|
builder.setIndexSchemaManagementStrategy(SchemaManagementStrategyName.CREATE);
|
||||||
} else {
|
} else {
|
||||||
builder.setIndexSchemaManagementStrategy(indexSchemaManagementStrategy);
|
builder.setIndexSchemaManagementStrategy(indexSchemaManagementStrategy);
|
||||||
}
|
}
|
||||||
// pretty_print_json_log: false
|
// pretty_print_json_log: false
|
||||||
Boolean refreshAfterWrite = environment.getProperty("elasticsearch.debug.refresh_after_write", Boolean.class);
|
Boolean refreshAfterWrite = environment.getProperty("elasticsearch.debug.refresh_after_write", Boolean.class);
|
||||||
if (refreshAfterWrite == null) {
|
if (refreshAfterWrite == null || refreshAfterWrite == false) {
|
||||||
builder.setDebugRefreshAfterWrite(false);
|
builder.setDebugIndexSyncStrategy(AutomaticIndexingSynchronizationStrategyNames.ASYNC);
|
||||||
} else {
|
} else {
|
||||||
builder.setDebugRefreshAfterWrite(refreshAfterWrite);
|
builder.setDebugIndexSyncStrategy(AutomaticIndexingSynchronizationStrategyNames.READ_SYNC);
|
||||||
}
|
}
|
||||||
// pretty_print_json_log: false
|
// pretty_print_json_log: false
|
||||||
Boolean prettyPrintJsonLog = environment.getProperty("elasticsearch.debug.pretty_print_json_log", Boolean.class);
|
Boolean prettyPrintJsonLog = environment.getProperty("elasticsearch.debug.pretty_print_json_log", Boolean.class);
|
||||||
@@ -74,7 +89,6 @@ public class EnvironmentHelper {
|
|||||||
}
|
}
|
||||||
builder.apply(properties);
|
builder.apply(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +96,10 @@ public class EnvironmentHelper {
|
|||||||
return environment.getProperty("elasticsearch.rest_url", String.class);
|
return environment.getProperty("elasticsearch.rest_url", String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getElasticsearchServerProtocol(ConfigurableEnvironment environment) {
|
||||||
|
return environment.getProperty("elasticsearch.protocol", String.class, "http");
|
||||||
|
}
|
||||||
|
|
||||||
public static String getElasticsearchServerUsername(ConfigurableEnvironment environment) {
|
public static String getElasticsearchServerUsername(ConfigurableEnvironment environment) {
|
||||||
return environment.getProperty("elasticsearch.username");
|
return environment.getProperty("elasticsearch.username");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package ca.uhn.fhir.jpa.starter;
|
|||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.binstore.DatabaseBlobBinaryStorageSvcImpl;
|
import ca.uhn.fhir.jpa.binstore.DatabaseBlobBinaryStorageSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc;
|
import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc;
|
||||||
import ca.uhn.fhir.jpa.config.HibernateDialectProvider;
|
import ca.uhn.fhir.jpa.config.HibernatePropertiesProvider;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings.CrossPartitionReferenceMode;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings.CrossPartitionReferenceMode;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
@@ -140,8 +140,8 @@ public class FhirServerConfigCommon {
|
|||||||
|
|
||||||
@Primary
|
@Primary
|
||||||
@Bean
|
@Bean
|
||||||
public HibernateDialectProvider jpaStarterDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
|
public HibernatePropertiesProvider jpaStarterDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
|
||||||
return new JpaHibernateDialectProvider(myEntityManagerFactory);
|
return new JpaHibernatePropertiesProvider(myEntityManagerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -162,6 +162,7 @@ public class FhirServerConfigCommon {
|
|||||||
modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL);
|
modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modelConfig.setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level());
|
||||||
return modelConfig;
|
return modelConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ import ca.uhn.fhir.jpa.config.BaseJavaConfigR4;
|
|||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.lastn.ElasticsearchSvcImpl;
|
import ca.uhn.fhir.jpa.search.lastn.ElasticsearchSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
|
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
|
||||||
|
import ca.uhn.fhir.jpa.starter.cql.StarterCqlR4Config;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.*;
|
||||||
import org.springframework.context.annotation.Conditional;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
@@ -19,6 +17,7 @@ import javax.sql.DataSource;
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Conditional(OnR4Condition.class)
|
@Conditional(OnR4Condition.class)
|
||||||
|
@Import(StarterCqlR4Config.class)
|
||||||
public class FhirServerConfigR4 extends BaseJavaConfigR4 {
|
public class FhirServerConfigR4 extends BaseJavaConfigR4 {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -71,7 +70,13 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 {
|
|||||||
public ElasticsearchSvcImpl elasticsearchSvc() {
|
public ElasticsearchSvcImpl elasticsearchSvc() {
|
||||||
if (EnvironmentHelper.isElasticsearchEnabled(configurableEnvironment)) {
|
if (EnvironmentHelper.isElasticsearchEnabled(configurableEnvironment)) {
|
||||||
String elasticsearchUrl = EnvironmentHelper.getElasticsearchServerUrl(configurableEnvironment);
|
String elasticsearchUrl = EnvironmentHelper.getElasticsearchServerUrl(configurableEnvironment);
|
||||||
String elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://")+3, elasticsearchUrl.lastIndexOf(":"));
|
String elasticsearchHost;
|
||||||
|
if (elasticsearchUrl.startsWith("http")) {
|
||||||
|
elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://") + 3, elasticsearchUrl.lastIndexOf(":"));
|
||||||
|
} else {
|
||||||
|
elasticsearchHost = elasticsearchUrl.substring(0, elasticsearchUrl.indexOf(":"));
|
||||||
|
}
|
||||||
|
|
||||||
String elasticsearchUsername = EnvironmentHelper.getElasticsearchServerUsername(configurableEnvironment);
|
String elasticsearchUsername = EnvironmentHelper.getElasticsearchServerUsername(configurableEnvironment);
|
||||||
String elasticsearchPassword = EnvironmentHelper.getElasticsearchServerPassword(configurableEnvironment);
|
String elasticsearchPassword = EnvironmentHelper.getElasticsearchServerPassword(configurableEnvironment);
|
||||||
int elasticsearchPort = Integer.parseInt(elasticsearchUrl.substring(elasticsearchUrl.lastIndexOf(":")+1));
|
int elasticsearchPort = Integer.parseInt(elasticsearchUrl.substring(elasticsearchUrl.lastIndexOf(":")+1));
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
|
||||||
|
|
||||||
|
public interface IRepositoryValidationInterceptorFactory {
|
||||||
|
RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions();
|
||||||
|
|
||||||
|
RepositoryValidatingInterceptor build();
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package ca.uhn.fhir.jpa.starter;
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.jpa.config.HibernateDialectProvider;
|
import ca.uhn.fhir.jpa.config.HibernatePropertiesProvider;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver;
|
import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver;
|
||||||
import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
|
import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
|
||||||
@@ -10,11 +10,11 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
|||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class JpaHibernateDialectProvider extends HibernateDialectProvider {
|
public class JpaHibernatePropertiesProvider extends HibernatePropertiesProvider {
|
||||||
|
|
||||||
private final Dialect dialect;
|
private final Dialect dialect;
|
||||||
|
|
||||||
public JpaHibernateDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
|
public JpaHibernatePropertiesProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
|
||||||
DataSource connection = myEntityManagerFactory.getDataSource();
|
DataSource connection = myEntityManagerFactory.getDataSource();
|
||||||
try {
|
try {
|
||||||
dialect = new StandardDialectResolver()
|
dialect = new StandardDialectResolver()
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.IRepositoryValidatingRule;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.jpa.starter.annotations.OnDSTU3Condition;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be customized to enable the {@link RepositoryValidatingInterceptor}
|
||||||
|
* on this server.
|
||||||
|
* <p>
|
||||||
|
* The <code>enable_repository_validating_interceptor</code> property must be enabled in <code>application.yaml</code>
|
||||||
|
* in order to use this class.
|
||||||
|
*/
|
||||||
|
@ConditionalOnProperty(prefix = "hapi.fhir", name = "enable_repository_validating_interceptor", havingValue = "true")
|
||||||
|
@Configuration
|
||||||
|
@Conditional(OnDSTU3Condition.class)
|
||||||
|
public class RepositoryValidationInterceptorFactoryDstu3 implements IRepositoryValidationInterceptorFactory {
|
||||||
|
|
||||||
|
private final FhirContext fhirContext;
|
||||||
|
private final RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder;
|
||||||
|
private final IFhirResourceDao structureDefinitionResourceProvider;
|
||||||
|
|
||||||
|
public RepositoryValidationInterceptorFactoryDstu3(RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder, DaoRegistry daoRegistry) {
|
||||||
|
this.repositoryValidatingRuleBuilder = repositoryValidatingRuleBuilder;
|
||||||
|
this.fhirContext = daoRegistry.getSystemDao().getContext();
|
||||||
|
structureDefinitionResourceProvider = daoRegistry.getResourceDao("StructureDefinition");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions() {
|
||||||
|
|
||||||
|
IBundleProvider results = structureDefinitionResourceProvider.search(new SearchParameterMap().add(StructureDefinition.SP_KIND, new TokenParam("resource")));
|
||||||
|
Map<String, List<StructureDefinition>> structureDefintions = results.getResources(0, results.size())
|
||||||
|
.stream()
|
||||||
|
.map(StructureDefinition.class::cast)
|
||||||
|
.collect(Collectors.groupingBy(StructureDefinition::getType));
|
||||||
|
|
||||||
|
structureDefintions.entrySet().forEach(structureDefinitionListEntry ->
|
||||||
|
{
|
||||||
|
String[] urls = structureDefinitionListEntry.getValue().stream().map(StructureDefinition::getUrl).toArray(String[]::new);
|
||||||
|
repositoryValidatingRuleBuilder.forResourcesOfType(structureDefinitionListEntry.getKey()).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles();
|
||||||
|
});
|
||||||
|
|
||||||
|
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||||
|
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepositoryValidatingInterceptor build() {
|
||||||
|
|
||||||
|
// Customize the ruleBuilder here to have the rules you want! We will give a simple example
|
||||||
|
// of enabling validation for all Patient resources
|
||||||
|
repositoryValidatingRuleBuilder.forResourcesOfType("Patient").requireAtLeastProfile("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient").and().requireValidationToDeclaredProfiles();
|
||||||
|
|
||||||
|
// Do not customize below this line
|
||||||
|
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||||
|
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.IRepositoryValidatingRule;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be customized to enable the {@link ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor}
|
||||||
|
* on this server.
|
||||||
|
* <p>
|
||||||
|
* The <code>enable_repository_validating_interceptor</code> property must be enabled in <code>application.yaml</code>
|
||||||
|
* in order to use this class.
|
||||||
|
*/
|
||||||
|
@ConditionalOnProperty(prefix = "hapi.fhir", name = "enable_repository_validating_interceptor", havingValue = "true")
|
||||||
|
@Configuration
|
||||||
|
@Conditional(OnR4Condition.class)
|
||||||
|
public class RepositoryValidationInterceptorFactoryR4 implements IRepositoryValidationInterceptorFactory {
|
||||||
|
|
||||||
|
private final FhirContext fhirContext;
|
||||||
|
private final RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder;
|
||||||
|
private final IFhirResourceDao structureDefinitionResourceProvider;
|
||||||
|
|
||||||
|
public RepositoryValidationInterceptorFactoryR4(RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder, DaoRegistry daoRegistry) {
|
||||||
|
this.repositoryValidatingRuleBuilder = repositoryValidatingRuleBuilder;
|
||||||
|
this.fhirContext = daoRegistry.getSystemDao().getContext();
|
||||||
|
structureDefinitionResourceProvider = daoRegistry.getResourceDao("StructureDefinition");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions() {
|
||||||
|
|
||||||
|
IBundleProvider results = structureDefinitionResourceProvider.search(new SearchParameterMap().add(StructureDefinition.SP_KIND, new TokenParam("resource")));
|
||||||
|
Map<String, List<StructureDefinition>> structureDefintions = results.getResources(0, results.size())
|
||||||
|
.stream()
|
||||||
|
.map(StructureDefinition.class::cast)
|
||||||
|
.collect(Collectors.groupingBy(StructureDefinition::getType));
|
||||||
|
|
||||||
|
structureDefintions.entrySet().forEach(structureDefinitionListEntry ->
|
||||||
|
{
|
||||||
|
String[] urls = structureDefinitionListEntry.getValue().stream().map(StructureDefinition::getUrl).toArray(String[]::new);
|
||||||
|
repositoryValidatingRuleBuilder.forResourcesOfType(structureDefinitionListEntry.getKey()).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles();
|
||||||
|
});
|
||||||
|
|
||||||
|
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||||
|
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepositoryValidatingInterceptor build() {
|
||||||
|
|
||||||
|
// Customize the ruleBuilder here to have the rules you want! We will give a simple example
|
||||||
|
// of enabling validation for all Patient resources
|
||||||
|
repositoryValidatingRuleBuilder.forResourcesOfType("Patient").requireAtLeastProfile("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient").and().requireValidationToDeclaredProfiles();
|
||||||
|
|
||||||
|
// Do not customize below this line
|
||||||
|
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||||
|
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.IRepositoryValidatingRule;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.jpa.starter.annotations.OnR5Condition;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be customized to enable the {@link RepositoryValidatingInterceptor}
|
||||||
|
* on this server.
|
||||||
|
* <p>
|
||||||
|
* The <code>enable_repository_validating_interceptor</code> property must be enabled in <code>application.yaml</code>
|
||||||
|
* in order to use this class.
|
||||||
|
*/
|
||||||
|
@ConditionalOnProperty(prefix = "hapi.fhir", name = "enable_repository_validating_interceptor", havingValue = "true")
|
||||||
|
@Configuration
|
||||||
|
@Conditional(OnR5Condition.class)
|
||||||
|
public class RepositoryValidationInterceptorFactoryR5 implements IRepositoryValidationInterceptorFactory {
|
||||||
|
|
||||||
|
private final FhirContext fhirContext;
|
||||||
|
private final RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder;
|
||||||
|
private final IFhirResourceDao structureDefinitionResourceProvider;
|
||||||
|
|
||||||
|
public RepositoryValidationInterceptorFactoryR5(RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder, DaoRegistry daoRegistry) {
|
||||||
|
this.repositoryValidatingRuleBuilder = repositoryValidatingRuleBuilder;
|
||||||
|
this.fhirContext = daoRegistry.getSystemDao().getContext();
|
||||||
|
structureDefinitionResourceProvider = daoRegistry.getResourceDao("StructureDefinition");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions() {
|
||||||
|
|
||||||
|
IBundleProvider results = structureDefinitionResourceProvider.search(new SearchParameterMap().add(StructureDefinition.SP_KIND, new TokenParam("resource")));
|
||||||
|
Map<String, List<StructureDefinition>> structureDefintions = results.getResources(0, results.size())
|
||||||
|
.stream()
|
||||||
|
.map(StructureDefinition.class::cast)
|
||||||
|
.collect(Collectors.groupingBy(StructureDefinition::getType));
|
||||||
|
|
||||||
|
structureDefintions.entrySet().forEach(structureDefinitionListEntry ->
|
||||||
|
{
|
||||||
|
String[] urls = structureDefinitionListEntry.getValue().stream().map(StructureDefinition::getUrl).toArray(String[]::new);
|
||||||
|
repositoryValidatingRuleBuilder.forResourcesOfType(structureDefinitionListEntry.getKey()).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles();
|
||||||
|
});
|
||||||
|
|
||||||
|
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||||
|
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepositoryValidatingInterceptor build() {
|
||||||
|
|
||||||
|
// Customize the ruleBuilder here to have the rules you want! We will give a simple example
|
||||||
|
// of enabling validation for all Patient resources
|
||||||
|
repositoryValidatingRuleBuilder.forResourcesOfType("Patient").requireAtLeastProfile("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient").and().requireValidationToDeclaredProfiles();
|
||||||
|
|
||||||
|
// Do not customize below this line
|
||||||
|
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||||
|
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cql;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Condition;
|
||||||
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
|
||||||
|
public class CqlConfigCondition implements Condition {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ConditionContext theConditionContext, AnnotatedTypeMetadata theAnnotatedTypeMetadata) {
|
||||||
|
String property = theConditionContext.getEnvironment().getProperty("hapi.fhir.cql_enabled");
|
||||||
|
boolean enabled = Boolean.parseBoolean(property);
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cql;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.cql.config.CqlDstu3Config;
|
||||||
|
import ca.uhn.fhir.jpa.starter.annotations.OnDSTU3Condition;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Conditional({OnDSTU3Condition.class, CqlConfigCondition.class})
|
||||||
|
@Import({CqlDstu3Config.class})
|
||||||
|
public class StarterCqlDstu3Config {
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cql;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.cql.config.CqlR4Config;
|
||||||
|
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
@Conditional({OnR4Condition.class, CqlConfigCondition.class})
|
||||||
|
@Import({CqlR4Config.class})
|
||||||
|
public class StarterCqlR4Config {
|
||||||
|
}
|
||||||
@@ -8,19 +8,23 @@ spring:
|
|||||||
max-active: 15
|
max-active: 15
|
||||||
jpa:
|
jpa:
|
||||||
properties:
|
properties:
|
||||||
|
hibernate.format_sql: false
|
||||||
|
hibernate.show_sql: false
|
||||||
# hibernate.dialect: org.hibernate.dialect.h2dialect
|
# hibernate.dialect: org.hibernate.dialect.h2dialect
|
||||||
# hibernate.search.model_mapping: ca.uhn.fhir.jpa.search.lucenesearchmappingfactory
|
|
||||||
# hibernate.format_sql: false
|
|
||||||
# hibernate.show_sql: false
|
|
||||||
# hibernate.hbm2ddl.auto: update
|
# hibernate.hbm2ddl.auto: update
|
||||||
# hibernate.jdbc.batch_size: 20
|
# hibernate.jdbc.batch_size: 20
|
||||||
# hibernate.cache.use_query_cache: false
|
# hibernate.cache.use_query_cache: false
|
||||||
# hibernate.cache.use_second_level_cache: false
|
# hibernate.cache.use_second_level_cache: false
|
||||||
# hibernate.cache.use_structured_entries: false
|
# hibernate.cache.use_structured_entries: false
|
||||||
# hibernate.cache.use_minimal_puts: false
|
# hibernate.cache.use_minimal_puts: false
|
||||||
# hibernate.search.default.directory_provider: filesystem
|
|
||||||
# hibernate.search.default.indexbase: target/lucenefiles
|
# These settings will enable fulltext search with lucene
|
||||||
# hibernate.search.lucene_version: lucene_current
|
# hibernate.search.enabled: true
|
||||||
|
# hibernate.search.backend.type: lucene
|
||||||
|
# hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer
|
||||||
|
# hibernate.search.backend.directory.type: local-filesystem
|
||||||
|
# hibernate.search.backend.directory.root: target/lucenefiles
|
||||||
|
# hibernate.search.backend.lucene_version: lucene_current
|
||||||
|
|
||||||
batch:
|
batch:
|
||||||
job:
|
job:
|
||||||
@@ -54,9 +58,11 @@ hapi:
|
|||||||
# allow_override_default_search_params: true
|
# allow_override_default_search_params: true
|
||||||
# allow_placeholder_references: true
|
# allow_placeholder_references: true
|
||||||
# auto_create_placeholder_reference_targets: false
|
# auto_create_placeholder_reference_targets: false
|
||||||
|
# cql_enabled: true
|
||||||
# default_encoding: JSON
|
# default_encoding: JSON
|
||||||
# default_pretty_print: true
|
# default_pretty_print: true
|
||||||
# default_page_size: 20
|
# default_page_size: 20
|
||||||
|
# enable_repository_validating_interceptor: false
|
||||||
# enable_index_missing_fields: false
|
# enable_index_missing_fields: false
|
||||||
# enforce_referential_integrity_on_delete: false
|
# enforce_referential_integrity_on_delete: false
|
||||||
# enforce_referential_integrity_on_write: false
|
# enforce_referential_integrity_on_write: false
|
||||||
@@ -122,6 +128,11 @@ hapi:
|
|||||||
# startTlsRequired:
|
# startTlsRequired:
|
||||||
# quitWait:
|
# quitWait:
|
||||||
# lastn_enabled: true
|
# lastn_enabled: true
|
||||||
|
### This is configuration for normalized quantity serach level default is 0
|
||||||
|
### 0: NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED - default
|
||||||
|
### 1: NORMALIZED_QUANTITY_STORAGE_SUPPORTED
|
||||||
|
### 2: NORMALIZED_QUANTITY_SEARCH_SUPPORTED
|
||||||
|
# normalized_quantity_search_level: 2
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -132,6 +143,7 @@ hapi:
|
|||||||
# enabled: false
|
# enabled: false
|
||||||
# password: SomePassword
|
# password: SomePassword
|
||||||
# required_index_status: YELLOW
|
# required_index_status: YELLOW
|
||||||
# rest_url: 'http://localhost:9200'
|
# rest_url: 'localhost:9200'
|
||||||
|
# protocol: 'http'
|
||||||
# schema_management_strategy: CREATE
|
# schema_management_strategy: CREATE
|
||||||
# username: SomeUsername
|
# username: SomeUsername
|
||||||
|
|||||||
@@ -9,6 +9,12 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework.beans" level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
<logger name="org.springframework.core" level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "1",
|
"version": "1",
|
||||||
|
"mdmTypes": ["Patient", "Practitioner"],
|
||||||
"candidateSearchParams": [
|
"candidateSearchParams": [
|
||||||
{
|
{
|
||||||
"resourceType": "Patient",
|
"resourceType": "Patient",
|
||||||
@@ -26,11 +26,13 @@ import org.springframework.context.ApplicationContextInitializer;
|
|||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
import pl.allegro.tech.embeddedelasticsearch.EmbeddedElastic;
|
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||||
import pl.allegro.tech.embeddedelasticsearch.PopularProperties;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
|
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -49,7 +51,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
// Because the port is set randomly, we will set the rest_url using the Initializer.
|
// Because the port is set randomly, we will set the rest_url using the Initializer.
|
||||||
// "elasticsearch.rest_url='http://localhost:9200'",
|
// "elasticsearch.rest_url='http://localhost:9200'",
|
||||||
"elasticsearch.username=SomeUsername",
|
"elasticsearch.username=SomeUsername",
|
||||||
"elasticsearch.password=SomePassword"
|
"elasticsearch.password=SomePassword",
|
||||||
|
"elasticsearch.protocol=http"
|
||||||
})
|
})
|
||||||
@ContextConfiguration(initializers = ElasticsearchLastNR4IT.Initializer.class)
|
@ContextConfiguration(initializers = ElasticsearchLastNR4IT.Initializer.class)
|
||||||
public class ElasticsearchLastNR4IT {
|
public class ElasticsearchLastNR4IT {
|
||||||
@@ -57,28 +60,18 @@ public class ElasticsearchLastNR4IT {
|
|||||||
private IGenericClient ourClient;
|
private IGenericClient ourClient;
|
||||||
private FhirContext ourCtx;
|
private FhirContext ourCtx;
|
||||||
|
|
||||||
private static final String ELASTIC_VERSION = "6.5.4";
|
private static final String ELASTIC_VERSION = "7.10.1";
|
||||||
private static EmbeddedElastic embeddedElastic;
|
private static final String ELASTIC_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch:" + ELASTIC_VERSION;
|
||||||
|
|
||||||
|
private static ElasticsearchContainer embeddedElastic;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ElasticsearchSvcImpl myElasticsearchSvc;
|
private ElasticsearchSvcImpl myElasticsearchSvc;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
|
embeddedElastic = new ElasticsearchContainer(ELASTIC_IMAGE).withStartupTimeout(Duration.of(300, ChronoUnit.SECONDS));
|
||||||
embeddedElastic = null;
|
embeddedElastic.start();
|
||||||
try {
|
|
||||||
embeddedElastic = EmbeddedElastic.builder()
|
|
||||||
.withElasticVersion(ELASTIC_VERSION)
|
|
||||||
.withSetting(PopularProperties.TRANSPORT_TCP_PORT, 0)
|
|
||||||
.withSetting(PopularProperties.HTTP_PORT, 0)
|
|
||||||
.withSetting(PopularProperties.CLUSTER_NAME, UUID.randomUUID())
|
|
||||||
.withStartTimeout(60, TimeUnit.SECONDS)
|
|
||||||
.build()
|
|
||||||
.start();
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
throw new ConfigurationException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
@@ -136,7 +129,7 @@ public class ElasticsearchLastNR4IT {
|
|||||||
public void initialize(
|
public void initialize(
|
||||||
ConfigurableApplicationContext configurableApplicationContext) {
|
ConfigurableApplicationContext configurableApplicationContext) {
|
||||||
// Since the port is dynamically generated, replace the URL with one that has the correct port
|
// Since the port is dynamically generated, replace the URL with one that has the correct port
|
||||||
TestPropertyValues.of("elasticsearch.rest_url=http://localhost:" + embeddedElastic.getHttpPort())
|
TestPropertyValues.of("elasticsearch.rest_url=" + embeddedElastic.getHost() +":" + embeddedElastic.getMappedPort(9200))
|
||||||
.applyTo(configurableApplicationContext.getEnvironment());
|
.applyTo(configurableApplicationContext.getEnvironment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,35 @@
|
|||||||
package ca.uhn.fhir.jpa.starter;
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
import org.hl7.fhir.dstu3.model.*;
|
||||||
import org.hl7.fhir.dstu3.model.Observation;
|
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
|
||||||
import org.hl7.fhir.dstu3.model.Subscription;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.junit.Assert;
|
||||||
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.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.web.server.LocalServerPort;
|
import org.springframework.boot.web.server.LocalServerPort;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@@ -34,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
{
|
{
|
||||||
"spring.batch.job.enabled=false",
|
"spring.batch.job.enabled=false",
|
||||||
"spring.datasource.url=jdbc:h2:mem:dbr3",
|
"spring.datasource.url=jdbc:h2:mem:dbr3",
|
||||||
|
"hapi.fhir.cql_enabled=true",
|
||||||
"hapi.fhir.fhir_version=dstu3",
|
"hapi.fhir.fhir_version=dstu3",
|
||||||
"hapi.fhir.subscription.websocket_enabled=true",
|
"hapi.fhir.subscription.websocket_enabled=true",
|
||||||
"hapi.fhir.allow_external_references=true",
|
"hapi.fhir.allow_external_references=true",
|
||||||
@@ -41,15 +49,28 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
public class ExampleServerDstu3IT {
|
public class ExampleServerDstu3IT implements IServerSupport {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
||||||
private IGenericClient ourClient;
|
private IGenericClient ourClient;
|
||||||
private FhirContext ourCtx;
|
private FhirContext ourCtx;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DaoRegistry myDaoRegistry;
|
||||||
|
|
||||||
@LocalServerPort
|
@LocalServerPort
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void beforeEach() {
|
||||||
|
ourCtx = FhirContext.forDstu3();
|
||||||
|
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||||
|
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||||
|
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||||
|
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||||
|
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateAndRead() {
|
public void testCreateAndRead() {
|
||||||
|
|
||||||
@@ -63,6 +84,75 @@ public class ExampleServerDstu3IT {
|
|||||||
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Currently fails with:
|
||||||
|
// ca.uhn.fhir.rest.server.exceptions.InternalErrorException: HTTP 500 : Failed to call access method: java.lang.IllegalArgumentException: Could not load library source for libraries referenced in Measure/Measure/measure-EXM104-FHIR3-8.1.000/_history/1.
|
||||||
|
//@Test
|
||||||
|
public void testCQLEvaluateMeasureEXM104() throws IOException {
|
||||||
|
String measureId = "measure-EXM104-FHIR3-8.1.000";
|
||||||
|
|
||||||
|
int numFilesLoaded = loadDataFromDirectory("dstu3/EXM104/EXM104_FHIR3-8.1.000-files");
|
||||||
|
//assertEquals(numFilesLoaded, 3);
|
||||||
|
ourLog.info("{} files imported successfully!", numFilesLoaded);
|
||||||
|
//loadBundle("dstu3/EXM104/EXM104_FHIR3-8.1.000-bundle.json", ourCtx, ourClient);
|
||||||
|
|
||||||
|
// http://localhost:8080/fhir/Measure/measure-EXM104-FHIR3-8.1.000/$evaluate-measure?periodStart=2019-01-01&periodEnd=2019-12-31
|
||||||
|
Parameters inParams = new Parameters();
|
||||||
|
// inParams.addParameter().setName("measure").setValue(new StringType("Measure/measure-EXM104-8.2.000"));
|
||||||
|
// inParams.addParameter().setName("patient").setValue(new StringType("Patient/numer-EXM104-FHIR3"));
|
||||||
|
// inParams.addParameter().setName("periodStart").setValue(new StringType("2019-01-01"));
|
||||||
|
// inParams.addParameter().setName("periodEnd").setValue(new StringType("2019-12-31"));
|
||||||
|
|
||||||
|
Parameters outParams = ourClient
|
||||||
|
.operation()
|
||||||
|
.onInstance(new IdDt("Measure", measureId))
|
||||||
|
.named("$evaluate-measure")
|
||||||
|
.withParameters(inParams)
|
||||||
|
.cacheControl(new CacheControlDirective().setNoCache(true))
|
||||||
|
.withAdditionalHeader("Content-Type", "application/json")
|
||||||
|
.useHttpGet()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
List<Parameters.ParametersParameterComponent> response = outParams.getParameter();
|
||||||
|
Assert.assertTrue(!response.isEmpty());
|
||||||
|
Parameters.ParametersParameterComponent component = response.get(0);
|
||||||
|
Assert.assertTrue(component.getResource() instanceof MeasureReport);
|
||||||
|
MeasureReport report = (MeasureReport) component.getResource();
|
||||||
|
Assert.assertEquals("Measure/"+measureId, report.getMeasure());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int loadDataFromDirectory(String theDirectoryName) throws IOException {
|
||||||
|
int count = 0;
|
||||||
|
ourLog.info("Reading files in directory: {}", theDirectoryName);
|
||||||
|
ClassPathResource dir = new ClassPathResource(theDirectoryName);
|
||||||
|
Collection<File> files = FileUtils.listFiles(dir.getFile(), null, false);
|
||||||
|
ourLog.info("{} files found.", files.size());
|
||||||
|
for (File file : files) {
|
||||||
|
String filename = file.getAbsolutePath();
|
||||||
|
ourLog.info("Processing filename '{}'", filename);
|
||||||
|
if (filename.endsWith(".cql") || filename.contains("expectedresults")) {
|
||||||
|
// Ignore .cql and expectedresults files
|
||||||
|
ourLog.info("Ignoring file: '{}'", filename);
|
||||||
|
} else if (filename.endsWith(".json")) {
|
||||||
|
if (filename.contains("bundle")) {
|
||||||
|
loadBundle(filename, ourCtx, ourClient);
|
||||||
|
} else {
|
||||||
|
loadResource(filename, ourCtx, myDaoRegistry);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
ourLog.info("Ignoring file: '{}'", filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bundle loadBundle(String theLocation, FhirContext theCtx, IGenericClient theClient) throws IOException {
|
||||||
|
String json = stringFromResource(theLocation);
|
||||||
|
Bundle bundle = (Bundle) theCtx.newJsonParser().parseResource(json);
|
||||||
|
Bundle result = (Bundle) theClient.transaction().withBundle(bundle).execute();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWebsocketSubscription() throws Exception {
|
public void testWebsocketSubscription() throws Exception {
|
||||||
/*
|
/*
|
||||||
@@ -121,15 +211,4 @@ public class ExampleServerDstu3IT {
|
|||||||
ourClient.delete().resourceById(mySubscriptionId).execute();
|
ourClient.delete().resourceById(mySubscriptionId).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void beforeEach() {
|
|
||||||
|
|
||||||
ourCtx = FhirContext.forDstu3();
|
|
||||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
|
||||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
|
||||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
|
||||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
|
||||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,12 @@ import org.eclipse.jetty.websocket.api.Session;
|
|||||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Order;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
@@ -21,31 +25,33 @@ import org.springframework.boot.web.server.LocalServerPort;
|
|||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static ca.uhn.fhir.util.TestUtil.waitForSize;
|
import static ca.uhn.fhir.util.TestUtil.waitForSize;
|
||||||
|
import static java.lang.Thread.sleep;
|
||||||
|
import static java.util.Comparator.comparing;
|
||||||
import static org.awaitility.Awaitility.await;
|
import static org.awaitility.Awaitility.await;
|
||||||
|
import static org.awaitility.Awaitility.pollInSameThread;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
||||||
{
|
{
|
||||||
"spring.batch.job.enabled=false",
|
"spring.batch.job.enabled=false",
|
||||||
"spring.datasource.url=jdbc:h2:mem:dbr4",
|
"spring.datasource.url=jdbc:h2:mem:dbr4",
|
||||||
|
"hapi.fhir.enable_repository_validating_interceptor=true",
|
||||||
"hapi.fhir.fhir_version=r4",
|
"hapi.fhir.fhir_version=r4",
|
||||||
"hapi.fhir.subscription.websocket_enabled=true",
|
"hapi.fhir.subscription.websocket_enabled=true",
|
||||||
"hapi.fhir.empi_enabled=true",
|
"hapi.fhir.mdm_enabled=true",
|
||||||
//Override is currently required when using Empi as the construction of the Empi beans are ambiguous as they are constructed multiple places. This is evident when running in a spring boot environment
|
//Override is currently required when using MDM as the construction of the MDM beans are ambiguous as they are constructed multiple places. This is evident when running in a spring boot environment
|
||||||
"spring.main.allow-bean-definition-overriding=true"
|
"spring.main.allow-bean-definition-overriding=true"
|
||||||
})
|
})
|
||||||
public class ExampleServerR4IT {
|
public class ExampleServerR4IT {
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerR4IT.class);
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
|
||||||
private IGenericClient ourClient;
|
private IGenericClient ourClient;
|
||||||
private FhirContext ourCtx;
|
private FhirContext ourCtx;
|
||||||
|
|
||||||
@@ -54,9 +60,10 @@ public class ExampleServerR4IT {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Order(0)
|
||||||
void testCreateAndRead() {
|
void testCreateAndRead() {
|
||||||
|
String methodName = "testCreateAndRead";
|
||||||
String methodName = "testCreateResourceConditional";
|
ourLog.info("Entering " + methodName + "()...");
|
||||||
|
|
||||||
Patient pt = new Patient();
|
Patient pt = new Patient();
|
||||||
pt.setActive(true);
|
pt.setActive(true);
|
||||||
@@ -68,29 +75,38 @@ public class ExampleServerR4IT {
|
|||||||
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
||||||
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
||||||
|
|
||||||
// Test EMPI
|
|
||||||
|
|
||||||
// Wait until the EMPI message has been processed
|
// Wait until the MDM message has been processed
|
||||||
await().until(() -> getPeople().size() > 0);
|
await().until(() -> {
|
||||||
List<Person> persons = getPeople();
|
sleep(1000);
|
||||||
|
return getGoldenResourcePatient() != null;
|
||||||
|
});
|
||||||
|
Patient goldenRecord = getGoldenResourcePatient();
|
||||||
|
|
||||||
// Verify a Person was created that links to our Patient
|
// Verify that a golden record Patient was created
|
||||||
Optional<String> personLinkToCreatedPatient = persons.stream()
|
assertNotNull(goldenRecord.getMeta().getTag("http://hapifhir.io/fhir/NamingSystem/mdm-record-status", "GOLDEN_RECORD"));
|
||||||
.map(Person::getLink)
|
|
||||||
.flatMap(Collection::stream)
|
|
||||||
.map(Person.PersonLinkComponent::getTarget)
|
|
||||||
.map(Reference::getReference)
|
|
||||||
.filter(pid -> id.toUnqualifiedVersionless().getValue().equals(pid))
|
|
||||||
.findAny();
|
|
||||||
assertTrue(personLinkToCreatedPatient.isPresent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Person> getPeople() {
|
private List<Patient> getPatients() {
|
||||||
Bundle bundle = ourClient.search().forResource(Person.class).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute();
|
Bundle bundle = ourClient.search().forResource(Patient.class).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute();
|
||||||
return BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Person.class);
|
List<Patient> retVal = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class);
|
||||||
|
retVal.sort(comparing(o -> ((Patient) o).getMeta().getLastUpdated()).reversed());
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
private Patient getGoldenResourcePatient() {
|
||||||
|
Bundle bundle = ourClient.search()
|
||||||
|
.forResource(Patient.class)
|
||||||
|
.withTag("http://hapifhir.io/fhir/NamingSystem/mdm-record-status", "GOLDEN_RECORD")
|
||||||
|
.cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute();
|
||||||
|
if (bundle.getEntryFirstRep() != null) {
|
||||||
|
return (Patient) bundle.getEntryFirstRep().getResource();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Order(1)
|
||||||
public void testWebsocketSubscription() throws Exception {
|
public void testWebsocketSubscription() throws Exception {
|
||||||
/*
|
/*
|
||||||
* Create subscription
|
* Create subscription
|
||||||
@@ -135,7 +151,7 @@ public class ExampleServerR4IT {
|
|||||||
ourClient.create().resource(obs).execute();
|
ourClient.create().resource(obs).execute();
|
||||||
|
|
||||||
// Give some time for the subscription to deliver
|
// Give some time for the subscription to deliver
|
||||||
Thread.sleep(2000);
|
sleep(2000);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that we receive a ping on the websocket
|
* Ensure that we receive a ping on the websocket
|
||||||
@@ -161,6 +177,6 @@ public class ExampleServerR4IT {
|
|||||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
// ourClient.registerInterceptor(new LoggingInterceptor(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
|||||||
"spring.batch.job.enabled=false",
|
"spring.batch.job.enabled=false",
|
||||||
"spring.datasource.url=jdbc:h2:mem:dbr5",
|
"spring.datasource.url=jdbc:h2:mem:dbr5",
|
||||||
"hapi.fhir.fhir_version=r5",
|
"hapi.fhir.fhir_version=r5",
|
||||||
|
"hapi.fhir.subscription.websocket_enabled=true",
|
||||||
"hapi.fhir.subscription.websocket_enabled=true"
|
"hapi.fhir.subscription.websocket_enabled=true"
|
||||||
})
|
})
|
||||||
public class ExampleServerR5IT {
|
public class ExampleServerR5IT {
|
||||||
|
|||||||
42
src/test/java/ca/uhn/fhir/jpa/starter/IServerSupport.java
Normal file
42
src/test/java/ca/uhn/fhir/jpa/starter/IServerSupport.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public interface IServerSupport {
|
||||||
|
|
||||||
|
default IBaseResource loadResource(String theLocation, FhirContext theFhirContext, DaoRegistry theDaoRegistry) throws IOException {
|
||||||
|
String json = stringFromResource(theLocation);
|
||||||
|
IBaseResource resource = theFhirContext.newJsonParser().parseResource(json);
|
||||||
|
IFhirResourceDao<IBaseResource> dao = theDaoRegistry.getResourceDao(resource.getIdElement().getResourceType());
|
||||||
|
if (dao == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
dao.update(resource);
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default String stringFromResource(String theLocation) throws IOException {
|
||||||
|
InputStream is = null;
|
||||||
|
if (theLocation.startsWith(File.separator)) {
|
||||||
|
is = new FileInputStream(theLocation);
|
||||||
|
} else {
|
||||||
|
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
Resource resource = resourceLoader.getResource(theLocation);
|
||||||
|
is = resource.getInputStream();
|
||||||
|
}
|
||||||
|
return IOUtils.toString(is, Charsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ hapi:
|
|||||||
# allow_override_default_search_params: true
|
# allow_override_default_search_params: true
|
||||||
# allow_placeholder_references: true
|
# allow_placeholder_references: true
|
||||||
# auto_create_placeholder_reference_targets: false
|
# auto_create_placeholder_reference_targets: false
|
||||||
|
# cql_enabled: false
|
||||||
# default_encoding: JSON
|
# default_encoding: JSON
|
||||||
# default_pretty_print: true
|
# default_pretty_print: true
|
||||||
# default_page_size: 20
|
# default_page_size: 20
|
||||||
|
|||||||
4409
src/test/resources/dstu3/EXM104/EXM104_FHIR3-8.1.000-bundle.json
Normal file
4409
src/test/resources/dstu3/EXM104/EXM104_FHIR3-8.1.000-bundle.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,303 @@
|
|||||||
|
{
|
||||||
|
"resourceType": "MeasureReport",
|
||||||
|
"id": "measurereport-denom-EXM104-FHIR3-8.1.000-expectedresults",
|
||||||
|
"contained": [
|
||||||
|
{
|
||||||
|
"resourceType": "Bundle",
|
||||||
|
"id": "b20ba55e-a72e-493d-868d-e9f6c007d11a",
|
||||||
|
"type": "collection",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"fullUrl": "Condition/denom-EXM104-FHIR3-1",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Condition",
|
||||||
|
"id": "denom-EXM104-FHIR3-1",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"verificationStatus": "confirmed",
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
|
||||||
|
"code": "encounter-diagnosis",
|
||||||
|
"display": "Encounter Diagnosis"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "116288000",
|
||||||
|
"display": "Paralytic stroke (disorder)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Encounter/denom-EXM104-FHIR3-2",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Encounter",
|
||||||
|
"id": "denom-EXM104-FHIR3-2",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": "finished",
|
||||||
|
"class": {
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||||
|
"code": "IMP",
|
||||||
|
"display": "inpatient encounter"
|
||||||
|
},
|
||||||
|
"type": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "32485007",
|
||||||
|
"display": "Hospital admission (procedure)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-08-21T00:00:00-06:00",
|
||||||
|
"end": "2019-12-19T08:15:00-07:00"
|
||||||
|
},
|
||||||
|
"diagnosis": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"reference": "Condition/denom-EXM104-FHIR3-1"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://hl7.org/fhir/diagnosis-role",
|
||||||
|
"code": "billing",
|
||||||
|
"display": "Billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rank": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Patient/denom-EXM104-FHIR3",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Patient",
|
||||||
|
"id": "denom-EXM104-FHIR3",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"status": "generated",
|
||||||
|
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\">Rick <b>JONES </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>9999999910</td></tr><tr><td>Date of birth</td><td><span>05 November 1955</span></td></tr></tbody></table></div>"
|
||||||
|
},
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2054-5",
|
||||||
|
"display": "Black or African American"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2135-2",
|
||||||
|
"display": "Hispanic or Latino"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"identifier": [
|
||||||
|
{
|
||||||
|
"use": "usual",
|
||||||
|
"type": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "MR",
|
||||||
|
"display": "Medical Record Number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"system": "http://hospital.smarthealthit.org",
|
||||||
|
"value": "9999999910"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"family": "Jones",
|
||||||
|
"given": [
|
||||||
|
"Rick"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gender": "male",
|
||||||
|
"birthDate": "1955-11-05"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "a6811e61-b875-43ac-960d-de15dab68184",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "a6811e61-b875-43ac-960d-de15dab68184",
|
||||||
|
"title": "initial-population",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3-2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "f8cb86c0-faf5-433d-bb60-d1bbbaf67abc",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "f8cb86c0-faf5-433d-bb60-d1bbbaf67abc",
|
||||||
|
"title": "denominator",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "complete",
|
||||||
|
"type": "individual",
|
||||||
|
"measure": {
|
||||||
|
"reference": "Measure/measure-EXM104-FHIR3-8.1.000"
|
||||||
|
},
|
||||||
|
"patient": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-01-01T00:00:00-07:00",
|
||||||
|
"end": "2019-12-31T00:00:00-07:00"
|
||||||
|
},
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "group-1"
|
||||||
|
},
|
||||||
|
"population": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "initial-population-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "initial-population",
|
||||||
|
"display": "Initial Population"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "numerator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "numerator",
|
||||||
|
"display": "Numerator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator",
|
||||||
|
"display": "Denominator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-exclusions-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator-exclusion",
|
||||||
|
"display": "Denominator Exclusion"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"measureScore": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"evaluatedResources": {
|
||||||
|
"reference": "#b20ba55e-a72e-493d-868d-e9f6c007d11a"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,353 @@
|
|||||||
|
{
|
||||||
|
"resourceType": "MeasureReport",
|
||||||
|
"id": "measurereport-numer-EXM104-FHIR3-8.1.000-expectedresults",
|
||||||
|
"contained": [
|
||||||
|
{
|
||||||
|
"resourceType": "Bundle",
|
||||||
|
"id": "edc87d47-5804-4d85-8874-ee2d50e51c51",
|
||||||
|
"type": "collection",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"fullUrl": "MedicationRequest/numer-EXM104-FHIR3-5",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "MedicationRequest",
|
||||||
|
"id": "numer-EXM104-FHIR3-5",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00"
|
||||||
|
},
|
||||||
|
"status": "completed",
|
||||||
|
"intent": "order",
|
||||||
|
"category": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/medicationrequest-category",
|
||||||
|
"code": "discharge",
|
||||||
|
"display": "Discharge"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"medicationCodeableConcept": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
|
||||||
|
"code": "1037045",
|
||||||
|
"display": "dabigatran etexilate 150 MG Oral Capsule"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"authoredOn": "2019-12-19T08:00:00-07:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Patient/numer-EXM104-FHIR3",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Patient",
|
||||||
|
"id": "numer-EXM104-FHIR3",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"status": "generated",
|
||||||
|
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\">Louise <b>JONES </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>9999999911</td></tr><tr><td>Date of birth</td><td><span>21 November 1971</span></td></tr></tbody></table></div>"
|
||||||
|
},
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2106-3",
|
||||||
|
"display": "White"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2186-5",
|
||||||
|
"display": "Not Hispanic or Latino"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"identifier": [
|
||||||
|
{
|
||||||
|
"use": "usual",
|
||||||
|
"type": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "MR",
|
||||||
|
"display": "Medical Record Number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"system": "http://hospital.smarthealthit.org",
|
||||||
|
"value": "9999999911"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"family": "Jones",
|
||||||
|
"given": [
|
||||||
|
"Louise"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gender": "female",
|
||||||
|
"birthDate": "1971-11-21"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "475b43c7-73fd-4400-a23b-b0accf116c79",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "475b43c7-73fd-4400-a23b-b0accf116c79",
|
||||||
|
"title": "initial-population",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "94606d36-6bd7-48b5-a519-7af88afa0b68",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "94606d36-6bd7-48b5-a519-7af88afa0b68",
|
||||||
|
"title": "denominator",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "7720275f-18c4-435c-8eeb-b154ac3b882a",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "7720275f-18c4-435c-8eeb-b154ac3b882a",
|
||||||
|
"title": "numerator",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Encounter/numer-EXM104-FHIR3-2",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Encounter",
|
||||||
|
"id": "numer-EXM104-FHIR3-2",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": "finished",
|
||||||
|
"class": {
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||||
|
"code": "IMP",
|
||||||
|
"display": "inpatient encounter"
|
||||||
|
},
|
||||||
|
"type": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "32485007",
|
||||||
|
"display": "Hospital admission (procedure)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-08-21T00:00:00-06:00",
|
||||||
|
"end": "2019-12-19T08:15:00-07:00"
|
||||||
|
},
|
||||||
|
"diagnosis": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"reference": "Condition/numer-EXM104-FHIR3-1"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://hl7.org/fhir/diagnosis-role",
|
||||||
|
"code": "billing",
|
||||||
|
"display": "Billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rank": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Condition/numer-EXM104-FHIR3-1",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Condition",
|
||||||
|
"id": "numer-EXM104-FHIR3-1",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"verificationStatus": "confirmed",
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
|
||||||
|
"code": "encounter-diagnosis",
|
||||||
|
"display": "Encounter Diagnosis"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "116288000",
|
||||||
|
"display": "Paralytic stroke (disorder)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "complete",
|
||||||
|
"type": "individual",
|
||||||
|
"measure": {
|
||||||
|
"reference": "Measure/measure-EXM104-FHIR3-8.1.000"
|
||||||
|
},
|
||||||
|
"patient": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-01-01T00:00:00-07:00",
|
||||||
|
"end": "2019-12-31T00:00:00-07:00"
|
||||||
|
},
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "group-1"
|
||||||
|
},
|
||||||
|
"population": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "initial-population-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "initial-population",
|
||||||
|
"display": "Initial Population"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "numerator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "numerator",
|
||||||
|
"display": "Numerator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator",
|
||||||
|
"display": "Denominator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-exclusions-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator-exclusion",
|
||||||
|
"display": "Denominator Exclusion"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"measureScore": 1.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"evaluatedResources": {
|
||||||
|
"reference": "#edc87d47-5804-4d85-8874-ee2d50e51c51"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,480 @@
|
|||||||
|
{
|
||||||
|
"resourceType": "Bundle",
|
||||||
|
"id": "tests-denom-EXM104-FHIR3-bundle",
|
||||||
|
"type": "transaction",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Condition",
|
||||||
|
"id": "denom-EXM104-FHIR3-1",
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"verificationStatus": "confirmed",
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
|
||||||
|
"code": "encounter-diagnosis",
|
||||||
|
"display": "Encounter Diagnosis"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "116288000",
|
||||||
|
"display": "Paralytic stroke (disorder)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Condition/denom-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Encounter",
|
||||||
|
"id": "denom-EXM104-FHIR3-2",
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": "finished",
|
||||||
|
"class": {
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||||
|
"code": "IMP",
|
||||||
|
"display": "inpatient encounter"
|
||||||
|
},
|
||||||
|
"type": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "32485007",
|
||||||
|
"display": "Hospital admission (procedure)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-08-21T00:00:00-06:00",
|
||||||
|
"end": "2019-12-19T08:15:00-07:00"
|
||||||
|
},
|
||||||
|
"diagnosis": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"reference": "Condition/denom-EXM104-FHIR3-1"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://hl7.org/fhir/diagnosis-role",
|
||||||
|
"code": "billing",
|
||||||
|
"display": "Billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rank": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Encounter/denom-EXM104-FHIR3-2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "MeasureReport",
|
||||||
|
"id": "measurereport-denom-EXM104-FHIR3",
|
||||||
|
"contained": [
|
||||||
|
{
|
||||||
|
"resourceType": "Bundle",
|
||||||
|
"id": "b20ba55e-a72e-493d-868d-e9f6c007d11a",
|
||||||
|
"type": "collection",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"fullUrl": "Condition/denom-EXM104-FHIR3-1",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Condition",
|
||||||
|
"id": "denom-EXM104-FHIR3-1",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"verificationStatus": "confirmed",
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
|
||||||
|
"code": "encounter-diagnosis",
|
||||||
|
"display": "Encounter Diagnosis"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "116288000",
|
||||||
|
"display": "Paralytic stroke (disorder)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Encounter/denom-EXM104-FHIR3-2",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Encounter",
|
||||||
|
"id": "denom-EXM104-FHIR3-2",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": "finished",
|
||||||
|
"class": {
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||||
|
"code": "IMP",
|
||||||
|
"display": "inpatient encounter"
|
||||||
|
},
|
||||||
|
"type": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "32485007",
|
||||||
|
"display": "Hospital admission (procedure)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-08-21T00:00:00-06:00",
|
||||||
|
"end": "2019-12-19T08:15:00-07:00"
|
||||||
|
},
|
||||||
|
"diagnosis": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"reference": "Condition/denom-EXM104-FHIR3-1"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://hl7.org/fhir/diagnosis-role",
|
||||||
|
"code": "billing",
|
||||||
|
"display": "Billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rank": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Patient/denom-EXM104-FHIR3",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Patient",
|
||||||
|
"id": "denom-EXM104-FHIR3",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"status": "generated",
|
||||||
|
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\">Rick <b>JONES </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>9999999910</td></tr><tr><td>Date of birth</td><td><span>05 November 1955</span></td></tr></tbody></table></div>"
|
||||||
|
},
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2054-5",
|
||||||
|
"display": "Black or African American"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2135-2",
|
||||||
|
"display": "Hispanic or Latino"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"identifier": [
|
||||||
|
{
|
||||||
|
"use": "usual",
|
||||||
|
"type": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "MR",
|
||||||
|
"display": "Medical Record Number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"system": "http://hospital.smarthealthit.org",
|
||||||
|
"value": "9999999910"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"family": "Jones",
|
||||||
|
"given": [
|
||||||
|
"Rick"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gender": "male",
|
||||||
|
"birthDate": "1955-11-05"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "a6811e61-b875-43ac-960d-de15dab68184",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "a6811e61-b875-43ac-960d-de15dab68184",
|
||||||
|
"title": "initial-population",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3-2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "f8cb86c0-faf5-433d-bb60-d1bbbaf67abc",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "f8cb86c0-faf5-433d-bb60-d1bbbaf67abc",
|
||||||
|
"title": "denominator",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "denom-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "complete",
|
||||||
|
"type": "individual",
|
||||||
|
"measure": {
|
||||||
|
"reference": "Measure/measure-EXM104-FHIR3-8.1.000"
|
||||||
|
},
|
||||||
|
"patient": {
|
||||||
|
"reference": "Patient/denom-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-01-01T00:00:00-07:00",
|
||||||
|
"end": "2019-12-31T00:00:00-07:00"
|
||||||
|
},
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "group-1"
|
||||||
|
},
|
||||||
|
"population": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "initial-population-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "initial-population",
|
||||||
|
"display": "Initial Population"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "numerator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "numerator",
|
||||||
|
"display": "Numerator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator",
|
||||||
|
"display": "Denominator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-exclusions-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator-exclusion",
|
||||||
|
"display": "Denominator Exclusion"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"measureScore": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"evaluatedResources": {
|
||||||
|
"reference": "#b20ba55e-a72e-493d-868d-e9f6c007d11a"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "MeasureReport/measurereport-denom-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Patient",
|
||||||
|
"id": "denom-EXM104-FHIR3",
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2054-5",
|
||||||
|
"display": "Black or African American"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2135-2",
|
||||||
|
"display": "Hispanic or Latino"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"identifier": [
|
||||||
|
{
|
||||||
|
"use": "usual",
|
||||||
|
"type": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "MR",
|
||||||
|
"display": "Medical Record Number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"system": "http://hospital.smarthealthit.org",
|
||||||
|
"value": "9999999910"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"family": "Jones",
|
||||||
|
"given": [
|
||||||
|
"Rick"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gender": "male",
|
||||||
|
"birthDate": "1955-11-05"
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Patient/denom-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,564 @@
|
|||||||
|
{
|
||||||
|
"resourceType": "Bundle",
|
||||||
|
"id": "tests-numer-EXM104-FHIR3-bundle",
|
||||||
|
"type": "transaction",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Condition",
|
||||||
|
"id": "numer-EXM104-FHIR3-1",
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"verificationStatus": "confirmed",
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
|
||||||
|
"code": "encounter-diagnosis",
|
||||||
|
"display": "Encounter Diagnosis"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "116288000",
|
||||||
|
"display": "Paralytic stroke (disorder)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Condition/numer-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Encounter",
|
||||||
|
"id": "numer-EXM104-FHIR3-2",
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": "finished",
|
||||||
|
"class": {
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||||
|
"code": "IMP",
|
||||||
|
"display": "inpatient encounter"
|
||||||
|
},
|
||||||
|
"type": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "32485007",
|
||||||
|
"display": "Hospital admission (procedure)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-08-21T00:00:00-06:00",
|
||||||
|
"end": "2019-12-19T08:15:00-07:00"
|
||||||
|
},
|
||||||
|
"diagnosis": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"reference": "Condition/numer-EXM104-FHIR3-1"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://hl7.org/fhir/diagnosis-role",
|
||||||
|
"code": "billing",
|
||||||
|
"display": "Billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rank": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Encounter/numer-EXM104-FHIR3-2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "MeasureReport",
|
||||||
|
"id": "measurereport-numer-EXM104-FHIR3",
|
||||||
|
"contained": [
|
||||||
|
{
|
||||||
|
"resourceType": "Bundle",
|
||||||
|
"id": "edc87d47-5804-4d85-8874-ee2d50e51c51",
|
||||||
|
"type": "collection",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"fullUrl": "MedicationRequest/numer-EXM104-FHIR3-5",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "MedicationRequest",
|
||||||
|
"id": "numer-EXM104-FHIR3-5",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00"
|
||||||
|
},
|
||||||
|
"status": "completed",
|
||||||
|
"intent": "order",
|
||||||
|
"category": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/medicationrequest-category",
|
||||||
|
"code": "discharge",
|
||||||
|
"display": "Discharge"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"medicationCodeableConcept": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
|
||||||
|
"code": "1037045",
|
||||||
|
"display": "dabigatran etexilate 150 MG Oral Capsule"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"authoredOn": "2019-12-19T08:00:00-07:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Patient/numer-EXM104-FHIR3",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Patient",
|
||||||
|
"id": "numer-EXM104-FHIR3",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"status": "generated",
|
||||||
|
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\">Louise <b>JONES </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>9999999911</td></tr><tr><td>Date of birth</td><td><span>21 November 1971</span></td></tr></tbody></table></div>"
|
||||||
|
},
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2106-3",
|
||||||
|
"display": "White"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2186-5",
|
||||||
|
"display": "Not Hispanic or Latino"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"identifier": [
|
||||||
|
{
|
||||||
|
"use": "usual",
|
||||||
|
"type": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "MR",
|
||||||
|
"display": "Medical Record Number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"system": "http://hospital.smarthealthit.org",
|
||||||
|
"value": "9999999911"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"family": "Jones",
|
||||||
|
"given": [
|
||||||
|
"Louise"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gender": "female",
|
||||||
|
"birthDate": "1971-11-21"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "475b43c7-73fd-4400-a23b-b0accf116c79",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "475b43c7-73fd-4400-a23b-b0accf116c79",
|
||||||
|
"title": "initial-population",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "94606d36-6bd7-48b5-a519-7af88afa0b68",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "94606d36-6bd7-48b5-a519-7af88afa0b68",
|
||||||
|
"title": "denominator",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "7720275f-18c4-435c-8eeb-b154ac3b882a",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "List",
|
||||||
|
"id": "7720275f-18c4-435c-8eeb-b154ac3b882a",
|
||||||
|
"title": "numerator",
|
||||||
|
"entry": [
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"reference": "numer-EXM104-FHIR3-5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Encounter/numer-EXM104-FHIR3-2",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Encounter",
|
||||||
|
"id": "numer-EXM104-FHIR3-2",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": "finished",
|
||||||
|
"class": {
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||||
|
"code": "IMP",
|
||||||
|
"display": "inpatient encounter"
|
||||||
|
},
|
||||||
|
"type": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "32485007",
|
||||||
|
"display": "Hospital admission (procedure)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-08-21T00:00:00-06:00",
|
||||||
|
"end": "2019-12-19T08:15:00-07:00"
|
||||||
|
},
|
||||||
|
"diagnosis": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"reference": "Condition/numer-EXM104-FHIR3-1"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://hl7.org/fhir/diagnosis-role",
|
||||||
|
"code": "billing",
|
||||||
|
"display": "Billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rank": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fullUrl": "Condition/numer-EXM104-FHIR3-1",
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Condition",
|
||||||
|
"id": "numer-EXM104-FHIR3-1",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2019-12-18T22:42:17.748-07:00",
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"verificationStatus": "confirmed",
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
|
||||||
|
"code": "encounter-diagnosis",
|
||||||
|
"display": "Encounter Diagnosis"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://snomed.info/sct",
|
||||||
|
"code": "116288000",
|
||||||
|
"display": "Paralytic stroke (disorder)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "complete",
|
||||||
|
"type": "individual",
|
||||||
|
"measure": {
|
||||||
|
"reference": "Measure/measure-EXM104-FHIR3-8.1.000"
|
||||||
|
},
|
||||||
|
"patient": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2019-01-01T00:00:00-07:00",
|
||||||
|
"end": "2019-12-31T00:00:00-07:00"
|
||||||
|
},
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "group-1"
|
||||||
|
},
|
||||||
|
"population": [
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "initial-population-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "initial-population",
|
||||||
|
"display": "Initial Population"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "numerator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "numerator",
|
||||||
|
"display": "Numerator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator",
|
||||||
|
"display": "Denominator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": {
|
||||||
|
"value": "denominator-exclusions-identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
|
||||||
|
"code": "denominator-exclusion",
|
||||||
|
"display": "Denominator Exclusion"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"measureScore": 1.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"evaluatedResources": {
|
||||||
|
"reference": "#edc87d47-5804-4d85-8874-ee2d50e51c51"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "MeasureReport/measurereport-numer-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "MedicationRequest",
|
||||||
|
"id": "numer-EXM104-FHIR3-5",
|
||||||
|
"status": "completed",
|
||||||
|
"intent": "order",
|
||||||
|
"category": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/medicationrequest-category",
|
||||||
|
"code": "discharge",
|
||||||
|
"display": "Discharge"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"medicationCodeableConcept": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
|
||||||
|
"code": "1037045",
|
||||||
|
"display": "dabigatran etexilate 150 MG Oral Capsule"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/numer-EXM104-FHIR3"
|
||||||
|
},
|
||||||
|
"authoredOn": "2019-12-19T08:00:00-07:00"
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "MedicationRequest/numer-EXM104-FHIR3-5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"resourceType": "Patient",
|
||||||
|
"id": "numer-EXM104-FHIR3",
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2106-3",
|
||||||
|
"display": "White"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
|
||||||
|
"extension": [
|
||||||
|
{
|
||||||
|
"url": "ombCategory",
|
||||||
|
"valueCoding": {
|
||||||
|
"system": "urn:oid:2.16.840.1.113883.6.238",
|
||||||
|
"code": "2186-5",
|
||||||
|
"display": "Not Hispanic or Latino"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"identifier": [
|
||||||
|
{
|
||||||
|
"use": "usual",
|
||||||
|
"type": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"code": "MR",
|
||||||
|
"display": "Medical Record Number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"system": "http://hospital.smarthealthit.org",
|
||||||
|
"value": "9999999911"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"family": "Jones",
|
||||||
|
"given": [
|
||||||
|
"Louise"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gender": "female",
|
||||||
|
"birthDate": "1971-11-21"
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"method": "PUT",
|
||||||
|
"url": "Patient/numer-EXM104-FHIR3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
4021
src/test/resources/r4/EXM104/EXM104-8.2.000-bundle.json
Normal file
4021
src/test/resources/r4/EXM104/EXM104-8.2.000-bundle.json
Normal file
File diff suppressed because one or more lines are too long
3495
src/test/resources/r4/EXM130/EXM130-7.3.000-bundle.json
Normal file
3495
src/test/resources/r4/EXM130/EXM130-7.3.000-bundle.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user