Skip to content

Commit

Permalink
Move input-representations for query operators into QueryOperation enum
Browse files Browse the repository at this point in the history
- Provide consistent methods to get a QueryOperation by an input- / output-representation
- Provide a static method to return all existing input representations

Signed-off-by: Benjamin Rögner <[email protected]>
  • Loading branch information
roegi committed Sep 27, 2024
1 parent 76cd7e4 commit e66453a
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ private Future<List<Space>> getSpacesWithFullAccess(SpaceSelectionCondition sele
if (propsQuery != null) {
valueMap.put(":typeValue", "SPACE");
valueMap.put(":contentUpdatedAtValue", propsQuery.get(0).get(0).getValues().get(0));
String operator = QueryOperation.getOperation(propsQuery.get(0).get(0).getOperation());
String operator = QueryOperation.getOutputRepresentation(propsQuery.get(0).get(0).getOperation());

spaces.getIndex("type-contentUpdatedAt-index")
.query(new QuerySpec()
Expand Down Expand Up @@ -580,7 +580,7 @@ private Future<Void> filterByContentUpdatedAt(PropertiesQuery propsQuery, Set<St
Map<String, Object> valueMap = new HashMap<>();
valueMap.put(":typeValue", "SPACE");
valueMap.put(":contentUpdatedAtValue", propsQuery.get(0).get(0).getValues().get(0));
String operator = QueryOperation.getOperation(propsQuery.get(0).get(0).getOperation());
String operator = QueryOperation.getOutputRepresentation(propsQuery.get(0).get(0).getOperation());
var contentUpdatedAtSpaceIds = new HashSet<String>();
spaces.getIndex("type-contentUpdatedAt-index").query(new QuerySpec()
.withKeyConditionExpression("#type = :typeValue and contentUpdatedAt " + operator + " :contentUpdatedAtValue")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ protected Future<List<Space>> getSelectedSpaces(Marker marker, SpaceAuthorizatio
List<String> contentUpdatedAtConjunctions = new ArrayList<>();
conjunctions.forEach(conj -> {
conj.getValues().forEach(v -> {
contentUpdatedAtConjunctions.add("(cast(config->>'contentUpdatedAt' AS TEXT) "+ QueryOperation.getOperation(conj.getOperation()) + "'" +v + "' )");
contentUpdatedAtConjunctions.add("(cast(config->>'contentUpdatedAt' AS TEXT) "+ QueryOperation.getOutputRepresentation(conj.getOperation()) + "'" +v + "' )");
});
});
whereConjunctions.add(String.join(" OR ", contentUpdatedAtConjunctions));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ protected Future<List<Space>> getSelectedSpaces(Marker marker, SpaceAuthorizatio
propsQuery.forEach(conjunctions -> {
conjunctions.forEach(conj -> {
conj.getValues().forEach(v -> {
String operator = QueryOperation.getOperation(conj.getOperation());
String operator = QueryOperation.getOutputRepresentation(conj.getOperation());
contentUpdatedAtList.add(operator);
contentUpdatedAtList.add(v.toString());
});
Expand Down
58 changes: 20 additions & 38 deletions xyz-hub-service/src/main/java/com/here/xyz/hub/rest/ApiParam.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,24 +195,6 @@ public static class Query {

static final String DRY_RUN = "dryRun";

private static Map<String, QueryOperation> operators = new HashMap<String, QueryOperation>() {{
put("!=", QueryOperation.NOT_EQUALS);
put(">=", QueryOperation.GREATER_THAN_OR_EQUALS);
put("=gte=", QueryOperation.GREATER_THAN_OR_EQUALS);
put("<=", QueryOperation.LESS_THAN_OR_EQUALS);
put("=lte=", QueryOperation.LESS_THAN_OR_EQUALS);
put(">", QueryOperation.GREATER_THAN);
put("=gt=", QueryOperation.GREATER_THAN);
put("<", QueryOperation.LESS_THAN);
put("=lt=", QueryOperation.LESS_THAN);
put("=", QueryOperation.EQUALS);
put("@>", QueryOperation.CONTAINS);
put("=cs=", QueryOperation.CONTAINS);
}};

private static List<String> shortOperators = new ArrayList<>(operators.keySet());


/**
* Get access to the custom parsed query parameters. Used as a temporary replacement for context.queryParam until
* https://github.com/vert-x3/issues/issues/380 is resolved.
Expand Down Expand Up @@ -376,8 +358,8 @@ static PropertiesQuery getPropertiesQuery(RoutingContext context) {
}

/**
* Returns the first property found in the query string in the format of key-operator-value(s)
* @param query the query part in the url without the '?' symbol
* Returns the first property found in the query string in the format of: `<key> <operator> <value(s)>`
* @param query the query part in the url without the '?' or '&' symbol
* @param key the property to be searched
* @param multiValue when true, checks for comma separated values, otherwise return the first value found
* @return null in case none is found
Expand All @@ -393,12 +375,12 @@ static PropertyQuery getPropertyQuery(String query, String key, boolean multiVal
return null;
}

int startIndex;
if ((startIndex=query.indexOf(key)) != -1) {
int startIndex = query.indexOf(key);
if (startIndex != -1) {
String opValue = query.substring(startIndex + key.length()); // e.g. =eq=head
String operation = shortOperators
String operation = QueryOperation.inputRepresentations()
.stream()
.sorted(Comparator.comparingInt(k->k.length() * -1)) // reverse a sorted list because u want to get the longer ops first.
.sorted(Comparator.comparingInt(k -> k.length() * -1)) // reverse a sorted list because u want to get the longer ops first.
.filter(opValue::startsWith) // e.g. in case of key=eq=val, 2 ops will be filtered in: '=eq=' and '='.
.findFirst() // The reversed sort plus the findFirst makes sure the =eq= is the one you are looking for.
.orElse(null); // e.g. anything different from the allowed operators
Expand All @@ -413,7 +395,7 @@ static PropertyQuery getPropertyQuery(String query, String key, boolean multiVal

return new PropertyQuery()
.withKey(key)
.withOperation(operators.get(operation))
.withOperation(QueryOperation.fromInputRepresentation(operation))
.withValues(values);
}

Expand Down Expand Up @@ -442,8 +424,8 @@ public static PropertiesQuery parsePropertiesQuery(String query, String property
int position=0;
String op=null;

/** store "main" operator. Needed for such cases foo=bar-->test*/
for (String shortOperator : shortOperators) {
//store "main" operator. Needed for such cases foo=bar-->test
for (String shortOperator : QueryOperation.inputRepresentations()) {
int currentPositionOfOp = keyValuePair.indexOf(shortOperator);
if (currentPositionOfOp != -1) {
if(
Expand All @@ -458,23 +440,23 @@ public static PropertiesQuery parsePropertiesQuery(String query, String property
}
}

if(op != null){
String[] keyVal = new String[]{keyValuePair.substring(0, position).replaceAll(operatorComma,","),
keyValuePair.substring(position + op.length())
};
/** Cut from API-Gateway appended "=" */
if ((">".equals(op) || "<".equals(op)) && keyVal[1].endsWith("=")) {
if (op != null) {
String[] keyVal = new String[] {
keyValuePair.substring(0, position).replaceAll(operatorComma,","),
keyValuePair.substring(position + op.length())
};
//Cut from API-Gateway appended "="
if ((">".equals(op) || "<".equals(op)) && keyVal[1].endsWith("="))
keyVal[1] = keyVal[1].substring(0, keyVal[1].length() - 1);
}

propertyQuery.setKey(spaceProperties ? keyVal[0] : getConvertedKey(keyVal[0]));
propertyQuery.setOperation(operators.get(op));
String[] rawValues = keyVal[1].split( operatorComma );
propertyQuery.setOperation(QueryOperation.fromInputRepresentation(op));
String[] rawValues = keyVal[1].split(operatorComma);

ArrayList<Object> values = new ArrayList<>();
for (String rawValue : rawValues) {
for (String rawValue : rawValues)
values.add(getConvertedValue(rawValue));
}

propertyQuery.setValues(values);
pql.add(propertyQuery);
}
Expand Down
62 changes: 35 additions & 27 deletions xyz-models/src/main/java/com/here/xyz/events/PropertyQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeName;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeName(value = "PropertyQuery")
Expand Down Expand Up @@ -80,36 +83,41 @@ public PropertyQuery withValues(List<Object> values) {
}

public enum QueryOperation {
EQUALS,
NOT_EQUALS,
LESS_THAN,
GREATER_THAN,
LESS_THAN_OR_EQUALS,
GREATER_THAN_OR_EQUALS,
CONTAINS;

public static String getOperation(QueryOperation op) {
EQUALS("=", "="),
NOT_EQUALS("!=", "<>"),
LESS_THAN(Set.of("<", "=lt="), "<"),
GREATER_THAN(Set.of(">", "=gt="), ">"),
LESS_THAN_OR_EQUALS(Set.of("<=", "=lte="), "<="),
GREATER_THAN_OR_EQUALS(Set.of(">=", "=gte="), ">="),
CONTAINS(Set.of("@>", "=cs="), "@>");

public final Set<String> inputRepresentations;
public final String outputRepresentation;

QueryOperation (Set<String> inputRepresentations, String outputRepresentation) {
this.inputRepresentations = inputRepresentations;
this.outputRepresentation = outputRepresentation;
}

QueryOperation (String inputRepresentation, String outputRepresentation) {
this(Set.of(inputRepresentation), outputRepresentation);
}

public static String getOutputRepresentation(QueryOperation op) {
if (op == null)
throw new NullPointerException("op is required");
return op.outputRepresentation;
}

public static QueryOperation fromInputRepresentation(String inputRepresentation) {
for (QueryOperation op : values())
if (op.inputRepresentations.contains(inputRepresentation))
return op;
return null;
}

switch (op) {
case EQUALS:
return "=";
case NOT_EQUALS:
return "<>";
case LESS_THAN:
return "<";
case GREATER_THAN:
return ">";
case LESS_THAN_OR_EQUALS:
return "<=";
case GREATER_THAN_OR_EQUALS:
return ">=";
case CONTAINS:
return "@>";
}

return "";
public static Set<String> inputRepresentations() {
return Arrays.stream(values()).flatMap(operator -> operator.inputRepresentations.stream()).collect(Collectors.toSet());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ protected static SQLQuery generatePropertiesQuery(SearchForFeaturesEvent event)
else {
predicateQuery = new SQLQuery("${{keyPath}} ${{operation}} ${{value}}")
.withQueryFragment("keyPath", keyPath)
.withQueryFragment("operation", QueryOperation.getOperation(op))
.withQueryFragment("operation", QueryOperation.getOutputRepresentation(op))
.withQueryFragment("value", value == null ? "" : value);
namedParams.put(paramName, v);
}
Expand Down

0 comments on commit e66453a

Please sign in to comment.