diff --git a/config-service-api/src/main/proto/org/hypertrace/config/service/v1/config_service.proto b/config-service-api/src/main/proto/org/hypertrace/config/service/v1/config_service.proto index 27d94559..d569d037 100644 --- a/config-service-api/src/main/proto/org/hypertrace/config/service/v1/config_service.proto +++ b/config-service-api/src/main/proto/org/hypertrace/config/service/v1/config_service.proto @@ -212,6 +212,8 @@ enum RelationalOperator { RELATIONAL_OPERATOR_LT = 6; RELATIONAL_OPERATOR_GTE = 7; RELATIONAL_OPERATOR_LTE = 8; + RELATIONAL_OPERATOR_EXISTS = 9; + RELATIONAL_OPERATOR_NOT_EXISTS = 10; } enum LogicalOperator { diff --git a/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterBuilder.java b/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterBuilder.java index 760377d5..378debf0 100644 --- a/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterBuilder.java +++ b/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterBuilder.java @@ -92,6 +92,14 @@ private Filter evaluateLeafExpression(RelationalFilter relationalFilter) { case RELATIONAL_OPERATOR_GTE: return new Filter( Filter.Op.GTE, buildConfigFieldPath(relationalFilter.getConfigJsonPath()), value); + case RELATIONAL_OPERATOR_EXISTS: + return new Filter( + Filter.Op.EXISTS, buildConfigFieldPath(relationalFilter.getConfigJsonPath()), value); + case RELATIONAL_OPERATOR_NOT_EXISTS: + return new Filter( + Filter.Op.NOT_EXISTS, + buildConfigFieldPath(relationalFilter.getConfigJsonPath()), + value); case UNRECOGNIZED: default: throw Status.INVALID_ARGUMENT diff --git a/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterExpressionBuilder.java b/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterExpressionBuilder.java index eb5c400b..724b3d29 100644 --- a/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterExpressionBuilder.java +++ b/config-service-impl/src/main/java/org/hypertrace/config/service/store/FilterExpressionBuilder.java @@ -78,6 +78,12 @@ private FilterTypeExpression buildRelationalExpression(RelationalFilter relation case RELATIONAL_OPERATOR_GTE: operator = RelationalOperator.GTE; break; + case RELATIONAL_OPERATOR_EXISTS: + operator = RelationalOperator.EXISTS; + break; + case RELATIONAL_OPERATOR_NOT_EXISTS: + operator = RelationalOperator.NOT_EXISTS; + break; case UNRECOGNIZED: default: throw Status.INVALID_ARGUMENT diff --git a/config-service-impl/src/test/java/org/hypertrace/config/service/store/FilterBuilderTest.java b/config-service-impl/src/test/java/org/hypertrace/config/service/store/FilterBuilderTest.java index 62bbfcad..b9112b87 100644 --- a/config-service-impl/src/test/java/org/hypertrace/config/service/store/FilterBuilderTest.java +++ b/config-service-impl/src/test/java/org/hypertrace/config/service/store/FilterBuilderTest.java @@ -83,6 +83,41 @@ void buildDocStoreFilter2() { assertEquals(docFilter.toString(), filterBuilder.buildDocStoreFilter(filter).toString()); } + @Test + void testExistsAndNotExistsOperators() { + // Test EXISTS operator + Filter existsFilter = + Filter.newBuilder() + .setRelationalFilter( + RelationalFilter.newBuilder() + .setConfigJsonPath("testField") + .setOperator(RelationalOperator.RELATIONAL_OPERATOR_EXISTS)) + .build(); + + org.hypertrace.core.documentstore.Filter expectedExistsFilter = + new org.hypertrace.core.documentstore.Filter( + org.hypertrace.core.documentstore.Filter.Op.EXISTS, "config.testField", null); + assertEquals( + expectedExistsFilter.toString(), + filterBuilder.buildDocStoreFilter(existsFilter).toString()); + + // Test NOT_EXISTS operator + Filter notExistsFilter = + Filter.newBuilder() + .setRelationalFilter( + RelationalFilter.newBuilder() + .setConfigJsonPath("anotherField") + .setOperator(RelationalOperator.RELATIONAL_OPERATOR_NOT_EXISTS)) + .build(); + + org.hypertrace.core.documentstore.Filter expectedNotExistsFilter = + new org.hypertrace.core.documentstore.Filter( + org.hypertrace.core.documentstore.Filter.Op.NOT_EXISTS, "config.anotherField", null); + assertEquals( + expectedNotExistsFilter.toString(), + filterBuilder.buildDocStoreFilter(notExistsFilter).toString()); + } + @Test void buildDocStoreFilter3() { Filter filter =