CLeanup
This commit is contained in:
parent
c948ef4707
commit
1468bc1b49
|
@ -70,7 +70,6 @@ import ca.uhn.fhir.jpa.searchparam.util.LastNParameterHelper;
|
|||
import ca.uhn.fhir.jpa.util.BaseIterator;
|
||||
import ca.uhn.fhir.jpa.util.CartesianProductUtil;
|
||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.util.PermutationBuilder;
|
||||
import ca.uhn.fhir.jpa.util.QueryChunker;
|
||||
import ca.uhn.fhir.jpa.util.SqlQueryList;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
|
@ -943,7 +942,6 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
theQueryStack.addSortOnLastUpdated(ascending);
|
||||
|
||||
} else {
|
||||
// FIXME: test for activation
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
|
||||
myResourceName, theSort.getParamName(), ISearchParamRegistry.ContextEnum.SORT);
|
||||
|
||||
|
@ -2043,7 +2041,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
String nextOrValue = nextOr.getValueAsQueryToken(myContext);
|
||||
|
||||
RuntimeSearchParam nextParamDef =
|
||||
mySearchParamRegistry.getActiveSearchParam(myResourceName, nextParamName);
|
||||
mySearchParamRegistry.getActiveSearchParam(myResourceName, nextParamName, ISearchParamRegistry.ContextEnum.SEARCH);
|
||||
if (theComboParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE) {
|
||||
if (nextParamDef.getParamType() == RestSearchParameterTypeEnum.STRING) {
|
||||
nextOrValue = StringUtil.normalizeStringForSearchIndexing(nextOrValue);
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class for
|
||||
*/
|
||||
public class PermutationBuilder {
|
||||
|
||||
/**
|
||||
* Non instantiable
|
||||
*/
|
||||
private PermutationBuilder() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of lists of options, returns a list of every possible combination of options.
|
||||
* For example, given the input lists:
|
||||
* <pre>
|
||||
* [
|
||||
* [ A0, A1 ],
|
||||
* [ B0, B1, B2 ]
|
||||
* ]
|
||||
* </pre>
|
||||
* This method will return the following output lists:
|
||||
* <pre>
|
||||
* [
|
||||
* [ A0, B0 ],
|
||||
* [ A1, B0 ],
|
||||
* [ A0, B1 ],
|
||||
* [ A1, B1 ],
|
||||
* [ A0, B2 ],
|
||||
* [ A1, B2 ]
|
||||
* ]
|
||||
* </pre>
|
||||
* <p>
|
||||
* This method will return a newly created list and will not modify the input lists.
|
||||
* </p>
|
||||
*
|
||||
* @param theInput A list of lists to calculate permutations of
|
||||
* @param <T> The type associated with {@literal theInput}. The actual type doesn't matter, this method does not look at the
|
||||
* values at all other than to copy them to the output lists.
|
||||
* @since 7.4.0
|
||||
*/
|
||||
public static <T> List<List<T>> calculatePermutations(List<List<T>> theInput) {
|
||||
List<List<T>> listToPopulate = new ArrayList<>(calculatePermutationCount(theInput));
|
||||
int[] indices = new int[theInput.size()];
|
||||
doCalculatePermutationsIntoIndicesArrayAndPopulateList(0, indices, theInput, listToPopulate);
|
||||
return listToPopulate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively called/calling method which navigates across a list of input ArrayLists and populates the array of indices
|
||||
*
|
||||
* @param thePositionX The offset within {@literal theInput}. We navigate recursively from 0 through {@literal theInput.size()}
|
||||
* @param theIndices The array to populate. This array has a length matching the size of {@literal theInput} and each entry
|
||||
* represents an offset within the list at {@literal theInput.get(arrayIndex)}
|
||||
* @param theInput The input List of ArrayLists
|
||||
* @param theOutput A list to populate with all permutations
|
||||
* @param <T> The type associated with {@literal theInput}. The actual type doesn't matter, this method does not look at the
|
||||
* values at all other than to copy them to the output lists.
|
||||
*/
|
||||
private static <T> void doCalculatePermutationsIntoIndicesArrayAndPopulateList(
|
||||
int thePositionX, int[] theIndices, List<List<T>> theInput, List<List<T>> theOutput) {
|
||||
if (thePositionX != theInput.size()) {
|
||||
// If we're not at the end of the list of input vectors, recursively self-invoke once for each
|
||||
// possible option at the current position in the list of input vectors.
|
||||
for (int positionY = 0; positionY < theInput.get(thePositionX).size(); positionY++) {
|
||||
theIndices[thePositionX] = positionY;
|
||||
doCalculatePermutationsIntoIndicesArrayAndPopulateList(
|
||||
thePositionX + 1, theIndices, theInput, theOutput);
|
||||
}
|
||||
} else {
|
||||
// If we're at the end of the list of input vectors, then we've been passed the
|
||||
List<T> nextList = new ArrayList<>(theInput.size());
|
||||
for (int positionX = 0; positionX < theInput.size(); positionX++) {
|
||||
nextList.add(theInput.get(positionX).get(theIndices[positionX]));
|
||||
}
|
||||
theOutput.add(nextList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of permutations that {@link #calculatePermutations(List)} will
|
||||
* calculate for the given list.
|
||||
*
|
||||
* @throws ArithmeticException If the number of permutations exceeds {@link Integer#MAX_VALUE}
|
||||
* @since 7.4.0
|
||||
*/
|
||||
public static <T> int calculatePermutationCount(List<List<T>> theLists) throws ArithmeticException {
|
||||
int retVal = !theLists.isEmpty() ? 1 : 0;
|
||||
for (List<T> theList : theLists) {
|
||||
retVal = Math.multiplyExact(retVal, theList.size());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class PermutationBuilderTest {
|
||||
|
||||
@Test
|
||||
public void testCalculatePermutations() {
|
||||
List<List<String>> input = List.of(
|
||||
List.of("A0", "A1"),
|
||||
List.of("B0", "B1", "B2"),
|
||||
List.of("C0", "C1")
|
||||
);
|
||||
|
||||
List<List<String>> output = PermutationBuilder.calculatePermutations(input);
|
||||
assertThat(output).containsExactlyInAnyOrder(
|
||||
List.of("A0", "B0", "C0"),
|
||||
List.of("A1", "B0", "C0"),
|
||||
List.of("A0", "B1", "C0"),
|
||||
List.of("A1", "B1", "C0"),
|
||||
List.of("A0", "B2", "C0"),
|
||||
List.of("A1", "B2", "C0"),
|
||||
List.of("A0", "B0", "C1"),
|
||||
List.of("A1", "B0", "C1"),
|
||||
List.of("A0", "B1", "C1"),
|
||||
List.of("A1", "B1", "C1"),
|
||||
List.of("A0", "B2", "C1"),
|
||||
List.of("A1", "B2", "C1")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePermutations_OneDimensonalInputOnX() {
|
||||
List<List<String>> input = List.of(
|
||||
List.of("A0", "A1")
|
||||
);
|
||||
|
||||
List<List<String>> output = PermutationBuilder.calculatePermutations(input);
|
||||
assertThat(output).containsExactlyInAnyOrder(
|
||||
List.of("A0"),
|
||||
List.of("A1")
|
||||
);
|
||||
assertNotSame(input, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePermutations_OneDimensonalInputOnY() {
|
||||
List<List<String>> input = List.of(
|
||||
List.of("A0"),
|
||||
List.of("B0"),
|
||||
List.of("C0")
|
||||
);
|
||||
|
||||
List<List<String>> output = PermutationBuilder.calculatePermutations(input);
|
||||
assertThat(output).containsExactlyInAnyOrder(
|
||||
List.of("A0", "B0", "C0")
|
||||
);
|
||||
assertNotSame(input, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePermutations_OneDimensonalInputOnXandY() {
|
||||
List<List<String>> input = List.of(
|
||||
List.of("A0")
|
||||
);
|
||||
|
||||
List<List<String>> output = PermutationBuilder.calculatePermutations(input);
|
||||
assertThat(output).containsExactlyInAnyOrder(
|
||||
List.of("A0")
|
||||
);
|
||||
assertNotSame(input, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePermutationCount() {
|
||||
List<List<String>> input = List.of(
|
||||
List.of("A0", "A1"),
|
||||
List.of("B0", "B1", "B2"),
|
||||
List.of("C0", "C1")
|
||||
);
|
||||
assertEquals(12, PermutationBuilder.calculatePermutationCount(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePermutationCountEmpty() {
|
||||
List<List<String>> input = List.of();
|
||||
assertEquals(0, PermutationBuilder.calculatePermutationCount(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePermutationCountOverflow() {
|
||||
List<Integer> ranges = IntStream.range(0, 10001).boxed().toList();
|
||||
List<List<Integer>> input = IntStream.range(0, 20).boxed().map(t -> ranges).toList();
|
||||
assertThrows(ArithmeticException.class, () -> PermutationBuilder.calculatePermutationCount(input));
|
||||
}
|
||||
|
||||
}
|
|
@ -122,8 +122,10 @@ public class SearchParamRegistryImpl
|
|||
// Can still be null in unit test scenarios
|
||||
if (myActiveSearchParams != null) {
|
||||
RuntimeSearchParam param = myActiveSearchParams.get(theResourceName, theParamName);
|
||||
if (isAllowedForContext(param, theContext)) {
|
||||
return param;
|
||||
if (param != null) {
|
||||
if (isAllowedForContext(param, theContext)) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,6 @@ public interface ISearchParamRegistry {
|
|||
* @param theResourceType the resource type.
|
||||
* @return the {@link ResourceSearchParams} that has all the search params.
|
||||
*/
|
||||
// FIXME: can this be removed?
|
||||
default ResourceSearchParams getRuntimeSearchParams(String theResourceType, ContextEnum theContext) {
|
||||
ResourceSearchParams availableSearchParams =
|
||||
getActiveSearchParams(theResourceType, theContext).makeCopy();
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.HashMap;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static ca.uhn.fhir.rest.server.util.ISearchParamRegistry.isAllowedForContext;
|
||||
|
@ -35,6 +36,7 @@ import static ca.uhn.fhir.rest.server.util.ISearchParamRegistry.isAllowedForCont
|
|||
public class ResourceSearchParams {
|
||||
private final String myResourceName;
|
||||
private final Map<String, RuntimeSearchParam> myMap;
|
||||
private final Map<ISearchParamRegistry.ContextEnum, ResourceSearchParams> myContextToParams = new HashMap<>();
|
||||
|
||||
public ResourceSearchParams(String theResourceName) {
|
||||
myResourceName = theResourceName;
|
||||
|
@ -50,16 +52,30 @@ public class ResourceSearchParams {
|
|||
return myMap.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered view of this {@link ResourceSearchParams} instance if
|
||||
* any parameters are not valid for the given {@literal theContext}.
|
||||
*/
|
||||
public ResourceSearchParams toFilteredForContext(ISearchParamRegistry.ContextEnum theContext) {
|
||||
Map<String, RuntimeSearchParam> filteredMap = new HashMap<>(myMap.size());
|
||||
for (var nextEntry : myMap.entrySet()) {
|
||||
String key = nextEntry.getKey();
|
||||
RuntimeSearchParam nextParam = nextEntry.getValue();
|
||||
if (isAllowedForContext(nextParam, theContext)) {
|
||||
filteredMap.put(key, nextParam);
|
||||
}
|
||||
if (theContext == null) {
|
||||
return this;
|
||||
}
|
||||
synchronized (this) {
|
||||
ResourceSearchParams retVal = myContextToParams.get(theContext);
|
||||
if (retVal == null) {
|
||||
Map<String, RuntimeSearchParam> filteredMap = new HashMap<>(myMap.size());
|
||||
for (var nextEntry : myMap.entrySet()) {
|
||||
String key = nextEntry.getKey();
|
||||
RuntimeSearchParam nextParam = nextEntry.getValue();
|
||||
if (isAllowedForContext(nextParam, theContext)) {
|
||||
filteredMap.put(key, nextParam);
|
||||
}
|
||||
}
|
||||
retVal = new ResourceSearchParams(myResourceName, filteredMap);
|
||||
myContextToParams.put(theContext, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
return new ResourceSearchParams(myResourceName, filteredMap);
|
||||
}
|
||||
|
||||
public static ResourceSearchParams empty(String theResourceName) {
|
||||
|
@ -71,6 +87,7 @@ public class ResourceSearchParams {
|
|||
}
|
||||
|
||||
public void remove(String theName) {
|
||||
myContextToParams.clear();
|
||||
myMap.remove(theName);
|
||||
}
|
||||
|
||||
|
@ -83,10 +100,12 @@ public class ResourceSearchParams {
|
|||
}
|
||||
|
||||
public RuntimeSearchParam put(String theName, RuntimeSearchParam theSearchParam) {
|
||||
myContextToParams.clear();
|
||||
return myMap.put(theName, theSearchParam);
|
||||
}
|
||||
|
||||
public void addSearchParamIfAbsent(String theParamName, RuntimeSearchParam theRuntimeSearchParam) {
|
||||
myContextToParams.clear();
|
||||
myMap.putIfAbsent(theParamName, theRuntimeSearchParam);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue