Cleanup sql test
This commit is contained in:
parent
d05079da22
commit
4cf3af3f39
|
@ -5,9 +5,7 @@ import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.param.UriParam;
|
import ca.uhn.fhir.rest.param.UriParam;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
@ -17,7 +15,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.CsvSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -26,7 +24,6 @@ import java.util.UUID;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
|
|
||||||
public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
@ -47,80 +44,73 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
record SqlGenerationTestCase(String comment, String restQuery, String expectedSql, String expectedPartitionedSql) {}
|
||||||
* One regular search params - Doesn't need HFJ_RESOURCE as root
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSingleRegularSearchParam() {
|
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
static List<SqlGenerationTestCase> sqlGenerationTestCases() {
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous(Patient.SP_NAME, new StringParam("FOO"));
|
return List.of(
|
||||||
myPatientDao.search(map);
|
new SqlGenerationTestCase(
|
||||||
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
"single string - no hfj_resource root",
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
"Patient?name=FOO",
|
||||||
assertEquals("SELECT t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))", sql);
|
"SELECT t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))",
|
||||||
|
"SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))"
|
||||||
|
)
|
||||||
|
, new SqlGenerationTestCase(
|
||||||
|
"two regular params - should use hfj_resource as root",
|
||||||
|
"Patient?name=smith&active=true",
|
||||||
|
"SELECT t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON (t1.RES_ID = t0.RES_ID) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (t1.RES_ID = t2.RES_ID) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_VALUE = ?))",
|
||||||
|
"SELECT t1.PARTITION_ID,t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON ((t1.PARTITION_ID = t0.PARTITION_ID) AND (t1.RES_ID = t0.RES_ID)) INNER JOIN HFJ_SPIDX_TOKEN t2 ON ((t1.PARTITION_ID = t2.PARTITION_ID) AND (t1.RES_ID = t2.RES_ID)) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_VALUE = ?))"
|
||||||
|
)
|
||||||
|
, new SqlGenerationTestCase(
|
||||||
|
"token not as a NOT IN subselect",
|
||||||
|
"Encounter?class:not=not-there",
|
||||||
|
"SELECT t0.RES_ID FROM HFJ_RESOURCE t0 WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t0.RES_ID) NOT IN (SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))",
|
||||||
|
"SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_RESOURCE t0 WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t0.PARTITION_ID,t0.RES_ID) NOT IN (SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))"
|
||||||
|
)
|
||||||
|
, new SqlGenerationTestCase(
|
||||||
|
"token not on chain join - NOT IN from hfj_res_link target columns",
|
||||||
|
"Observation?encounter.class:not=not-there",
|
||||||
|
"SELECT t0.SRC_RESOURCE_ID FROM HFJ_RES_LINK t0 WHERE ((t0.SRC_PATH = ?) AND ((t0.TARGET_RESOURCE_ID) NOT IN (SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))",
|
||||||
|
"SELECT t0.PARTITION_ID,t0.SRC_RESOURCE_ID FROM HFJ_RES_LINK t0 WHERE ((t0.SRC_PATH = ?) AND ((t0.TARGET_RES_PARTITION_ID,t0.TARGET_RESOURCE_ID) NOT IN (SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))"
|
||||||
|
)
|
||||||
|
, new SqlGenerationTestCase(
|
||||||
|
"bare sort",
|
||||||
|
"Patient?_sort=name",
|
||||||
|
"SELECT t0.RES_ID FROM HFJ_RESOURCE t0 LEFT OUTER JOIN HFJ_SPIDX_STRING t1 ON ((t0.RES_ID = t1.RES_ID) AND (t1.HASH_IDENTITY = ?)) WHERE ((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) ORDER BY t1.SP_VALUE_NORMALIZED ASC NULLS LAST",
|
||||||
|
"SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_RESOURCE t0 LEFT OUTER JOIN HFJ_SPIDX_STRING t1 ON ((t0.PARTITION_ID = t1.PARTITION_ID) AND (t0.RES_ID = t1.RES_ID) AND (t1.HASH_IDENTITY = ?)) WHERE ((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) ORDER BY t1.SP_VALUE_NORMALIZED ASC NULLS LAST"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("sqlGenerationTestCases")
|
||||||
|
void testSqlGeneration_DefaultNoPartitionJoin(SqlGenerationTestCase theTestCase) {
|
||||||
|
// default config
|
||||||
|
|
||||||
|
String sql = getSqlForRestQuery(theTestCase.restQuery);
|
||||||
|
|
||||||
|
assertEquals(theTestCase.expectedSql, sql, theTestCase.comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@CsvSource(textBlock = """
|
@MethodSource("sqlGenerationTestCases")
|
||||||
single param - no hfj_resource, Patient?name=smith , 'SELECT t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))'
|
void testSqlGeneration_WithPartitionJoins(SqlGenerationTestCase theTestCase) {
|
||||||
single join, Patient?name=smith&active=true ,'SELECT t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON (t1.RES_ID = t0.RES_ID) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (t1.RES_ID = t2.RES_ID) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_VALUE = ?))'
|
// include partition_id in joins
|
||||||
not, Encounter?class:not=not-there ,'SELECT t0.RES_ID FROM HFJ_RESOURCE t0 WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t0.RES_ID) NOT IN (SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
|
||||||
not in chain, Observation?encounter.class:not=not-there ,'SELECT t0.SRC_RESOURCE_ID FROM HFJ_RES_LINK t0 WHERE ((t0.SRC_PATH = ?) AND ((t0.TARGET_RESOURCE_ID) NOT IN (SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
|
||||||
bare sort, Patient?_sort=name ,'SELECT t0.RES_ID FROM HFJ_RESOURCE t0 LEFT OUTER JOIN HFJ_SPIDX_STRING t1 ON ((t0.RES_ID = t1.RES_ID) AND (t1.HASH_IDENTITY = ?)) WHERE ((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) ORDER BY t1.SP_VALUE_NORMALIZED ASC NULLS LAST'
|
|
||||||
""")
|
|
||||||
public void testSqlGeneration(String theComment, String theFhirRestQuery, String theExpectedSql) {
|
|
||||||
// setup
|
|
||||||
myCaptureQueriesListener.clear();
|
|
||||||
|
|
||||||
// execute
|
|
||||||
myTestDaoSearch.searchForIds(theFhirRestQuery);
|
|
||||||
|
|
||||||
// verify
|
|
||||||
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
|
||||||
assertEquals(theExpectedSql, sql, theComment);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@CsvSource(textBlock = """
|
|
||||||
single- no hfj_resource,Patient?name=smith ,'SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))'
|
|
||||||
single join, Patient?name=smith&active=true ,'SELECT t1.PARTITION_ID,t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON ((t1.PARTITION_ID = t0.PARTITION_ID) AND (t1.RES_ID = t0.RES_ID)) INNER JOIN HFJ_SPIDX_TOKEN t2 ON ((t1.PARTITION_ID = t2.PARTITION_ID) AND (t1.RES_ID = t2.RES_ID)) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_VALUE = ?))'
|
|
||||||
not, Encounter?class:not=not-there ,'SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_RESOURCE t0 WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t0.PARTITION_ID,t0.RES_ID) NOT IN (SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
|
||||||
not in chain, Observation?encounter.class:not=not-there ,'SELECT t0.PARTITION_ID,t0.SRC_RESOURCE_ID FROM HFJ_RES_LINK t0 WHERE ((t0.SRC_PATH = ?) AND ((t0.TARGET_RES_PARTITION_ID,t0.TARGET_RESOURCE_ID) NOT IN (SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
|
||||||
bare sort, Patient?_sort=name ,'SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_RESOURCE t0 LEFT OUTER JOIN HFJ_SPIDX_STRING t1 ON ((t0.PARTITION_ID = t1.PARTITION_ID) AND (t0.RES_ID = t1.RES_ID) AND (t1.HASH_IDENTITY = ?)) WHERE ((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) ORDER BY t1.SP_VALUE_NORMALIZED ASC NULLS LAST'
|
|
||||||
""")
|
|
||||||
public void testSqlGenerationWithPartitionJoins(String theComment, String theFhirRestQuery, String theExpectedSql) {
|
|
||||||
// setup
|
|
||||||
myPartitionSettings.setDefaultPartitionId(0);
|
myPartitionSettings.setDefaultPartitionId(0);
|
||||||
myPartitionSettings.setPartitionIdsInPrimaryKeys(true);
|
myPartitionSettings.setPartitionIdsInPrimaryKeys(true);
|
||||||
myCaptureQueriesListener.clear();
|
|
||||||
|
|
||||||
// execute
|
String sql = getSqlForRestQuery(theTestCase.restQuery);
|
||||||
|
|
||||||
|
assertEquals(theTestCase.expectedPartitionedSql, sql, theTestCase.comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSqlForRestQuery(String theFhirRestQuery) {
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
myTestDaoSearch.searchForIds(theFhirRestQuery);
|
myTestDaoSearch.searchForIds(theFhirRestQuery);
|
||||||
|
|
||||||
// verify
|
|
||||||
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
return myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
||||||
assertEquals(theExpectedSql, sql, theComment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Two regular search params - Should use HFJ_RESOURCE as root
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testTwoRegularSearchParams() {
|
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous()
|
|
||||||
.add(Patient.SP_NAME, new StringParam("FOO"))
|
|
||||||
.add(Patient.SP_GENDER, new TokenParam("a", "b"));
|
|
||||||
myPatientDao.search(map);
|
|
||||||
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
|
||||||
assertEquals("SELECT t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON (t1.RES_ID = t0.RES_ID) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (t1.RES_ID = t2.RES_ID) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_SYS_AND_VALUE = ?))", sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchByProfile_VersionedMode() {
|
public void testSearchByProfile_VersionedMode() {
|
||||||
|
@ -129,14 +119,14 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
String code = "http://" + UUID.randomUUID();
|
String code = "http://" + UUID.randomUUID();
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.getMeta().addProfile(code);
|
p.getMeta().addProfile(code);
|
||||||
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
myMemoryCacheService.invalidateAllCaches();
|
myMemoryCacheService.invalidateAllCaches();
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous()
|
SearchParameterMap map = SearchParameterMap.newSynchronous()
|
||||||
.add(Constants.PARAM_PROFILE, new TokenParam(code));
|
.add(Constants.PARAM_PROFILE, new TokenParam(code));
|
||||||
IBundleProvider outcome = myPatientDao.search(map);
|
IBundleProvider outcome = myPatientDao.search(map, mySrd);
|
||||||
assertEquals(3, myCaptureQueriesListener.countSelectQueries());
|
assertEquals(3, myCaptureQueriesListener.countSelectQueries());
|
||||||
// Query 1 - Find resources: Make sure we search for tag type+system+code always
|
// Query 1 - Find resources: Make sure we search for tag type+system+code always
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
||||||
|
@ -158,7 +148,6 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
boolean reindexParamCache = myStorageSettings.isMarkResourcesForReindexingUponSearchParameterChange();
|
boolean reindexParamCache = myStorageSettings.isMarkResourcesForReindexingUponSearchParameterChange();
|
||||||
myStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(false);
|
myStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(false);
|
||||||
|
|
||||||
// SearchParameter searchParameter = FhirResourceDaoR4TagsTest.createSearchParamForInlineResourceProfile();
|
|
||||||
SearchParameter searchParameter = FhirResourceDaoR4TagsInlineTest.createSearchParameterForInlineProfile();
|
SearchParameter searchParameter = FhirResourceDaoR4TagsInlineTest.createSearchParameterForInlineProfile();
|
||||||
ourLog.debug("SearchParam:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(searchParameter));
|
ourLog.debug("SearchParam:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(searchParameter));
|
||||||
mySearchParameterDao.update(searchParameter, mySrd);
|
mySearchParameterDao.update(searchParameter, mySrd);
|
||||||
|
@ -168,14 +157,14 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
String code = "http://" + UUID.randomUUID();
|
String code = "http://" + UUID.randomUUID();
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.getMeta().addProfile(code);
|
p.getMeta().addProfile(code);
|
||||||
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
myMemoryCacheService.invalidateAllCaches();
|
myMemoryCacheService.invalidateAllCaches();
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous()
|
SearchParameterMap map = SearchParameterMap.newSynchronous()
|
||||||
.add(Constants.PARAM_PROFILE, new UriParam(code));
|
.add(Constants.PARAM_PROFILE, new UriParam(code));
|
||||||
IBundleProvider outcome = myPatientDao.search(map);
|
IBundleProvider outcome = myPatientDao.search(map, mySrd);
|
||||||
assertEquals(2, myCaptureQueriesListener.countSelectQueries());
|
assertEquals(2, myCaptureQueriesListener.countSelectQueries());
|
||||||
// Query 1 - Find resources: Just a standard token search in this mode
|
// Query 1 - Find resources: Just a standard token search in this mode
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
||||||
|
|
Loading…
Reference in New Issue