Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,58 @@ void getSolarSystemsWithNoneOfThePlanetsHavingBothWaterAndOxygenTogether(
JSONAssert.assertEquals(expected, actual, JSONCompareMode.LENIENT);
}

/**
* Tests returning documents where environment IDs are a subset of the provided allowed
* environment IDs.
*/
@ParameterizedTest
@ArgumentsSource(MongoProvider.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything we build in document-store needs to be compatible with Postgres too to avoid digressing them too much. Could you please sync. with the respective team to get this working on Postgres too? I believe that should be a smaller fix too.

void getDocumentsWithEnvironmentIdsSubsetOfGivenList(final String dataStoreName)
throws JSONException, IOException {
// Create a temporary collection for this test
final String testCollectionName = "environment_scope_test";
final Datastore datastore = datastoreMap.get(dataStoreName);

// Setup test data
final Map<Key, Document> testDocuments =
Utils.buildDocumentsFromResource("query/array_operators/environment_scope_test.json");
datastore.deleteCollection(testCollectionName);
datastore.createCollection(testCollectionName, null);
final Collection collection = datastore.getCollection(testCollectionName);
collection.bulkUpsert(testDocuments);

final java.util.List<String> environmentIds = java.util.List.of("env-1", "env-2", "env-3");

final Query query =
Query.builder()
.setFilter(
and(
RelationalExpression.of(
IdentifierExpression.of("scope.environmentScope.environmentIds"),
RelationalOperator.EXISTS,
ConstantExpression.of(true)),
not(
ArrayRelationalFilterExpression.builder()
.operator(ANY)
.filter(
RelationalExpression.of(
IdentifierExpression.of(
"scope.environmentScope.environmentIds"),
RelationalOperator.NOT_IN,
ConstantExpression.ofStrings(environmentIds)))
.build())))
.build();

final Iterator<Document> documents = collection.aggregate(query);
final String expected = readResource("environment_ids_subset.json");
final String actual = iteratorToJson(documents);

// Cleanup
datastore.deleteCollection(testCollectionName);

JSONAssert.assertEquals(expected, actual, JSONCompareMode.LENIENT);
}

private String readResource(final String fileName) {
try {
return new String(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"scope": {
"environmentScope": {
"environmentIds": ["env-1", "env-2"]
}
},
"name": "Document A"
},
{
"scope": {
"environmentScope": {
"environmentIds": ["env-1", "env-2", "env-3"]
}
},
"name": "Document B"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[
{
"_id": 1,
"name": "Document A",
"scope": {
"environmentScope": {
"environmentIds": ["env-1", "env-2"]
}
}
},
{
"_id": 2,
"name": "Document B",
"scope": {
"environmentScope": {
"environmentIds": ["env-1", "env-2", "env-3"]
}
}
},
{
"_id": 3,
"name": "Document C",
"scope": {
"environmentScope": {
"environmentIds": ["env-1", "env-4"]
}
}
},
{
"_id": 4,
"name": "Document D",
"scope": {
"environmentScope": {
"environmentIds": ["env-5", "env-6"]
}
}
},
{
"_id": 5,
"name": "Document E"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.hypertrace.core.documentstore.mongo.query.parser.filter;

import java.util.Map;
import lombok.AllArgsConstructor;
import org.hypertrace.core.documentstore.expression.impl.RelationalExpression;
import org.hypertrace.core.documentstore.mongo.query.parser.filter.MongoRelationalFilterParserFactory.MongoRelationalFilterContext;

/**
* Note: MongoDB does not have a native "NOT IN" aggregation operator. This parser simulates "NOT
* IN" functionality by combining the $not and $in operators.
*/
@AllArgsConstructor
public class MongoNotInExprRelationalFilterParser implements MongoRelationalFilterParser {
private static final String NOT_OP = "$not";
private static final String IN_OP = "$in";
private static final MongoStandardRelationalOperatorMapping mapping =
new MongoStandardRelationalOperatorMapping();

@Override
public Map<String, Object> parse(
final RelationalExpression expression, final MongoRelationalFilterContext context) {
final String parsedLhs = expression.getLhs().accept(context.lhsParser());
final Object parsedRhs = expression.getRhs().accept(context.rhsParser());
return Map.of(NOT_OP, Map.of(IN_OP, new Object[] {parsedLhs, parsedRhs}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,22 @@ public MongoRelationalFilterParser parser(
}

case IN:
if (INSIDE_EXPR.equals(context.location())) {
return new MongoStandardExprRelationalFilterParser();
} else if (OUTSIDE_EXPR.equals(context.location())) {
return new MongoStandardNonExprRelationalFilterParser();
} else {
throw new UnsupportedOperationException("Unsupported location: " + context.location());
}

case NOT_IN:
return new MongoStandardNonExprRelationalFilterParser();
if (INSIDE_EXPR.equals(context.location())) {
return new MongoNotInExprRelationalFilterParser();
} else if (OUTSIDE_EXPR.equals(context.location())) {
return new MongoStandardNonExprRelationalFilterParser();
} else {
throw new UnsupportedOperationException("Unsupported location: " + context.location());
}

case CONTAINS:
return new MongoContainsRelationalFilterParser();
Expand Down