Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
c83b330c48
|
@ -155,6 +155,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
@Override
|
||||
public void cancelAllActiveSearches() {
|
||||
for (SearchTask next : myIdToSearchTask.values()) {
|
||||
ourLog.info("Requesting immediate abort of search: {}", next.getSearch().getUuid());
|
||||
next.requestImmediateAbort();
|
||||
AsyncUtil.awaitLatchAndIgnoreInterrupt(next.getCompletionLatch(), 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
@ -631,6 +632,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
Integer awaitInitialSync() {
|
||||
ourLog.trace("Awaiting initial sync");
|
||||
do {
|
||||
ourLog.trace("Search {} aborted: {}", getSearch().getUuid(), !isNotAborted());
|
||||
if (AsyncUtil.awaitLatchAndThrowInternalErrorExceptionOnInterrupt(getInitialCollectionLatch(), 250L, TimeUnit.MILLISECONDS)) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,10 @@ import ca.uhn.fhir.rest.client.apache.ResourceEntity;
|
|||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
|
@ -96,7 +98,7 @@ public class BulkDataExportProviderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulInitiateBulkRequest() throws IOException {
|
||||
public void testSuccessfulInitiateBulkRequest_Post() throws IOException {
|
||||
|
||||
IBulkDataExportSvc.JobInfo jobInfo = new IBulkDataExportSvc.JobInfo()
|
||||
.setJobId(A_JOB_ID);
|
||||
|
@ -110,9 +112,12 @@ public class BulkDataExportProviderTest {
|
|||
input.addParameter(JpaConstants.PARAM_EXPORT_SINCE, now);
|
||||
input.addParameter(JpaConstants.PARAM_EXPORT_TYPE_FILTER, new StringType("Patient?identifier=foo"));
|
||||
|
||||
ourLog.info(myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(input));
|
||||
|
||||
HttpPost post = new HttpPost("http://localhost:" + myPort + "/" + JpaConstants.OPERATION_EXPORT);
|
||||
post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC);
|
||||
post.setEntity(new ResourceEntity(myCtx, input));
|
||||
ourLog.info("Request: {}", post);
|
||||
try (CloseableHttpResponse response = myClient.execute(post)) {
|
||||
ourLog.info("Response: {}", response.toString());
|
||||
|
||||
|
@ -129,6 +134,40 @@ public class BulkDataExportProviderTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulInitiateBulkRequest_Get() throws IOException {
|
||||
|
||||
IBulkDataExportSvc.JobInfo jobInfo = new IBulkDataExportSvc.JobInfo()
|
||||
.setJobId(A_JOB_ID);
|
||||
when(myBulkDataExportSvc.submitJob(any(), any(), any(), any())).thenReturn(jobInfo);
|
||||
|
||||
InstantType now = InstantType.now();
|
||||
|
||||
String url = "http://localhost:" + myPort + "/" + JpaConstants.OPERATION_EXPORT
|
||||
+ "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON)
|
||||
+ "&" + JpaConstants.PARAM_EXPORT_TYPE + "=" + UrlUtil.escapeUrlParam("Patient, Practitioner")
|
||||
+ "&" + JpaConstants.PARAM_EXPORT_SINCE+ "="+ UrlUtil.escapeUrlParam(now.getValueAsString())
|
||||
+ "&" + JpaConstants.PARAM_EXPORT_TYPE_FILTER + "=" + UrlUtil.escapeUrlParam("Patient?identifier=foo");
|
||||
|
||||
HttpGet get = new HttpGet(url);
|
||||
get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC);
|
||||
ourLog.info("Request: {}", url);
|
||||
try (CloseableHttpResponse response = myClient.execute(get)) {
|
||||
ourLog.info("Response: {}", response.toString());
|
||||
|
||||
assertEquals(202, response.getStatusLine().getStatusCode());
|
||||
assertEquals("Accepted", response.getStatusLine().getReasonPhrase());
|
||||
assertEquals("http://localhost:" + myPort + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue());
|
||||
}
|
||||
|
||||
verify(myBulkDataExportSvc, times(1)).submitJob(myOutputFormatCaptor.capture(), myResourceTypesCaptor.capture(), mySinceCaptor.capture(), myFiltersCaptor.capture());
|
||||
assertEquals(Constants.CT_FHIR_NDJSON, myOutputFormatCaptor.getValue());
|
||||
assertThat(myResourceTypesCaptor.getValue(), containsInAnyOrder("Patient", "Practitioner"));
|
||||
assertThat(mySinceCaptor.getValue(), notNullValue());
|
||||
assertThat(myFiltersCaptor.getValue(), containsInAnyOrder("Patient?identifier=foo"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPollForStatus_BUILDING() throws IOException {
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.Date;
|
|||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static ca.uhn.fhir.jpa.search.cache.DatabaseSearchCacheSvcImpl.DEFAULT_CUTOFF_SLACK;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
@ -165,13 +166,10 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
DatabaseSearchCacheSvcImpl.setNowForUnitTests(search3timestamp.get() + 2100);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertFalse("Search 1 still exists", mySearchEntityDao.findByUuidAndFetchIncludes(searchUuid1).isPresent());
|
||||
assertFalse("Search 3 still exists", mySearchEntityDao.findByUuidAndFetchIncludes(searchUuid3).isPresent());
|
||||
}
|
||||
});
|
||||
|
||||
await().until(()-> newTxTemplate().execute(t -> !mySearchEntityDao.findByUuidAndFetchIncludes(searchUuid1).isPresent()));
|
||||
await().until(()-> newTxTemplate().execute(t -> !mySearchEntityDao.findByUuidAndFetchIncludes(searchUuid3).isPresent()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,7 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -39,8 +37,12 @@ import org.springframework.transaction.TransactionStatus;
|
|||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
|
@ -108,9 +110,9 @@ public class SearchCoordinatorSvcImplTest {
|
|||
}).when(myCallingDao).injectDependenciesIntoBundleProvider(any(PersistedJpaBundleProvider.class));
|
||||
}
|
||||
|
||||
private List<Long> createPidSequence(int from, int to) {
|
||||
private List<Long> createPidSequence(int to) {
|
||||
List<Long> pids = new ArrayList<>();
|
||||
for (long i = from; i < to; i++) {
|
||||
for (long i = 10; i < to; i++) {
|
||||
pids.add(i);
|
||||
}
|
||||
return pids;
|
||||
|
@ -134,7 +136,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 800);
|
||||
List<Long> pids = createPidSequence(800);
|
||||
IResultIterator iter = new FailAfterNIterator(new SlowIterator(pids.iterator(), 2), 300);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), any())).thenReturn(iter);
|
||||
|
||||
|
@ -166,7 +168,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 800);
|
||||
List<Long> pids = createPidSequence(800);
|
||||
SlowIterator iter = new SlowIterator(pids.iterator(), 1);
|
||||
when(mySearchBuilder.createQuery(any(), any(), any())).thenReturn(iter);
|
||||
doAnswer(loadPids()).when(mySearchBuilder).loadResourcesByPid(any(Collection.class), any(Collection.class), any(List.class), anyBoolean(), any());
|
||||
|
@ -203,9 +205,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
myCurrentSearch = search;
|
||||
return search;
|
||||
});
|
||||
when(mySearchCacheSvc.fetchByUuid(any())).thenAnswer(t -> {
|
||||
return Optional.ofNullable(myCurrentSearch);
|
||||
});
|
||||
when(mySearchCacheSvc.fetchByUuid(any())).thenAnswer(t -> Optional.ofNullable(myCurrentSearch));
|
||||
IFhirResourceDao dao = myCallingDao;
|
||||
when(myDaoRegistry.getResourceDao(any(String.class))).thenReturn(dao);
|
||||
|
||||
|
@ -274,7 +274,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 800);
|
||||
List<Long> pids = createPidSequence(800);
|
||||
SlowIterator iter = new SlowIterator(pids.iterator(), 2);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), any())).thenReturn(iter);
|
||||
|
||||
|
@ -294,32 +294,43 @@ public class SearchCoordinatorSvcImplTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCancelActiveSearches() {
|
||||
public void testCancelActiveSearches() throws InterruptedException {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 400);
|
||||
SlowIterator iter = new SlowIterator(pids.iterator(), 50);
|
||||
List<Long> pids = createPidSequence(800);
|
||||
SlowIterator iter = new SlowIterator(pids.iterator(), 500);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), any())).thenReturn(iter);
|
||||
|
||||
doAnswer(loadPids()).when(mySearchBuilder).loadResourcesByPid(any(Collection.class), any(Collection.class), any(List.class), anyBoolean(), any());
|
||||
|
||||
IBundleProvider result = mySvc.registerSearch(myCallingDao, params, "Patient", new CacheControlDirective(), null);
|
||||
assertNotNull(result.getUuid());
|
||||
assertEquals(null, result.size());
|
||||
|
||||
List<IBaseResource> resources;
|
||||
|
||||
resources = result.getResources(0, 1);
|
||||
CountDownLatch completionLatch = new CountDownLatch(1);
|
||||
Runnable taskStarter = () -> {
|
||||
try {
|
||||
ourLog.info("About to pull the first resource");
|
||||
List<IBaseResource> resources = result.getResources(0, 1);
|
||||
ourLog.info("Done pulling the first resource");
|
||||
assertEquals(1, resources.size());
|
||||
} finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
};
|
||||
new Thread(taskStarter).start();
|
||||
|
||||
await().until(()->iter.getCountReturned() >= 3);
|
||||
|
||||
ourLog.info("About to cancel all searches");
|
||||
mySvc.cancelAllActiveSearches();
|
||||
ourLog.info("Done cancelling all searches");
|
||||
|
||||
try {
|
||||
result.getResources(10, 20);
|
||||
} catch (InternalErrorException e) {
|
||||
assertEquals("Abort has been requested", e.getMessage());
|
||||
}
|
||||
|
||||
completionLatch.await(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,7 +342,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 800);
|
||||
List<Long> pids = createPidSequence(800);
|
||||
IResultIterator iter = new SlowIterator(pids.iterator(), 2);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), any())).thenReturn(iter);
|
||||
when(mySearchCacheSvc.save(any())).thenAnswer(t -> t.getArguments()[0]);
|
||||
|
@ -376,7 +387,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 100);
|
||||
List<Long> pids = createPidSequence(100);
|
||||
SlowIterator iter = new SlowIterator(pids.iterator(), 2);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), any())).thenReturn(iter);
|
||||
|
||||
|
@ -384,7 +395,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
|
||||
IBundleProvider result = mySvc.registerSearch(myCallingDao, params, "Patient", new CacheControlDirective(), null);
|
||||
assertNotNull(result.getUuid());
|
||||
assertEquals(90, result.size().intValue());
|
||||
assertEquals(90, Objects.requireNonNull(result.size()).intValue());
|
||||
|
||||
List<IBaseResource> resources = result.getResources(0, 30);
|
||||
assertEquals(30, resources.size());
|
||||
|
@ -396,6 +407,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
@Test
|
||||
public void testGetPage() {
|
||||
Pageable page = SearchCoordinatorSvcImpl.toPage(50, 73);
|
||||
assert page != null;
|
||||
assertEquals(50, page.getOffset());
|
||||
assertEquals(23, page.getPageSize());
|
||||
}
|
||||
|
@ -458,14 +470,14 @@ public class SearchCoordinatorSvcImplTest {
|
|||
params.setLoadSynchronous(true);
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 800);
|
||||
List<Long> pids = createPidSequence(800);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), any())).thenReturn(new ResultIterator(pids.iterator()));
|
||||
|
||||
doAnswer(loadPids()).when(mySearchBuilder).loadResourcesByPid(any(Collection.class), any(Collection.class), any(List.class), anyBoolean(), any());
|
||||
|
||||
IBundleProvider result = mySvc.registerSearch(myCallingDao, params, "Patient", new CacheControlDirective(), null);
|
||||
assertNull(result.getUuid());
|
||||
assertEquals(790, result.size().intValue());
|
||||
assertEquals(790, Objects.requireNonNull(result.size()).intValue());
|
||||
|
||||
List<IBaseResource> resources = result.getResources(0, 10000);
|
||||
assertEquals(790, resources.size());
|
||||
|
@ -479,15 +491,15 @@ public class SearchCoordinatorSvcImplTest {
|
|||
params.setLoadSynchronousUpTo(100);
|
||||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 800);
|
||||
List<Long> pids = createPidSequence(800);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), nullable(RequestDetails.class))).thenReturn(new ResultIterator(pids.iterator()));
|
||||
|
||||
pids = createPidSequence(10, 110);
|
||||
pids = createPidSequence(110);
|
||||
doAnswer(loadPids()).when(mySearchBuilder).loadResourcesByPid(eq(pids), any(Collection.class), any(List.class), anyBoolean(), nullable(RequestDetails.class));
|
||||
|
||||
IBundleProvider result = mySvc.registerSearch(myCallingDao, params, "Patient", new CacheControlDirective(), null);
|
||||
assertNull(result.getUuid());
|
||||
assertEquals(100, result.size().intValue());
|
||||
assertEquals(100, Objects.requireNonNull(result.size()).intValue());
|
||||
|
||||
List<IBaseResource> resources = result.getResources(0, 10000);
|
||||
assertEquals(100, resources.size());
|
||||
|
@ -628,6 +640,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
private int myDelay;
|
||||
private Iterator<Long> myWrap;
|
||||
private List<Long> myReturnedValues = new ArrayList<>();
|
||||
private AtomicInteger myCountReturned = new AtomicInteger(0);
|
||||
|
||||
SlowIterator(Iterator<Long> theWrap, int theDelay) {
|
||||
myWrap = theWrap;
|
||||
|
@ -648,6 +661,10 @@ public class SearchCoordinatorSvcImplTest {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public int getCountReturned() {
|
||||
return myCountReturned.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long next() {
|
||||
try {
|
||||
|
@ -657,6 +674,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
}
|
||||
Long retVal = myWrap.next();
|
||||
myReturnedValues.add(retVal);
|
||||
myCountReturned.incrementAndGet();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package ca.uhn.fhir.test.utilities.server;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.rules.TestRule;
|
||||
|
@ -14,7 +13,6 @@ public class HashMapResourceProviderRule<T extends IBaseResource> extends HashMa
|
|||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theFhirContext The FHIR context
|
||||
* @param theResourceType The resource type to support
|
||||
*/
|
||||
public HashMapResourceProviderRule(RestfulServerRule theRestfulServerRule, Class<T> theResourceType) {
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
<ul class="dropdown-menu" role="menu">
|
||||
<li th:each="serverEntry : ${serverEntries}">
|
||||
<a th:href="'javascript:selectServer(\'' + ${serverEntry.key} + '\');'">
|
||||
<span class="fa fa-check-square-o" th:if="${serverEntry.key} == ${serverId}"></span>
|
||||
<span class="fa fa-square-o" style="color: #CCC;" th:unless="${serverEntry.key} == ${serverId}"></span>
|
||||
<i class="far fa-check-square" th:if="${serverEntry.key} == ${serverId}"></i>
|
||||
<i class="far fa-square" style="color: #CCC;" th:unless="${serverEntry.key} == ${serverId}"></i>
|
||||
|
||||
<th:block th:text="${serverEntry.value}"/>
|
||||
</a>
|
||||
|
|
|
@ -20,10 +20,10 @@ function addSearchParamRow() {
|
|||
addSearchParamRow();
|
||||
});
|
||||
|
||||
var params = new Array();
|
||||
var params = [];
|
||||
conformance.rest.forEach(function(rest){
|
||||
rest.resource.forEach(function(restResource){
|
||||
if (restResource.type == resourceName) {
|
||||
if (restResource.type === resourceName) {
|
||||
if (restResource.searchParam) {
|
||||
for (var i = 0; i < restResource.searchParam.length; i++) {
|
||||
var searchParam = restResource.searchParam[i];
|
||||
|
@ -63,7 +63,7 @@ function updateSearchDateQualifier(qualifierBtn, qualifierInput, qualifier) {
|
|||
function addSearchControls(theConformance, theSearchParamType, theSearchParamName, theSearchParamChain, theSearchParamTarget, theContainerRowNum, theRowNum) {
|
||||
|
||||
var addNameAndType = true;
|
||||
if (theSearchParamType == 'id') {
|
||||
if (theSearchParamType === 'id') {
|
||||
$('#search-param-rowopts-' + theContainerRowNum).append(
|
||||
$('<div />', { 'class': 'col-sm-3' }).append(
|
||||
$('<input />', { id: 'param.' + theRowNum + '.0', placeholder: 'id', type: 'text', 'class': 'form-control' })
|
||||
|
@ -71,37 +71,37 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
);
|
||||
} else if (theSearchParamType == 'token') {
|
||||
|
||||
var tokenQualifiers = new Array();
|
||||
tokenQualifiers.push(new Object());
|
||||
var tokenQualifiers = [];
|
||||
tokenQualifiers.push({});
|
||||
tokenQualifiers[0].name='Matches';
|
||||
tokenQualifiers[0].value='';
|
||||
|
||||
tokenQualifiers.push(new Object());
|
||||
tokenQualifiers.push({});
|
||||
tokenQualifiers[1].name='Text';
|
||||
tokenQualifiers[1].value=':text';
|
||||
tokenQualifiers[1].description='The search parameter is processed as a string that searches text associated with the code/value.';
|
||||
|
||||
tokenQualifiers.push(new Object());
|
||||
tokenQualifiers.push({});
|
||||
tokenQualifiers[2].name='Not';
|
||||
tokenQualifiers[2].value=':not';
|
||||
tokenQualifiers[2].description='Reverse the code matching described in the paragraph above. Note that this includes resources that have no value for the parameter.';
|
||||
|
||||
tokenQualifiers.push(new Object());
|
||||
tokenQualifiers.push({});
|
||||
tokenQualifiers[3].name='Above';
|
||||
tokenQualifiers[3].value=':above';
|
||||
tokenQualifiers[3].description='The search parameter is a concept with the form [system]|[code], and the search parameter tests whether the coding in a resource subsumes the specified search code. For example, the search concept has an is-a relationship with the coding in the resource, and this includes the coding itself.';
|
||||
|
||||
tokenQualifiers.push(new Object());
|
||||
tokenQualifiers.push({});
|
||||
tokenQualifiers[4].name='Below';
|
||||
tokenQualifiers[4].value=':below';
|
||||
tokenQualifiers[4].description='The search parameter is a concept with the form [system]|[code], and the search parameter tests whether the coding in a resource is subsumed by the specified search code. For example, the coding in the resource has an is-a relationship with the search concept, and this includes the coding itself.';
|
||||
|
||||
tokenQualifiers.push(new Object());
|
||||
tokenQualifiers.push({});
|
||||
tokenQualifiers[5].name='In';
|
||||
tokenQualifiers[5].value=':in';
|
||||
tokenQualifiers[5].description='The search parameter is a URI (relative or absolute) that identifies a value set, and the search parameter tests whether the coding is in the specified value set. The reference may be literal (to an address where the value set can be found) or logical (a reference to ValueSet.url). If the server can treat the reference as a literal URL, it does, else it tries to match known logical ValueSet.url values.';
|
||||
|
||||
tokenQualifiers.push(new Object());
|
||||
tokenQualifiers.push({});
|
||||
tokenQualifiers[6].name='Not-in';
|
||||
tokenQualifiers[6].value=':not-in';
|
||||
tokenQualifiers[6].description='The search parameter is a URI (relative or absolute) that identifies a value set, and the search parameter tests whether the coding is not in the specified value set.';
|
||||
|
@ -117,8 +117,8 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
tokenQualifierInput.val(value);
|
||||
tokenQualifierLabel.text(name);
|
||||
}
|
||||
};
|
||||
var tokenQualifierLabel = $('<span>' + tokenQualifiers[0].name + '</span>');
|
||||
}
|
||||
var tokenQualifierLabel = $('<span>' + tokenQualifiers[0].name + '</span>');
|
||||
var tokenQualifierDropdown = $('<ul />', {'class':'dropdown-menu', role:'menu'});
|
||||
for (var i = 0; i < tokenQualifiers.length; i++) {
|
||||
var qualName = tokenQualifiers[i].name;
|
||||
|
@ -152,13 +152,13 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
)
|
||||
);
|
||||
|
||||
} else if (theSearchParamType == 'string') {
|
||||
} else if (theSearchParamType === 'string') {
|
||||
var placeholderText = 'value';
|
||||
var qualifiers = new Array();
|
||||
qualifiers.push(new Object());
|
||||
var qualifiers = [];
|
||||
qualifiers.push({});
|
||||
qualifiers[0].name='Matches';
|
||||
qualifiers[0].value='';
|
||||
qualifiers.push(new Object());
|
||||
qualifiers.push({});
|
||||
qualifiers[1].name='Exactly';
|
||||
qualifiers[1].value=':exact';
|
||||
|
||||
|
@ -167,7 +167,6 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
qualifierInput
|
||||
);
|
||||
|
||||
|
||||
var matchesLabel = $('<span>' + qualifiers[0].name + '</span>');
|
||||
var qualifierDropdown = $('<ul />', {'class':'dropdown-menu', role:'menu'});
|
||||
|
||||
|
@ -176,9 +175,8 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
qualifierInput.val(value);
|
||||
matchesLabel.text(name);
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0; i < qualifiers.length; i++) {
|
||||
}
|
||||
for (var i = 0; i < qualifiers.length; i++) {
|
||||
var nextLink = $('<a>' + qualifiers[i].name+'</a>');
|
||||
var qualName = qualifiers[i].name;
|
||||
var nextValue = qualifiers[i].value;
|
||||
|
@ -241,7 +239,7 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
var select = $('<select/>', {/*style:'margin-left:30px;'*/});
|
||||
|
||||
var newContainerRowNum = theContainerRowNum + "-0";
|
||||
var newContainer = $('<div />', { id: 'search-param-rowopts-' + newContainerRowNum })
|
||||
var newContainer = $('<div />', { id: 'search-param-rowopts-' + newContainerRowNum });
|
||||
|
||||
$('#search-param-rowopts-' + theContainerRowNum).append(
|
||||
$('<br clear="all" />'),
|
||||
|
@ -255,14 +253,14 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
newContainer
|
||||
);
|
||||
|
||||
var params = new Array();
|
||||
var params = [];
|
||||
{
|
||||
var param = new Object();
|
||||
var param = {};
|
||||
param.type = 'id';
|
||||
param.chain = '';
|
||||
param.name = theSearchParamName;
|
||||
param.documentation = 'The resource identity';
|
||||
param.target = new Array();
|
||||
param.target = [];
|
||||
params[theSearchParamName] = param;
|
||||
select.append(
|
||||
$('<option />', { value: theSearchParamName }).text(param.name + ' - ' + param.documentation)
|
||||
|
@ -299,7 +297,63 @@ function addSearchControls(theConformance, theSearchParamType, theSearchParamNam
|
|||
handleSearchParamTypeChange(select, params, newContainerRowNum, theRowNum);
|
||||
select.change(function(){ handleSearchParamTypeChange(select, params, newContainerRowNum, theRowNum); });
|
||||
addNameAndType = false;
|
||||
}
|
||||
|
||||
} else if (theSearchParamType == 'uri') {
|
||||
var placeholderText = 'value';
|
||||
var qualifiers = [];
|
||||
qualifiers.push({});
|
||||
qualifiers[0].name = 'Equals';
|
||||
qualifiers[0].value = '';
|
||||
qualifiers.push({});
|
||||
qualifiers[1].name = 'Above';
|
||||
qualifiers[1].value = ':above';
|
||||
qualifiers.push({});
|
||||
qualifiers[2].name = 'Below';
|
||||
qualifiers[2].value = ':below';
|
||||
|
||||
var qualifierInput = $('<input />', {id: 'param.' + theRowNum + '.qualifier', type: 'hidden'});
|
||||
$('#search-param-rowopts-' + theContainerRowNum).append(
|
||||
qualifierInput
|
||||
);
|
||||
|
||||
|
||||
var matchesLabel = $('<span>' + qualifiers[0].name + '</span>');
|
||||
var qualifierDropdown = $('<ul />', {'class': 'dropdown-menu', role: 'menu'});
|
||||
|
||||
function clickFunction(value, name) {
|
||||
return function () {
|
||||
qualifierInput.val(value);
|
||||
matchesLabel.text(name);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < qualifiers.length; i++) {
|
||||
var nextLink = $('<a>' + qualifiers[i].name + '</a>');
|
||||
var qualName = qualifiers[i].name;
|
||||
var nextValue = qualifiers[i].value;
|
||||
qualifierDropdown.append($('<li />').append(nextLink));
|
||||
nextLink.click(clickFunction(nextValue, qualName));
|
||||
}
|
||||
|
||||
$('#search-param-rowopts-' + theContainerRowNum).append(
|
||||
$('<div />', {'class': 'col-sm-5 input-group'}).append(
|
||||
$('<div />', {'class': 'input-group-btn'}).append(
|
||||
$('<button />', {'class': 'btn btn-default dropdown-toggle', 'data-toggle': 'dropdown'}).append(
|
||||
matchesLabel,
|
||||
$('<span class="caret" style="margin-left: 5px;"></span>')
|
||||
),
|
||||
qualifierDropdown
|
||||
),
|
||||
$('<input />', {
|
||||
id: 'param.' + theRowNum + '.0',
|
||||
placeholder: placeholderText,
|
||||
type: 'text',
|
||||
'class': 'form-control'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
addNameAndType = true;
|
||||
}
|
||||
|
||||
if (addNameAndType) {
|
||||
$('#search-param-rowopts-' + theContainerRowNum).append(
|
||||
|
@ -314,12 +368,13 @@ function addSearchControlDate(theSearchParamName, theContainerRowNum, theRowNum,
|
|||
var inputId0 = theRowNum + '.' + (theLower ? 0 : 2);
|
||||
var inputId1 = theRowNum + '.' + (theLower ? 1 : 3);
|
||||
|
||||
var qualifier = $('<input />', {type:'hidden', id:'param.'+inputId0, id:'param.'+inputId0});
|
||||
var qualifier = $('<input />', {type:'hidden', id:'param.'+inputId0});
|
||||
|
||||
var input;
|
||||
if (/date$/.test(theSearchParamName)) {
|
||||
var input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DD' });
|
||||
input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DD' });
|
||||
} else {
|
||||
var input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DDTHH:mm:ss' });
|
||||
input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DDTHH:mm:ss' });
|
||||
}
|
||||
var qualifierDiv = $('<div />');
|
||||
|
||||
|
@ -426,7 +481,7 @@ function addSearchControlQuantity(theSearchParamName, theContainerRowNum, theRow
|
|||
function handleSearchParamTypeChange(select, params, theContainerRowNum, theParamRowNum) {
|
||||
var oldVal = select.prevVal;
|
||||
var newVal = select.val();
|
||||
if (oldVal == newVal) {
|
||||
if (oldVal === newVal) {
|
||||
return;
|
||||
}
|
||||
$('#search-param-rowopts-' + theContainerRowNum).empty();
|
||||
|
@ -448,10 +503,9 @@ function handleSearchParamTypeChange(select, params, theContainerRowNum, thePara
|
|||
function readFromEntriesTable(source, type, id, vid) {
|
||||
var btn = $(source);
|
||||
btn.button('loading');
|
||||
var resId = source.resourceid;
|
||||
btn.append($('<input />', { type: 'hidden', name: 'id', value: id }));
|
||||
var resVid = source.resourcevid;
|
||||
if (resVid != '') {
|
||||
if (resVid !== '') {
|
||||
btn.append($('<input />', { type: 'hidden', name: 'vid', value: vid }));
|
||||
}
|
||||
setResource(btn, type);
|
||||
|
@ -465,10 +519,9 @@ function readFromEntriesTable(source, type, id, vid) {
|
|||
function updateFromEntriesTable(source, type, id, vid) {
|
||||
var btn = $(source);
|
||||
btn.button('loading');
|
||||
var resId = source.resourceid;
|
||||
btn.append($('<input />', { type: 'hidden', name: 'updateId', value: id }));
|
||||
var resVid = source.resourcevid;
|
||||
if (resVid != '') {
|
||||
if (resVid !== '') {
|
||||
btn.append($('<input />', { type: 'hidden', name: 'updateVid', value: vid }));
|
||||
}
|
||||
setResource(btn, type);
|
||||
|
@ -488,7 +541,7 @@ function updateURLParameter(url, param, paramVal){
|
|||
if (additionalURL) {
|
||||
tempArray = additionalURL.split("&");
|
||||
for (i=0; i<tempArray.length; i++){
|
||||
if(tempArray[i].split('=')[0] != param){
|
||||
if(tempArray[i].split('=')[0] !== param){
|
||||
newAdditionalURL += temp + tempArray[i];
|
||||
temp = "&";
|
||||
}
|
||||
|
@ -501,8 +554,9 @@ function updateURLParameter(url, param, paramVal){
|
|||
|
||||
|
||||
function selectServer(serverId) {
|
||||
$('#serverSelectorFhirIcon').removeClass();
|
||||
$('#serverSelectorFhirIcon').addClass('fa fa-spinner fa-spin');
|
||||
let $serverSelectorFhirIcon = $('#serverSelectorFhirIcon');
|
||||
$serverSelectorFhirIcon.removeClass();
|
||||
$serverSelectorFhirIcon.addClass('fa fa-spinner fa-spin');
|
||||
$('#serverSelectorName').text("Loading...");
|
||||
$('#serverId').val(serverId);
|
||||
$("#outerForm").attr("action", "home").submit();
|
||||
|
@ -511,7 +565,6 @@ function selectServer(serverId) {
|
|||
function setResource(target, resourceName) {
|
||||
var resource = $('#resource');
|
||||
if (resourceName != null) {
|
||||
var input = $('#resource');
|
||||
if (resource.length) {
|
||||
resource.val(resourceName);
|
||||
} else {
|
||||
|
@ -527,7 +580,7 @@ function setResource(target, resourceName) {
|
|||
|
||||
function updateSort(value) {
|
||||
$('#sort_by').val(value);
|
||||
if (value == '') {
|
||||
if (value === '') {
|
||||
$('#search_sort_button').text('Default Sort');
|
||||
} else {
|
||||
$('#search_sort_button').text(value);
|
||||
|
@ -536,7 +589,7 @@ function updateSort(value) {
|
|||
|
||||
function updateSortDirection(value) {
|
||||
$('#sort_direction').val(value);
|
||||
if (value == '') {
|
||||
if (value === '') {
|
||||
$('#search_sort_direction_button').text('Default');
|
||||
} else {
|
||||
$('#search_sort_direction_button').text(value);
|
||||
|
|
|
@ -473,6 +473,9 @@
|
|||
The @ProvidesResources annotation has been removed from HAPI FHIR, as it was not documented
|
||||
and did not do anything useful. Please get in touch if this causes any issues.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Search parameters of type URI did not work in the hapi-fhir-testpage-overlay. This has been corrected.
|
||||
</action>
|
||||
</release>
|
||||
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue