-
Notifications
You must be signed in to change notification settings - Fork 7
Filtering pagination support impl #286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3ebee57
6c21044
b10aa57
f1dc350
ddcdf31
6a3bdaa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package org.hypertrace.config.service.store; | ||
|
|
||
| import com.google.protobuf.Value; | ||
| import io.grpc.Status; | ||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
| import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; | ||
|
|
||
| public class ConstantExpressionConverter { | ||
|
|
||
| public static ConstantExpression fromProtoValue(Value value) { | ||
| switch (value.getKindCase()) { | ||
| case STRING_VALUE: | ||
| return ConstantExpression.of(value.getStringValue()); | ||
| case NUMBER_VALUE: | ||
| return ConstantExpression.of(value.getNumberValue()); | ||
| case BOOL_VALUE: | ||
| return ConstantExpression.of(value.getBoolValue()); | ||
| case LIST_VALUE: | ||
| List<Value> values = value.getListValue().getValuesList(); | ||
| if (values.isEmpty()) { | ||
| // Default to empty string list — or change logic based on expected behavior | ||
| return ConstantExpression.ofStrings(List.of()); | ||
| } | ||
|
|
||
| Value.KindCase elementType = values.get(0).getKindCase(); | ||
| boolean isHomogeneous = values.stream().allMatch(v -> v.getKindCase() == elementType); | ||
|
|
||
| if (!isHomogeneous) { | ||
| throw Status.INVALID_ARGUMENT | ||
| .withDescription("List contains mixed types. All elements must be of the same type.") | ||
| .asRuntimeException(); | ||
| } | ||
| switch (elementType) { | ||
| case STRING_VALUE: | ||
| return ConstantExpression.ofStrings( | ||
| values.stream().map(Value::getStringValue).collect(Collectors.toList())); | ||
| case NUMBER_VALUE: | ||
| return ConstantExpression.ofNumbers( | ||
| values.stream().map(Value::getNumberValue).collect(Collectors.toList())); | ||
| case BOOL_VALUE: | ||
| return ConstantExpression.ofBooleans( | ||
| values.stream().map(Value::getBoolValue).collect(Collectors.toList())); | ||
| default: | ||
| throw Status.UNIMPLEMENTED | ||
| .withDescription("Unsupported list element type: " + elementType) | ||
| .asRuntimeException(); | ||
| } | ||
| case STRUCT_VALUE: | ||
| throw Status.UNIMPLEMENTED | ||
| .withDescription("Struct not supported directly in ConstantExpression") | ||
| .asRuntimeException(); | ||
| case NULL_VALUE: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't compare to null?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not able to find support Null values in ConstantExpression. Thats why marked as unsupported for now.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, we should add that at some point. For now, the main use case is probably |
||
| case KIND_NOT_SET: | ||
| default: | ||
| throw Status.INVALID_ARGUMENT | ||
| .withDescription("Unsupported or null value in ConstantExpression") | ||
| .asRuntimeException(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| package org.hypertrace.config.service.store; | ||
|
|
||
| import static org.hypertrace.config.service.store.ConfigDocument.CONFIG_FIELD_NAME; | ||
|
|
||
| import io.grpc.Status; | ||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
| import org.hypertrace.config.service.v1.Filter; | ||
| import org.hypertrace.config.service.v1.LogicalFilter; | ||
| import org.hypertrace.config.service.v1.RelationalFilter; | ||
| import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; | ||
| import org.hypertrace.core.documentstore.expression.impl.LogicalExpression; | ||
| import org.hypertrace.core.documentstore.expression.impl.RelationalExpression; | ||
| import org.hypertrace.core.documentstore.expression.operators.LogicalOperator; | ||
| import org.hypertrace.core.documentstore.expression.operators.RelationalOperator; | ||
| import org.hypertrace.core.documentstore.expression.type.FilterTypeExpression; | ||
|
|
||
| public class FilterExpressionBuilder { | ||
|
|
||
| public FilterTypeExpression buildFilterTypeExpression(Filter filter) { | ||
| switch (filter.getTypeCase()) { | ||
| case LOGICAL_FILTER: | ||
| return buildLogicalExpression(filter.getLogicalFilter()); | ||
| case RELATIONAL_FILTER: | ||
| return buildRelationalExpression(filter.getRelationalFilter()); | ||
| case TYPE_NOT_SET: | ||
| default: | ||
| throw Status.INVALID_ARGUMENT.withDescription("Filter type unset").asRuntimeException(); | ||
| } | ||
| } | ||
|
|
||
| private FilterTypeExpression buildLogicalExpression(LogicalFilter logicalFilter) { | ||
| List<FilterTypeExpression> childExpressions = | ||
| logicalFilter.getOperandsList().stream() | ||
| .map(this::buildFilterTypeExpression) | ||
| .collect(Collectors.toUnmodifiableList()); | ||
|
|
||
| LogicalOperator operator; | ||
| switch (logicalFilter.getOperator()) { | ||
| case LOGICAL_OPERATOR_AND: | ||
| operator = LogicalOperator.AND; | ||
| break; | ||
| case LOGICAL_OPERATOR_OR: | ||
| operator = LogicalOperator.OR; | ||
| break; | ||
| case LOGICAL_OPERATOR_UNSPECIFIED: | ||
| default: | ||
| throw Status.INVALID_ARGUMENT | ||
| .withDescription("Unknown logical operator while building expression") | ||
| .asRuntimeException(); | ||
| } | ||
| return LogicalExpression.builder().operator(operator).operands(childExpressions).build(); | ||
| } | ||
|
|
||
| private FilterTypeExpression buildRelationalExpression(RelationalFilter relationalFilter) { | ||
| RelationalOperator operator; | ||
| switch (relationalFilter.getOperator()) { | ||
| case RELATIONAL_OPERATOR_EQ: | ||
| operator = RelationalOperator.EQ; | ||
| break; | ||
| case RELATIONAL_OPERATOR_NEQ: | ||
| operator = RelationalOperator.NEQ; | ||
| break; | ||
| case RELATIONAL_OPERATOR_IN: | ||
| operator = RelationalOperator.IN; | ||
| break; | ||
| case RELATIONAL_OPERATOR_NOT_IN: | ||
| operator = RelationalOperator.NOT_IN; | ||
| break; | ||
| case RELATIONAL_OPERATOR_LT: | ||
| operator = RelationalOperator.LT; | ||
| break; | ||
| case RELATIONAL_OPERATOR_GT: | ||
| operator = RelationalOperator.GT; | ||
| break; | ||
| case RELATIONAL_OPERATOR_LTE: | ||
| operator = RelationalOperator.LTE; | ||
| break; | ||
| case RELATIONAL_OPERATOR_GTE: | ||
| operator = RelationalOperator.GTE; | ||
| break; | ||
| case UNRECOGNIZED: | ||
| default: | ||
| throw Status.INVALID_ARGUMENT | ||
| .withDescription("Unknown relational operator while building expression") | ||
| .asRuntimeException(); | ||
| } | ||
|
|
||
| return RelationalExpression.of( | ||
| IdentifierExpression.of(buildConfigFieldPath(relationalFilter.getConfigJsonPath())), | ||
| operator, | ||
| ConstantExpressionConverter.fromProtoValue(relationalFilter.getValue())); | ||
| } | ||
|
|
||
| private String buildConfigFieldPath(String configJsonPath) { | ||
| return String.format("%s.%s", CONFIG_FIELD_NAME, configJsonPath); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed total_count for now, will add it later if required