From 5e478bc00048e76ed28bff4a4f9ea3fd7296cdcf Mon Sep 17 00:00:00 2001 From: Benedikt Waldvogel Date: Wed, 31 May 2023 10:22:26 +0200 Subject: [PATCH] Fix return type of $split aggregation #214 This is relevant if the values are processed in other expressions. --- .../mongo/backend/aggregation/Expression.java | 3 ++- .../mongo/wire/bson/BsonEncoder.java | 6 ++--- .../backend/aggregation/ExpressionTest.java | 4 ++-- .../backend/AbstractAggregationTest.java | 22 +++++++++++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/de/bwaldvogel/mongo/backend/aggregation/Expression.java b/core/src/main/java/de/bwaldvogel/mongo/backend/aggregation/Expression.java index 46e24ea2..47a116ed 100644 --- a/core/src/main/java/de/bwaldvogel/mongo/backend/aggregation/Expression.java +++ b/core/src/main/java/de/bwaldvogel/mongo/backend/aggregation/Expression.java @@ -1379,7 +1379,8 @@ Object apply(List expressionValue, Document document) { name() + " requires an expression that evaluates to a string as a second argument, found: " + describeType(delimiter)); } - return ((String) string).split(Pattern.quote((String) delimiter)); + String[] values = ((String) string).split(Pattern.quote((String) delimiter), -1); + return List.of(values); } }, diff --git a/core/src/main/java/de/bwaldvogel/mongo/wire/bson/BsonEncoder.java b/core/src/main/java/de/bwaldvogel/mongo/wire/bson/BsonEncoder.java index c3107cde..2f4dea3a 100644 --- a/core/src/main/java/de/bwaldvogel/mongo/wire/bson/BsonEncoder.java +++ b/core/src/main/java/de/bwaldvogel/mongo/wire/bson/BsonEncoder.java @@ -184,7 +184,7 @@ public static byte determineType(Object value) { return BsonConstants.TYPE_BOOLEAN; } else if (value instanceof BinData || value instanceof UUID || value instanceof LegacyUUID) { return BsonConstants.TYPE_DATA; - } else if (value instanceof Collection || value instanceof String[]) { + } else if (value instanceof Collection) { return BsonConstants.TYPE_ARRAY; } else if (value instanceof Instant) { return BsonConstants.TYPE_UTC_DATETIME; @@ -206,9 +206,7 @@ public static byte determineType(Object value) { } private static List collectionToList(Object value) { - if (value instanceof String[]) { - return List.of((String[]) value); - } else if (value instanceof List) { + if (value instanceof List) { return (List) value; } else { return new ArrayList<>((Collection) value); diff --git a/core/src/test/java/de/bwaldvogel/mongo/backend/aggregation/ExpressionTest.java b/core/src/test/java/de/bwaldvogel/mongo/backend/aggregation/ExpressionTest.java index 87085f10..0a9b5415 100644 --- a/core/src/test/java/de/bwaldvogel/mongo/backend/aggregation/ExpressionTest.java +++ b/core/src/test/java/de/bwaldvogel/mongo/backend/aggregation/ExpressionTest.java @@ -1087,8 +1087,8 @@ void testEvaluateSlice() throws Exception { @Test void testEvaluateSplit() throws Exception { - assertThat((String[]) Expression.evaluate(json("$split: ['June-15-2013', '-']"), json(""))).containsExactly("June", "15", "2013"); - assertThat((String[]) Expression.evaluate(json("$split: ['$a', '$b']"), json("a: 'foo bar', b: ' '"))).containsExactly("foo", "bar"); + assertThat((List) Expression.evaluate(json("$split: ['June-15-2013', '-']"), json(""))).containsExactly("June", "15", "2013"); + assertThat((List) Expression.evaluate(json("$split: ['$a', '$b']"), json("a: 'foo bar', b: ' '"))).containsExactly("foo", "bar"); assertThat(Expression.evaluate(json("$split: [null, ' ']"), json(""))).isNull(); assertThat(Expression.evaluate(json("$split: ['$doesNotExist', ' ']"), json(""))).isNull(); diff --git a/test-common/src/main/java/de/bwaldvogel/mongo/backend/AbstractAggregationTest.java b/test-common/src/main/java/de/bwaldvogel/mongo/backend/AbstractAggregationTest.java index 6150a820..cb252614 100644 --- a/test-common/src/main/java/de/bwaldvogel/mongo/backend/AbstractAggregationTest.java +++ b/test-common/src/main/java/de/bwaldvogel/mongo/backend/AbstractAggregationTest.java @@ -1177,6 +1177,28 @@ void testAggregateWithSplit() throws Exception { ); } + // https://github.com/bwaldvogel/mongo-java-server/issues/214 + @Test + void testAggregateWithSplitAndArrayElementAt() throws Exception { + List pipeline = jsonList("$addFields: { pathSegments: { $split: ['$path', '/'] }}", + "$project: { pathSegments: 1, firstSegment: { $arrayElemAt: ['$pathSegments', 0] }}"); + + assertThat(collection.aggregate(pipeline)).isEmpty(); + + collection.insertOne(json("_id: 1, path: 'path/to/file'")); + collection.insertOne(json("_id: 2, path: '/path/to/file'")); + collection.insertOne(json("_id: 3, path: '/path/to/file/'")); + collection.insertOne(json("_id: 4")); + + assertThat(collection.aggregate(pipeline)) + .containsExactly( + json("_id: 1, pathSegments: ['path', 'to', 'file'], firstSegment: 'path'"), + json("_id: 2, pathSegments: ['', 'path', 'to', 'file'], firstSegment: ''"), + json("_id: 3, pathSegments: ['', 'path', 'to', 'file', ''], firstSegment: ''"), + json("_id: 4, pathSegments: null, firstSegment: null") + ); + } + @Test void testAggregateWithUnwind() throws Exception { testAggregateWithUnwind(json("$unwind: '$sizes'"));