Skip to content

DATAMONGO-3695 - Add support for $replaceOne & $replaceAll aggregation operators #3861

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

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4491301
Polishing.
mp911de Aug 26, 2021
2d8d66d
taking latest from main.
divyajnu08 Aug 29, 2021
037cac0
resolving merge conflict
divyajnu08 Aug 29, 2021
1010f81
Merge branch 'spring-projects-main'
divyajnu08 Aug 29, 2021
4cd6cf9
Merge branch 'spring-projects:main' into main
divyajnu08 Sep 10, 2021
3430298
Merge branch 'spring-projects:main' into main
divyajnu08 Sep 10, 2021
703b2eb
Merge branch 'spring-projects:main' into main
divyajnu08 Sep 14, 2021
825eff7
Merge branch 'spring-projects:main' into main
divyajnu08 Sep 14, 2021
853e10a
Merge branch 'spring-projects:main' into main
divyajnu08 Sep 18, 2021
e3c4202
Merge branch 'spring-projects:main' into main
divyajnu08 Sep 21, 2021
53fcdb7
Merge branch 'spring-projects:main' into main
divyajnu08 Sep 27, 2021
eb997b5
Merge branch 'spring-projects:main' into main
divyajnu08 Oct 5, 2021
0917e68
DATAMONGO-2637 - Fields and projection API are very inconvenient
divyajnu08 Sep 27, 2021
e830626
Revert "DATAMONGO-2637 - Fields and projection API are very inconveni…
divyajnu08 Sep 28, 2021
e3bdf33
DATAMONGO-2637 - Fields and projection API are very inconvenient
divyajnu08 Sep 27, 2021
857e065
Revert "DATAMONGO-2637 - Fields and projection API are very inconveni…
divyajnu08 Sep 28, 2021
e003f04
Merge branch 'spring-projects:main' into main
divyajnu08 Oct 9, 2021
a499d85
Merge branch 'main' of https://github.com/divyajnu08/spring-data-mongodb
divyajnu08 Oct 9, 2021
07d66af
Merge branch 'spring-projects:main' into main
divyajnu08 Oct 16, 2021
84f521e
Merge branch 'main' of https://github.com/divyajnu08/spring-data-mongodb
divyajnu08 Oct 16, 2021
e114956
DATAMONGO - 3695 - Add support for $replaceOne & $replaceAll aggregat…
divyajnu08 Oct 17, 2021
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 @@ -686,10 +686,28 @@ public RegexMatch regexMatch(String regex, String options) {
private RegexMatch createRegexMatch() {
return usesFieldRef() ? RegexMatch.valueOf(fieldReference) : RegexMatch.valueOf(expression);
}

public ReplaceOne replaceOne(String find,String replacement) {
return createReplaceOne().find(find).replacement(replacement);
}

private ReplaceOne createReplaceOne() {
return usesFieldRef() ? ReplaceOne.valueOf(fieldReference) : ReplaceOne.valueOf(expression);
}

public ReplaceAll replaceAll(String find,String replacement) {
return createReplaceAll().find(find).replacement(replacement);
}

private ReplaceAll createReplaceAll() {
return usesFieldRef() ? ReplaceAll.valueOf(fieldReference) : ReplaceAll.valueOf(expression);
}

private boolean usesFieldRef() {
return fieldReference != null;
}


}

/**
Expand Down Expand Up @@ -2078,4 +2096,260 @@ protected String getMongoMethod() {
return "$regexMatch";
}
}

/**
* {@link AggregationExpression} for {@code $replaceOne} which replaces the first instance of a search string in an
* input string with a replacement string. <br />
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
*/
public static class ReplaceOne extends AbstractAggregationExpression {

protected ReplaceOne(Object value) {
super(value);
}

/**
* Creates new {@link ReplaceOne} using the value of the provided {@link Field fieldReference} as {@literal input}
* value.
*
* @param fieldReference must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public static ReplaceOne valueOf(String fieldReference) {

Assert.notNull(fieldReference, "FieldReference must not be null!");

return new ReplaceOne(Collections.singletonMap("input", Fields.field(fieldReference)));
}

/**
* Creates new {@link ReplaceOne} using the result of the provided {@link AggregationExpression} as {@literal input}
* value.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public static ReplaceOne valueOf(AggregationExpression expression) {

Assert.notNull(expression, "Expression must not be null!");

return new ReplaceOne(Collections.singletonMap("input", expression));
}

/**
* The string to use to replace the first matched instance of {@code find} in input.
*
* @param replacement must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public ReplaceOne replacement(String replacement) {

Assert.notNull(replacement, "Replacement must not be null!");

return new ReplaceOne(append("replacement", replacement));
}

/**
* Specifies the reference to the {@link Field field} holding the string to use to replace the first matched
* instance of {@code find} in input.
*
* @param fieldReference must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public ReplaceOne replacementOf(String fieldReference) {

Assert.notNull(fieldReference, "FieldReference must not be null!");

return new ReplaceOne(append("replacement", Fields.field(fieldReference)));
}

/**
* Specifies the {@link AggregationExpression} evaluating to the string to use to replace the first matched instance
* of {@code find} in {@code input}.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public ReplaceOne replacementOf(AggregationExpression expression) {

Assert.notNull(expression, "Expression must not be null!");

return new ReplaceOne(append("replacement", expression));
}

/**
* The string to search for within the given input field.
*
* @param find must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public ReplaceOne find(String searchStr) {

Assert.notNull(searchStr, "Search string must not be null!");

Map<String, Object> search = append("find", searchStr);

return new ReplaceOne(search);
}

/**
* Specify the reference to the {@link Field field} holding the string to search for within the given input field.
*
* @param find must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public ReplaceOne findOf(String fieldReference) {

Assert.notNull(fieldReference, "fieldReference must not be null!");

return new ReplaceOne(append("find", fieldReference));
}

/**
* Specify the {@link AggregationExpression} evaluating to the the string to search for within the given input
* field.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link ReplaceOne}.
*/
public ReplaceOne findOf(AggregationExpression expression) {

Assert.notNull(expression, "Expression must not be null!");

return new ReplaceOne(append("find", expression));
}

@Override
protected String getMongoMethod() {
return "$replaceOne";
}
}

/**
* {@link AggregationExpression} for {@code $replaceAll} which replaces all instances of a search string in an input
* string with a replacement string. <br />
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
*/
public static class ReplaceAll extends AbstractAggregationExpression {

protected ReplaceAll(Object value) {
super(value);
}

/**
* Creates new {@link ReplaceAll} using the value of the provided {@link Field fieldReference} as {@literal input}
* value.
*
* @param fieldReference must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public static ReplaceAll valueOf(String fieldReference) {

Assert.notNull(fieldReference, "FieldReference must not be null!");

return new ReplaceAll(Collections.singletonMap("input", Fields.field(fieldReference)));
}

/**
* Creates new {@link ReplaceAll} using the result of the provided {@link AggregationExpression} as {@literal input}
* value.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public static ReplaceAll valueOf(AggregationExpression expression) {

Assert.notNull(expression, "Expression must not be null!");

return new ReplaceAll(Collections.singletonMap("input", expression));
}

/**
* The string to use to replace the first matched instance of {@code find} in input.
*
* @param replacement must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public ReplaceAll replacement(String replacement) {

Assert.notNull(replacement, "Replacement must not be null!");

return new ReplaceAll(append("replacement", replacement));
}

/**
* Specifies the reference to the {@link Field field} holding the string to use to replace the first matched
* instance of {@code find} in input.
*
* @param fieldReference must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public ReplaceAll replacementOf(String fieldReference) {

Assert.notNull(fieldReference, "FieldReference must not be null!");

return new ReplaceAll(append("replacement", Fields.field(fieldReference)));
}

/**
* Specifies the {@link AggregationExpression} evaluating to the string to use to replace the first matched instance
* of {@code find} in input.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public ReplaceAll replacementOf(AggregationExpression expression) {

Assert.notNull(expression, "Expression must not be null!");

return new ReplaceAll(append("replacement", expression));
}

/**
* The string to search for within the given input field.
*
* @param find must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public ReplaceAll find(String searchStr) {

Assert.notNull(searchStr, "Search string must not be null!");

Map<String, Object> search = append("find", searchStr);

return new ReplaceAll(search);
}

/**
* Specify the reference to the {@link Field field} holding the string to search for within the given input field.
*
* @param find must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public ReplaceAll findOf(String fieldReference) {

Assert.notNull(fieldReference, "fieldReference must not be null!");

return new ReplaceAll(append("find", fieldReference));
}

/**
* Specify the {@link AggregationExpression} evaluating to the string to search for within the given input field.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link ReplaceAll}.
*/
public ReplaceAll findOf(AggregationExpression expression) {

Assert.notNull(expression, "Expression must not be null!");

return new ReplaceAll(append("find", expression));
}

@Override
protected String getMongoMethod() {
return "$replaceAll";
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("regexFind", mapArgRef().forOperator("$regexFind").mappingParametersTo("input", "regex" , "options"));
map.put("regexFindAll", mapArgRef().forOperator("$regexFindAll").mappingParametersTo("input", "regex" , "options"));
map.put("regexMatch", mapArgRef().forOperator("$regexMatch").mappingParametersTo("input", "regex" , "options"));
map.put("replaceOne", mapArgRef().forOperator("$replaceOne").mappingParametersTo("input", "find" , "replacement"));
map.put("replaceAll", mapArgRef().forOperator("$replaceAll").mappingParametersTo("input", "find" , "replacement"));

// TEXT SEARCH OPERATORS
map.put("meta", singleArgRef().forOperator("$meta"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,20 @@ void shouldRenderRegexMatchWithOptionsFromFieldReference() {
assertThat(transform("regexMatch(field1,'e',field2)"))
.isEqualTo("{ \"$regexMatch\" : {\"input\" : \"$field1\" , \"regex\" : \"e\" , \"options\" : \"$field2\"}}");
}

@Test
void shouldRenderReplaceOne() {

assertThat(transform("replaceOne(field,'bar','baz')"))
.isEqualTo("{ \"$replaceOne\" : {\"input\" : \"$field\" , \"find\" : \"bar\" , \"replacement\" : \"baz\"}}");
}

@Test
void shouldRenderReplaceAll() {

assertThat(transform("replaceAll(field,'bar','baz')"))
.isEqualTo("{ \"$replaceAll\" : {\"input\" : \"$field\" , \"find\" : \"bar\" , \"replacement\" : \"baz\"}}");
}


@Test // DATAMONGO-2077
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,35 @@ void shouldRenderRegexFindWithOptionsExpression() {
.isEqualTo("{ $regexFind: { \"input\" : \"$shrewd\", \"regex\" : \"e\" , \"options\" : " + EXPRESSION_STRING
+ " } } ");
}

@Test
void shouldRenderReplaceOne() {

assertThat(StringOperators.valueOf("bar").replaceOne("foobar","baz").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $replaceOne : {\"find\" : \"foobar\", \"input\" : \"$bar\", \"replacement\" : \"baz\"}}");
}

@Test
void shouldRenderReplaceOneForExpression() {

assertThat(StringOperators.valueOf(EXPRESSION).replaceOne("a","s").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $replaceOne : {\"find\" : \"a\", \"input\" : " + EXPRESSION_STRING + ", \"replacement\" : \"s\"}}");
}

@Test
void shouldRenderReplaceAll() {

assertThat(StringOperators.valueOf("bar").replaceAll("foobar","baz").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $replaceAll : {\"find\" : \"foobar\", \"input\" : \"$bar\", \"replacement\" : \"baz\"}}");
}

@Test
void shouldRenderReplaceAllForExpression() {

assertThat(StringOperators.valueOf(EXPRESSION).replaceAll("a","s").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $replaceAll : {\"find\" : \"a\", \"input\" : " + EXPRESSION_STRING + ", \"replacement\" : \"s\"}}");
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<bean id="mongoClient" class="org.springframework.data.mongodb.core.ReactiveMongoClientFactoryBean">
<property name="host" value="127.0.0.1"/>
<property name="port" value="27017"/>
<property name="port" value="27018"/>
</bean>

<bean id="reactiveMongoDbFactory" class="org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory">
Expand Down