Work on multitenancy

This commit is contained in:
jamesagnew 2020-04-16 15:33:48 -04:00
parent cd06137745
commit 25cdbb15c2
55 changed files with 709 additions and 176 deletions

View File

@ -1401,12 +1401,12 @@ public enum Pointcut {
* </li> * </li>
* </ul> * </ul>
* <p> * <p>
* Hooks should return an instance of <code>ca.uhn.fhir.jpa.model.entity.PartitionId</code> or <code>null</code>. * Hooks should return an instance of <code>ca.uhn.fhir.jpa.api.model.PartitionId</code> or <code>null</code>.
* </p> * </p>
*/ */
STORAGE_PARTITION_IDENTIFY_CREATE( STORAGE_PARTITION_IDENTIFY_CREATE(
// Return type // Return type
"ca.uhn.fhir.jpa.model.entity.PartitionId", "ca.uhn.fhir.interceptor.model.PartitionId",
// Params // Params
"org.hl7.fhir.instance.model.api.IBaseResource", "org.hl7.fhir.instance.model.api.IBaseResource",
"ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.rest.api.server.RequestDetails",
@ -1437,12 +1437,12 @@ public enum Pointcut {
* </li> * </li>
* </ul> * </ul>
* <p> * <p>
* Hooks should return an instance of <code>ca.uhn.fhir.jpa.model.entity.PartitionId</code> or <code>null</code>. * Hooks should return an instance of <code>ca.uhn.fhir.jpa.api.model.PartitionId</code> or <code>null</code>.
* </p> * </p>
*/ */
STORAGE_PARTITION_IDENTIFY_READ( STORAGE_PARTITION_IDENTIFY_READ(
// Return type // Return type
"ca.uhn.fhir.jpa.model.entity.PartitionId", "ca.uhn.fhir.interceptor.model.PartitionId",
// Params // Params
"ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails" "ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"

View File

@ -1,35 +1,41 @@
package ca.uhn.fhir.jpa.model.entity; package ca.uhn.fhir.interceptor.model;
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.time.LocalDate; import java.time.LocalDate;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
@Embeddable public class PartitionId {
public class PartitionId implements Cloneable {
static final String PARTITION_ID = "PARTITION_ID";
@Column(name = PARTITION_ID, nullable = true, insertable = true, updatable = false)
private Integer myPartitionId; private Integer myPartitionId;
@Column(name = "PARTITION_DATE", nullable = true, insertable = true, updatable = false)
private LocalDate myPartitionDate; private LocalDate myPartitionDate;
/**
* Constructor
*/
public PartitionId() {
super();
}
/** /**
* Constructor * Constructor
*/ */
public PartitionId(@Nullable Integer thePartitionId, @Nullable LocalDate thePartitionDate) { public PartitionId(@Nullable Integer thePartitionId, @Nullable LocalDate thePartitionDate) {
setPartitionId(thePartitionId); myPartitionId = thePartitionId;
setPartitionDate(thePartitionDate); myPartitionDate = thePartitionDate;
} }
@Nullable @Nullable
@ -37,29 +43,11 @@ public class PartitionId implements Cloneable {
return myPartitionId; return myPartitionId;
} }
public PartitionId setPartitionId(@Nullable Integer thePartitionId) {
myPartitionId = thePartitionId;
return this;
}
@Nullable @Nullable
public LocalDate getPartitionDate() { public LocalDate getPartitionDate() {
return myPartitionDate; return myPartitionDate;
} }
public PartitionId setPartitionDate(@Nullable LocalDate thePartitionDate) {
myPartitionDate = thePartitionDate;
return this;
}
@SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException", "MethodDoesntCallSuperMethod"})
@Override
protected PartitionId clone() {
return new PartitionId()
.setPartitionId(getPartitionId())
.setPartitionDate(getPartitionDate());
}
@Override @Override
public String toString() { public String toString() {
return getPartitionIdStringOrNullString(); return getPartitionIdStringOrNullString();
@ -82,4 +70,5 @@ public class PartitionId implements Cloneable {
} }
return retVal; return retVal;
} }
} }

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.client.interceptor; package ca.uhn.fhir.rest.client.interceptor;
/*-
* #%L
* HAPI FHIR - Client Framework
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface InterceptorOrders { public interface InterceptorOrders {
int LOGGING_INTERCEPTOR_REQUEST = -2; int LOGGING_INTERCEPTOR_REQUEST = -2;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.client.interceptor; package ca.uhn.fhir.rest.client.interceptor;
/*-
* #%L
* HAPI FHIR - Client Framework
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.interceptor.api.Hook; import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -16,17 +16,49 @@ These examples each have different properties in terms of security rules, and ho
# Architecture # Architecture
Partitioning involves the addition of two new columns to many tables within the HAPI FHIR JPA database schema: Partitioning involves the use of two dedicated columns to many tables within the HAPI FHIR JPA database schema:
* **PARTITION_ID** &ndash; This is an integer indicating the specific partition that a given resource is placed in. This column can also be *NULL*, meaning that the given resource is in the **Default Partition**. * **PARTITION_ID** &ndash; This is an integer indicating the specific partition that a given resource is placed in. This column can also be *NULL*, meaning that the given resource is in the **Default Partition**.
* **PARTITION_DATE** &ndash; This is a date/time column that can be assigned an arbitrary value depending on your use case. * **PARTITION_DATE** &ndash; This is a date/time column that can be assigned an arbitrary value depending on your use case. Typically, this would be used for use cases where data should be automatically dropped after a certain time period using native database partition drops.
When partitioning is used, these two columns will be populated with the same value on all resource-specific tables (this includes [HFJ_RESOURCE](./schema.html#HFJ_RESOURCE) and all tables that have a foreign key relationship to it including [HFJ_RES_VER](./schema.html#HFJ_RES_VER), [HFJ_RESLINK](./schema.html#HFJ_RES_LINK), [HFJ_SPIDX_*](./schema.html#indexes), etc.)
# Enabling Partitioning At the time that a resource is being **created**, an [interceptor hook](#partition-iInterceptors) is invoked in order to request the partition ID and date, and these will be written to the resource.
At the time that a resource is being **updated**, the partition ID and date from the previous version will be used.
When a **read operation** is being performed (e.g. a read, search, history, etc.), a separate [interceptor hook](#partition-iInterceptors) is invoked in order to determine whether the operation should target a specific partition. The outcome of this hook determines how the partitioning manifests itself to the end user:
* If all read operations are scoped by the interceptor to only apply to a single partition, then the partitioning behaves as a **multitenant** solution.
* If read operations are scopes to all partitions, then the partitioning is simply partitioning the data into logical segments.
# Enabling Partitioning in HAPI FHIR
Enabling partitioning on the server involves a set of steps. Enabling partitioning on the server involves a set of steps.
The [PartitionConfig](/apidocs/hapi-fhir-jpaserver-model/ca/uhn/fhir/jpa/model/config/PartitionConfig.html) bean contains configuration settings related to partitioning within the server. To enable partitioning, the The [PartitionConfig](/apidocs/hapi-fhir-jpaserver-model/ca/uhn/fhir/jpa/model/config/PartitionConfig.html) bean contains configuration settings related to partitioning within the server. To enable partitioning, the [PartitioningEnabled](/apidocs/hapi-fhir-jpaserver-model/ca/uhn/fhir/jpa/model/config/PartitionConfig.html#PartitioningEnabled(boolean)) property should be enabled.
# Partition Interceptors
In order to implement partitioning, an interceptor must be registered against the interceptor registry (either the REST Server registry, or the JPA Server registry will work).
This interceptor can implement the hooks shown below.
## Identify Partition for Create (Required)
A hook against the [Pointcut#STORAGE_PARTITION_IDENTIFY_CREATE](/apidocs/hapi-fhir-base/ca/uhn/fhir/interceptor/api/Pointcut.html#STORAGE_PARTITION_IDENTIFY_CREATE) pointcut must be registered, and this hook method will be invoked every time a resource is being created in order to determine the partition to create the resource in.
The criteria for determining the partition will depend on your use case. For example:
* If you are implementing multi-tenancy the partition might be determined by using the [Request Tenant ID](/docs/server_plain/multitenancy.html). It could also be determined by looking at request headers, or the authorized user/session context, etc.
* If you are implementing segmented data partitioning, the partition might be determined by examining the actual resource being created, by the identity of the sending system, etc.
## Identify Partition for Read (Optional)
A hook against the [Pointcut#STORAGE_PARTITION_IDENTIFY_CREATE](/apidocs/hapi-fhir-base/ca/uhn/fhir/interceptor/api/Pointcut.html#STORAGE_PARTITION_IDENTIFY_CREATE) pointcut must be registered, and this hook method will be invoked every time a resource is being created in order to determine the partition to create the resource in.
# Limitations # Limitations

View File

@ -0,0 +1,118 @@
# HAPI FHIR JPA Schema
**This page is a work in progress. It is not yet comprehensive.**
It contains a description of the tables within the HAPI FHIR JPA database. Note that columns are shown using Java datatypes as opposed to SQL datatypes, because the exact SQL datatype used will vary depending on the underlying database platform.
# Concepts: PID
The HAPI FHIR JPA schema relies heavily on the concept of internal persistent IDs on tables, using a Java type of Long (8-byte integer, which translates to an *int8* or *number(19)* on various database platforms).
Many tables use an internal persistent ID as their primary key, allowing the flexibility for other more complex business identifiers to be changed and minimizing the amount of data consumed by foreign key relationships. These persistent ID columns are generally assigned using a dedicated database sequence on platforms which support sequences.
The persistent ID column is generally called `PID` in the database schema, although there are exceptions.
# Individual Resources: HFJ_RESOURCE, HFJ_RES_VER, HFJ_FORCED_ID
<img src="/hapi-fhir/docs/images/jpa_erd_resources.png" alt="Resources" align="right"/>
<a name="HFJ_RESOURCE"/>
# HFJ_RESOURCE: Resource Master Table
The HFJ_RESOURCE table indicates a single resource of any type in the database. For example, the resource `Patient/1` will have exactly one row in this table, representing all versions of the resource.
<a name="HFJ_RES_VER"/>
# HFJ_RES_VER: Resource Versions and Contents
The HFJ_RES_VER table contains individual versions of a resource. If the resource `Patient/1` has 3 versions, there will be 3 rows in this table.
The complete raw contents of the resource is stored in the `RES_TEXT` column, using the encoding specified in the `RES_ENCODING` column.
## Encodings
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>JSONC</td>
<td>
The resource is serialized using FHIR JSON encoding, and then compressed into a byte stream using GZIP compression.
</td>
</tr>
</tbody>
</table>
<a name="HFJ_FORCED_ID"/>
# HFJ_FORCED_ID: Client Assigned/Visible Resource IDs
By default, the **HFJ_RESOURCE.RES_ID** column is used as the resource ID for all server-assigned IDs. For example, if a Patient resource is created in a completely empty database, it will be assigned the ID `Patient/1` by the server and RES_ID will have a value of 1.
However, when client-assigned IDs are used, these may contain text values in order to allow a client to create an ID such as `Patient/ABC`. When a client-assigned ID is given to a resource, a row is created in the **HFJ_RESOURCE** table. When an **HFJ_FORCED_ID** row exists corresponding to the equivalent **HFJ_RESOURCE** row, the RES_ID value is no longer visible or usable by FHIR clients and it becomes purely an internal ID to the JPA server.
If the server has been configured with a [Resource Server ID Strategy](/apidocs/hapi-fhir-jpaserver-api/undefined/ca/uhn/fhir/jpa/api/config/DaoConfig.html#setResourceServerIdStrategy(ca.uhn.fhir.jpa.api.config.DaoConfig.IdStrategyEnum)) of [UUID](/apidocs/hapi-fhir-jpaserver-api/undefined/ca/uhn/fhir/jpa/api/config/DaoConfig.IdStrategyEnum.html#UUID), or the server has been configured with a [Resource Client ID Strategy](/apidocs/hapi-fhir-jpaserver-api/undefined/ca/uhn/fhir/jpa/api/config/DaoConfig.html#setResourceClientIdStrategy(ca.uhn.fhir.jpa.api.config.DaoConfig.ClientIdStrategyEnum)) of [ANY](/apidocs/hapi-fhir-jpaserver-api/undefined/ca/uhn/fhir/jpa/api/config/DaoConfig.ClientIdStrategyEnum.html#ANY) the server will create a Forced ID for all resources (not only resources having textual IDs).
<a name="HFJ_RES_LINK"/>
# HFJ_RES_LINK: Search Links
<img src="/hapi-fhir/docs/images/jpa_erd_resources.png" alt="Resources" align="right"/>
When a resource is created or updated, it is indexed for searching. Any search parameters of type [Reference](http://hl7.org/fhir/search.html#reference) are resolved, and one or more rows may be created in the **HFJ_RES_LINK** table.
## Columns
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Datatype</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>PID</td>
<td>Long</td>
<td>
Holds the persistent ID
</td>
</tr>
<tr>
<td>SRC_PATH</td>
<td>String</td>
<td>
Contains the FHIRPath expression within the source resource containing the path to the target resource, as supplied by the SearchParameter resource that defined the link.
</td>
</tr>
<tr>
<td>SRC_RESOURCE_ID</td>
<td>Long</td>
<td>
Contains a FK reference to the resource containing the link to the target resource.
</td>
</tr>
<tr>
<td>TARGET_RESOURCE_ID</td>
<td>Long</td>
<td>
Contains a FK reference to the resource that is the target resource.
</td>
</tr>
</tbody>
</table>
<a name="indexes"/>
# HFJ_SPIDX_xxx: Search Indexes
The HFJ_SPIDX (Search Parameter Index) tables are used to index resources for searching. When a resource is created or updated, a set of rows in these tables will be added. These are used for finding appropriate rows to return when performing FHIR searches.

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
@ -38,7 +39,6 @@ import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.BaseHasResource; import ca.uhn.fhir.jpa.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.model.entity.BaseTag; import ca.uhn.fhir.jpa.model.entity.BaseTag;
import ca.uhn.fhir.jpa.model.entity.ForcedId; import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.entity.TagDefinition; import ca.uhn.fhir.jpa.model.entity.TagDefinition;
@ -453,11 +453,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
ResourceTable entity = new ResourceTable(); ResourceTable entity = new ResourceTable();
entity.setResourceType(toResourceName(theResource)); entity.setResourceType(toResourceName(theResource));
entity.setPartitionId(thePartitionId);
if (thePartitionId != null) {
ourLog.debug("Resource has been assigned partition ID: {}", thePartitionId);
entity.setPartitionId(thePartitionId);
}
if (isNotBlank(theIfNoneExist)) { if (isNotBlank(theIfNoneExist)) {
Set<ResourcePersistentId> match = myMatchResourceUrlService.processMatchUrl(theIfNoneExist, myResourceType, theRequest); Set<ResourcePersistentId> match = myMatchResourceUrlService.processMatchUrl(theIfNoneExist, myResourceType, theRequest);

View File

@ -20,11 +20,11 @@ package ca.uhn.fhir.jpa.dao;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao; import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.index.IdHelperService; import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperService; import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperService;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;

View File

@ -21,8 +21,8 @@ package ca.uhn.fhir.jpa.dao;
*/ */
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails; import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
@ -47,7 +47,7 @@ public interface ISearchBuilder {
void loadResourcesByPid(Collection<ResourcePersistentId> thePids, Collection<ResourcePersistentId> theIncludedPids, List<IBaseResource> theResourceListToPopulate, boolean theForHistoryOperation, RequestDetails theDetails); void loadResourcesByPid(Collection<ResourcePersistentId> thePids, Collection<ResourcePersistentId> theIncludedPids, List<IBaseResource> theResourceListToPopulate, boolean theForHistoryOperation, RequestDetails theDetails);
Set<ResourcePersistentId> loadIncludes(FhirContext theContext, EntityManager theEntityManager, Collection<ResourcePersistentId> theMatches, Set<Include> theRevIncludes, boolean theReverseMode, Set<ResourcePersistentId> loadIncludes(FhirContext theContext, EntityManager theEntityManager, Collection<ResourcePersistentId> theMatches, Set<Include> theRevIncludes, boolean theReverseMode,
DateRangeParam theLastUpdated, String theSearchIdOrDescription, RequestDetails theRequest); DateRangeParam theLastUpdated, String theSearchIdOrDescription, RequestDetails theRequest);
/** /**
* How many results may be fetched at once * How many results may be fetched at once

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.IDao; import ca.uhn.fhir.jpa.api.dao.IDao;
import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao; import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao;
@ -42,7 +43,6 @@ import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
import ca.uhn.fhir.jpa.model.entity.ResourceLink; import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
@ -92,7 +92,6 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType; import javax.persistence.PersistenceContextType;
@ -136,10 +135,11 @@ public class SearchBuilder implements ISearchBuilder {
private static final List<ResourcePersistentId> EMPTY_LONG_LIST = Collections.unmodifiableList(new ArrayList<>()); private static final List<ResourcePersistentId> EMPTY_LONG_LIST = Collections.unmodifiableList(new ArrayList<>());
private static final Logger ourLog = LoggerFactory.getLogger(SearchBuilder.class); private static final Logger ourLog = LoggerFactory.getLogger(SearchBuilder.class);
private static ResourcePersistentId NO_MORE = new ResourcePersistentId(-1L); private static final ResourcePersistentId NO_MORE = new ResourcePersistentId(-1L);
private final QueryRoot myQueryRoot = new QueryRoot(); private final QueryRoot myQueryRoot = new QueryRoot();
private final String myResourceName; private final String myResourceName;
private final Class<? extends IBaseResource> myResourceType; private final Class<? extends IBaseResource> myResourceType;
private final IDao myCallingDao;
@Autowired @Autowired
protected IInterceptorBroadcaster myInterceptorBroadcaster; protected IInterceptorBroadcaster myInterceptorBroadcaster;
@Autowired @Autowired
@ -162,7 +162,6 @@ public class SearchBuilder implements ISearchBuilder {
private PredicateBuilderFactory myPredicateBuilderFactory; private PredicateBuilderFactory myPredicateBuilderFactory;
private List<ResourcePersistentId> myAlsoIncludePids; private List<ResourcePersistentId> myAlsoIncludePids;
private CriteriaBuilder myCriteriaBuilder; private CriteriaBuilder myCriteriaBuilder;
private IDao myCallingDao;
private SearchParameterMap myParams; private SearchParameterMap myParams;
private String mySearchUuid; private String mySearchUuid;
private int myFetchSize; private int myFetchSize;
@ -237,7 +236,7 @@ public class SearchBuilder implements ISearchBuilder {
* @param thePidSet May be null * @param thePidSet May be null
*/ */
@Override @Override
public void setPreviouslyAddedResourcePids(@Nullable List<ResourcePersistentId> thePidSet) { public void setPreviouslyAddedResourcePids(@Nonnull List<ResourcePersistentId> thePidSet) {
myPidSet = new HashSet<>(thePidSet); myPidSet = new HashSet<>(thePidSet);
} }
@ -261,7 +260,6 @@ public class SearchBuilder implements ISearchBuilder {
} }
private TypedQuery<Long> createQuery(SortSpec sort, Integer theMaximumResults, boolean theCount, RequestDetails theRequest) { private TypedQuery<Long> createQuery(SortSpec sort, Integer theMaximumResults, boolean theCount, RequestDetails theRequest) {
CriteriaQuery<Long> outerQuery; CriteriaQuery<Long> outerQuery;
/* /*
@ -942,10 +940,6 @@ public class SearchBuilder implements ISearchBuilder {
return myResourceName; return myResourceName;
} }
public IDao getCallingDao() {
return myCallingDao;
}
@VisibleForTesting @VisibleForTesting
public void setDaoConfigForUnitTest(DaoConfig theDaoConfig) { public void setDaoConfigForUnitTest(DaoConfig theDaoConfig) {
myDaoConfig = theDaoConfig; myDaoConfig = theDaoConfig;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParserErrorHandler; import ca.uhn.fhir.parser.IParserErrorHandler;

View File

@ -26,11 +26,12 @@ import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.model.cross.IResourceLookup; import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver; import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
@ -42,7 +43,6 @@ import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao; import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
@ -31,7 +32,6 @@ import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
import ca.uhn.fhir.jpa.model.cross.ResourceLookup; import ca.uhn.fhir.jpa.model.cross.ResourceLookup;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.ForcedId; import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage; import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster; import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;

View File

@ -30,7 +30,6 @@ import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
import ca.uhn.fhir.jpa.model.entity.ResourceLink; import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;

View File

@ -21,12 +21,13 @@ package ca.uhn.fhir.jpa.dao.predicate;
*/ */
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable; import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent; import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;

View File

@ -20,7 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import javax.annotation.Nullable; import javax.annotation.Nullable;

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.*; import ca.uhn.fhir.jpa.model.entity.*;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;

View File

@ -20,8 +20,8 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.CoordCalculator; import ca.uhn.fhir.jpa.util.CoordCalculator;
@ -59,7 +59,8 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
String theResourceName, String theResourceName,
String theParamName, String theParamName,
CriteriaBuilder theBuilder, CriteriaBuilder theBuilder,
From<?, ResourceIndexedSearchParamCoords> theFrom, PartitionId thePartitionId) { From<?, ResourceIndexedSearchParamCoords> theFrom,
PartitionId thePartitionId) {
String latitudeValue; String latitudeValue;
String longitudeValue; String longitudeValue;
Double distanceKm = 0.0; Double distanceKm = 0.0;

View File

@ -20,8 +20,8 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;

View File

@ -20,8 +20,8 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;

View File

@ -20,9 +20,9 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;

View File

@ -30,15 +30,15 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IDao; import ca.uhn.fhir.jpa.api.dao.IDao;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.dao.index.IdHelperService; import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
@ -659,8 +659,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
private Predicate processFilter(SearchFilterParser.Filter theFilter, String theResourceName, RequestDetails theRequest, PartitionId thePartitionId) { private Predicate processFilter(SearchFilterParser.Filter theFilter, String theResourceName, RequestDetails theRequest, PartitionId thePartitionId) {
if (theFilter instanceof SearchFilterParser.FilterParameter) { if (theFilter instanceof SearchFilterParser.FilterParameter) {
return processFilterParameter((SearchFilterParser.FilterParameter) theFilter, return processFilterParameter((SearchFilterParser.FilterParameter) theFilter, theResourceName, theRequest, thePartitionId);
theResourceName, theRequest, thePartitionId);
} else if (theFilter instanceof SearchFilterParser.FilterLogical) { } else if (theFilter instanceof SearchFilterParser.FilterLogical) {
// Left side // Left side
Predicate xPredicate = processFilter(((SearchFilterParser.FilterLogical) theFilter).getFilter1(), theResourceName, theRequest, thePartitionId); Predicate xPredicate = processFilter(((SearchFilterParser.FilterLogical) theFilter).getFilter1(), theResourceName, theRequest, thePartitionId);
@ -875,7 +874,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
return retVal; return retVal;
} }
private void addPredicateHas(String theResourceType, List<List<IQueryParameterType>> theHasParameters, RequestDetails theRequest,PartitionId thePartitionId) { private void addPredicateHas(String theResourceType, List<List<IQueryParameterType>> theHasParameters, RequestDetails theRequest, PartitionId thePartitionId) {
for (List<? extends IQueryParameterType> nextOrList : theHasParameters) { for (List<? extends IQueryParameterType> nextOrList : theHasParameters) {

View File

@ -20,10 +20,10 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.dao.index.IdHelperService; import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;

View File

@ -20,9 +20,9 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.StringNormalizer; import ca.uhn.fhir.jpa.model.util.StringNormalizer;

View File

@ -20,8 +20,8 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTag; import ca.uhn.fhir.jpa.model.entity.ResourceTag;
import ca.uhn.fhir.jpa.model.entity.TagDefinition; import ca.uhn.fhir.jpa.model.entity.TagDefinition;

View File

@ -24,14 +24,13 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition; import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.util.VersionIndependentConcept;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc; import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.model.base.composite.BaseCodingDt;
@ -40,6 +39,7 @@ import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.VersionIndependentConcept;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl; import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.predicate.BooleanStaticAssertionPredicate; import org.hibernate.query.criteria.internal.predicate.BooleanStaticAssertionPredicate;
@ -47,20 +47,31 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.persistence.criteria.*; import javax.persistence.criteria.CriteriaBuilder;
import java.util.*; import javax.persistence.criteria.Expression;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.*; import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Component @Component
@Scope("prototype") @Scope("prototype")
class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBuilder { class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBuilder {
private final PredicateBuilder myPredicateBuilder;
@Autowired @Autowired
private ITermReadSvc myTerminologySvc; private ITermReadSvc myTerminologySvc;
@Autowired @Autowired
private ISearchParamRegistry mySearchParamRegistry; private ISearchParamRegistry mySearchParamRegistry;
private final PredicateBuilder myPredicateBuilder;
PredicateBuilderToken(SearchBuilder theSearchBuilder, PredicateBuilder thePredicateBuilder) { PredicateBuilderToken(SearchBuilder theSearchBuilder, PredicateBuilder thePredicateBuilder) {
super(theSearchBuilder); super(theSearchBuilder);

View File

@ -20,10 +20,10 @@ package ca.uhn.fhir.jpa.dao.predicate;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao; import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
@ -97,7 +97,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
List<String> toFind = new ArrayList<>(); List<String> toFind = new ArrayList<>();
for (String next : candidates) { for (String next : candidates) {
if (value.length() >= next.length()) { if (value.length() >= next.length()) {
if (value.substring(0, next.length()).equals(next)) { if (value.startsWith(next)) {
toFind.add(next); toFind.add(next);
} }
} }

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.entity; package ca.uhn.fhir.jpa.entity;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.partition; package ca.uhn.fhir.jpa.partition;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.entity.PartitionEntity;
public interface IPartitionConfigSvc { public interface IPartitionConfigSvc {

View File

@ -1,6 +1,26 @@
package ca.uhn.fhir.jpa.partition; package ca.uhn.fhir.jpa.partition;
import ca.uhn.fhir.jpa.model.entity.PartitionId; /*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.partition; package ca.uhn.fhir.jpa.partition;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.data.IPartitionDao; import ca.uhn.fhir.jpa.dao.data.IPartitionDao;
import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.entity.PartitionEntity;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.partition; package ca.uhn.fhir.jpa.partition;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.jpa.model.util.ProviderConstants; import ca.uhn.fhir.jpa.model.util.ProviderConstants;

View File

@ -1,12 +1,32 @@
package ca.uhn.fhir.jpa.partition; package ca.uhn.fhir.jpa.partition;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;

View File

@ -1,10 +1,30 @@
package ca.uhn.fhir.jpa.partition; package ca.uhn.fhir.jpa.partition;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.Hook; import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -19,17 +39,17 @@ public class RequestTenantPartitionInterceptor {
private FhirContext myFhirContext; private FhirContext myFhirContext;
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE) @Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)
public PartitionId PartitionIdentifyCreate(IBaseResource theResource, ServletRequestDetails theRequestDetails) { public PartitionablePartitionId PartitionIdentifyCreate(IBaseResource theResource, ServletRequestDetails theRequestDetails) {
return extractPartitionIdFromRequest(theRequestDetails); return extractPartitionIdFromRequest(theRequestDetails);
} }
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ) @Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
public PartitionId PartitionIdentifyRead(ServletRequestDetails theRequestDetails) { public PartitionablePartitionId PartitionIdentifyRead(ServletRequestDetails theRequestDetails) {
return extractPartitionIdFromRequest(theRequestDetails); return extractPartitionIdFromRequest(theRequestDetails);
} }
@NotNull @NotNull
private PartitionId extractPartitionIdFromRequest(ServletRequestDetails theRequestDetails) { private PartitionablePartitionId extractPartitionIdFromRequest(ServletRequestDetails theRequestDetails) {
String tenantId = theRequestDetails.getTenantId(); String tenantId = theRequestDetails.getTenantId();
PartitionEntity partition; PartitionEntity partition;
@ -40,7 +60,7 @@ public class RequestTenantPartitionInterceptor {
throw new ResourceNotFoundException(msg); throw new ResourceNotFoundException(msg);
} }
PartitionId retVal = new PartitionId(); PartitionablePartitionId retVal = new PartitionablePartitionId();
retVal.setPartitionId(partition.getId()); retVal.setPartitionId(partition.getId());
return retVal; return retVal;
} }

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IDao; import ca.uhn.fhir.jpa.api.dao.IDao;
@ -33,13 +34,12 @@ import ca.uhn.fhir.jpa.dao.IResultIterator;
import ca.uhn.fhir.jpa.dao.ISearchBuilder; import ca.uhn.fhir.jpa.dao.ISearchBuilder;
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory; import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperService; import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperService;
import ca.uhn.fhir.jpa.partition.RequestPartitionHelperService;
import ca.uhn.fhir.jpa.entity.Search; import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.entity.SearchInclude; import ca.uhn.fhir.jpa.entity.SearchInclude;
import ca.uhn.fhir.jpa.entity.SearchTypeEnum; import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails; import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails; import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum; import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc; import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc;
@ -630,8 +630,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
private boolean myAdditionalPrefetchThresholdsRemaining; private boolean myAdditionalPrefetchThresholdsRemaining;
private List<ResourcePersistentId> myPreviouslyAddedResourcePids; private List<ResourcePersistentId> myPreviouslyAddedResourcePids;
private Integer myMaxResultsToFetch; private Integer myMaxResultsToFetch;
private SearchRuntimeDetails mySearchRuntimeDetails; private final SearchRuntimeDetails mySearchRuntimeDetails;
private Transaction myParentTransaction; private final Transaction myParentTransaction;
/** /**
* Constructor * Constructor
@ -970,11 +970,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
} }
private void doSaveSearch() { private void doSaveSearch() {
Search newSearch = mySearchCacheSvc.save(mySearch);
// This is an attempt to track down an intermittent test
// failure in testAsyncSearchLargeResultSetBigCountSameCoordinator
Object searchObj = mySearchCacheSvc.save(mySearch);
Search newSearch = (Search) searchObj;
// mySearchDao.save is not supposed to return null, but in unit tests // mySearchDao.save is not supposed to return null, but in unit tests
// it can if the mock search dao isn't set up to handle that // it can if the mock search dao isn't set up to handle that

View File

@ -1,13 +1,13 @@
package ca.uhn.fhir.jpa.dao.dstu3; package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.GZipUtil; import ca.uhn.fhir.jpa.dao.GZipUtil;
import ca.uhn.fhir.jpa.dao.r4.FhirSystemDaoR4; import ca.uhn.fhir.jpa.dao.r4.FhirSystemDaoR4;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.model.entity.ResourceTag; import ca.uhn.fhir.jpa.model.entity.ResourceTag;
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum; import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.LenientErrorHandler; import ca.uhn.fhir.parser.LenientErrorHandler;
@ -15,17 +15,30 @@ import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle.*; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryRequestComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryResponseComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.*; import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@ -39,10 +52,23 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.*; import static org.hamcrest.Matchers.containsString;
import static org.mockito.Matchers.eq; import static org.hamcrest.Matchers.empty;
import static org.mockito.Mockito.verify; import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.matchesPattern;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest { public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.interceptor.api.Hook; import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Interceptor; import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.entity.*; import ca.uhn.fhir.jpa.model.entity.*;
@ -153,7 +154,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
obs.getSubject().setReference(patientId.getValue()); obs.getSubject().setReference(patientId.getValue());
IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless(); IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
runInTransaction(()->{ runInTransaction(() -> {
List<ResourceLink> resLinks = myResourceLinkDao.findAll(); List<ResourceLink> resLinks = myResourceLinkDao.findAll();
ourLog.info("Resource links:\n{}", resLinks.toString()); ourLog.info("Resource links:\n{}", resLinks.toString());
assertEquals(2, resLinks.size()); assertEquals(2, resLinks.size());
@ -202,7 +203,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
obs.getSubject().setReference(patientId.getValue()); obs.getSubject().setReference(patientId.getValue());
IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless(); IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
runInTransaction(()->{ runInTransaction(() -> {
List<ResourceLink> resLinks = myResourceLinkDao.findAll(); List<ResourceLink> resLinks = myResourceLinkDao.findAll();
ourLog.info("Resource links:\n{}", resLinks.toString()); ourLog.info("Resource links:\n{}", resLinks.toString());
assertEquals(2, resLinks.size()); assertEquals(2, resLinks.size());
@ -249,7 +250,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
obs.getSubject().setReference(patientId.getValue()); obs.getSubject().setReference(patientId.getValue());
IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless(); IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
runInTransaction(()->{ runInTransaction(() -> {
List<ResourceLink> resLinks = myResourceLinkDao.findAll(); List<ResourceLink> resLinks = myResourceLinkDao.findAll();
ourLog.info("Resource links:\n{}", resLinks.toString()); ourLog.info("Resource links:\n{}", resLinks.toString());
assertEquals(2, resLinks.size()); assertEquals(2, resLinks.size());
@ -273,7 +274,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
obs.getSubject().setReference(patientId.getValue()); obs.getSubject().setReference(patientId.getValue());
IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless(); IIdType obsId = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
runInTransaction(()->{ runInTransaction(() -> {
List<ResourceLink> resLinks = myResourceLinkDao.findAll(); List<ResourceLink> resLinks = myResourceLinkDao.findAll();
ourLog.info("Resource links:\n{}", resLinks.toString()); ourLog.info("Resource links:\n{}", resLinks.toString());
assertEquals(2, resLinks.size()); assertEquals(2, resLinks.size());
@ -1493,7 +1494,8 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
IIdType patientId = createPatient(null, withBirthdate("2020-01-01")); IIdType patientId = createPatient(null, withBirthdate("2020-01-01"));
IIdType observationId = createObservation(null, withSubject(patientId)); IIdType observationId = createObservation(null, withSubject(patientId));
addDefaultReadPartition();; addDefaultReadPartition();
;
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
map.add(Observation.SP_SUBJECT, new ReferenceParam(patientId)); map.add(Observation.SP_SUBJECT, new ReferenceParam(patientId));
@ -1566,7 +1568,8 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
IIdType patientId = createPatient(null, withId("ONE"), withBirthdate("2020-01-01")); IIdType patientId = createPatient(null, withId("ONE"), withBirthdate("2020-01-01"));
IIdType observationId = createObservation(null, withSubject(patientId)); IIdType observationId = createObservation(null, withSubject(patientId));
addDefaultReadPartition();; addDefaultReadPartition();
;
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
map.add(Observation.SP_SUBJECT, new ReferenceParam(patientId)); map.add(Observation.SP_SUBJECT, new ReferenceParam(patientId));

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.search;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
@ -12,10 +13,8 @@ import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
import ca.uhn.fhir.jpa.entity.Search; import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.entity.SearchTypeEnum; import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum; import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperService; import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperService;
import ca.uhn.fhir.jpa.partition.RequestPartitionHelperService;
import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc; import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc;
import ca.uhn.fhir.jpa.search.cache.ISearchResultCacheSvc; import ca.uhn.fhir.jpa.search.cache.ISearchResultCacheSvc;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.model.config; package ca.uhn.fhir.jpa.model.config;
/*-
* #%L
* HAPI FHIR Model
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
/** /**
* @since 5.0.0 * @since 5.0.0
*/ */

View File

@ -1,5 +1,28 @@
package ca.uhn.fhir.jpa.model.entity; package ca.uhn.fhir.jpa.model.entity;
/*-
* #%L
* HAPI FHIR Model
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.interceptor.model.PartitionId;
import javax.annotation.Nullable;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
@ -9,21 +32,29 @@ import java.io.Serializable;
public class BasePartitionable implements Serializable { public class BasePartitionable implements Serializable {
@Embedded @Embedded
private PartitionId myPartitionId; private PartitionablePartitionId myPartitionId;
/** /**
* This is here to support queries only, do not set this field directly * This is here to support queries only, do not set this field directly
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Column(name = PartitionId.PARTITION_ID, insertable = false, updatable = false, nullable = true) @Column(name = PartitionablePartitionId.PARTITION_ID, insertable = false, updatable = false, nullable = true)
private Integer myPartitionIdValue; private Integer myPartitionIdValue;
public PartitionId getPartitionId() { public PartitionId getPartitionId() {
return myPartitionId; if (myPartitionId != null) {
return myPartitionId.toPartitionId();
} else {
return null;
}
} }
public void setPartitionId(PartitionId thePartitionId) { public void setPartitionId(@Nullable PartitionId thePartitionId) {
myPartitionId = thePartitionId; if (thePartitionId != null) {
myPartitionId = new PartitionablePartitionId(thePartitionId.getPartitionId(), thePartitionId.getPartitionDate());
} else {
myPartitionId = null;
}
} }

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
@ -157,15 +158,15 @@ public abstract class BaseResourceIndexedSearchParam extends BaseResourceIndex {
throw new UnsupportedOperationException("No parameter matcher for " + theParam); throw new UnsupportedOperationException("No parameter matcher for " + theParam);
} }
public PartitionConfig getPartitionConfig() {
return myPartitionConfig;
}
public BaseResourceIndexedSearchParam setPartitionConfig(PartitionConfig thePartitionConfig) { public BaseResourceIndexedSearchParam setPartitionConfig(PartitionConfig thePartitionConfig) {
myPartitionConfig = thePartitionConfig; myPartitionConfig = thePartitionConfig;
return this; return this;
} }
public PartitionConfig getPartitionConfig() {
return myPartitionConfig;
}
public static long calculateHashIdentity(PartitionConfig thePartitionConfig, PartitionId thePartitionId, String theResourceType, String theParamName) { public static long calculateHashIdentity(PartitionConfig thePartitionConfig, PartitionId thePartitionId, String theResourceType, String theParamName) {
return hash(thePartitionConfig, thePartitionId, theResourceType, theParamName); return hash(thePartitionConfig, thePartitionId, theResourceType, theParamName);
} }

View File

@ -0,0 +1,86 @@
package ca.uhn.fhir.jpa.model.entity;
/*-
* #%L
* HAPI FHIR Model
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.interceptor.model.PartitionId;
import javax.annotation.Nullable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.time.LocalDate;
@Embeddable
public class PartitionablePartitionId implements Cloneable {
static final String PARTITION_ID = "PARTITION_ID";
@Column(name = PARTITION_ID, nullable = true, insertable = true, updatable = false)
private Integer myPartitionId;
@Column(name = "PARTITION_DATE", nullable = true, insertable = true, updatable = false)
private LocalDate myPartitionDate;
/**
* Constructor
*/
public PartitionablePartitionId() {
super();
}
/**
* Constructor
*/
public PartitionablePartitionId(@Nullable Integer thePartitionId, @Nullable LocalDate thePartitionDate) {
setPartitionId(thePartitionId);
setPartitionDate(thePartitionDate);
}
@Nullable
public Integer getPartitionId() {
return myPartitionId;
}
public PartitionablePartitionId setPartitionId(@Nullable Integer thePartitionId) {
myPartitionId = thePartitionId;
return this;
}
@Nullable
public LocalDate getPartitionDate() {
return myPartitionDate;
}
public PartitionablePartitionId setPartitionDate(@Nullable LocalDate thePartitionDate) {
myPartitionDate = thePartitionDate;
return this;
}
@SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException", "MethodDoesntCallSuperMethod"})
@Override
protected PartitionablePartitionId clone() {
return new PartitionablePartitionId()
.setPartitionId(getPartitionId())
.setPartitionDate(getPartitionDate());
}
public PartitionId toPartitionId() {
return new PartitionId(getPartitionId(), getPartitionDate());
}
}

View File

@ -20,6 +20,8 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import javax.persistence.*; import javax.persistence.*;
import java.io.Serializable; import java.io.Serializable;

View File

@ -21,7 +21,11 @@ package ca.uhn.fhir.jpa.model.entity;
*/ */
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.*; import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.*; import javax.persistence.*;
@ -30,7 +34,7 @@ import javax.persistence.*;
@Index(name = ResourceIndexedCompositeStringUnique.IDX_IDXCMPSTRUNIQ_STRING, columnList = "IDX_STRING", unique = true), @Index(name = ResourceIndexedCompositeStringUnique.IDX_IDXCMPSTRUNIQ_STRING, columnList = "IDX_STRING", unique = true),
@Index(name = ResourceIndexedCompositeStringUnique.IDX_IDXCMPSTRUNIQ_RESOURCE, columnList = "RES_ID", unique = false) @Index(name = ResourceIndexedCompositeStringUnique.IDX_IDXCMPSTRUNIQ_RESOURCE, columnList = "RES_ID", unique = false)
}) })
public class ResourceIndexedCompositeStringUnique implements Comparable<ResourceIndexedCompositeStringUnique> { public class ResourceIndexedCompositeStringUnique extends BasePartitionable implements Comparable<ResourceIndexedCompositeStringUnique> {
public static final int MAX_STRING_LENGTH = 200; public static final int MAX_STRING_LENGTH = 200;
public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING"; public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING";
@ -48,13 +52,12 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
private Long myResourceId; private Long myResourceId;
@Column(name = "IDX_STRING", nullable = false, length = MAX_STRING_LENGTH) @Column(name = "IDX_STRING", nullable = false, length = MAX_STRING_LENGTH)
private String myIndexString; private String myIndexString;
@Embedded
private PartitionId myPartitionId;
/** /**
* This is here to support queries only, do not set this field directly * This is here to support queries only, do not set this field directly
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Column(name = PartitionId.PARTITION_ID, insertable = false, updatable = false, nullable = true) @Column(name = PartitionablePartitionId.PARTITION_ID, insertable = false, updatable = false, nullable = true)
private Integer myPartitionIdValue; private Integer myPartitionIdValue;
/** /**
@ -73,14 +76,6 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
setPartitionId(theResource.getPartitionId()); setPartitionId(theResource.getPartitionId());
} }
public PartitionId getPartitionId() {
return myPartitionId;
}
public void setPartitionId(PartitionId thePartitionId) {
myPartitionId = thePartitionId;
}
@Override @Override
public int compareTo(ResourceIndexedCompositeStringUnique theO) { public int compareTo(ResourceIndexedCompositeStringUnique theO) {
CompareToBuilder b = new CompareToBuilder(); CompareToBuilder b = new CompareToBuilder();
@ -133,7 +128,7 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
.append("id", myId) .append("id", myId)
.append("resourceId", myResourceId) .append("resourceId", myResourceId)
.append("indexString", myIndexString) .append("indexString", myIndexString)
.append("tenant", myPartitionId) .append("partition", getPartitionId())
.toString(); .toString();
} }
} }

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.util.BigDecimalNumericFieldBridge; import ca.uhn.fhir.jpa.model.util.BigDecimalNumericFieldBridge;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
@ -191,7 +192,7 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
@Override @Override
public void setId(Long theId) { public void setId(Long theId) {
myId =theId; myId = theId;
} }
public String getSystem() { public String getSystem() {
@ -262,25 +263,25 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
// Only match on system if it wasn't specified // Only match on system if it wasn't specified
String quantityUnitsString = defaultString(quantity.getUnits()); String quantityUnitsString = defaultString(quantity.getUnits());
if (quantity.getSystem() == null && isBlank(quantityUnitsString)) { if (quantity.getSystem() == null && isBlank(quantityUnitsString)) {
if (Objects.equals(getValue(),quantity.getValue())) { if (Objects.equals(getValue(), quantity.getValue())) {
retval = true; retval = true;
} }
} else { } else {
String unitsString = defaultString(getUnits()); String unitsString = defaultString(getUnits());
if (quantity.getSystem() == null) { if (quantity.getSystem() == null) {
if (unitsString.equalsIgnoreCase(quantityUnitsString) && if (unitsString.equalsIgnoreCase(quantityUnitsString) &&
Objects.equals(getValue(),quantity.getValue())) { Objects.equals(getValue(), quantity.getValue())) {
retval = true; retval = true;
} }
} else if (isBlank(quantityUnitsString)) { } else if (isBlank(quantityUnitsString)) {
if (getSystem().equalsIgnoreCase(quantity.getSystem()) && if (getSystem().equalsIgnoreCase(quantity.getSystem()) &&
Objects.equals(getValue(),quantity.getValue())) { Objects.equals(getValue(), quantity.getValue())) {
retval = true; retval = true;
} }
} else { } else {
if (getSystem().equalsIgnoreCase(quantity.getSystem()) && if (getSystem().equalsIgnoreCase(quantity.getSystem()) &&
unitsString.equalsIgnoreCase(quantityUnitsString) && unitsString.equalsIgnoreCase(quantityUnitsString) &&
Objects.equals(getValue(),quantity.getValue())) { Objects.equals(getValue(), quantity.getValue())) {
retval = true; retval = true;
} }
} }

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.util.StringNormalizer; import ca.uhn.fhir.jpa.model.util.StringNormalizer;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
@ -28,9 +29,14 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.search.annotations.*; import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.ContainedIn;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Fields;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
import javax.persistence.Index;
import javax.persistence.*; import javax.persistence.*;
import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.defaultString;
@ -128,11 +134,6 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
myHashNormalizedPrefix = source.myHashNormalizedPrefix; myHashNormalizedPrefix = source.myHashNormalizedPrefix;
} }
public void setHashIdentity(Long theHashIdentity) {
myHashIdentity = theHashIdentity;
}
@Override @Override
@PrePersist @PrePersist
@PreUpdate @PreUpdate
@ -182,6 +183,10 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
return myHashIdentity; return myHashIdentity;
} }
public void setHashIdentity(Long theHashIdentity) {
myHashIdentity = theHashIdentity;
}
public Long getHashExact() { public Long getHashExact() {
calculateHashes(); calculateHashes();
return myHashExact; return myHashExact;
@ -207,7 +212,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
@Override @Override
public void setId(Long theId) { public void setId(Long theId) {
myId =theId; myId = theId;
} }
@ -264,6 +269,16 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
return b.build(); return b.build();
} }
@Override
public boolean matches(IQueryParameterType theParam) {
if (!(theParam instanceof StringParam)) {
return false;
}
StringParam string = (StringParam) theParam;
String normalizedString = StringNormalizer.normalizeString(defaultString(string.getValue()));
return defaultString(getValueNormalized()).startsWith(normalizedString);
}
public static long calculateHashExact(PartitionConfig thePartitionConfig, PartitionId thePartitionId, String theResourceType, String theParamName, String theValueExact) { public static long calculateHashExact(PartitionConfig thePartitionConfig, PartitionId thePartitionId, String theResourceType, String theParamName, String theValueExact) {
return hash(thePartitionConfig, thePartitionId, theResourceType, theParamName, theValueExact); return hash(thePartitionConfig, thePartitionId, theResourceType, theParamName, theValueExact);
} }
@ -282,14 +297,4 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
return hash(thePartitionConfig, thePartitionId, theResourceType, theParamName, left(theValueNormalized, hashPrefixLength)); return hash(thePartitionConfig, thePartitionId, theResourceType, theParamName, left(theValueNormalized, hashPrefixLength));
} }
@Override
public boolean matches(IQueryParameterType theParam) {
if (!(theParam instanceof StringParam)) {
return false;
}
StringParam string = (StringParam)theParam;
String normalizedString = StringNormalizer.normalizeString(defaultString(string.getValue()));
return defaultString(getValueNormalized()).startsWith(normalizedString);
}
} }

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.param.UriParam;
@ -161,7 +162,7 @@ public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchPara
@Override @Override
public void setId(Long theId) { public void setId(Long theId) {
myId =theId; myId = theId;
} }

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -117,14 +118,14 @@ public class SearchParamPresent extends BasePartitionable implements Serializabl
return b.build(); return b.build();
} }
public void setPartitionConfig(PartitionConfig thePartitionConfig) {
myPartitionConfig = thePartitionConfig;
}
public PartitionConfig getPartitionConfig() { public PartitionConfig getPartitionConfig() {
return myPartitionConfig; return myPartitionConfig;
} }
public void setPartitionConfig(PartitionConfig thePartitionConfig) {
myPartitionConfig = thePartitionConfig;
}
public static long calculateHashPresence(PartitionConfig thePartitionConfig, PartitionId thePartitionId, String theResourceType, String theParamName, Boolean thePresent) { public static long calculateHashPresence(PartitionConfig thePartitionConfig, PartitionId thePartitionId, String theResourceType, String theParamName, Boolean thePresent) {
String string = thePresent != null ? Boolean.toString(thePresent) : Boolean.toString(false); String string = thePresent != null ? Boolean.toString(thePresent) : Boolean.toString(false);
return BaseResourceIndexedSearchParam.hash(thePartitionConfig, thePartitionId, theResourceType, theParamName, string); return BaseResourceIndexedSearchParam.hash(thePartitionConfig, thePartitionId, theResourceType, theParamName, string);

View File

@ -21,8 +21,8 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
*/ */
import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.cross.IResourceLookup; import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;

View File

@ -26,6 +26,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.PartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionConfig; import ca.uhn.fhir.jpa.model.config.PartitionConfig;
import ca.uhn.fhir.jpa.model.cross.IResourceLookup; import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
import ca.uhn.fhir.jpa.model.entity.*; import ca.uhn.fhir.jpa.model.entity.*;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.test.utilities; package ca.uhn.fhir.test.utilities;
/*-
* #%L
* HAPI FHIR Test Utilities
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.springframework.aop.framework.AopProxyUtils; import org.springframework.aop.framework.AopProxyUtils;