Skip to content

Commit

Permalink
regex filter merge
Browse files Browse the repository at this point in the history
  • Loading branch information
evanchooly committed Jan 9, 2025
1 parent 33b1ca0 commit 35374b4
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package dev.morphia.rewrite.recipes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import dev.morphia.aggregation.Aggregation;
import dev.morphia.aggregation.stages.Match;
import dev.morphia.aggregation.stages.Stage;
import dev.morphia.query.filters.Filter;

import org.jetbrains.annotations.NotNull;
Expand All @@ -29,8 +26,6 @@
public class PipelineRewrite extends Recipe {
static final String AGGREGATION = "dev.morphia.aggregation.Aggregation";

public static final MethodMatcher PIPELINE = new MethodMatcher(AGGREGATION + " pipeline(..)");

static final List<MethodMatcher> matchers = List.of(
new MethodMatcher(AGGREGATION + " addFields(dev.morphia.aggregation.stages.AddFields)"),
new MethodMatcher(AGGREGATION + " autoBucket(dev.morphia.aggregation.stages.AutoBucket)"),
Expand Down Expand Up @@ -74,14 +69,6 @@ public boolean matches(@Nullable MethodCall methodCall) {
}
};

private static final JavaTemplate PIPELINE_TEMPLATE = (JavaTemplate.builder("Aggregation.pipeline(#{any(List<Stage>)})"))
.javaParser(JavaParser.fromJavaVersion()
.classpath("morphia-core"))
.imports(Aggregation.class.getName())
.imports(Stage.class.getName())
.doBeforeParseTemplate(System.out::println)
.build();

private static final JavaTemplate MATCH = (JavaTemplate.builder("Match.match()"))
.javaParser(JavaParser.fromJavaVersion()
.classpath("morphia-core"))
Expand All @@ -90,21 +77,22 @@ public boolean matches(@Nullable MethodCall methodCall) {
.build();

@Override
public String getDisplayName() {
public @NotNull String getDisplayName() {
return "Aggregation pipeline rewrite";
}

@Override
public String getDescription() {
public @NotNull String getDescription() {
return "Rewrites an aggregation from using stage-named methods to using pipeline(Stage...).";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
public @NotNull TreeVisitor<?, ExecutionContext> getVisitor() {

return new JavaIsoVisitor<>() {
@Override
public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodInvocation, @NotNull ExecutionContext context) {
public @NotNull MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodInvocation,
@NotNull ExecutionContext context) {
if (MEGA_MATCHER.matches(methodInvocation)) {
var updated = methodInvocation;
while (MEGA_MATCHER.matches(updated) && MEGA_MATCHER.matches(updated.getSelect())) {
Expand All @@ -127,7 +115,6 @@ public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodIn

updated = invocation.withArguments(list);
}
// return updated.withName(methodInvocation.getName().withSimpleName("pipeline"));
return maybeAutoFormat(methodInvocation, updated.withName(methodInvocation.getName().withSimpleName("pipeline"))
.withPrefix(Space.build("\n", emptyList())), context);
} else {
Expand All @@ -146,40 +133,4 @@ public static String getIndent(Space after) {
return whitespace + " ";
}

public TreeVisitor<?, ExecutionContext> getVisitor2() {

return new JavaIsoVisitor<>() {
@Override
public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodInvocation, @NotNull ExecutionContext context) {
if (MEGA_MATCHER.matches(methodInvocation)) {
var updated = methodInvocation;
final List<Expression> args = new ArrayList<>();
while (MEGA_MATCHER.matches(updated) && MEGA_MATCHER.matches(updated.getSelect())) {
MethodInvocation invocation = (MethodInvocation) updated.getSelect();
if (invocation.getSimpleName().equals("match")) {

MethodInvocation applied = MATCH.apply(new Cursor(getCursor(), invocation),
invocation.getCoordinates().replaceMethod(),
invocation.getArguments().toArray());
args.add(applied.withSelect(null));
} else {
args.addAll(invocation.getArguments());
}
updated = invocation;
}
args.addAll(updated.getArguments());

Collections.reverse(args);
return updated.withName(methodInvocation.getName().withSimpleName("pipeline"))
.withArguments(args);
// MethodInvocation applied = PIPELINE_TEMPLATE.apply(new Cursor(getCursor(), updated),
// updated.getCoordinates().replaceMethod(), args.toArray() );
// return autoFormat(applied, context);
} else {
return super.visitMethodInvocation(methodInvocation, context);
}
}

};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package dev.morphia.rewrite.recipes;

import java.util.ArrayList;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.NlsRewrite.Description;
import org.openrewrite.NlsRewrite.DisplayName;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J.MethodInvocation;

public class RegexPatternMerge extends Recipe {
private static final MethodMatcher MATCHER = new MethodMatcher("dev.morphia.query.filters.RegexFilter *(..)");

@NotNull
@Override
public @DisplayName String getDisplayName() {
return "Merge regex filter expression and pattern calls";
}

@NotNull
@Override
public @Description String getDescription() {
return "This merges the fluent-style API calls in to a single method call.";
}

@NotNull
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<>() {
@NotNull
@Override
public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation invocation,
@NotNull ExecutionContext executionContext) {
if (MATCHER.matches(invocation)) {
MethodInvocation pattern = findPattern(invocation);
if (pattern != null) {
var arguments = pattern.getArguments();
Expression select = invocation;
var methods = new ArrayList<MethodInvocation>();
while (select instanceof MethodInvocation parentInvocation) {
if (parentInvocation.getSimpleName().equals("regex")) {
arguments.addAll(0, parentInvocation.getArguments());
methods.add(0, parentInvocation);
} else if (!parentInvocation.getSimpleName().equals("pattern")) {
methods.add(0, parentInvocation);
}
select = parentInvocation.getSelect();
}
if (methods.size() == 1) {
return maybeAutoFormat(invocation, methods.get(0).withArguments(arguments), executionContext);
}
MethodInvocation newMethod = methods.get(0)
.withArguments(arguments);
for (MethodInvocation method : methods.subList(1, methods.size())) {
newMethod = method.withSelect(newMethod);
}
return maybeAutoFormat(invocation, newMethod, executionContext);
}
}

return super.visitMethodInvocation(invocation, executionContext);
}
};
}

@Nullable
private MethodInvocation findPattern(Expression expression) {
if (expression == null) {
return null;
}
if (expression instanceof MethodInvocation invocation) {
if (invocation.getSimpleName().equals("pattern")) {
return invocation;
} else {
return findPattern(invocation.getSelect());
}
}
return null;
}
}
3 changes: 3 additions & 0 deletions rewrite/src/main/resources/META-INF/rewrite/rewrite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ recipeList:
- dev.morphia.rewrite.recipes.PipelineRewrite
- dev.morphia.rewrite.recipes.CreateDatastoreMigration
- dev.morphia.rewrite.recipes.MorphiaConfigMigration
- dev.morphia.rewrite.recipes.RegexPatternMerge
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: dev.morphia.mapping.MapperOptions
newFullyQualifiedTypeName: dev.morphia.config.MorphiaConfig
Expand Down Expand Up @@ -41,3 +42,5 @@ recipeList:
filePattern: src/test/java/dev/morphia/test/BuildConfigTest.java
- org.openrewrite.DeleteSourceFiles:
filePattern: src/test/java/dev/morphia/test/models/Keys.java
- org.openrewrite.DeleteSourceFiles:
filePattern: src/test/java/dev/morphia/test/MorphiaVersionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package dev.morphia.rewrite.recipes.test;

import dev.morphia.rewrite.recipes.RegexPatternMerge;

import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import org.openrewrite.Recipe;

import static org.openrewrite.java.Assertions.java;

class RegexPatternMergeTest extends MorphiaRewriteTest {

@NotNull
@Override
protected Recipe getRecipe() {
return new RegexPatternMerge();
}

@Test
public void testPatternFirstCall() {
rewriteRun(java(
//language=java
"""
import dev.morphia.Datastore;
import static dev.morphia.query.filters.Filters.regex;
import static java.util.regex.Pattern.quote;
public class Regexes {
public void find(Datastore ds) {
ds.find(Object.class)
.filter(regex("name")
.pattern(quote("'> FISH BONES") + "$")
.multiline()
.options("options")
);
}
}
""",
//language=java
"""
import dev.morphia.Datastore;
import static dev.morphia.query.filters.Filters.regex;
import static java.util.regex.Pattern.quote;
public class Regexes {
public void find(Datastore ds) {
ds.find(Object.class)
.filter(regex("name", quote("'> FISH BONES") + "$")
.multiline()
.options("options")
);
}
}
"""));
}

@Test
public void testPatternMerge() {
rewriteRun(java(
//language=java
"""
import dev.morphia.Datastore;
import static dev.morphia.query.filters.Filters.regex;
import static java.util.regex.Pattern.quote;
public class Regexes {
public void find(Datastore ds) {
ds.find(Object.class)
.filter(regex("name")
.multiline()
.pattern(quote("'> FISH BONES") + "$")
.options("options")
);
}
}
""",
//language=java
"""
import dev.morphia.Datastore;
import static dev.morphia.query.filters.Filters.regex;
import static java.util.regex.Pattern.quote;
public class Regexes {
public void find(Datastore ds) {
ds.find(Object.class)
.filter(regex("name", quote("'> FISH BONES") + "$")
.multiline()
.options("options")
);
}
}
"""));
}

@Test
public void testOnlyPatternCalled() {
rewriteRun(java(
//language=java
"""
import dev.morphia.Datastore;
import static dev.morphia.query.filters.Filters.regex;
import static java.util.regex.Pattern.quote;
public class Regexes {
public void find(Datastore ds) {
ds.find(Object.class)
.filter(regex("name")
.pattern(quote("'> FISH BONES") + "$")
);
}
}
""",
//language=java
"""
import dev.morphia.Datastore;
import static dev.morphia.query.filters.Filters.regex;
import static java.util.regex.Pattern.quote;
public class Regexes {
public void find(Datastore ds) {
ds.find(Object.class)
.filter(regex("name", quote("'> FISH BONES") + "$")
);
}
}
"""));
}

}

0 comments on commit 35374b4

Please sign in to comment.