Add some more sql syntax tests for Postgres, Oracle, and Sql Server (#5923)

Also:
- fix total parsing in internal MatchUrl service.
- Add more syntax tests for our docker database tests
- Change DaoTestDataBuilder to use a bundle with delete entries for teardown.
This commit is contained in:
Michael Buckley 2024-05-15 18:10:32 -04:00 committed by GitHub
parent 729c0c8546
commit 0a009901b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 65 additions and 29 deletions

View File

@ -127,12 +127,18 @@ public class MatchUrlService {
&& !paramList.isEmpty() && !paramList.isEmpty()
&& !paramList.get(0).isEmpty()) { && !paramList.get(0).isEmpty()) {
String totalModeEnumStr = paramList.get(0).get(0); String totalModeEnumStr = paramList.get(0).get(0);
try { SearchTotalModeEnum searchTotalMode = SearchTotalModeEnum.fromCode(totalModeEnumStr);
paramMap.setSearchTotalMode(SearchTotalModeEnum.valueOf(totalModeEnumStr)); if (searchTotalMode == null) {
} catch (IllegalArgumentException e) { // We had an oops here supporting the UPPER CASE enum instead of the FHIR code for _total.
throw new InvalidRequestException(Msg.code(2078) + "Invalid " // Keep supporting it in case someone is using it.
+ Constants.PARAM_SEARCH_TOTAL_MODE + " value: " + totalModeEnumStr); try {
paramMap.setSearchTotalMode(SearchTotalModeEnum.valueOf(totalModeEnumStr));
} catch (IllegalArgumentException e) {
throw new InvalidRequestException(Msg.code(2078) + "Invalid "
+ Constants.PARAM_SEARCH_TOTAL_MODE + " value: " + totalModeEnumStr);
}
} }
paramMap.setSearchTotalMode(searchTotalMode);
} }
} else if (Constants.PARAM_OFFSET.equals(nextParamName)) { } else if (Constants.PARAM_OFFSET.equals(nextParamName)) {
if (paramList != null if (paramList != null

View File

@ -6,6 +6,7 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.searchparam.util.Dstu3DistanceHelper; import ca.uhn.fhir.jpa.searchparam.util.Dstu3DistanceHelper;
import ca.uhn.fhir.jpa.test.BaseJpaTest; import ca.uhn.fhir.jpa.test.BaseJpaTest;
import ca.uhn.fhir.jpa.test.config.TestDstu3Config; import ca.uhn.fhir.jpa.test.config.TestDstu3Config;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.rest.param.QuantityParam; import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
@ -97,6 +98,26 @@ public class MatchUrlServiceTest extends BaseJpaTest {
} }
} }
@Test
void testTotal_fromStandardLowerCase() {
// given
// when
var map = myMatchUrlService.translateMatchUrl("Patient?family=smith&_total=none", ourCtx.getResourceDefinition("Patient"));
// then
assertEquals(SearchTotalModeEnum.NONE, map.getSearchTotalMode());
}
@Test
void testTotal_fromUpperCase() {
// given
// when
var map = myMatchUrlService.translateMatchUrl("Patient?family=smith&_total=none", ourCtx.getResourceDefinition("Patient"));
// then
assertEquals(SearchTotalModeEnum.NONE, map.getSearchTotalMode());
}
@Override @Override
protected FhirContext getFhirContext() { protected FhirContext getFhirContext() {
return ourCtx; return ourCtx;

View File

@ -11,11 +11,9 @@ import ca.uhn.fhir.jpa.migrate.SchemaMigrator;
import ca.uhn.fhir.jpa.migrate.dao.HapiMigrationDao; import ca.uhn.fhir.jpa.migrate.dao.HapiMigrationDao;
import ca.uhn.fhir.jpa.migrate.tasks.HapiFhirJpaMigrationTasks; import ca.uhn.fhir.jpa.migrate.tasks.HapiFhirJpaMigrationTasks;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.test.BaseJpaTest; import ca.uhn.fhir.jpa.test.BaseJpaTest;
import ca.uhn.fhir.jpa.test.config.TestR5Config; import ca.uhn.fhir.jpa.test.config.TestR5Config;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
@ -36,6 +34,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -57,6 +56,7 @@ import java.util.Set;
import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_EVERYTHING; import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_EVERYTHING;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -160,22 +160,23 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements
assertThat(values.toString(), values, containsInAnyOrder(expectedIds.toArray(new String[0]))); assertThat(values.toString(), values, containsInAnyOrder(expectedIds.toArray(new String[0])));
} }
@Test @ParameterizedTest
void testChainedSort() { @CsvSource(textBlock = """
// given query string, Patient?name=smith
query date, Observation?date=2021
// when query token, Patient?active=true
SearchParameterMap map = SearchParameterMap sort string, Patient?_sort=name
.newSynchronous() sort date, Observation?_sort=date
.setSort(new SortSpec("Practitioner:general-practitioner.family")); sort token, Patient?_sort=active
myCaptureQueriesListener.clear(); sort chained date, Observation?_sort=patient.birthdate
myPatientDao.search(map, mySrd); sort chained string, Observation?_sort=patient.name
sort chained qualified, Patient?_sort=Practitioner:general-practitioner.family
sort chained token, Observation?_sort=patient.active
""")
void testSyntaxForVariousQueries(String theMessage, String theQuery) {
assertDoesNotThrow(()->myTestDaoSearch.searchForBundleProvider(theQuery), theMessage);
} }
@Configuration @Configuration
public static class TestConfig extends TestR5Config { public static class TestConfig extends TestR5Config {
@ -238,11 +239,13 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements
} }
} }
@SuppressWarnings("unchecked")
@Override @Override
public IIdType doCreateResource(IBaseResource theResource) { public IIdType doCreateResource(IBaseResource theResource) {
return myDaoRegistry.getResourceDao(myFhirContext.getResourceType(theResource)).create(theResource, new SystemRequestDetails()).getId(); return myDaoRegistry.getResourceDao(myFhirContext.getResourceType(theResource)).create(theResource, new SystemRequestDetails()).getId();
} }
@SuppressWarnings("unchecked")
@Override @Override
public IIdType doUpdateResource(IBaseResource theResource) { public IIdType doUpdateResource(IBaseResource theResource) {
return myDaoRegistry.getResourceDao(myFhirContext.getResourceType(theResource)).update(theResource, new SystemRequestDetails()).getId(); return myDaoRegistry.getResourceDao(myFhirContext.getResourceType(theResource)).update(theResource, new SystemRequestDetails()).getId();

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.test.utilities.ITestDataBuilder; import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import ca.uhn.fhir.util.BundleBuilder;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -97,21 +98,26 @@ public class DaoTestDataBuilder implements ITestDataBuilder.WithSupport, ITestDa
} }
/** /**
* Delete anything created * Delete anything created by this builder since the last cleanup().
*/ */
public void cleanup() { public void cleanup() {
ourLog.info("cleanup {}", myIds); ourLog.info("cleanup {}", myIds);
myIds.keySet().stream() var builder = new BundleBuilder(myFhirCtx);
.sorted() // Hack to ensure Patients are deleted before Practitioners. This may need to be refined. myIds.values()
.forEach(nextType->{ .forEach(builder::addTransactionDeleteEntry);
// todo do this in a bundle for perf. var bundle = builder.getBundle();
IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(nextType);
myIds.get(nextType).forEach(dao::delete); ourLog.trace("Deleting in bundle {}", myFhirCtx.newJsonParser().encodeToString(bundle));
}); //noinspection unchecked
myDaoRegistry.getSystemDao().transaction(mySrd, bundle);
myIds.clear(); myIds.clear();
} }
/**
* Tear down and cleanup any Resources created during execution.
*/
@Override @Override
public void afterEach(ExtensionContext context) throws Exception { public void afterEach(ExtensionContext context) throws Exception {
cleanup(); cleanup();