diff --git a/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/DistanceSearchProjectionTypeCheckingAndConversionIT.java b/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/DistanceSearchProjectionTypeCheckingAndConversionIT.java index a2b193c8289..13ee020684a 100644 --- a/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/DistanceSearchProjectionTypeCheckingAndConversionIT.java +++ b/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/DistanceSearchProjectionTypeCheckingAndConversionIT.java @@ -55,6 +55,7 @@ public class DistanceSearchProjectionTypeCheckingAndConversionIT { private static final String COMPATIBLE_INDEX_DOCUMENT_1 = "compatible_1"; private static final String RAW_FIELD_COMPATIBLE_INDEX_DOCUMENT_1 = "raw_field_compatible_1"; + private static final String MISSING_FIELD_INDEX_DOCUMENT_1 = "missing_field_1"; @ClassRule public static final SearchSetupHelper setupHelper = new SearchSetupHelper(); @@ -65,13 +66,15 @@ public class DistanceSearchProjectionTypeCheckingAndConversionIT { SimpleMappedIndex.of( CompatibleIndexBinding::new ).name( "compatible" ); private static final SimpleMappedIndex rawFieldCompatibleIndex = SimpleMappedIndex.of( RawFieldCompatibleIndexBinding::new ).name( "rawFieldCompatible" ); + private static final SimpleMappedIndex missingFieldIndex = + SimpleMappedIndex.of( MissingFieldIndexBinding::new ).name( "missingField" ); private static final SimpleMappedIndex incompatibleIndex = SimpleMappedIndex.of( IncompatibleIndexBinding::new ).name( "incompatible" ); @BeforeClass public static void setup() { setupHelper.start() - .withIndexes( mainIndex, compatibleIndex, rawFieldCompatibleIndex, incompatibleIndex ) + .withIndexes( mainIndex, compatibleIndex, rawFieldCompatibleIndex, missingFieldIndex, incompatibleIndex ) .setup(); initData(); @@ -203,6 +206,26 @@ public void multiIndex_withRawFieldCompatibleIndex() { ); } + @Test + @TestForIssue(jiraKey = "HSEARCH-4173") + public void multiIndex_withMissingFieldIndex() { + StubMappingScope scope = mainIndex.createScope( missingFieldIndex ); + + assertThatQuery( scope.query() + .select( f -> f.distance( getFieldWithConverterPath(), CENTER_POINT_1 ) ) + .where( f -> f.matchAll() ) + .toQuery() ) + .hits().asIs() + .usingElementComparator( TestComparators.APPROX_M_COMPARATOR ) + .containsExactlyInAnyOrder( + getFieldDistance( 1 ), + getFieldDistance( 2 ), + getFieldDistance( 3 ), + null, // Empty document + null // From the "missing field" index + ); + } + @Test public void multiIndex_withIncompatibleIndex() { StubMappingScope scope = mainIndex.createScope( incompatibleIndex ); @@ -284,7 +307,9 @@ private static void initData() { BulkIndexer rawFieldCompatibleIndexer = rawFieldCompatibleIndex.bulkIndexer() .add( RAW_FIELD_COMPATIBLE_INDEX_DOCUMENT_1, document -> addFieldValue( document, rawFieldCompatibleIndex.binding().fieldWithConverterModel, 1 ) ); - mainIndexer.join( compatibleIndexer, rawFieldCompatibleIndexer ); + BulkIndexer missingFieldIndexer = missingFieldIndex.bulkIndexer() + .add( MISSING_FIELD_INDEX_DOCUMENT_1, document -> { } ); + mainIndexer.join( compatibleIndexer, rawFieldCompatibleIndexer, missingFieldIndexer ); } private static class IndexBinding { @@ -389,6 +414,11 @@ public ValueWrapper convert(Object value, FromDocumentFieldValueConvertContext c } } + private static class MissingFieldIndexBinding { + MissingFieldIndexBinding(IndexSchemaElement root) { + } + } + private static class IncompatibleIndexBinding { final ObjectBinding flattenedObject; diff --git a/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/FieldSearchProjectionTypeCheckingAndConversionIT.java b/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/FieldSearchProjectionTypeCheckingAndConversionIT.java index 2f7ea82a4f5..0815e955785 100644 --- a/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/FieldSearchProjectionTypeCheckingAndConversionIT.java +++ b/integrationtest/backend/tck/src/main/java/org/hibernate/search/integrationtest/backend/tck/search/projection/FieldSearchProjectionTypeCheckingAndConversionIT.java @@ -67,6 +67,7 @@ public static Object[][] parameters() { private static final String COMPATIBLE_INDEX_DOCUMENT_1 = "compatible_1"; private static final String RAW_FIELD_COMPATIBLE_INDEX_DOCUMENT_1 = "raw_field_compatible_1"; + private static final String MISSING_FIELD_INDEX_DOCUMENT_1 = "missing_field_1"; @ClassRule public static final SearchSetupHelper setupHelper = new SearchSetupHelper(); @@ -77,13 +78,15 @@ public static Object[][] parameters() { SimpleMappedIndex.of( CompatibleIndexBinding::new ).name( "compatible" ); private static final SimpleMappedIndex rawFieldCompatibleIndex = SimpleMappedIndex.of( RawFieldCompatibleIndexBinding::new ).name( "rawFieldCompatible" ); + private static final SimpleMappedIndex missingFieldIndex = + SimpleMappedIndex.of( MissingFieldIndexBinding::new ).name( "missingField" ); private static final SimpleMappedIndex incompatibleIndex = SimpleMappedIndex.of( IncompatibleIndexBinding::new ).name( "incompatible" ); @BeforeClass public static void setup() { setupHelper.start() - .withIndexes( mainIndex, compatibleIndex, rawFieldCompatibleIndex, incompatibleIndex ) + .withIndexes( mainIndex, compatibleIndex, rawFieldCompatibleIndex, missingFieldIndex, incompatibleIndex ) .setup(); initData(); @@ -361,6 +364,46 @@ public void multiIndex_withRawFieldCompatibleIndex_projectionConverterDisabled() ); } + @Test + @TestForIssue(jiraKey = "HSEARCH-4173") + public void multiIndex_withMissingFieldIndex_projectionConverterEnabled() { + StubMappingScope scope = mainIndex.createScope( missingFieldIndex ); + + String fieldPath = getFieldWithConverterPath(); + + assertThatQuery( scope.query() + .select( f -> f.field( fieldPath, ValueWrapper.class ) ) + .where( f -> f.matchAll() ) + .toQuery() ) + .hasHitsAnyOrder( + new ValueWrapper( getFieldValue( 1 ) ), + new ValueWrapper( getFieldValue( 2 ) ), + new ValueWrapper( getFieldValue( 3 ) ), + new ValueWrapper( null ), // Empty document + new ValueWrapper( null ) // From the "missing field" index + ); + } + + @Test + @TestForIssue(jiraKey = "HSEARCH-4173") + public void multiIndex_withMissingFieldIndex_projectionConverterDisabled() { + StubMappingScope scope = mainIndex.createScope( missingFieldIndex ); + + String fieldPath = getFieldWithConverterPath(); + + assertThatQuery( scope.query() + .select( f -> f.field( fieldPath, fieldType.getJavaType(), ValueConvert.NO ) ) + .where( f -> f.matchAll() ) + .toQuery() ) + .hasHitsAnyOrder( + getFieldValue( 1 ), + getFieldValue( 2 ), + getFieldValue( 3 ), + null, // Empty document + null // From the "missing field" index + ); + } + @Test public void multiIndex_withIncompatibleIndex_projectionConverterEnabled() { StubMappingScope scope = mainIndex.createScope( incompatibleIndex ); @@ -459,7 +502,9 @@ private static void initData() { .add( RAW_FIELD_COMPATIBLE_INDEX_DOCUMENT_1, document -> rawFieldCompatibleIndex.binding().fieldWithConverterModels .forEach( f -> addFieldValue( document, f, 1 ) ) ); - mainIndexer.join( compatibleIndexer, rawFieldCompatibleIndexer ); + BulkIndexer missingFieldIndexer = missingFieldIndex.bulkIndexer() + .add( MISSING_FIELD_INDEX_DOCUMENT_1, document -> { } ); + mainIndexer.join( compatibleIndexer, rawFieldCompatibleIndexer, missingFieldIndexer ); } private static class IndexBinding { @@ -566,6 +611,11 @@ public ValueWrapper convert(Object value, FromDocumentFieldValueConvertContext c } } + private static class MissingFieldIndexBinding { + MissingFieldIndexBinding(IndexSchemaElement root) { + } + } + private static class IncompatibleIndexBinding { final ObjectBinding flattenedObject;