Skip to content

Commit

Permalink
HSEARCH-3290 Introduce toSort() and toPredicate() methods in the DSLs
Browse files Browse the repository at this point in the history
They can be used wherever end() can be used, but they always return a
SearchSort/SearchPredicate, unlike end() that returns a context-specific
type.

This adds in particular the ability to cache predicates at any level of
the DSL tree, not just the root like we used to.
  • Loading branch information
yrodiere authored and gsmet committed Nov 2, 2018
1 parent 3ad0c32 commit 4dbd227
Show file tree
Hide file tree
Showing 22 changed files with 284 additions and 200 deletions.
Expand Up @@ -12,6 +12,7 @@
import org.hibernate.search.engine.search.dsl.sort.NonEmptySortContext;
import org.hibernate.search.engine.search.dsl.sort.SearchSortContainerContext;
import org.hibernate.search.engine.search.dsl.sort.spi.DelegatingSearchSortContainerContextImpl;
import org.hibernate.search.engine.search.dsl.sort.spi.NonEmptySortContextImpl;
import org.hibernate.search.engine.search.dsl.sort.spi.SearchSortDslContext;


Expand All @@ -38,16 +39,6 @@ public NonEmptySortContext<N> fromJsonString(String jsonString) {
}

private NonEmptySortContext<N> nonEmptyContext() {
return new NonEmptySortContext<N>() {
@Override
public SearchSortContainerContext<N> then() {
return ElasticsearchSearchSortContainerContextImpl.this;
}

@Override
public N end() {
return dslContext.getNextContext();
}
};
return new NonEmptySortContextImpl<>( this, dslContext );
}
}
Expand Up @@ -14,6 +14,7 @@
import org.hibernate.search.engine.search.dsl.sort.NonEmptySortContext;
import org.hibernate.search.engine.search.dsl.sort.SearchSortContainerContext;
import org.hibernate.search.engine.search.dsl.sort.spi.DelegatingSearchSortContainerContextImpl;
import org.hibernate.search.engine.search.dsl.sort.spi.NonEmptySortContextImpl;
import org.hibernate.search.engine.search.dsl.sort.spi.SearchSortDslContext;


Expand Down Expand Up @@ -46,16 +47,6 @@ public NonEmptySortContext<N> fromLuceneSort(Sort luceneSort) {
}

private NonEmptySortContext<N> nonEmptyContext() {
return new NonEmptySortContext<N>() {
@Override
public SearchSortContainerContext<N> then() {
return LuceneSearchSortContainerContextImpl.this;
}

@Override
public N end() {
return dslContext.getNextContext();
}
};
return new NonEmptySortContextImpl<>( this, dslContext );
}
}
Expand Up @@ -7,6 +7,8 @@
package org.hibernate.search.engine.search.dsl.predicate;


import org.hibernate.search.engine.search.SearchPredicate;

/**
* The terminal context of the predicate DSL.
*
Expand All @@ -21,4 +23,12 @@ public interface SearchPredicateTerminalContext<N> {
*/
N end();

/**
* Create a {@link SearchPredicate} instance
* matching the definition given in the previous DSL steps.
*
* @return The {@link SearchPredicate} resulting from the previous DSL steps.
*/
SearchPredicate toPredicate();

}
Expand Up @@ -15,17 +15,17 @@
import org.hibernate.search.engine.search.dsl.predicate.BooleanJunctionPredicateContext;
import org.hibernate.search.engine.search.dsl.predicate.MinimumShouldMatchContext;
import org.hibernate.search.engine.search.dsl.predicate.SearchPredicateContainerContext;
import org.hibernate.search.engine.search.dsl.predicate.spi.AbstractObjectCreatingSearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateDslContext;
import org.hibernate.search.engine.search.predicate.spi.BooleanJunctionPredicateBuilder;
import org.hibernate.search.engine.search.predicate.spi.SearchPredicateFactory;


class BooleanJunctionPredicateContextImpl<N, B>
extends AbstractObjectCreatingSearchPredicateContributor<B>
implements BooleanJunctionPredicateContext<N>, SearchPredicateContributor<B> {

private final SearchPredicateFactory<?, B> factory;

private final Supplier<N> nextContextProvider;

private final BooleanJunctionPredicateBuilder<B> builder;
Expand All @@ -39,7 +39,7 @@ class BooleanJunctionPredicateContextImpl<N, B>

BooleanJunctionPredicateContextImpl(SearchPredicateFactory<?, B> factory,
Supplier<N> nextContextProvider) {
this.factory = factory;
super( factory );
this.nextContextProvider = nextContextProvider;
this.builder = factory.bool();
this.must = new OccurContext();
Expand Down Expand Up @@ -112,7 +112,7 @@ public BooleanJunctionPredicateContext<N> minimumShouldMatch(
}

@Override
public B contribute() {
protected B doContribute() {
must.contribute( builder::must );
mustNot.contribute( builder::mustNot );
should.contribute( builder::should );
Expand Down
Expand Up @@ -14,6 +14,7 @@
import org.hibernate.search.engine.search.SearchPredicate;
import org.hibernate.search.engine.search.dsl.predicate.MatchAllPredicateContext;
import org.hibernate.search.engine.search.dsl.predicate.SearchPredicateContainerContext;
import org.hibernate.search.engine.search.dsl.predicate.spi.AbstractObjectCreatingSearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateDslContext;
import org.hibernate.search.engine.search.predicate.spi.BooleanJunctionPredicateBuilder;
Expand All @@ -22,17 +23,17 @@


class MatchAllPredicateContextImpl<N, B>
extends AbstractObjectCreatingSearchPredicateContributor<B>
implements MatchAllPredicateContext<N>, SearchPredicateContributor<B> {

private final SearchPredicateFactory<?, B> factory;
private final Supplier<N> nextContextProvider;

private final MatchAllPredicateBuilder<B> matchAllBuilder;
private MatchAllExceptContext exceptContext;

MatchAllPredicateContextImpl(SearchPredicateFactory<?, B> factory,
Supplier<N> nextContextProvider) {
this.factory = factory;
super( factory );
this.nextContextProvider = nextContextProvider;
this.matchAllBuilder = factory.matchAll();
}
Expand All @@ -56,7 +57,7 @@ public MatchAllPredicateContext<N> except(Consumer<? super SearchPredicateContai
}

@Override
public B contribute() {
protected B doContribute() {
if ( exceptContext != null ) {
return exceptContext.contribute();
}
Expand Down
Expand Up @@ -11,21 +11,21 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.hibernate.search.engine.search.dsl.predicate.spi.AbstractObjectCreatingSearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateContributor;
import org.hibernate.search.engine.search.predicate.spi.BooleanJunctionPredicateBuilder;
import org.hibernate.search.engine.search.predicate.spi.SearchPredicateFactory;

class MultiFieldPredicateCommonState<N, B, F extends MultiFieldPredicateCommonState.FieldSetContext<B>>
extends AbstractObjectCreatingSearchPredicateContributor<B>
implements SearchPredicateContributor<B> {

private final SearchPredicateFactory<?, B> factory;

private final Supplier<N> nextContextProvider;

private final List<F> fieldSetContexts = new ArrayList<>();

MultiFieldPredicateCommonState(SearchPredicateFactory<?, B> factory, Supplier<N> nextContextProvider) {
this.factory = factory;
super( factory );
this.nextContextProvider = nextContextProvider;
}

Expand All @@ -46,7 +46,7 @@ List<F> getFieldSetContexts() {
}

@Override
public B contribute() {
protected B doContribute() {
List<B> predicateBuilders = new ArrayList<>();
for ( F fieldSetContext : fieldSetContexts ) {
fieldSetContext.contributePredicateBuilders( predicateBuilders::add );
Expand Down
Expand Up @@ -16,6 +16,7 @@
import org.hibernate.search.engine.search.dsl.predicate.NestedPredicateContext;
import org.hibernate.search.engine.search.dsl.predicate.NestedPredicateFieldContext;
import org.hibernate.search.engine.search.dsl.predicate.SearchPredicateContainerContext;
import org.hibernate.search.engine.search.dsl.predicate.spi.AbstractObjectCreatingSearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateDslContext;
import org.hibernate.search.engine.search.predicate.spi.NestedPredicateBuilder;
Expand All @@ -24,20 +25,20 @@


class NestedPredicateContextImpl<N, B>
extends AbstractObjectCreatingSearchPredicateContributor<B>
implements NestedPredicateContext<N>, NestedPredicateFieldContext<N>, SearchPredicateTerminalContext<N>,
SearchPredicateDslContext<N, B>, SearchPredicateContributor<B> {

private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );

private final SearchPredicateFactory<?, B> factory;
private final Supplier<N> nextContextProvider;

private final SearchPredicateContainerContext<?> containerContext;
private NestedPredicateBuilder<B> builder;
private SearchPredicateContributor<? extends B> childPredicateContributor;

NestedPredicateContextImpl(SearchPredicateFactory<?, B> factory, Supplier<N> nextContextProvider) {
this.factory = factory;
super( factory );
this.nextContextProvider = nextContextProvider;
this.containerContext = new SearchPredicateContainerContextImpl<>( factory, this );
}
Expand Down Expand Up @@ -79,7 +80,7 @@ public N getNextContext() {
}

@Override
public B contribute() {
protected B doContribute() {
builder.nested( childPredicateContributor.contribute() );
return builder.toImplementation();
}
Expand Down
Expand Up @@ -88,10 +88,10 @@ static class CommonState<N, B> extends MultiFieldPredicateCommonState<N, B, Rang
}

@Override
public B contribute() {
protected B doContribute() {
// Just in case from() was called, but not to()
checkHasNonNullBound();
return super.contribute();
return super.doContribute();
}

RangePredicateFromContext<N> from(Object value, RangeBoundInclusion inclusion) {
Expand Down
Expand Up @@ -12,11 +12,11 @@
import org.hibernate.search.engine.backend.index.spi.IndexSearchTarget;
import org.hibernate.search.engine.logging.impl.Log;
import org.hibernate.search.engine.search.SearchPredicate;
import org.hibernate.search.engine.search.dsl.predicate.spi.AbstractObjectCreatingSearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateContributor;
import org.hibernate.search.engine.search.dsl.predicate.spi.SearchPredicateDslContext;
import org.hibernate.search.engine.search.dsl.query.SearchQueryResultContext;
import org.hibernate.search.engine.search.predicate.spi.SearchPredicateFactory;
import org.hibernate.search.util.AssertionFailure;
import org.hibernate.search.util.impl.common.LoggerFactory;

/**
Expand All @@ -26,23 +26,20 @@
* (in which case the lambda may retrieve the resulting {@link SearchPredicate} object and cache it).
*/
public final class RootSearchPredicateDslContextImpl<B>
extends AbstractObjectCreatingSearchPredicateContributor<B>
implements SearchPredicateDslContext<SearchPredicate, B> {

private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );

private final SearchPredicateFactory<?, B> factory;

private SearchPredicateContributor<? extends B> singlePredicateContributor;
private boolean usedContributor = false;
private SearchPredicate predicateResult;

public RootSearchPredicateDslContextImpl(SearchPredicateFactory<?, B> factory) {
this.factory = factory;
super( factory );
}

@Override
public void addChild(SearchPredicateContributor<? extends B> child) {
if ( usedContributor ) {
if ( isContributed() ) {
throw log.cannotAddPredicateToUsedContext();
}
if ( this.singlePredicateContributor != null ) {
Expand All @@ -53,43 +50,15 @@ public void addChild(SearchPredicateContributor<? extends B> child) {

@Override
public SearchPredicate getNextContext() {
if ( predicateResult == null ) {
if ( usedContributor ) {
// HSEARCH-3207: we must never call a contribution twice. Contributions may have side-effects.
throw new AssertionFailure(
"A predicate object was requested after the corresponding information was contributed to the DSL." +
" There is a bug in Hibernate Search, please report it."
);
}
predicateResult = factory.toSearchPredicate( getResultingBuilder() );
}
return predicateResult;
return toPredicate();
}

public B getResultingBuilder() {
if ( predicateResult != null ) {
/*
* If the SearchPredicate object was already created,
* we can't use the builder collected by the aggregator anymore: it might be single-use.
* We just ask the factory to convert the SearchPredicate object back to a builder.
* If the builders can be used multiple times, the factory can optimize this.
*/
return factory.toImplementation( predicateResult );
}
else {
if ( usedContributor ) {
// HSEARCH-3207: we must never call a contribution twice. Contributions may have side-effects.
throw new AssertionFailure(
"A predicate contributor was called twice. There is a bug in Hibernate Search, please report it."
);
}
usedContributor = true;
/*
* Optimization: we know the user will not be able to request a SearchPredicate object anymore,
* so we don't need to build a SearchPredicate object in this case,
* we can just use the builder collected by the aggregator directly.
*/
return singlePredicateContributor.contribute();
}
return contribute();
}

@Override
protected B doContribute() {
return singlePredicateContributor.contribute();
}
}

0 comments on commit 4dbd227

Please sign in to comment.