From c4f97ccaa388bf2c291683b1da4193e5fb33d17d Mon Sep 17 00:00:00 2001 From: evanchooly Date: Sun, 5 Jan 2025 18:16:10 -0500 Subject: [PATCH] fix pipeline formatting add some internal recipes for upgrade testing --- .../rewrite/recipes/PipelineRewrite.java | 117 ++++++------ .../resources/META-INF/rewrite/rewrite.yml | 22 +++ .../recipes/test/PipelineRewriteTest.java | 178 ++++++++++++------ 3 files changed, 198 insertions(+), 119 deletions(-) diff --git a/rewrite/src/main/java/dev/morphia/rewrite/recipes/PipelineRewrite.java b/rewrite/src/main/java/dev/morphia/rewrite/recipes/PipelineRewrite.java index fff5b34bba1..6290f8d11d5 100644 --- a/rewrite/src/main/java/dev/morphia/rewrite/recipes/PipelineRewrite.java +++ b/rewrite/src/main/java/dev/morphia/rewrite/recipes/PipelineRewrite.java @@ -32,62 +32,62 @@ public class PipelineRewrite extends Recipe { public static final MethodMatcher PIPELINE = new MethodMatcher(AGGREGATION + " pipeline(..)"); static final List matchers = List.of( - new MethodMatcher(AGGREGATION + " addFields(dev.morphia.aggregation.stages.AddFields)"), - new MethodMatcher(AGGREGATION + " autoBucket(dev.morphia.aggregation.stages.AutoBucket)"), - new MethodMatcher(AGGREGATION + " bucket(dev.morphia.aggregation.stages.Bucket)"), - new MethodMatcher(AGGREGATION + " changeStream()"), - new MethodMatcher(AGGREGATION + " changeStream(dev.morphia.aggregation.stages.ChangeStream)"), - new MethodMatcher(AGGREGATION + " collStats(dev.morphia.aggregation.stages.CollectionStats)"), - new MethodMatcher(AGGREGATION + " count(dev.morphia.aggregation.stages.Count)"), - new MethodMatcher(AGGREGATION + " currentOp(dev.morphia.aggregation.stages.CountOp)"), - new MethodMatcher(AGGREGATION + " densify(dev.morphia.aggregation.stages.Densify)"), - new MethodMatcher(AGGREGATION + " documents(dev.morphia.aggregation.expressions.impls.DocumentExpression)"), - new MethodMatcher(AGGREGATION + " facet(dev.morphia.aggregation.stages.Facet)"), - new MethodMatcher(AGGREGATION + " fill(dev.morphia.aggregation.stages.Fill)"), - new MethodMatcher(AGGREGATION + " geoNear(dev.morphia.aggregation.stages.GeoNear)"), - new MethodMatcher(AGGREGATION + " graphLookup(dev.morphia.aggregation.stages.GraphLookup)"), - new MethodMatcher(AGGREGATION + " group(dev.morphia.aggregation.stages.Group)"), - new MethodMatcher(AGGREGATION + " indexStats(dev.morphia.aggregation.stages.IndexStats)"), - new MethodMatcher(AGGREGATION + " limit(long)"), - new MethodMatcher(AGGREGATION + " lookup(dev.morphia.aggregation.stages.Lookup)"), - new MethodMatcher(AGGREGATION + " match(dev.morphia.query.filters.Filter...)"), - new MethodMatcher(AGGREGATION + " planCacheStats()"), - new MethodMatcher(AGGREGATION + " project(dev.morphia.aggregation.stages.Projection)"), - new MethodMatcher(AGGREGATION + " redact(dev.morphia.aggregation.stages.Redact)"), - new MethodMatcher(AGGREGATION + " replaceRoot(dev.morphia.aggregation.stages.ReplaceRoot)"), - new MethodMatcher(AGGREGATION + " replaceWith(dev.morphia.aggregation.stages.ReplaceWith)"), - new MethodMatcher(AGGREGATION + " sample(dev.morphia.aggregation.stages.Sample)"), - new MethodMatcher(AGGREGATION + " set(dev.morphia.aggregation.stages.Set)"), - new MethodMatcher(AGGREGATION + " skip(long)"), - new MethodMatcher(AGGREGATION + " sort(dev.morphia.aggregation.stages.Sort)"), - new MethodMatcher(AGGREGATION + " sortByCount(dev.morphia.aggregation.stages.SortByCount)"), - new MethodMatcher(AGGREGATION + " unionWith(Class,Stage...)"), - new MethodMatcher(AGGREGATION + " unionWith(String,Stage...)"), - new MethodMatcher(AGGREGATION + " unset(dev.morphia.aggregation.stages.Unset)"), - new MethodMatcher(AGGREGATION + " unwind(dev.morphia.aggregation.stages.Unwind)")); + new MethodMatcher(AGGREGATION + " addFields(dev.morphia.aggregation.stages.AddFields)"), + new MethodMatcher(AGGREGATION + " autoBucket(dev.morphia.aggregation.stages.AutoBucket)"), + new MethodMatcher(AGGREGATION + " bucket(dev.morphia.aggregation.stages.Bucket)"), + new MethodMatcher(AGGREGATION + " changeStream()"), + new MethodMatcher(AGGREGATION + " changeStream(dev.morphia.aggregation.stages.ChangeStream)"), + new MethodMatcher(AGGREGATION + " collStats(dev.morphia.aggregation.stages.CollectionStats)"), + new MethodMatcher(AGGREGATION + " count(dev.morphia.aggregation.stages.Count)"), + new MethodMatcher(AGGREGATION + " currentOp(dev.morphia.aggregation.stages.CountOp)"), + new MethodMatcher(AGGREGATION + " densify(dev.morphia.aggregation.stages.Densify)"), + new MethodMatcher(AGGREGATION + " documents(dev.morphia.aggregation.expressions.impls.DocumentExpression)"), + new MethodMatcher(AGGREGATION + " facet(dev.morphia.aggregation.stages.Facet)"), + new MethodMatcher(AGGREGATION + " fill(dev.morphia.aggregation.stages.Fill)"), + new MethodMatcher(AGGREGATION + " geoNear(dev.morphia.aggregation.stages.GeoNear)"), + new MethodMatcher(AGGREGATION + " graphLookup(dev.morphia.aggregation.stages.GraphLookup)"), + new MethodMatcher(AGGREGATION + " group(dev.morphia.aggregation.stages.Group)"), + new MethodMatcher(AGGREGATION + " indexStats(dev.morphia.aggregation.stages.IndexStats)"), + new MethodMatcher(AGGREGATION + " limit(long)"), + new MethodMatcher(AGGREGATION + " lookup(dev.morphia.aggregation.stages.Lookup)"), + new MethodMatcher(AGGREGATION + " match(dev.morphia.query.filters.Filter...)"), + new MethodMatcher(AGGREGATION + " planCacheStats()"), + new MethodMatcher(AGGREGATION + " project(dev.morphia.aggregation.stages.Projection)"), + new MethodMatcher(AGGREGATION + " redact(dev.morphia.aggregation.stages.Redact)"), + new MethodMatcher(AGGREGATION + " replaceRoot(dev.morphia.aggregation.stages.ReplaceRoot)"), + new MethodMatcher(AGGREGATION + " replaceWith(dev.morphia.aggregation.stages.ReplaceWith)"), + new MethodMatcher(AGGREGATION + " sample(dev.morphia.aggregation.stages.Sample)"), + new MethodMatcher(AGGREGATION + " set(dev.morphia.aggregation.stages.Set)"), + new MethodMatcher(AGGREGATION + " skip(long)"), + new MethodMatcher(AGGREGATION + " sort(dev.morphia.aggregation.stages.Sort)"), + new MethodMatcher(AGGREGATION + " sortByCount(dev.morphia.aggregation.stages.SortByCount)"), + new MethodMatcher(AGGREGATION + " unionWith(Class,Stage...)"), + new MethodMatcher(AGGREGATION + " unionWith(String,Stage...)"), + new MethodMatcher(AGGREGATION + " unset(dev.morphia.aggregation.stages.Unset)"), + new MethodMatcher(AGGREGATION + " unwind(dev.morphia.aggregation.stages.Unwind)")); private static final MethodMatcher MEGA_MATCHER = new MethodMatcher( - AGGREGATION + " addFields(dev.morphia.aggregation.stages.AddFields)") { + AGGREGATION + " addFields(dev.morphia.aggregation.stages.AddFields)") { @Override public boolean matches(@Nullable MethodCall methodCall) { - return matchers.stream().anyMatch(matcher -> matcher.matches(methodCall)) || PIPELINE.matches(methodCall); + return matchers.stream().anyMatch(matcher -> matcher.matches(methodCall)); } }; private static final JavaTemplate PIPELINE_TEMPLATE = (JavaTemplate.builder("Aggregation.pipeline(#{any(List)})")) - .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(#{any()})")) - .javaParser(JavaParser.fromJavaVersion() - .classpath("morphia-core")) - .imports(Filter.class.getName()) - .imports(Match.class.getName()) - .build(); + .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")) + .imports(Filter.class.getName()) + .imports(Match.class.getName()) + .build(); @Override public String getDisplayName() { @@ -99,7 +99,6 @@ public String getDescription() { return "Rewrites an aggregation from using stage-named methods to using pipeline(Stage...)."; } - @Override public TreeVisitor getVisitor() { @@ -112,11 +111,10 @@ public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodIn final List args = new ArrayList<>(); MethodInvocation invocation = (MethodInvocation) updated.getSelect(); if (invocation.getSimpleName().equals("match")) { - + maybeAddImport(Match.class.getName(), "match", false); MethodInvocation applied = MATCH.apply(new Cursor(getCursor(), invocation), - invocation.getCoordinates().replaceMethod(), - invocation.getArguments().toArray()); - args.add(applied.withSelect(null)); + invocation.getCoordinates().replaceMethod()); + args.add(applied.withArguments(invocation.getArguments()).withSelect(null)); } else { args.addAll(invocation.getArguments()); } @@ -124,13 +122,14 @@ public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodIn Space after = methodInvocation.getPadding().getSelect().getAfter(); Space space = Space.build(getIndent(after), emptyList()); var list = args.stream() - .map(a -> (Expression) a.withPrefix(space)) - .toList(); + .map(a -> (Expression) a.withPrefix(space)) + .toList(); updated = invocation.withArguments(list); } // return updated.withName(methodInvocation.getName().withSimpleName("pipeline")); - return updated.withName(methodInvocation.getName().withSimpleName("pipeline")); + return maybeAutoFormat(methodInvocation, updated.withName(methodInvocation.getName().withSimpleName("pipeline")) + .withPrefix(Space.build("\n", emptyList())), context); } else { return super.visitMethodInvocation(methodInvocation, context); } @@ -160,8 +159,8 @@ public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodIn if (invocation.getSimpleName().equals("match")) { MethodInvocation applied = MATCH.apply(new Cursor(getCursor(), invocation), - invocation.getCoordinates().replaceMethod(), - invocation.getArguments().toArray()); + invocation.getCoordinates().replaceMethod(), + invocation.getArguments().toArray()); args.add(applied.withSelect(null)); } else { args.addAll(invocation.getArguments()); @@ -172,7 +171,7 @@ public MethodInvocation visitMethodInvocation(@NotNull MethodInvocation methodIn Collections.reverse(args); return updated.withName(methodInvocation.getName().withSimpleName("pipeline")) - .withArguments(args); + .withArguments(args); // MethodInvocation applied = PIPELINE_TEMPLATE.apply(new Cursor(getCursor(), updated), // updated.getCoordinates().replaceMethod(), args.toArray() ); // return autoFormat(applied, context); diff --git a/rewrite/src/main/resources/META-INF/rewrite/rewrite.yml b/rewrite/src/main/resources/META-INF/rewrite/rewrite.yml index 00c58ac5fb0..9139f5a7c75 100644 --- a/rewrite/src/main/resources/META-INF/rewrite/rewrite.yml +++ b/rewrite/src/main/resources/META-INF/rewrite/rewrite.yml @@ -15,7 +15,29 @@ recipeList: - org.openrewrite.java.ChangeType: oldFullyQualifiedTypeName: dev.morphia.DatastoreImpl newFullyQualifiedTypeName: dev.morphia.MorphiaDatastore + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: dev.morphia.utils.IndexDirection + newFullyQualifiedTypeName: dev.morphia.mapping.IndexDirection + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: dev.morphia.utils.IndexType + newFullyQualifiedTypeName: dev.morphia.mapping.IndexType + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: dev.morphia.mapping.MapperOptions.PropertyDiscovery + newFullyQualifiedTypeName: dev.morphia.mapping.PropertyDiscovery - org.openrewrite.maven.UpgradeDependencyVersion: groupId: dev.morphia.morphia artifactId: morphia-core newVersion: 3.0.0-SNAPSHOT +--- +type: specs.openrewrite.org/v1beta/recipe +name: dev.morphia.InternalOnly +displayName: Recipe definitions specifically for testing in morphia-upgrade-testing. not for external use. +recipeList: + - org.openrewrite.DeleteSourceFiles: + filePattern: src/test/java/dev/morphia/test/TestLegacyUpdate.java + - org.openrewrite.DeleteSourceFiles: + filePattern: src/test/java/dev/morphia/test/query/legacy/TestLegacyQuery.java + - org.openrewrite.DeleteSourceFiles: + filePattern: src/test/java/dev/morphia/test/BuildConfigTest.java + - org.openrewrite.DeleteSourceFiles: + filePattern: src/test/java/dev/morphia/test/models/Keys.java diff --git a/rewrite/src/test/java/dev/morphia/rewrite/recipes/test/PipelineRewriteTest.java b/rewrite/src/test/java/dev/morphia/rewrite/recipes/test/PipelineRewriteTest.java index a7d4652a562..e945153514a 100644 --- a/rewrite/src/test/java/dev/morphia/rewrite/recipes/test/PipelineRewriteTest.java +++ b/rewrite/src/test/java/dev/morphia/rewrite/recipes/test/PipelineRewriteTest.java @@ -19,64 +19,122 @@ protected Recipe getRecipe() { @Test void unwrapStageMethods() { rewriteRun(java( - //language=java - """ - import dev.morphia.aggregation.expressions.ComparisonExpressions; - - import static dev.morphia.aggregation.expressions.AccumulatorExpressions.sum; - import static dev.morphia.aggregation.stages.Group.group; - import static dev.morphia.aggregation.stages.Group.id; - import static dev.morphia.aggregation.stages.Projection.project; - import static dev.morphia.aggregation.expressions.Expressions.field; - import static dev.morphia.aggregation.expressions.Expressions.value; - import static dev.morphia.aggregation.stages.Sort.sort; - import static dev.morphia.query.filters.Filters.eq; - - import dev.morphia.aggregation.Aggregation; - import dev.morphia.query.MorphiaCursor; - import org.bson.Document; - - public class UnwrapTest { - public MorphiaCursor update(Aggregation aggregation) { - return aggregation - .match(eq("author", "Sanderson")) - .group(group(id("author")).field("count", sum(value(1)))) - .sort(sort().ascending("1")) - .sort(sort().ascending("2")) - .sort(sort().ascending("3")) - .sort(sort().ascending("4")) - .execute(Document.class); - } - }""", - //language=java - """ - import dev.morphia.aggregation.expressions.ComparisonExpressions; - - import static dev.morphia.aggregation.expressions.AccumulatorExpressions.sum; - import static dev.morphia.aggregation.stages.Group.group; - import static dev.morphia.aggregation.stages.Group.id; - import static dev.morphia.aggregation.stages.Projection.project; - import static dev.morphia.aggregation.expressions.Expressions.field; - import static dev.morphia.aggregation.expressions.Expressions.value; - import static dev.morphia.aggregation.stages.Sort.sort; - import static dev.morphia.query.filters.Filters.eq; - - import dev.morphia.aggregation.Aggregation; - import dev.morphia.query.MorphiaCursor; - import org.bson.Document; - - public class UnwrapTest { - public MorphiaCursor update(Aggregation aggregation) { - return aggregation - .pipeline( - match(eq("author", "Sanderson")), - group(id("author")).field("count", sum(value(1))), - sort().ascending("1"), - sort().ascending("2"), - sort().ascending("3"), - sort().ascending("4")) - .execute(Document.class); - } - }""")); - } + //language=java + """ + import dev.morphia.aggregation.expressions.ComparisonExpressions; + + import static dev.morphia.aggregation.expressions.AccumulatorExpressions.sum; + import static dev.morphia.aggregation.stages.Group.group; + import static dev.morphia.aggregation.stages.Group.id; + import static dev.morphia.aggregation.stages.Projection.project; + import static dev.morphia.aggregation.expressions.Expressions.field; + import static dev.morphia.aggregation.expressions.Expressions.value; + import static dev.morphia.aggregation.stages.Sort.sort; + import static dev.morphia.query.filters.Filters.eq; + + import dev.morphia.aggregation.Aggregation; + import dev.morphia.query.MorphiaCursor; + import org.bson.Document; + + public class UnwrapTest { + public MorphiaCursor update(Aggregation aggregation) { + return aggregation + .match(eq("author", "Sanderson")) + .group(group(id("author")).field("count", sum(value(1)))) + .sort(sort().ascending("1")) + .sort(sort().ascending("2")) + .sort(sort().ascending("3")) + .sort(sort().ascending("4")) + .execute(Document.class); + } + }""", + //language=java + """ + import dev.morphia.aggregation.expressions.ComparisonExpressions; + + import static dev.morphia.aggregation.expressions.AccumulatorExpressions.sum; + import static dev.morphia.aggregation.stages.Group.group; + import static dev.morphia.aggregation.stages.Group.id; + import static dev.morphia.aggregation.stages.Match.match; + import static dev.morphia.aggregation.stages.Projection.project; + import static dev.morphia.aggregation.expressions.Expressions.field; + import static dev.morphia.aggregation.expressions.Expressions.value; + import static dev.morphia.aggregation.stages.Sort.sort; + import static dev.morphia.query.filters.Filters.eq; + + import dev.morphia.aggregation.Aggregation; + import dev.morphia.query.MorphiaCursor; + import org.bson.Document; + + public class UnwrapTest { + public MorphiaCursor update(Aggregation aggregation) { + return# + aggregation + .pipeline( + match(eq("author", "Sanderson")), + group(id("author")).field("count", sum(value(1))), + sort().ascending("1"), + sort().ascending("2"), + sort().ascending("3"), + sort().ascending("4")) + .execute(Document.class); + } + }""".replace('#', ' '))); + } + + @Test + public void testWhitespace() { + rewriteRun(java( + //language=java + """ + import dev.morphia.aggregation.Aggregation; + + import static dev.morphia.aggregation.expressions.AccumulatorExpressions.top; + import static dev.morphia.aggregation.expressions.ArrayExpressions.array; + import static dev.morphia.aggregation.expressions.Expressions.field; + import static dev.morphia.aggregation.stages.Group.group; + import static dev.morphia.aggregation.stages.Group.id; + import static dev.morphia.query.Sort.descending; + import static dev.morphia.query.filters.Filters.eq; + + public class UnwrapTest { + Aggregation aggregation; + public Aggregation testWhitespace() { + return aggregation + .match(eq("gameId", "G1")) + .group(group(id(field("gameId"))) + .field("playerId", top( + array(field("playerId"), field("score")), + descending("score")))); + } + } + """, + //language=java + """ + import dev.morphia.aggregation.Aggregation; + + import static dev.morphia.aggregation.expressions.AccumulatorExpressions.top; + import static dev.morphia.aggregation.expressions.ArrayExpressions.array; + import static dev.morphia.aggregation.expressions.Expressions.field; + import static dev.morphia.aggregation.stages.Group.group; + import static dev.morphia.aggregation.stages.Group.id; + import static dev.morphia.aggregation.stages.Match.match; + import static dev.morphia.query.Sort.descending; + import static dev.morphia.query.filters.Filters.eq; + + public class UnwrapTest { + Aggregation aggregation; + public Aggregation testWhitespace() { + return + aggregation + .pipeline( + match(eq("gameId", "G1")), + group(id(field("gameId"))) + .field("playerId", top( + array(field("playerId"), field("score")), + descending("score")))); + } + }""")); + } + }