Skip to content

Commit

Permalink
Add tests for terminal operation optimization #31
Browse files Browse the repository at this point in the history
  • Loading branch information
julgus committed May 23, 2023
1 parent 8a080da commit 53884c4
Show file tree
Hide file tree
Showing 12 changed files with 567 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,8 +24,7 @@
public interface IntermediateOperationFactory {

<T> IntermediateOperation<Stream<T>, Stream<T>> createFilter(Predicate<? super T> predicate);



<T, R> IntermediateOperation<Stream<T>, Stream<R>> createMap(Function<? super T, ? extends R> mapper);

<T> IntermediateOperation<Stream<T>, IntStream> createMapToInt(ToIntFunction<? super T> mapper);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand Down Expand Up @@ -53,7 +54,6 @@ public <T> IntermediateOperation<Stream<T>, Stream<T>> createFilter(final Predic
Stream.class,
function,
predicate);

}

@Override
Expand Down
5 changes: 4 additions & 1 deletion provider/termopoptimizer-standard/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@
<artifactId>pipeline-standard</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.speedment.jpastreamer</groupId>
<artifactId>field</artifactId>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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 <T> Pipeline<T> optimize(Pipeline<T> pipeline) {
Expand All @@ -52,32 +59,49 @@ public <T> Pipeline<T> optimize(Pipeline<T> pipeline) {
}

private <T> Pipeline<T> optimizeAnyMatch(Pipeline<T> pipeline) {
pipeline.intermediateOperations().add(iof.createLimit(1));
pipeline.intermediateOperations().add(
iof.createFilter(pipeline.terminatingOperation().predicate()));
pipeline.terminatingOperation(tof.createAnyMatch(p -> true));
this.<T>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 <T> Pipeline<T> optimizeNoneMatch(Pipeline<T> 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.<T>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 <T> Pipeline<T> optimizeFindFirst(Pipeline<T> pipeline) {
pipeline.intermediateOperations().add(iof.createLimit(1));
pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1));
return pipeline;
}

private <T> Pipeline<T> optimizeFindAny(Pipeline<T> pipeline) {
pipeline.ordered(false);
pipeline.intermediateOperations().add(iof.createLimit(1));
pipeline.intermediateOperations().add(intermediateOperationFactory.createLimit(1));
return pipeline;
}

private <T> Optional<SpeedmentPredicate<T>> 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<T>) arguments[0]);
}

return Optional.empty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
module jpastreamer.termopoptimizer.standard {
requires transitive jpastreamer.termopoptimizer;
requires jpastreamer.rootfactory;
requires jpastreamer.predicate;

exports com.speedment.jpastreamer.termopoptimizer.standard;

Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> {
final class AnyMatchTest extends StandardTerminalOperationOptimizerTest<Film> {

@Override
Class<String> getEntityClass() {
return String.class;
Class<Film> getEntityClass() {
return Film.class;
}

@Override
protected Stream<PipelineTestCase<String>> pipelines() {
protected Stream<PipelineTestCase<Film>> pipelines() {
return Stream.of(
noAnyMatch(),
anyMatch()
anyMatchLambda(),
anyMatchSpeedmentPredicate()
);
}

private PipelineTestCase<String> noAnyMatch() {
final Pipeline<String> noAnyMatch = createPipeline(
private PipelineTestCase<Film> noAnyMatch() {
final Pipeline<Film> noAnyMatch = createPipeline(
tof.createAllMatch(s -> s.equals("test")),
iof.createLimit(1)
iof.createLimit(100)
);

final Pipeline<String> noAnyMatchExpected = createPipeline(
final Pipeline<Film> noAnyMatchExpected = createPipeline(
tof.createAllMatch(s -> s.equals("test")),
iof.createLimit(1)
iof.createLimit(100)
);

return new PipelineTestCase<>("No Any Match", noAnyMatch, noAnyMatchExpected);
}

private PipelineTestCase<String> anyMatch() {
final Predicate<String> p = s -> (s.equals("test"));
private PipelineTestCase<Film> anyMatchLambda() {
final Predicate<Film> p = f -> f.getTitle().startsWith("A");

final Pipeline<String> anyMatch = createPipeline(
final Pipeline<Film> anyMatch = createPipeline(
tof.createAnyMatch(p),
iof.createLimit(100)
);

final Pipeline<String> anyMatchExpected = createPipeline(
final Pipeline<Film> anyMatchExpected = createPipeline(
tof.createAnyMatch(s -> true),
iof.createLimit(100)
);

return new PipelineTestCase<>("Any Match Lambda", anyMatch, anyMatchExpected);
}

private PipelineTestCase<Film> anyMatchSpeedmentPredicate() {
SpeedmentPredicate<Film> predicate = Film$.title.startsWith("A");

final Pipeline<Film> anyMatch = createPipeline(
tof.createAnyMatch(predicate),
iof.createLimit(100)
);

final Pipeline<Film> 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);
}

}
Original file line number Diff line number Diff line change
@@ -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.
* <p> 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<Film, Short> length = ComparableField.create(
Film.class,
"length",
Film::getLength,
false
);
/**
* This Field corresponds to the {@link Film} field "filmId".
*/
public static final ShortField<Film> filmId = ShortField.create(
Film.class,
"filmId",
Film::getFilmId,
false
);
/**
* This Field corresponds to the {@link Film} field "replacementCost".
*/
public static final ComparableField<Film, BigDecimal> replacementCost = ComparableField.create(
Film.class,
"replacementCost",
Film::getReplacementCost,
false
);

/**
* This Field corresponds to the {@link Film} field "rating".
*/
public static final StringField<Film> rating = StringField.create(
Film.class,
"rating",
Film::getRating,
false
);
/**
* This Field corresponds to the {@link Film} field "title".
*/
public static final StringField<Film> title = StringField.create(
Film.class,
"title",
Film::getTitle,
false
);
/**
* This Field corresponds to the {@link Film} field "languageId".
*/
public static final ShortField<Film> languageId = ShortField.create(
Film.class,
"languageId",
Film::getLanguageId,
false
);
/**
* This Field corresponds to the {@link Film} field "description".
*/
public static final StringField<Film> description = StringField.create(
Film.class,
"description",
Film::getDescription,
false
);
/**
* This Field corresponds to the {@link Film} field "rentalRate".
*/
public static final ComparableField<Film, BigDecimal> rentalRate = ComparableField.create(
Film.class,
"rentalRate",
Film::getRentalRate,
false
);
/**
* This Field corresponds to the {@link Film} field "rentalDuration".
*/
public static final ShortField<Film> rentalDuration = ShortField.create(
Film.class,
"rentalDuration",
Film::getRentalDuration,
false
);
/**
* This Field corresponds to the {@link Film} field "lastUpdate".
*/
public static final ComparableField<Film, Timestamp> lastUpdate = ComparableField.create(
Film.class,
"lastUpdate",
Film::getLastUpdate,
false
);
}

0 comments on commit 53884c4

Please sign in to comment.