Skip to content

Commit

Permalink
HSEARCH-1409 Allowing field bridge instances to be passed to Query DSL
Browse files Browse the repository at this point in the history
  • Loading branch information
gunnarmorling authored and Sanne committed Sep 23, 2013
1 parent 7d61078 commit 180e395
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 36 deletions.
Expand Up @@ -681,29 +681,37 @@ public String objectToString(String fieldName, Object value, ConversionContext c
throw new AssertionFailure( "Field name should not be null" );
}

DocumentFieldMetadata idFieldMetaData = idPropertyMetadata.getFieldMetadata( idFieldName );
if ( fieldName.equals( idFieldMetaData.getName() ) ) {
return objectToString(
getIdBridge(),
idFieldMetaData.getName(),
value,
conversionContext
);
final DocumentFieldMetadata idFieldMetaData = idPropertyMetadata.getFieldMetadata( idFieldName );
final FieldBridge bridge = fieldName.equals( idFieldMetaData.getName() ) ?
getIdBridge() :
getBridge( getMetadata(), fieldName );

if ( bridge != null ) {
return objectToString( fieldName, bridge, value, conversionContext );
}

throw new SearchException( "Unable to find field " + fieldName + " in " + getBeanXClass() );
}

public String objectToString(String fieldName, FieldBridge bridge, Object value, ConversionContext conversionContext) {
if ( fieldName == null ) {
throw new AssertionFailure( "Field name should not be null" );
}
if ( bridge == null ) {
throw new AssertionFailure( "Field bridge should not be null" );
}

final Class<? extends FieldBridge> bridgeClass = bridge.getClass();

if ( TwoWayFieldBridge.class.isAssignableFrom( bridgeClass ) ) {
return objectToString( (TwoWayFieldBridge) bridge, fieldName, value, conversionContext );
}
else if ( StringBridge.class.isAssignableFrom( bridgeClass ) ) {
return objectToString( (StringBridge) bridge, fieldName, value, conversionContext );
}
else {
FieldBridge bridge = getBridge( getMetadata(), fieldName );
if ( bridge != null ) {
final Class<? extends FieldBridge> bridgeClass = bridge.getClass();
if ( TwoWayFieldBridge.class.isAssignableFrom( bridgeClass ) ) {
return objectToString( (TwoWayFieldBridge) bridge, fieldName, value, conversionContext );
}
else if ( StringBridge.class.isAssignableFrom( bridgeClass ) ) {
return objectToString( (StringBridge) bridge, fieldName, value, conversionContext );
}
throw log.fieldBridgeNotTwoWay( bridgeClass, fieldName, getBeanXClass() );
}
throw log.fieldBridgeNotTwoWay( bridgeClass, fieldName, getBeanXClass() );
}
throw new SearchException( "Unable to find field " + fieldName + " in " + getBeanXClass() );
}

private FieldBridge getNullBridge(EmbeddedTypeMetadata embeddedTypeMetadata, String fieldName) {
Expand Down
Expand Up @@ -92,13 +92,13 @@ public Query createQuery() {
}

private Query createQuery(FieldContext fieldContext, ConversionContext conversionContext) {
Query perFieldQuery;
final Query perFieldQuery;
final String fieldName = fieldContext.getField();
final Analyzer queryAnalyzer = queryContext.getQueryAnalyzer();

final DocumentBuilderIndexedEntity<?> documentBuilder = Helper.getDocumentBuilder( queryContext );

FieldBridge fieldBridge = documentBuilder.getBridge( fieldContext.getField() );
final FieldBridge fieldBridge = fieldContext.getFieldBridge() != null ? fieldContext.getFieldBridge() : documentBuilder.getBridge( fieldContext.getField() );

final Object fromObject = rangeContext.getFrom();
final Object toObject = rangeContext.getTo();
Expand All @@ -113,16 +113,12 @@ private Query createQuery(FieldContext fieldContext, ConversionContext conversio
);
}
else {
final String fromString = fieldContext.isIgnoreFieldBridge() ?
fromObject == null ? null : fromObject.toString() :
documentBuilder.objectToString( fieldName, fromObject, conversionContext );
final String fromString = fieldContext.objectToString( documentBuilder, fromObject, conversionContext );
final String lowerTerm = fromString == null ?
null :
Helper.getAnalyzedTerm( fieldName, fromString, "from", queryAnalyzer, fieldContext );

final String toString = fieldContext.isIgnoreFieldBridge() ?
toObject == null ? null : toObject.toString() :
documentBuilder.objectToString( fieldName, toObject, conversionContext );
final String toString = fieldContext.objectToString( documentBuilder, toObject, conversionContext );
final String upperTerm = toString == null ?
null :
Helper.getAnalyzedTerm( fieldName, toString, "to", queryAnalyzer, fieldContext );
Expand Down
Expand Up @@ -36,7 +36,6 @@
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.WildcardQuery;

import org.hibernate.annotations.common.AssertionFailure;
import org.hibernate.search.SearchException;
import org.hibernate.search.bridge.FieldBridge;
Expand Down Expand Up @@ -93,12 +92,12 @@ public Query createQuery() {
private Query createQuery(FieldContext fieldContext, ConversionContext conversionContext) {
final Query perFieldQuery;
final DocumentBuilderIndexedEntity<?> documentBuilder = Helper.getDocumentBuilder( queryContext );
FieldBridge fieldBridge = documentBuilder.getBridge( fieldContext.getField() );
final FieldBridge fieldBridge = fieldContext.getFieldBridge() != null ? fieldContext.getFieldBridge() : documentBuilder.getBridge( fieldContext.getField() );
if ( fieldBridge instanceof NumericFieldBridge ) {
return NumericFieldUtils.createExactMatchQuery( fieldContext.getField(), value );
}

String searchTerm = buildSearchTerm( fieldContext, documentBuilder, conversionContext );
final String searchTerm = buildSearchTerm( fieldContext, documentBuilder, conversionContext );

if ( fieldContext.isIgnoreAnalyzer() ) {
perFieldQuery = createTermQuery( fieldContext, searchTerm );
Expand Down Expand Up @@ -144,7 +143,7 @@ private String buildSearchTerm(FieldContext fieldContext, DocumentBuilderIndexed
}
else {
// need to go via the appropriate bridge, because value is an object, eg boolean, and must be converted to a string first
return documentBuilder.objectToString( fieldContext.getField(), value, conversionContext );
return fieldContext.objectToString( documentBuilder, value, conversionContext );
}
}

Expand Down
Expand Up @@ -27,13 +27,14 @@
import java.util.ArrayList;
import java.util.List;

import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.query.dsl.RangeMatchingContext;
import org.hibernate.search.query.dsl.RangeTerminationExcludable;

/**
* @author Emmanuel Bernard
*/
public class ConnectedRangeMatchingContext implements RangeMatchingContext {
public class ConnectedRangeMatchingContext implements RangeMatchingContext, FieldBridgeCustomization<RangeMatchingContext> {
private final QueryBuildingContext queryContext;
private final QueryCustomizer queryCustomizer;
private final RangeQueryContext rangeContext;
Expand Down Expand Up @@ -66,7 +67,7 @@ public <T> FromRangeContext<T> from(T from) {
}

static class ConnectedFromRangeContext<T> implements FromRangeContext<T> {
private ConnectedRangeMatchingContext mother;
private final ConnectedRangeMatchingContext mother;

ConnectedFromRangeContext(ConnectedRangeMatchingContext mother) {
this.mother = mother;
Expand Down Expand Up @@ -128,4 +129,12 @@ public RangeMatchingContext ignoreFieldBridge() {
}
return this;
}

@Override
public RangeMatchingContext withFieldBridge(FieldBridge fieldBridge) {
for ( FieldContext fieldContext : getCurrentFieldContexts() ) {
fieldContext.setFieldBridge( fieldBridge );
}
return this;
}
}
Expand Up @@ -27,13 +27,14 @@
import java.util.ArrayList;
import java.util.List;

import org.hibernate.search.query.dsl.TermTermination;
import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.query.dsl.TermMatchingContext;
import org.hibernate.search.query.dsl.TermTermination;

/**
* @author Emmanuel Bernard
*/
public class ConnectedTermMatchingContext implements TermMatchingContext {
public class ConnectedTermMatchingContext implements TermMatchingContext, FieldBridgeCustomization<TermMatchingContext> {
private final QueryBuildingContext queryContext;
private final QueryCustomizer queryCustomizer;
private final TermQueryContext termContext;
Expand Down Expand Up @@ -101,4 +102,12 @@ public TermMatchingContext ignoreFieldBridge() {
}
return this;
}

@Override
public TermMatchingContext withFieldBridge(FieldBridge fieldBridge) {
for ( FieldContext fieldContext : getCurrentFieldContexts() ) {
fieldContext.setFieldBridge( fieldBridge );
}
return this;
}
}
@@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/

package org.hibernate.search.query.dsl.impl;

import org.hibernate.search.bridge.FieldBridge;

/**
* Customization context which allows to inject a field bridge instance to be used for querying the current field.
* <p>
* Not part of the public DSL API for the time being in order to gain experiences with using the functionality first;
* may be made public in a future release by merging with {@code FieldCustomization}.
*
* @author Gunnar Morling
*/
public interface FieldBridgeCustomization<T> {

/**
* Sets the field bridge for querying the current field; any other bridge associated with this field will be ignored
* for the query
*
* @param fieldBridge the field bridge to use
* @return this object, following the method chaining pattern
*/
T withFieldBridge(FieldBridge fieldBridge);
}
Expand Up @@ -24,6 +24,10 @@

package org.hibernate.search.query.dsl.impl;

import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.bridge.spi.ConversionContext;
import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity;

/**
* @author Emmanuel Bernard
*/
Expand All @@ -32,6 +36,7 @@ public class FieldContext {
private boolean ignoreAnalyzer;
private final QueryCustomizer fieldCustomizer;
private boolean ignoreFieldBridge;
private FieldBridge fieldBridge;

public FieldContext(String field) {
this.field = field;
Expand Down Expand Up @@ -61,4 +66,24 @@ public boolean isIgnoreFieldBridge() {
public void setIgnoreFieldBridge(boolean ignoreFieldBridge) {
this.ignoreFieldBridge = ignoreFieldBridge;
}

public void setFieldBridge(FieldBridge fieldBridge) {
this.fieldBridge = fieldBridge;
}

public FieldBridge getFieldBridge() {
return fieldBridge;
}

public String objectToString(DocumentBuilderIndexedEntity<?> documentBuilder, Object value, ConversionContext conversionContext) {
if ( isIgnoreFieldBridge() ) {
return value == null ? null : value.toString();
}
else if ( fieldBridge != null ) {
return documentBuilder.objectToString( field, fieldBridge, value, conversionContext );
}
else {
return documentBuilder.objectToString( field, value, conversionContext );
}
}
}
43 changes: 43 additions & 0 deletions orm/src/test/java/org/hibernate/search/test/query/dsl/DSLTest.java
Expand Up @@ -48,9 +48,11 @@
import org.hibernate.search.Search;
import org.hibernate.search.SearchException;
import org.hibernate.search.annotations.Factory;
import org.hibernate.search.bridge.builtin.impl.String2FieldBridgeAdaptor;
import org.hibernate.search.cfg.SearchMapping;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.hibernate.search.query.dsl.Unit;
import org.hibernate.search.query.dsl.impl.ConnectedTermMatchingContext;
import org.hibernate.search.spatial.Coordinates;
import org.hibernate.search.spatial.impl.Point;
import org.hibernate.search.test.SearchTestCase;
Expand Down Expand Up @@ -101,6 +103,47 @@ public void testUseOfFieldBridge() throws Exception {
transaction.commit();
}

public void testUseOfCustomFieldBridgeInstance() throws Exception {
Transaction transaction = fullTextSession.beginTransaction();
final QueryBuilder monthQb = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity( Month.class ).get();

ConnectedTermMatchingContext termMatchingContext = (ConnectedTermMatchingContext) monthQb
.keyword()
.onField( MonthClassBridge.FIELD_NAME_1 );

Query query = termMatchingContext
.withFieldBridge( new String2FieldBridgeAdaptor( new RomanNumberFieldBridge() ) )
.matching( 2 )
.createQuery();

assertEquals( 1, fullTextSession.createFullTextQuery( query, Month.class ).getResultSize() );
transaction.commit();
}

public void testUseOfMultipleCustomFieldBridgeInstances() throws Exception {
Transaction transaction = fullTextSession.beginTransaction();
final QueryBuilder monthQb = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity( Month.class ).get();

//Rather complex code here as we're not exposing the #withFieldBridge methods on the public interface
final ConnectedTermMatchingContext field1Context = (ConnectedTermMatchingContext) monthQb
.keyword()
.onField( MonthClassBridge.FIELD_NAME_1 );

final ConnectedTermMatchingContext field2Context = (ConnectedTermMatchingContext) field1Context
.withFieldBridge( new String2FieldBridgeAdaptor( new RomanNumberFieldBridge() ) )
.andField( MonthClassBridge.FIELD_NAME_2 );

Query query = field2Context
.withFieldBridge( new String2FieldBridgeAdaptor( new RomanNumberFieldBridge() ) )
.matching( 2 )
.createQuery();

assertEquals( 1, fullTextSession.createFullTextQuery( query, Month.class ).getResultSize() );
transaction.commit();
}

public void testTermQueryOnAnalyzer() throws Exception {
Transaction transaction = fullTextSession.beginTransaction();
final QueryBuilder monthQb = fullTextSession.getSearchFactory()
Expand Down
Expand Up @@ -25,12 +25,14 @@
package org.hibernate.search.test.query.dsl;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.ClassBridge;
import org.hibernate.search.annotations.DateBridge;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.FieldBridge;
Expand All @@ -45,6 +47,7 @@
*/
@Entity
@Indexed
@ClassBridge(impl = MonthClassBridge.class)
public class Month {

public Month() {
Expand Down

0 comments on commit 180e395

Please sign in to comment.