From 8a080da4456d6dcd833c5aa6359969357387062d Mon Sep 17 00:00:00 2001 From: Julia Gustafsson Date: Tue, 23 May 2023 10:20:24 +0200 Subject: [PATCH 1/4] Work on #31 --- provider/renderer-standard/pom.xml | 4 + .../standard/internal/StandardRenderer.java | 5 + .../src/main/java9/module-info.java | 1 + provider/termopoptimizer-standard/pom.xml | 17 +++ .../StandardTerminalOperationOptimizer.java | 58 +++++++++- .../src/main/java9/module-info.java | 1 + ...TerminalOperationOptimizerFactoryTest.java | 16 +++ .../standard/internal/AnyMatchTest.java | 55 +++++++++ .../standard/internal/FindAnyTest.java | 4 + .../standard/internal/FindFirstTest.java | 4 + .../standard/internal/NoneMatchTest.java | 4 + ...tandardTerminalOperationOptimizerTest.java | 105 ++++++++++++++++++ 12 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java diff --git a/provider/renderer-standard/pom.xml b/provider/renderer-standard/pom.xml index 8626d11fb..960b463a4 100644 --- a/provider/renderer-standard/pom.xml +++ b/provider/renderer-standard/pom.xml @@ -71,6 +71,10 @@ jakarta.persistence-api ${jakarta.version} + + com.speedment.jpastreamer + termopoptimizer + diff --git a/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java b/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java index abf7a94ec..e0a0eca28 100644 --- a/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java +++ b/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java @@ -29,6 +29,7 @@ import com.speedment.jpastreamer.rootfactory.RootFactory; import com.speedment.jpastreamer.streamconfiguration.StreamConfiguration; +import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizerFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.TypedQuery; @@ -48,6 +49,7 @@ final class StandardRenderer implements Renderer { private final CriteriaFactory criteriaFactory; private final IntermediateOperationOptimizerFactory intermediateOperationOptimizerFactory; + private final TerminalOperationOptimizerFactory terminalOperationOptimizerFactory; private final MergerFactory mergerFactory; @@ -59,6 +61,7 @@ final class StandardRenderer implements Renderer { this.entityManager = requireNonNull(entityManagerSupplier).get(); this.criteriaFactory = RootFactory.getOrThrow(CriteriaFactory.class, ServiceLoader::load); this.intermediateOperationOptimizerFactory = RootFactory.getOrThrow(IntermediateOperationOptimizerFactory.class, ServiceLoader::load); + this.terminalOperationOptimizerFactory = RootFactory.getOrThrow(TerminalOperationOptimizerFactory.class, ServiceLoader::load); this.mergerFactory = RootFactory.getOrThrow(MergerFactory.class, ServiceLoader::load); } @@ -66,6 +69,7 @@ final class StandardRenderer implements Renderer { this.entityManager = entityManager; this.criteriaFactory = RootFactory.getOrThrow(CriteriaFactory.class, ServiceLoader::load); this.intermediateOperationOptimizerFactory = RootFactory.getOrThrow(IntermediateOperationOptimizerFactory.class, ServiceLoader::load); + this.terminalOperationOptimizerFactory = RootFactory.getOrThrow(TerminalOperationOptimizerFactory.class, ServiceLoader::load); this.mergerFactory = RootFactory.getOrThrow(MergerFactory.class, ServiceLoader::load); } @@ -180,6 +184,7 @@ private > S replay(final Stream stream, fina } private void optimizePipeline(final Pipeline pipeline) { + terminalOperationOptimizerFactory.get().optimize(pipeline); intermediateOperationOptimizerFactory.stream().forEach(intermediateOperationOptimizer -> intermediateOperationOptimizer.optimize(pipeline)); } diff --git a/provider/renderer-standard/src/main/java9/module-info.java b/provider/renderer-standard/src/main/java9/module-info.java index 39e8bca53..a1d8ef152 100644 --- a/provider/renderer-standard/src/main/java9/module-info.java +++ b/provider/renderer-standard/src/main/java9/module-info.java @@ -19,6 +19,7 @@ requires jpastreamer.criteria; requires jpastreamer.merger; requires jpastreamer.interopoptimizer; + requires jpastreamer.termopoptimizer; exports com.speedment.jpastreamer.renderer.standard; // Todo: Enable this diff --git a/provider/termopoptimizer-standard/pom.xml b/provider/termopoptimizer-standard/pom.xml index ee7828504..2e12c4ccb 100644 --- a/provider/termopoptimizer-standard/pom.xml +++ b/provider/termopoptimizer-standard/pom.xml @@ -39,6 +39,23 @@ com.speedment.jpastreamer termopoptimizer + + + com.speedment.jpastreamer + pipeline + + + + com.speedment.jpastreamer + rootfactory + + + + com.speedment.jpastreamer + pipeline-standard + test + + diff --git a/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java b/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java index 3fd766c4f..5f5b0bd87 100644 --- a/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java +++ b/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java @@ -15,15 +15,69 @@ import static java.util.Objects.requireNonNull; import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationType; +import com.speedment.jpastreamer.rootfactory.RootFactory; import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizer; -final class StandardTerminalOperationOptimizer implements TerminalOperationOptimizer { +import java.util.ServiceLoader; +final class StandardTerminalOperationOptimizer implements TerminalOperationOptimizer { + + final IntermediateOperationFactory iof = RootFactory + .getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); + final TerminalOperationFactory tof = + RootFactory.getOrThrow(TerminalOperationFactory.class, ServiceLoader::load); + @Override public Pipeline optimize(Pipeline pipeline) { requireNonNull(pipeline); - // For now, just return whatever we get. + + final TerminalOperationType terminalOperationType = pipeline.terminatingOperation().type(); + + switch (terminalOperationType) { + case ANY_MATCH: + return optimizeAnyMatch(pipeline); + case NONE_MATCH: + return optimizeNoneMatch(pipeline); + case FIND_FIRST: + return optimizeFindFirst(pipeline); + case FIND_ANY: + return optimizeFindAny(pipeline); + default: + return pipeline; + } + + } + + private Pipeline optimizeAnyMatch(Pipeline pipeline) { + pipeline.intermediateOperations().add(iof.createLimit(1)); + pipeline.intermediateOperations().add( + iof.createFilter(pipeline.terminatingOperation().predicate())); + pipeline.terminatingOperation(tof.createAnyMatch(p -> true)); + return pipeline; + } + + private Pipeline optimizeNoneMatch(Pipeline pipeline) { + pipeline.intermediateOperations().add(iof.createLimit(1)); + pipeline.intermediateOperations().add( + iof.createFilter(pipeline.terminatingOperation().predicate())); + // NoneMatch() - If the stream is empty then true is returned and the predicate is not evaluated. + // If the expression is evaluated => There is a match and the expression is always false. + pipeline.terminatingOperation(tof.createNoneMatch(e -> false)); + return pipeline; + } + + private Pipeline optimizeFindFirst(Pipeline pipeline) { + pipeline.intermediateOperations().add(iof.createLimit(1)); return pipeline; } + private Pipeline optimizeFindAny(Pipeline pipeline) { + pipeline.ordered(false); + pipeline.intermediateOperations().add(iof.createLimit(1)); + return pipeline; + } + } diff --git a/provider/termopoptimizer-standard/src/main/java9/module-info.java b/provider/termopoptimizer-standard/src/main/java9/module-info.java index 46961365a..dcb9426ac 100644 --- a/provider/termopoptimizer-standard/src/main/java9/module-info.java +++ b/provider/termopoptimizer-standard/src/main/java9/module-info.java @@ -12,6 +12,7 @@ */ module jpastreamer.termopoptimizer.standard { requires transitive jpastreamer.termopoptimizer; + requires jpastreamer.rootfactory; exports com.speedment.jpastreamer.termopoptimizer.standard; diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java new file mode 100644 index 000000000..85c1d5cc6 --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java @@ -0,0 +1,16 @@ +package com.speedment.jpastreamer.termopoptimizer.standard; + +import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizerFactory; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +final class StandardTerminalOperationOptimizerFactoryTest { + + @Test + void get() { + final TerminalOperationOptimizerFactory terminalOperationOptimizerFactory = new StandardTerminalOperationOptimizerFactory(); + assertNotNull(terminalOperationOptimizerFactory.get()); + } + +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java new file mode 100644 index 000000000..94e28c7e8 --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java @@ -0,0 +1,55 @@ +package com.speedment.jpastreamer.termopoptimizer.standard.internal; + +import com.speedment.jpastreamer.pipeline.Pipeline; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +final class AnyMatchTest extends StandardTerminalOperationOptimizerTest { + + @Override + Class getEntityClass() { + return String.class; + } + + @Override + protected Stream> pipelines() { + return Stream.of( + noAnyMatch(), + anyMatch() + ); + } + + private PipelineTestCase noAnyMatch() { + final Pipeline noAnyMatch = createPipeline( + tof.createAllMatch(s -> s.equals("test")), + iof.createLimit(1) + ); + + final Pipeline noAnyMatchExpected = createPipeline( + tof.createAllMatch(s -> s.equals("test")), + iof.createLimit(1) + ); + + return new PipelineTestCase<>("No Any Match", noAnyMatch, noAnyMatchExpected); + } + + private PipelineTestCase anyMatch() { + final Predicate p = s -> (s.equals("test")); + + final Pipeline anyMatch = createPipeline( + tof.createAnyMatch(p), + iof.createLimit(100) + ); + + final Pipeline anyMatchExpected = createPipeline( + tof.createAnyMatch(s -> true), + iof.createLimit(100), + iof.createLimit(1), + iof.createFilter(p) + ); + + return new PipelineTestCase<>("Any Match", anyMatch, anyMatchExpected); + } + +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java new file mode 100644 index 000000000..78412ab19 --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java @@ -0,0 +1,4 @@ +package com.speedment.jpastreamer.termopoptimizer.standard.internal; + +public class FindAnyTest { +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java new file mode 100644 index 000000000..979a74030 --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java @@ -0,0 +1,4 @@ +package com.speedment.jpastreamer.termopoptimizer.standard.internal; + +public class FindFirstTest { +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java new file mode 100644 index 000000000..6140ee182 --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java @@ -0,0 +1,4 @@ +package com.speedment.jpastreamer.termopoptimizer.standard.internal; + +public class NoneMatchTest { +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java new file mode 100644 index 000000000..e8fc5ab0c --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java @@ -0,0 +1,105 @@ +package com.speedment.jpastreamer.termopoptimizer.standard.internal; + +import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.pipeline.PipelineFactory; +import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperation; +import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationFactory; +import com.speedment.jpastreamer.rootfactory.RootFactory; +import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizer; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.util.List; +import java.util.ServiceLoader; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; + +abstract class StandardTerminalOperationOptimizerTest { + + protected final PipelineFactory pipelineFactory = RootFactory.getOrThrow(PipelineFactory.class, ServiceLoader::load); + protected final IntermediateOperationFactory iof = RootFactory.getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); + protected final TerminalOperationFactory tof = RootFactory.getOrThrow(TerminalOperationFactory.class, ServiceLoader::load); + protected final TerminalOperationOptimizer optimizer = new StandardTerminalOperationOptimizer(); + + abstract Class getEntityClass(); + + @TestFactory + Stream optimize() { + return pipelines().map(testCase -> dynamicTest(testCase.getName(), () -> { + this.optimizer.optimize(testCase.getPipeline()); + + assertTestCase(testCase); + })); + } + + protected abstract Stream> pipelines(); + + protected Pipeline createPipeline(final TerminalOperation terminalOperation, final IntermediateOperation... operations) { + final Pipeline pipeline = pipelineFactory.createPipeline(getEntityClass()); + + for (IntermediateOperation operation : operations) { + pipeline.intermediateOperations().add(operation); + } + + pipeline.terminatingOperation(terminalOperation); + + return pipeline; + } + + private void assertTestCase(final PipelineTestCase testCase) { + final Pipeline unoptimized = testCase.getPipeline(); + final Pipeline optimized = testCase.getExpectedPipeline(); + + final List> unoptimizedIntermediateOperations = unoptimized.intermediateOperations(); + final List> optimizedIntermediateOperations = optimized.intermediateOperations(); + + assertEquals(optimizedIntermediateOperations.size(), unoptimizedIntermediateOperations.size()); + + for (int i = 0; i < unoptimizedIntermediateOperations.size(); i++) { + final IntermediateOperation unoptimizedOperation = unoptimizedIntermediateOperations.get(i); + final IntermediateOperation optimizedOperation = optimizedIntermediateOperations.get(i); + + assertEquals(optimizedOperation.type(), unoptimizedOperation.type()); + assertArguments(optimizedOperation.arguments(), unoptimizedOperation.arguments()); + } + } + + protected void assertArguments(final Object[] expected, final Object[] actual) { + assertArrayEquals(expected, actual); + } + + protected static final class PipelineTestCase { + + private final String name; + private final Pipeline pipeline; + private final Pipeline expectedPipeline; + + protected PipelineTestCase( + final String name, + final Pipeline pipeline, + final Pipeline expectedPipeline + ) { + this.name = name; + this.pipeline = pipeline; + this.expectedPipeline = expectedPipeline; + } + + public String getName() { + return name; + } + + public Pipeline getPipeline() { + return pipeline; + } + + public Pipeline getExpectedPipeline() { + return expectedPipeline; + } + } + +} From 53884c4dd0aba81d07b455177a03101ae10b5c6d Mon Sep 17 00:00:00 2001 From: Julia Gustafsson Date: Tue, 23 May 2023 17:21:44 +0200 Subject: [PATCH 2/4] Add tests for terminal operation optimization #31 --- .../IntermediateOperationFactory.java | 5 +- .../StandardIntermediateOperationFactory.java | 1 + .../InternalIntermediateOperationFactory.java | 2 +- provider/termopoptimizer-standard/pom.xml | 5 +- .../StandardTerminalOperationOptimizer.java | 56 ++++-- .../src/main/java9/module-info.java | 1 + .../standard/internal/AnyMatchTest.java | 53 +++-- .../standard/internal/Film$.java | 111 ++++++++++ .../standard/internal/Film.java | 190 ++++++++++++++++++ .../standard/internal/FindAnyTest.java | 55 ++++- .../standard/internal/FindFirstTest.java | 54 ++++- .../standard/internal/NoneMatchTest.java | 73 ++++++- 12 files changed, 567 insertions(+), 39 deletions(-) create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film$.java create mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film.java diff --git a/pipeline/src/main/java/com/speedment/jpastreamer/pipeline/intermediate/IntermediateOperationFactory.java b/pipeline/src/main/java/com/speedment/jpastreamer/pipeline/intermediate/IntermediateOperationFactory.java index c12aa5483..0fdf4173a 100644 --- a/pipeline/src/main/java/com/speedment/jpastreamer/pipeline/intermediate/IntermediateOperationFactory.java +++ b/pipeline/src/main/java/com/speedment/jpastreamer/pipeline/intermediate/IntermediateOperationFactory.java @@ -12,6 +12,8 @@ */ package com.speedment.jpastreamer.pipeline.intermediate; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; + import java.util.Comparator; import java.util.function.*; import java.util.stream.DoubleStream; @@ -22,8 +24,7 @@ public interface IntermediateOperationFactory { IntermediateOperation, Stream> createFilter(Predicate predicate); - - + IntermediateOperation, Stream> createMap(Function mapper); IntermediateOperation, IntStream> createMapToInt(ToIntFunction mapper); diff --git a/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/intermediate/StandardIntermediateOperationFactory.java b/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/intermediate/StandardIntermediateOperationFactory.java index 04e4750bf..0efd4cee0 100644 --- a/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/intermediate/StandardIntermediateOperationFactory.java +++ b/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/intermediate/StandardIntermediateOperationFactory.java @@ -15,6 +15,7 @@ import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperation; import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; import com.speedment.jpastreamer.pipeline.standard.internal.intermediate.InternalIntermediateOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; import java.util.Comparator; import java.util.function.*; diff --git a/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/internal/intermediate/InternalIntermediateOperationFactory.java b/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/internal/intermediate/InternalIntermediateOperationFactory.java index 63a42d8e1..cc2fa6400 100644 --- a/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/internal/intermediate/InternalIntermediateOperationFactory.java +++ b/provider/pipeline-standard/src/main/java/com/speedment/jpastreamer/pipeline/standard/internal/intermediate/InternalIntermediateOperationFactory.java @@ -16,6 +16,7 @@ import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperation; import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationType; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; import java.util.Comparator; import java.util.function.*; @@ -53,7 +54,6 @@ public IntermediateOperation, Stream> createFilter(final Predic Stream.class, function, predicate); - } @Override diff --git a/provider/termopoptimizer-standard/pom.xml b/provider/termopoptimizer-standard/pom.xml index 2e12c4ccb..d3d3d5d7d 100644 --- a/provider/termopoptimizer-standard/pom.xml +++ b/provider/termopoptimizer-standard/pom.xml @@ -55,7 +55,10 @@ pipeline-standard test - + + com.speedment.jpastreamer + field + diff --git a/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java b/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java index 5f5b0bd87..57cbf11b9 100644 --- a/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java +++ b/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java @@ -14,21 +14,28 @@ import static java.util.Objects.requireNonNull; +import com.speedment.jpastreamer.criteria.PredicateFactory; +import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; import com.speedment.jpastreamer.pipeline.Pipeline; import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationFactory; import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationType; import com.speedment.jpastreamer.rootfactory.RootFactory; import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizer; +import java.util.Optional; import java.util.ServiceLoader; final class StandardTerminalOperationOptimizer implements TerminalOperationOptimizer { + + private final IntermediateOperationFactory intermediateOperationFactory; + private final TerminalOperationFactory terminalOperationFactory; - final IntermediateOperationFactory iof = RootFactory - .getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); - final TerminalOperationFactory tof = - RootFactory.getOrThrow(TerminalOperationFactory.class, ServiceLoader::load); + public StandardTerminalOperationOptimizer() { + this.intermediateOperationFactory = RootFactory.getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); + this.terminalOperationFactory = RootFactory.getOrThrow(TerminalOperationFactory.class, ServiceLoader::load); + } @Override public Pipeline optimize(Pipeline pipeline) { @@ -52,32 +59,49 @@ public Pipeline optimize(Pipeline pipeline) { } private Pipeline optimizeAnyMatch(Pipeline pipeline) { - pipeline.intermediateOperations().add(iof.createLimit(1)); - pipeline.intermediateOperations().add( - iof.createFilter(pipeline.terminatingOperation().predicate())); - pipeline.terminatingOperation(tof.createAnyMatch(p -> true)); + this.getPredicate(pipeline.terminatingOperation()).ifPresent(speedmentPredicate -> { + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); + pipeline.intermediateOperations().add( + intermediateOperationFactory.createFilter(speedmentPredicate)); + pipeline.terminatingOperation(terminalOperationFactory.createAnyMatch(p -> true)); + }); return pipeline; } private Pipeline optimizeNoneMatch(Pipeline pipeline) { - pipeline.intermediateOperations().add(iof.createLimit(1)); - pipeline.intermediateOperations().add( - iof.createFilter(pipeline.terminatingOperation().predicate())); - // NoneMatch() - If the stream is empty then true is returned and the predicate is not evaluated. - // If the expression is evaluated => There is a match and the expression is always false. - pipeline.terminatingOperation(tof.createNoneMatch(e -> false)); + this.getPredicate(pipeline.terminatingOperation()).ifPresent(speedmentPredicate -> { + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); + pipeline.intermediateOperations().add(intermediateOperationFactory.createFilter(speedmentPredicate)); + // NoneMatch() - If the stream is empty then true is returned and the predicate is not evaluated. + // If the expression is evaluated => There is a match and the expression is always false. + pipeline.terminatingOperation(terminalOperationFactory.createNoneMatch(e -> false)); + }); return pipeline; } private Pipeline optimizeFindFirst(Pipeline pipeline) { - pipeline.intermediateOperations().add(iof.createLimit(1)); + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); return pipeline; } private Pipeline optimizeFindAny(Pipeline pipeline) { pipeline.ordered(false); - pipeline.intermediateOperations().add(iof.createLimit(1)); + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); return pipeline; } + + private Optional> getPredicate(final TerminalOperation operation) { + final Object[] arguments = operation.arguments(); + + if (arguments.length != 1) { + return Optional.empty(); + } + + if (arguments[0] instanceof SpeedmentPredicate) { + return Optional.of((SpeedmentPredicate) arguments[0]); + } + + return Optional.empty(); + } } diff --git a/provider/termopoptimizer-standard/src/main/java9/module-info.java b/provider/termopoptimizer-standard/src/main/java9/module-info.java index dcb9426ac..169c0eb0f 100644 --- a/provider/termopoptimizer-standard/src/main/java9/module-info.java +++ b/provider/termopoptimizer-standard/src/main/java9/module-info.java @@ -13,6 +13,7 @@ module jpastreamer.termopoptimizer.standard { requires transitive jpastreamer.termopoptimizer; requires jpastreamer.rootfactory; + requires jpastreamer.predicate; exports com.speedment.jpastreamer.termopoptimizer.standard; diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java index 94e28c7e8..f6095a13b 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java @@ -1,55 +1,76 @@ package com.speedment.jpastreamer.termopoptimizer.standard.internal; +import com.speedment.jpastreamer.field.ComparableField; +import com.speedment.jpastreamer.field.ShortField; +import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; import com.speedment.jpastreamer.pipeline.Pipeline; +import java.math.BigDecimal; import java.util.function.Predicate; import java.util.stream.Stream; -final class AnyMatchTest extends StandardTerminalOperationOptimizerTest { +final class AnyMatchTest extends StandardTerminalOperationOptimizerTest { @Override - Class getEntityClass() { - return String.class; + Class getEntityClass() { + return Film.class; } @Override - protected Stream> pipelines() { + protected Stream> pipelines() { return Stream.of( noAnyMatch(), - anyMatch() + anyMatchLambda(), + anyMatchSpeedmentPredicate() ); } - private PipelineTestCase noAnyMatch() { - final Pipeline noAnyMatch = createPipeline( + private PipelineTestCase noAnyMatch() { + final Pipeline noAnyMatch = createPipeline( tof.createAllMatch(s -> s.equals("test")), - iof.createLimit(1) + iof.createLimit(100) ); - final Pipeline noAnyMatchExpected = createPipeline( + final Pipeline noAnyMatchExpected = createPipeline( tof.createAllMatch(s -> s.equals("test")), - iof.createLimit(1) + iof.createLimit(100) ); return new PipelineTestCase<>("No Any Match", noAnyMatch, noAnyMatchExpected); } - private PipelineTestCase anyMatch() { - final Predicate p = s -> (s.equals("test")); + private PipelineTestCase anyMatchLambda() { + final Predicate p = f -> f.getTitle().startsWith("A"); - final Pipeline anyMatch = createPipeline( + final Pipeline anyMatch = createPipeline( tof.createAnyMatch(p), iof.createLimit(100) ); - final Pipeline anyMatchExpected = createPipeline( + final Pipeline anyMatchExpected = createPipeline( + tof.createAnyMatch(s -> true), + iof.createLimit(100) + ); + + return new PipelineTestCase<>("Any Match Lambda", anyMatch, anyMatchExpected); + } + + private PipelineTestCase anyMatchSpeedmentPredicate() { + SpeedmentPredicate predicate = Film$.title.startsWith("A"); + + final Pipeline anyMatch = createPipeline( + tof.createAnyMatch(predicate), + iof.createLimit(100) + ); + + final Pipeline anyMatchExpected = createPipeline( tof.createAnyMatch(s -> true), iof.createLimit(100), iof.createLimit(1), - iof.createFilter(p) + iof.createFilter(predicate) ); - return new PipelineTestCase<>("Any Match", anyMatch, anyMatchExpected); + return new PipelineTestCase<>("Any Match Speedment Predicate", anyMatch, anyMatchExpected); } } diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film$.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film$.java new file mode 100644 index 000000000..389820db3 --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film$.java @@ -0,0 +1,111 @@ +package com.speedment.jpastreamer.termopoptimizer.standard.internal; + +import com.speedment.jpastreamer.field.ComparableField; +import com.speedment.jpastreamer.field.ReferenceField; +import com.speedment.jpastreamer.field.ShortField; +import com.speedment.jpastreamer.field.StringField; + +import java.math.BigDecimal; +import java.sql.Timestamp; + +/** + * The generated base for entity {@link Film} representing entities of the + * {@code film}-table in the database. + *

This file has been automatically generated by JPAStreamer. + * + * @author JPAStreamer + */ +public final class Film$ { + + /** + * This Field corresponds to the {@link Film} field "length". + */ + public static final ComparableField length = ComparableField.create( + Film.class, + "length", + Film::getLength, + false + ); + /** + * This Field corresponds to the {@link Film} field "filmId". + */ + public static final ShortField filmId = ShortField.create( + Film.class, + "filmId", + Film::getFilmId, + false + ); + /** + * This Field corresponds to the {@link Film} field "replacementCost". + */ + public static final ComparableField replacementCost = ComparableField.create( + Film.class, + "replacementCost", + Film::getReplacementCost, + false + ); + + /** + * This Field corresponds to the {@link Film} field "rating". + */ + public static final StringField rating = StringField.create( + Film.class, + "rating", + Film::getRating, + false + ); + /** + * This Field corresponds to the {@link Film} field "title". + */ + public static final StringField title = StringField.create( + Film.class, + "title", + Film::getTitle, + false + ); + /** + * This Field corresponds to the {@link Film} field "languageId". + */ + public static final ShortField languageId = ShortField.create( + Film.class, + "languageId", + Film::getLanguageId, + false + ); + /** + * This Field corresponds to the {@link Film} field "description". + */ + public static final StringField description = StringField.create( + Film.class, + "description", + Film::getDescription, + false + ); + /** + * This Field corresponds to the {@link Film} field "rentalRate". + */ + public static final ComparableField rentalRate = ComparableField.create( + Film.class, + "rentalRate", + Film::getRentalRate, + false + ); + /** + * This Field corresponds to the {@link Film} field "rentalDuration". + */ + public static final ShortField rentalDuration = ShortField.create( + Film.class, + "rentalDuration", + Film::getRentalDuration, + false + ); + /** + * This Field corresponds to the {@link Film} field "lastUpdate". + */ + public static final ComparableField lastUpdate = ComparableField.create( + Film.class, + "lastUpdate", + Film::getLastUpdate, + false + ); +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film.java new file mode 100644 index 000000000..b37d66b29 --- /dev/null +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film.java @@ -0,0 +1,190 @@ +package com.speedment.jpastreamer.termopoptimizer.standard.internal; + +import jakarta.persistence.*; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.HashSet; + +@Entity +@Table(name = "film", schema = "sakila") +public class Film { + public Film() {} + public Film(short filmId) { + this.filmId = filmId; + } + public Film(String description) { + this.description = description; + } + + public Film(short filmId, String title, String description) { + this.filmId = filmId; + this.title = title; + this.description = description; + } + + public Film(short filmId, String description) { + this.filmId = filmId; + this.description = description; + } + + @Id + @Column(name = "film_id", columnDefinition = "SMALLINT UNSIGNED") + private short filmId; + + @Basic + @Column(name = "title", columnDefinition = "VARCHAR(255)") + private String title; + + @Basic + @Column(name = "description", columnDefinition = "TEXT") + private String description; + @Basic + @Column(name = "rental_duration", columnDefinition = "YEAR") + private short rentalDuration; + @Basic + @Column(name = "language_id", columnDefinition = "SMALLINT UNSIGNED") + private short languageId; + @Basic + @Column(name = "rental_rate", columnDefinition = "DECIMAL(4,2)") + private BigDecimal rentalRate; + + @Basic + @Column(name = "length", columnDefinition = "SMALL UNSIGNED") + private Short length; + + @Basic + @Column(name = "rating", columnDefinition = "enum('G','PG','PG-13','R','NC-17')") + private String rating; + + @Basic + @Column(name = "replacement_cost") + private BigDecimal replacementCost; + + @Basic + @Column(name = "last_update") + private Timestamp lastUpdate; + + public short getFilmId() { + return filmId; + } + + public void setFilmId(short filmId) { + this.filmId = filmId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public short getLanguageId() { + return languageId; + } + + public void setLanguageId(short languageId) { + this.languageId = languageId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public short getRentalDuration() { + return rentalDuration; + } + + public void setRentalDuration(short rentalDuration) { + this.rentalDuration = rentalDuration; + } + + public String getRating() { return rating; } + + public void setRating(String rating) { this.rating = rating; } + + public BigDecimal getRentalRate() { + return rentalRate; + } + + public void setRentalRate(BigDecimal rentalRate) { + this.rentalRate = rentalRate; + } + + public Short getLength() { + return length; + } + + public void setLength(Short length) { + this.length = length; + } + + public BigDecimal getReplacementCost() { + return replacementCost; + } + + public void setReplacementCost(BigDecimal replacementCost) { + this.replacementCost = replacementCost; + } + public Timestamp getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Timestamp lastUpdate) { + this.lastUpdate = lastUpdate; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Film film = (Film) o; + + if (filmId != film.filmId) return false; + if (rentalDuration != film.rentalDuration) return false; + if (title != null ? !title.equals(film.title) : film.title != null) return false; + if (description != null ? !description.equals(film.description) : film.description != null) return false; + if (rentalRate != null ? !rentalRate.equals(film.rentalRate) : film.rentalRate != null) return false; + if (length != null ? !length.equals(film.length) : film.length != null) return false; + if (replacementCost != null ? !replacementCost.equals(film.replacementCost) : film.replacementCost != null) + return false; + if (lastUpdate != null ? !lastUpdate.equals(film.lastUpdate) : film.lastUpdate != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) filmId; + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + (description != null ? description.hashCode() : 0); + result = 31 * result + (int) rentalDuration; + result = 31 * result + (rentalRate != null ? rentalRate.hashCode() : 0); + result = 31 * result + (length != null ? length.hashCode() : 0); + result = 31 * result + (replacementCost != null ? replacementCost.hashCode() : 0); + result = 31 * result + (lastUpdate != null ? lastUpdate.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Film{" + + "filmId=" + filmId + + ", title='" + title + '\'' + + ", description='" + description + '\'' + + ", rentalDuration=" + rentalDuration + + ", languageId=" + languageId + + ", rentalRate=" + rentalRate + + ", length=" + length + + ", rating='" + rating + '\'' + + ", replacementCost=" + replacementCost + + ", lastUpdate=" + lastUpdate + + '}'; + } +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java index 78412ab19..4986b7791 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java @@ -1,4 +1,57 @@ package com.speedment.jpastreamer.termopoptimizer.standard.internal; -public class FindAnyTest { +import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; +import com.speedment.jpastreamer.pipeline.Pipeline; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class FindAnyTest extends StandardTerminalOperationOptimizerTest { + + @Override + Class getEntityClass() { + return Film.class; + } + + @Override + protected Stream> pipelines() { + return Stream.of( + noFindAny(), + findAny() + ); + } + + private PipelineTestCase noFindAny() { + final Pipeline noFindAny = createPipeline( + tof.createAllMatch(Film$.title.startsWith("A")), + iof.createLimit(100) + ); + + final Pipeline noFindAnyExpected = createPipeline( + tof.createAllMatch(Film$.title.startsWith("A")), + iof.createLimit(100) + ); + + return new PipelineTestCase<>("No Find Any", noFindAny, noFindAnyExpected); + } + + private PipelineTestCase findAny() { + final Predicate p = f -> f.getTitle().startsWith("A"); + + final Pipeline findAny = createPipeline( + tof.acquireFindAny(), + iof.createFilter(p), + iof.createLimit(100) + ); + + final Pipeline findAnyExpected = createPipeline( + tof.acquireFindAny(), + iof.createFilter(p), + iof.createLimit(100), + iof.createLimit(1) + ); + + return new PipelineTestCase<>("Find Any", findAny, findAnyExpected); + } + } diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java index 979a74030..0bd058518 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java @@ -1,4 +1,56 @@ package com.speedment.jpastreamer.termopoptimizer.standard.internal; -public class FindFirstTest { +import com.speedment.jpastreamer.pipeline.Pipeline; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class FindFirstTest extends StandardTerminalOperationOptimizerTest { + + @Override + Class getEntityClass() { + return Film.class; + } + + @Override + protected Stream> pipelines() { + return Stream.of( + noFindFirst(), + findFirst() + ); + } + + private PipelineTestCase noFindFirst() { + final Pipeline noFindFirst = createPipeline( + tof.createAllMatch(Film$.title.startsWith("A")), + iof.createLimit(100) + ); + + final Pipeline noFindFirstExpected = createPipeline( + tof.createAllMatch(Film$.title.startsWith("A")), + iof.createLimit(100) + ); + + return new PipelineTestCase<>("No Find First", noFindFirst, noFindFirstExpected); + } + + private PipelineTestCase findFirst() { + final Predicate p = f -> f.getTitle().startsWith("A"); + + final Pipeline findFirst = createPipeline( + tof.acquireFindFirst(), + iof.createFilter(p), + iof.createLimit(100) + ); + + final Pipeline findFirstExpected = createPipeline( + tof.acquireFindFirst(), + iof.createFilter(p), + iof.createLimit(100), + iof.createLimit(1) + ); + + return new PipelineTestCase<>("Find First", findFirst, findFirstExpected); + } + } diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java index 6140ee182..ec624ea84 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java +++ b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java @@ -1,4 +1,75 @@ package com.speedment.jpastreamer.termopoptimizer.standard.internal; -public class NoneMatchTest { +import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; +import com.speedment.jpastreamer.pipeline.Pipeline; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class NoneMatchTest extends StandardTerminalOperationOptimizerTest{ + + @Override + Class getEntityClass() { + return Film.class; + } + + @Override + protected Stream> pipelines() { + return Stream.of( + noNoneMatch(), + noneMatchLambda(), + noneMatchSpeedmentPredicate() + ); + } + + private PipelineTestCase noNoneMatch() { + final Predicate p = f -> f.getTitle().startsWith("A"); + + final Pipeline noAnyMatch = createPipeline( + tof.createAllMatch(p), + iof.createLimit(100) + ); + + final Pipeline noAnyMatchExpected = createPipeline( + tof.createAllMatch(p), + iof.createLimit(100) + ); + + return new PipelineTestCase<>("No None Match", noAnyMatch, noAnyMatchExpected); + } + + private PipelineTestCase noneMatchLambda() { + final Predicate p = f -> f.getTitle().startsWith("A"); + + final Pipeline anyMatch = createPipeline( + tof.createNoneMatch(p), + iof.createLimit(100) + ); + + final Pipeline anyMatchExpected = createPipeline( + tof.createNoneMatch(p), + iof.createLimit(100) + ); + + return new PipelineTestCase<>("None Match Lambda", anyMatch, anyMatchExpected); + } + + private PipelineTestCase noneMatchSpeedmentPredicate() { + SpeedmentPredicate p = Film$.title.startsWith("A"); + + final Pipeline anyMatch = createPipeline( + tof.createNoneMatch(p), + iof.createLimit(100) + ); + + final Pipeline anyMatchExpected = createPipeline( + tof.createNoneMatch(s -> true), + iof.createLimit(100), + iof.createLimit(1), + iof.createFilter(p) + ); + + return new PipelineTestCase<>("None Match Speedment Predicate", anyMatch, anyMatchExpected); + } + } From 3519795e6c84062e0c665f98eea684e4c9c3d405 Mon Sep 17 00:00:00 2001 From: Julia Gustafsson Date: Fri, 26 May 2023 11:40:11 +0200 Subject: [PATCH 3/4] Move terminal operation optimizations to modifier, add tests, work #31 --- core/pom.xml | 6 ++ .../InternalFieldGeneratorProcessor.java | 10 ++- provider/renderer-standard/pom.xml | 12 +-- .../standard/internal/StandardRenderer.java | 16 ++-- .../src/main/java9/module-info.java | 2 +- provider/termopmodifier-standard/pom.xml | 18 ++++ ...ternalTerminalOperatorModifierFactory.java | 1 + .../StandardTerminalOperatorModifier.java | 81 +++++++++++++++++- .../src/main/java9/module-info.java | 1 + ...dTerminalOperationModifierFactoryTest.java | 16 ++++ .../standard/internal/AnyMatchTest.java | 15 ++-- .../standard/internal/FindAnyTest.java | 10 +-- .../standard/internal/FindFirstTest.java | 8 +- .../standard/internal/NoneMatchTest.java | 15 ++-- ...tandardTerminalOperationModifierTest.java} | 22 ++--- .../standard/internal/model}/Film$.java | 14 +--- .../standard/internal/model}/Film.java | 20 +++-- provider/termopoptimizer-standard/pom.xml | 21 +---- .../StandardTerminalOperationOptimizer.java | 82 +------------------ .../src/main/java9/module-info.java | 2 - ...TerminalOperationOptimizerFactoryTest.java | 16 ---- 21 files changed, 205 insertions(+), 183 deletions(-) create mode 100644 provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/StandardTerminalOperationModifierFactoryTest.java rename provider/{termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer => termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier}/standard/internal/AnyMatchTest.java (84%) rename provider/{termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer => termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier}/standard/internal/FindAnyTest.java (82%) rename provider/{termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer => termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier}/standard/internal/FindFirstTest.java (83%) rename provider/{termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer => termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier}/standard/internal/NoneMatchTest.java (84%) rename provider/{termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java => termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperationModifierTest.java} (89%) rename provider/{termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal => termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model}/Film$.java (88%) rename provider/{termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal => termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model}/Film.java (95%) delete mode 100644 provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java diff --git a/core/pom.xml b/core/pom.xml index e863fc7a4..2093eb79e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -120,6 +120,12 @@ ${jpa-streamer.version} + + com.speedment.jpastreamer + termopmodifier-standard + ${jpa-streamer.version} + + com.speedment.jpastreamer announcer diff --git a/fieldgenerator/fieldgenerator-standard/src/main/java/com/speedment/jpastreamer/fieldgenerator/internal/InternalFieldGeneratorProcessor.java b/fieldgenerator/fieldgenerator-standard/src/main/java/com/speedment/jpastreamer/fieldgenerator/internal/InternalFieldGeneratorProcessor.java index 5b22c946f..89fd62e88 100644 --- a/fieldgenerator/fieldgenerator-standard/src/main/java/com/speedment/jpastreamer/fieldgenerator/internal/InternalFieldGeneratorProcessor.java +++ b/fieldgenerator/fieldgenerator-standard/src/main/java/com/speedment/jpastreamer/fieldgenerator/internal/InternalFieldGeneratorProcessor.java @@ -95,11 +95,19 @@ public boolean process(Set annotations, RoundEnvironment return false; } - roundEnv.getElementsAnnotatedWith(Entity.class).stream() + Set entities = roundEnv.getElementsAnnotatedWith(Entity.class); + + if (entities.isEmpty()) { + System.out.format("[JPAStreamer Field Generator Processor] Found no classes annotated with jakarta.persistence.Entity.\n"); + return true; + } + + entities.stream() .filter(ae -> ae.getKind() == ElementKind.CLASS) .forEach(ae -> { try { final String entityName = ae.asType().toString(); + System.out.format("[JPAStreamer Field Generator Processor] Generating class for: %s\n", entityName); final String shortEntityName = shortName(entityName); final String prefix = processingEnv.getOptions().getOrDefault("jpaStreamerPrefix", ""); diff --git a/provider/renderer-standard/pom.xml b/provider/renderer-standard/pom.xml index 960b463a4..af991d233 100644 --- a/provider/renderer-standard/pom.xml +++ b/provider/renderer-standard/pom.xml @@ -60,22 +60,22 @@ com.speedment.jpastreamer interopoptimizer - + com.speedment.jpastreamer rootfactory + + com.speedment.jpastreamer + termopmodifier + + jakarta.persistence jakarta.persistence-api ${jakarta.version} - - com.speedment.jpastreamer - termopoptimizer - - diff --git a/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java b/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java index e0a0eca28..8d8ca7c3c 100644 --- a/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java +++ b/provider/renderer-standard/src/main/java/com/speedment/jpastreamer/renderer/standard/internal/StandardRenderer.java @@ -29,7 +29,7 @@ import com.speedment.jpastreamer.rootfactory.RootFactory; import com.speedment.jpastreamer.streamconfiguration.StreamConfiguration; -import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizerFactory; +import com.speedment.jpastreamer.termopmodifier.TerminalOperationModifierFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.TypedQuery; @@ -49,7 +49,7 @@ final class StandardRenderer implements Renderer { private final CriteriaFactory criteriaFactory; private final IntermediateOperationOptimizerFactory intermediateOperationOptimizerFactory; - private final TerminalOperationOptimizerFactory terminalOperationOptimizerFactory; + private final TerminalOperationModifierFactory terminalOperationModifierFactory; private final MergerFactory mergerFactory; @@ -61,7 +61,7 @@ final class StandardRenderer implements Renderer { this.entityManager = requireNonNull(entityManagerSupplier).get(); this.criteriaFactory = RootFactory.getOrThrow(CriteriaFactory.class, ServiceLoader::load); this.intermediateOperationOptimizerFactory = RootFactory.getOrThrow(IntermediateOperationOptimizerFactory.class, ServiceLoader::load); - this.terminalOperationOptimizerFactory = RootFactory.getOrThrow(TerminalOperationOptimizerFactory.class, ServiceLoader::load); + this.terminalOperationModifierFactory = RootFactory.getOrThrow(TerminalOperationModifierFactory.class, ServiceLoader::load); this.mergerFactory = RootFactory.getOrThrow(MergerFactory.class, ServiceLoader::load); } @@ -69,13 +69,14 @@ final class StandardRenderer implements Renderer { this.entityManager = entityManager; this.criteriaFactory = RootFactory.getOrThrow(CriteriaFactory.class, ServiceLoader::load); this.intermediateOperationOptimizerFactory = RootFactory.getOrThrow(IntermediateOperationOptimizerFactory.class, ServiceLoader::load); - this.terminalOperationOptimizerFactory = RootFactory.getOrThrow(TerminalOperationOptimizerFactory.class, ServiceLoader::load); + this.terminalOperationModifierFactory = RootFactory.getOrThrow(TerminalOperationModifierFactory.class, ServiceLoader::load); this.mergerFactory = RootFactory.getOrThrow(MergerFactory.class, ServiceLoader::load); } @Override @SuppressWarnings("unchecked") public > RenderResult render(final Pipeline pipeline, final StreamConfiguration streamConfiguration) { + modifyPipeline(pipeline); optimizePipeline(pipeline); final Class entityClass = pipeline.root(); @@ -182,9 +183,12 @@ private > S replay(final Stream stream, fina return decorated; */ } - + + private void modifyPipeline(final Pipeline pipeline) { + terminalOperationModifierFactory.get().modify(pipeline); + } + private void optimizePipeline(final Pipeline pipeline) { - terminalOperationOptimizerFactory.get().optimize(pipeline); intermediateOperationOptimizerFactory.stream().forEach(intermediateOperationOptimizer -> intermediateOperationOptimizer.optimize(pipeline)); } diff --git a/provider/renderer-standard/src/main/java9/module-info.java b/provider/renderer-standard/src/main/java9/module-info.java index a1d8ef152..faa7c8791 100644 --- a/provider/renderer-standard/src/main/java9/module-info.java +++ b/provider/renderer-standard/src/main/java9/module-info.java @@ -19,7 +19,7 @@ requires jpastreamer.criteria; requires jpastreamer.merger; requires jpastreamer.interopoptimizer; - requires jpastreamer.termopoptimizer; + requires jpastreamer.termopmodifier; exports com.speedment.jpastreamer.renderer.standard; // Todo: Enable this diff --git a/provider/termopmodifier-standard/pom.xml b/provider/termopmodifier-standard/pom.xml index 87cc52ba3..c9f74aebf 100644 --- a/provider/termopmodifier-standard/pom.xml +++ b/provider/termopmodifier-standard/pom.xml @@ -35,10 +35,28 @@ + com.speedment.jpastreamer termopmodifier + + + com.speedment.jpastreamer + rootfactory + + + + com.speedment.jpastreamer + pipeline-standard + test + + + + com.speedment.jpastreamer + field + + diff --git a/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/InternalTerminalOperatorModifierFactory.java b/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/InternalTerminalOperatorModifierFactory.java index 6d29e34cc..c5a664602 100644 --- a/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/InternalTerminalOperatorModifierFactory.java +++ b/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/InternalTerminalOperatorModifierFactory.java @@ -23,4 +23,5 @@ public final class InternalTerminalOperatorModifierFactory implements TerminalOp public TerminalOperationModifier get() { return singleton; } + } diff --git a/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperatorModifier.java b/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperatorModifier.java index b63981c78..49b979ee1 100644 --- a/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperatorModifier.java +++ b/provider/termopmodifier-standard/src/main/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperatorModifier.java @@ -12,16 +12,93 @@ */ package com.speedment.jpastreamer.termopmodifier.standard.internal; +import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationType; +import com.speedment.jpastreamer.rootfactory.RootFactory; +import com.speedment.jpastreamer.termopmodifier.TerminalOperationModifier; + +import java.util.Optional; +import java.util.ServiceLoader; import static java.util.Objects.requireNonNull; -final class StandardTerminalOperatorModifier implements com.speedment.jpastreamer.termopmodifier.TerminalOperationModifier { +final class StandardTerminalOperatorModifier implements TerminalOperationModifier { + + private final IntermediateOperationFactory intermediateOperationFactory; + private final TerminalOperationFactory terminalOperationFactory; + StandardTerminalOperatorModifier() { + this.intermediateOperationFactory = RootFactory.getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); + this.terminalOperationFactory = RootFactory.getOrThrow(TerminalOperationFactory.class, ServiceLoader::load); + } + @Override public Pipeline modify(Pipeline pipeline) { requireNonNull(pipeline); - // For now, just return whatever we get. + + final TerminalOperationType terminalOperationType = pipeline.terminatingOperation().type(); + + switch (terminalOperationType) { + case ANY_MATCH: + return modifyAnyMatch(pipeline); + case NONE_MATCH: + return modifyNoneMatch(pipeline); + case FIND_FIRST: + return modifyFindFirst(pipeline); + case FIND_ANY: + return modifyFindAny(pipeline); + default: + return pipeline; + } + } + + private Pipeline modifyAnyMatch(Pipeline pipeline) { + this.getPredicate(pipeline.terminatingOperation()).ifPresent(speedmentPredicate -> { + pipeline.intermediateOperations().add(intermediateOperationFactory.createFilter(speedmentPredicate)); + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); + pipeline.terminatingOperation(terminalOperationFactory.createAnyMatch(p -> true)); + }); return pipeline; } + + private Pipeline modifyNoneMatch(Pipeline pipeline) { + this.getPredicate(pipeline.terminatingOperation()).ifPresent(speedmentPredicate -> { + pipeline.intermediateOperations().add(intermediateOperationFactory.createFilter(speedmentPredicate)); + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); + // NoneMatch() - If the stream is empty then true is returned and the predicate is not evaluated. + // If the expression is evaluated => There is a match and the expression is always false. + pipeline.terminatingOperation(terminalOperationFactory.createNoneMatch(e -> true)); + }); + return pipeline; + } + + private Pipeline modifyFindFirst(Pipeline pipeline) { + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); + return pipeline; + } + + private Pipeline modifyFindAny(Pipeline pipeline) { + pipeline.ordered(false); + pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); + return pipeline; + } + + private Optional> getPredicate(final TerminalOperation operation) { + final Object[] arguments = operation.arguments(); + + if (arguments.length != 1) { + return Optional.empty(); + } + + if (arguments[0] instanceof SpeedmentPredicate) { + return Optional.of((SpeedmentPredicate) arguments[0]); + } + + return Optional.empty(); + } + } diff --git a/provider/termopmodifier-standard/src/main/java9/module-info.java b/provider/termopmodifier-standard/src/main/java9/module-info.java index 06f5abb6b..b088b8c84 100644 --- a/provider/termopmodifier-standard/src/main/java9/module-info.java +++ b/provider/termopmodifier-standard/src/main/java9/module-info.java @@ -12,6 +12,7 @@ */ module jpastreamer.termopmodifier.standard { requires transitive jpastreamer.termopmodifier; + requires jpastreamer.rootfactory; exports com.speedment.jpastreamer.termopmodifier.standard; diff --git a/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/StandardTerminalOperationModifierFactoryTest.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/StandardTerminalOperationModifierFactoryTest.java new file mode 100644 index 000000000..11a65650a --- /dev/null +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/StandardTerminalOperationModifierFactoryTest.java @@ -0,0 +1,16 @@ +package com.speedment.jpastreamer.termopmodifier.standard; + +import com.speedment.jpastreamer.termopmodifier.TerminalOperationModifierFactory; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class StandardTerminalOperationModifierFactoryTest { + + @Test + void get() { + final TerminalOperationModifierFactory terminalOperationModifierFactory = new StandardTerminalOperatorModifierFactory(); + assertNotNull(terminalOperationModifierFactory.get()); + } + +} diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/AnyMatchTest.java similarity index 84% rename from provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java rename to provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/AnyMatchTest.java index f6095a13b..ef87937a9 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/AnyMatchTest.java +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/AnyMatchTest.java @@ -1,15 +1,14 @@ -package com.speedment.jpastreamer.termopoptimizer.standard.internal; +package com.speedment.jpastreamer.termopmodifier.standard.internal; -import com.speedment.jpastreamer.field.ComparableField; -import com.speedment.jpastreamer.field.ShortField; import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film$; -import java.math.BigDecimal; import java.util.function.Predicate; import java.util.stream.Stream; -final class AnyMatchTest extends StandardTerminalOperationOptimizerTest { +public class AnyMatchTest extends StandardTerminalOperationModifierTest { @Override Class getEntityClass() { @@ -24,7 +23,7 @@ protected Stream> pipelines() { anyMatchSpeedmentPredicate() ); } - + private PipelineTestCase noAnyMatch() { final Pipeline noAnyMatch = createPipeline( tof.createAllMatch(s -> s.equals("test")), @@ -66,8 +65,8 @@ private PipelineTestCase anyMatchSpeedmentPredicate() { final Pipeline anyMatchExpected = createPipeline( tof.createAnyMatch(s -> true), iof.createLimit(100), - iof.createLimit(1), - iof.createFilter(predicate) + iof.createFilter(predicate), + iof.createLimit(1) ); return new PipelineTestCase<>("Any Match Speedment Predicate", anyMatch, anyMatchExpected); diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/FindAnyTest.java similarity index 82% rename from provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java rename to provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/FindAnyTest.java index 4986b7791..22772a85a 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindAnyTest.java +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/FindAnyTest.java @@ -1,13 +1,14 @@ -package com.speedment.jpastreamer.termopoptimizer.standard.internal; +package com.speedment.jpastreamer.termopmodifier.standard.internal; -import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film$; import java.util.function.Predicate; import java.util.stream.Stream; -public class FindAnyTest extends StandardTerminalOperationOptimizerTest { - +public class FindAnyTest extends StandardTerminalOperationModifierTest { + @Override Class getEntityClass() { return Film.class; @@ -53,5 +54,4 @@ private PipelineTestCase findAny() { return new PipelineTestCase<>("Find Any", findAny, findAnyExpected); } - } diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/FindFirstTest.java similarity index 83% rename from provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java rename to provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/FindFirstTest.java index 0bd058518..2fb273414 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/FindFirstTest.java +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/FindFirstTest.java @@ -1,11 +1,13 @@ -package com.speedment.jpastreamer.termopoptimizer.standard.internal; +package com.speedment.jpastreamer.termopmodifier.standard.internal; import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film$; import java.util.function.Predicate; import java.util.stream.Stream; -public class FindFirstTest extends StandardTerminalOperationOptimizerTest { +public class FindFirstTest extends StandardTerminalOperationModifierTest { @Override Class getEntityClass() { @@ -52,5 +54,5 @@ private PipelineTestCase findFirst() { return new PipelineTestCase<>("Find First", findFirst, findFirstExpected); } - + } diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/NoneMatchTest.java similarity index 84% rename from provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java rename to provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/NoneMatchTest.java index ec624ea84..87f29aa84 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/NoneMatchTest.java +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/NoneMatchTest.java @@ -1,12 +1,15 @@ -package com.speedment.jpastreamer.termopoptimizer.standard.internal; +package com.speedment.jpastreamer.termopmodifier.standard.internal; + import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film; +import com.speedment.jpastreamer.termopmodifier.standard.internal.model.Film$; import java.util.function.Predicate; import java.util.stream.Stream; -public class NoneMatchTest extends StandardTerminalOperationOptimizerTest{ +public class NoneMatchTest extends StandardTerminalOperationModifierTest{ @Override Class getEntityClass() { @@ -24,7 +27,7 @@ protected Stream> pipelines() { private PipelineTestCase noNoneMatch() { final Predicate p = f -> f.getTitle().startsWith("A"); - + final Pipeline noAnyMatch = createPipeline( tof.createAllMatch(p), iof.createLimit(100) @@ -65,11 +68,11 @@ private PipelineTestCase noneMatchSpeedmentPredicate() { final Pipeline anyMatchExpected = createPipeline( tof.createNoneMatch(s -> true), iof.createLimit(100), - iof.createLimit(1), - iof.createFilter(p) + iof.createFilter(p), + iof.createLimit(1) ); return new PipelineTestCase<>("None Match Speedment Predicate", anyMatch, anyMatchExpected); } - + } diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperationModifierTest.java similarity index 89% rename from provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java rename to provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperationModifierTest.java index e8fc5ab0c..b1f730e8d 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizerTest.java +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/StandardTerminalOperationModifierTest.java @@ -1,4 +1,4 @@ -package com.speedment.jpastreamer.termopoptimizer.standard.internal; +package com.speedment.jpastreamer.termopmodifier.standard.internal; import com.speedment.jpastreamer.pipeline.Pipeline; import com.speedment.jpastreamer.pipeline.PipelineFactory; @@ -7,7 +7,7 @@ import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationFactory; import com.speedment.jpastreamer.rootfactory.RootFactory; -import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizer; +import com.speedment.jpastreamer.termopmodifier.TerminalOperationModifier; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; @@ -19,19 +19,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.DynamicTest.dynamicTest; -abstract class StandardTerminalOperationOptimizerTest { - +abstract class StandardTerminalOperationModifierTest { + protected final PipelineFactory pipelineFactory = RootFactory.getOrThrow(PipelineFactory.class, ServiceLoader::load); protected final IntermediateOperationFactory iof = RootFactory.getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); protected final TerminalOperationFactory tof = RootFactory.getOrThrow(TerminalOperationFactory.class, ServiceLoader::load); - protected final TerminalOperationOptimizer optimizer = new StandardTerminalOperationOptimizer(); - + protected final TerminalOperationModifier modifier = new StandardTerminalOperatorModifier(); + abstract Class getEntityClass(); - + @TestFactory - Stream optimize() { + Stream modify() { return pipelines().map(testCase -> dynamicTest(testCase.getName(), () -> { - this.optimizer.optimize(testCase.getPipeline()); + this.modifier.modify(testCase.getPipeline()); assertTestCase(testCase); })); @@ -45,8 +45,8 @@ protected Pipeline createPipeline(final TerminalOperation terminal for (IntermediateOperation operation : operations) { pipeline.intermediateOperations().add(operation); } - - pipeline.terminatingOperation(terminalOperation); + + pipeline.terminatingOperation(terminalOperation); return pipeline; } diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film$.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model/Film$.java similarity index 88% rename from provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film$.java rename to provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model/Film$.java index 389820db3..a32e055bc 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film$.java +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model/Film$.java @@ -1,21 +1,13 @@ -package com.speedment.jpastreamer.termopoptimizer.standard.internal; +package com.speedment.jpastreamer.termopmodifier.standard.internal.model; import com.speedment.jpastreamer.field.ComparableField; -import com.speedment.jpastreamer.field.ReferenceField; import com.speedment.jpastreamer.field.ShortField; import com.speedment.jpastreamer.field.StringField; import java.math.BigDecimal; import java.sql.Timestamp; -/** - * The generated base for entity {@link Film} representing entities of the - * {@code film}-table in the database. - *

This file has been automatically generated by JPAStreamer. - * - * @author JPAStreamer - */ -public final class Film$ { +public class Film$ { /** * This Field corresponds to the {@link Film} field "length". @@ -44,7 +36,7 @@ public final class Film$ { Film::getReplacementCost, false ); - + /** * This Field corresponds to the {@link Film} field "rating". */ diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film.java b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model/Film.java similarity index 95% rename from provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film.java rename to provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model/Film.java index b37d66b29..dfe68e0d8 100644 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/Film.java +++ b/provider/termopmodifier-standard/src/test/java/com/speedment/jpastreamer/termopmodifier/standard/internal/model/Film.java @@ -1,17 +1,20 @@ -package com.speedment.jpastreamer.termopoptimizer.standard.internal; +package com.speedment.jpastreamer.termopmodifier.standard.internal.model; import jakarta.persistence.*; + import java.math.BigDecimal; import java.sql.Timestamp; -import java.util.HashSet; @Entity @Table(name = "film", schema = "sakila") public class Film { - public Film() {} + public Film() { + } + public Film(short filmId) { this.filmId = filmId; } + public Film(String description) { this.description = description; } @@ -104,9 +107,13 @@ public void setRentalDuration(short rentalDuration) { this.rentalDuration = rentalDuration; } - public String getRating() { return rating; } + public String getRating() { + return rating; + } - public void setRating(String rating) { this.rating = rating; } + public void setRating(String rating) { + this.rating = rating; + } public BigDecimal getRentalRate() { return rentalRate; @@ -131,6 +138,7 @@ public BigDecimal getReplacementCost() { public void setReplacementCost(BigDecimal replacementCost) { this.replacementCost = replacementCost; } + public Timestamp getLastUpdate() { return lastUpdate; } @@ -138,7 +146,7 @@ public Timestamp getLastUpdate() { public void setLastUpdate(Timestamp lastUpdate) { this.lastUpdate = lastUpdate; } - + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/provider/termopoptimizer-standard/pom.xml b/provider/termopoptimizer-standard/pom.xml index d3d3d5d7d..546fecf3e 100644 --- a/provider/termopoptimizer-standard/pom.xml +++ b/provider/termopoptimizer-standard/pom.xml @@ -39,26 +39,7 @@ com.speedment.jpastreamer termopoptimizer - - - com.speedment.jpastreamer - pipeline - - - - com.speedment.jpastreamer - rootfactory - - - - com.speedment.jpastreamer - pipeline-standard - test - - - com.speedment.jpastreamer - field - + diff --git a/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java b/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java index 57cbf11b9..47d1bd897 100644 --- a/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java +++ b/provider/termopoptimizer-standard/src/main/java/com/speedment/jpastreamer/termopoptimizer/standard/internal/StandardTerminalOperationOptimizer.java @@ -12,96 +12,20 @@ */ package com.speedment.jpastreamer.termopoptimizer.standard.internal; -import static java.util.Objects.requireNonNull; - -import com.speedment.jpastreamer.criteria.PredicateFactory; -import com.speedment.jpastreamer.field.predicate.SpeedmentPredicate; import com.speedment.jpastreamer.pipeline.Pipeline; -import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; -import com.speedment.jpastreamer.pipeline.terminal.TerminalOperation; -import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationFactory; -import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationType; -import com.speedment.jpastreamer.rootfactory.RootFactory; import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizer; -import java.util.Optional; -import java.util.ServiceLoader; +import static java.util.Objects.requireNonNull; final class StandardTerminalOperationOptimizer implements TerminalOperationOptimizer { - - private final IntermediateOperationFactory intermediateOperationFactory; - private final TerminalOperationFactory terminalOperationFactory; - - public StandardTerminalOperationOptimizer() { - this.intermediateOperationFactory = RootFactory.getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); - this.terminalOperationFactory = RootFactory.getOrThrow(TerminalOperationFactory.class, ServiceLoader::load); - } @Override public Pipeline optimize(Pipeline pipeline) { requireNonNull(pipeline); - - final TerminalOperationType terminalOperationType = pipeline.terminatingOperation().type(); - - switch (terminalOperationType) { - case ANY_MATCH: - return optimizeAnyMatch(pipeline); - case NONE_MATCH: - return optimizeNoneMatch(pipeline); - case FIND_FIRST: - return optimizeFindFirst(pipeline); - case FIND_ANY: - return optimizeFindAny(pipeline); - default: - return pipeline; - } - } - - private Pipeline optimizeAnyMatch(Pipeline pipeline) { - this.getPredicate(pipeline.terminatingOperation()).ifPresent(speedmentPredicate -> { - pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); - pipeline.intermediateOperations().add( - intermediateOperationFactory.createFilter(speedmentPredicate)); - pipeline.terminatingOperation(terminalOperationFactory.createAnyMatch(p -> true)); - }); - return pipeline; - } - - private Pipeline optimizeNoneMatch(Pipeline pipeline) { - this.getPredicate(pipeline.terminatingOperation()).ifPresent(speedmentPredicate -> { - pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); - pipeline.intermediateOperations().add(intermediateOperationFactory.createFilter(speedmentPredicate)); - // NoneMatch() - If the stream is empty then true is returned and the predicate is not evaluated. - // If the expression is evaluated => There is a match and the expression is always false. - pipeline.terminatingOperation(terminalOperationFactory.createNoneMatch(e -> false)); - }); - return pipeline; - } - - private Pipeline optimizeFindFirst(Pipeline pipeline) { - pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); - return pipeline; - } - - private Pipeline optimizeFindAny(Pipeline pipeline) { - pipeline.ordered(false); - pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1)); + // For now, just return whatever we get. + return pipeline; } - - private Optional> getPredicate(final TerminalOperation operation) { - final Object[] arguments = operation.arguments(); - - if (arguments.length != 1) { - return Optional.empty(); - } - - if (arguments[0] instanceof SpeedmentPredicate) { - return Optional.of((SpeedmentPredicate) arguments[0]); - } - - return Optional.empty(); - } } diff --git a/provider/termopoptimizer-standard/src/main/java9/module-info.java b/provider/termopoptimizer-standard/src/main/java9/module-info.java index 169c0eb0f..46961365a 100644 --- a/provider/termopoptimizer-standard/src/main/java9/module-info.java +++ b/provider/termopoptimizer-standard/src/main/java9/module-info.java @@ -12,8 +12,6 @@ */ module jpastreamer.termopoptimizer.standard { requires transitive jpastreamer.termopoptimizer; - requires jpastreamer.rootfactory; - requires jpastreamer.predicate; exports com.speedment.jpastreamer.termopoptimizer.standard; diff --git a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java b/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java deleted file mode 100644 index 85c1d5cc6..000000000 --- a/provider/termopoptimizer-standard/src/test/java/com/speedment/jpastreamer/termopoptimizer/standard/StandardTerminalOperationOptimizerFactoryTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.speedment.jpastreamer.termopoptimizer.standard; - -import com.speedment.jpastreamer.termopoptimizer.TerminalOperationOptimizerFactory; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -final class StandardTerminalOperationOptimizerFactoryTest { - - @Test - void get() { - final TerminalOperationOptimizerFactory terminalOperationOptimizerFactory = new StandardTerminalOperationOptimizerFactory(); - assertNotNull(terminalOperationOptimizerFactory.get()); - } - -} From 2c4d61599817c9526eabeee6f0353acb827dae60 Mon Sep 17 00:00:00 2001 From: Julia Gustafsson Date: Mon, 5 Jun 2023 10:43:04 +0200 Subject: [PATCH 4/4] Update termopmodifier module-info --- .../termopmodifier-standard/src/main/java/module-info.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/provider/termopmodifier-standard/src/main/java/module-info.java b/provider/termopmodifier-standard/src/main/java/module-info.java index 1d068f01d..1e6961634 100644 --- a/provider/termopmodifier-standard/src/main/java/module-info.java +++ b/provider/termopmodifier-standard/src/main/java/module-info.java @@ -1,3 +1,6 @@ +import com.speedment.jpastreamer.pipeline.PipelineFactory; +import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; +import com.speedment.jpastreamer.pipeline.terminal.TerminalOperationFactory; import com.speedment.jpastreamer.termopmodifier.TerminalOperationModifierFactory; import com.speedment.jpastreamer.termopmodifier.standard.StandardTerminalOperatorModifierFactory; @@ -21,5 +24,9 @@ exports com.speedment.jpastreamer.termopmodifier.standard; + uses PipelineFactory; + uses TerminalOperationFactory; + uses IntermediateOperationFactory; + provides TerminalOperationModifierFactory with StandardTerminalOperatorModifierFactory; }