Skip to content

Commit

Permalink
HSEARCH-1383 Add support for dynamic types
Browse files Browse the repository at this point in the history
  • Loading branch information
marko-bekhta committed May 2, 2023
1 parent 850f137 commit 16ed0e3
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package org.hibernate.search.integrationtest.mapper.orm.automaticindexing;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Basic;
Expand All @@ -18,10 +19,13 @@
import javax.persistence.OneToMany;

import org.hibernate.search.mapper.orm.Search;
import org.hibernate.search.mapper.orm.cfg.HibernateOrmMapperSettings;
import org.hibernate.search.mapper.orm.mapping.HibernateOrmSearchMappingConfigurer;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded;
import org.hibernate.search.mapper.pojo.mapping.definition.programmatic.TypeMappingStep;
import org.hibernate.search.util.impl.integrationtest.common.rule.BackendMock;
import org.hibernate.search.util.impl.integrationtest.mapper.orm.OrmSetupHelper;
import org.hibernate.search.util.impl.integrationtest.mapper.orm.ReusableOrmSetupHolder;
Expand All @@ -41,6 +45,9 @@ public abstract class AbstractIndexingPlanFilterIT {

@Rule
public MethodRule setupHolderMethodRule = setupHolder.methodRule();
protected static final String DYNAMIC_BASE_TYPE_A = "DynamicA";
protected static final String DYNAMIC_SUBTYPE_B = "DynamicA_B";
protected static final String DYNAMIC_SUBTYPE_C = "DynamicA_C";

@ReusableOrmSetupHolder.Setup
public void setup(OrmSetupHelper.SetupContext setupContext) {
Expand All @@ -67,6 +74,35 @@ public void setup(OrmSetupHelper.SetupContext setupContext) {
EntityA.class, Entity1A.class, Entity1B.class, Entity2A.class, EntityFromSuperclass.class, SuperClass.class,
SimpleNotIndexedEntity.class, NotIndexedEntityFromSuperclass.class
);

// Add dynamic type mappings:
String hbmPath = "/AbstractIndexingPlanFilterIT/inheritance.hbm.xml";

setupContext.withConfiguration( builder -> builder.addHbmFromClassPath( hbmPath ) )
.withProperty(
HibernateOrmMapperSettings.MAPPING_CONFIGURER,
(HibernateOrmSearchMappingConfigurer) context -> {
TypeMappingStep entityATypeMapping = context.programmaticMapping().type( DYNAMIC_BASE_TYPE_A );
entityATypeMapping.indexed();
entityATypeMapping.property( "propertyOfA" ).genericField();

TypeMappingStep entityA_BTypeMapping = context.programmaticMapping().type( DYNAMIC_SUBTYPE_B );
entityA_BTypeMapping.indexed();
entityA_BTypeMapping.property( "propertyOfB" ).genericField();

TypeMappingStep entityA_CTypeMapping = context.programmaticMapping().type( DYNAMIC_SUBTYPE_C );
entityA_CTypeMapping.indexed();
entityA_CTypeMapping.property( "propertyOfC" ).genericField();
}
);
backendMock.expectSchema( DYNAMIC_BASE_TYPE_A, b -> b
.field( "propertyOfA", String.class ) )
.expectSchema( DYNAMIC_SUBTYPE_B, b -> b
.field( "propertyOfA", String.class )
.field( "propertyOfB", Integer.class ) )
.expectSchema( DYNAMIC_SUBTYPE_C, b -> b
.field( "propertyOfA", String.class )
.field( "propertyOfC", LocalDate.class ) );
}

@Before
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@

import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.hibernate.search.mapper.orm.Search;
import org.hibernate.search.util.common.SearchException;
Expand Down Expand Up @@ -446,4 +450,72 @@ public void filterByInterfaceMustFail() {
);
} );
}

@Test
public void dynamicTypeByNameDirectPersistUpdateDelete() {
setupHolder.runInTransaction( session -> {
Search.session( session ).indexingPlanFilter( ctx -> ctx.exclude( DYNAMIC_BASE_TYPE_A ) );

Map<String, Object> entity1 = new HashMap<>();
entity1.put( "id", 1 );
entity1.put( "propertyOfA", "string1" );
entity1.put( "propertyOfB", 1 );

Map<String, Object> entity2 = new HashMap<>();
entity2.put( "id", 2 );
entity2.put( "propertyOfA", "string2" );
entity2.put( "propertyOfC", LocalDate.of( 2023, Month.MAY, 2 ) );

session.persist( DYNAMIC_SUBTYPE_B, entity1 );
session.persist( DYNAMIC_SUBTYPE_C, entity2 );
} );
backendMock.verifyExpectationsMet();

setupHolder.runInTransaction( session -> {
Search.session( session ).indexingPlanFilter( ctx -> ctx.exclude( DYNAMIC_BASE_TYPE_A ) );

Map entity1 = (Map) session.get( DYNAMIC_SUBTYPE_B, 1 );
entity1.put( "propertyOfA", "updatedValue" );

} );
backendMock.verifyExpectationsMet();

setupHolder.runInTransaction( session -> {
Search.session( session ).indexingPlanFilter( ctx -> ctx.exclude( DYNAMIC_BASE_TYPE_A ) );

session.remove( session.get( DYNAMIC_SUBTYPE_B, 1 ) );
session.remove( session.get( DYNAMIC_SUBTYPE_C, 2 ) );

} );
backendMock.verifyExpectationsMet();
}

@Test
public void dynamicTypeByNameApplicationDisableAllSessionEnableSubtype() {
Search.mapping( setupHolder.entityManagerFactory() ).indexingPlanFilter(
ctx -> ctx.exclude( DYNAMIC_BASE_TYPE_A )
);
setupHolder.runInTransaction( session -> {
Search.session( session ).indexingPlanFilter( ctx -> ctx.include( DYNAMIC_SUBTYPE_B ) );

Map<String, Object> entity1 = new HashMap<>();
entity1.put( "id", 1 );
entity1.put( "propertyOfA", "string1" );
entity1.put( "propertyOfB", 1 );

Map<String, Object> entity2 = new HashMap<>();
entity2.put( "id", 2 );
entity2.put( "propertyOfA", "string2" );
entity2.put( "propertyOfC", LocalDate.of( 2023, Month.MAY, 2 ) );

session.persist( DYNAMIC_SUBTYPE_B, entity1 );
session.persist( DYNAMIC_SUBTYPE_C, entity2 );

backendMock.expectWorks( DYNAMIC_SUBTYPE_B )
.add( "1", b -> b.field( "propertyOfA", "string1" )
.field( "propertyOfB", 1 ) );
} );
backendMock.verifyExpectationsMet();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate Search, full-text search for your domain model
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class entity-name="DynamicA">
<id name="id" type="integer"/>
<discriminator />
<property name="propertyOfA" type="string"/>
<subclass entity-name="DynamicA_B">
<property name="propertyOfB" type="integer"/>
</subclass>
<subclass entity-name="DynamicA_C">
<property name="propertyOfC" type="LocalDate"/>
</subclass>
</class>
</hibernate-mapping>
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public <E> void addIndexed(PojoRawTypeModel<E> typeModel, PojoIndexedTypeManager
.forEach( clazz -> {
indexedBySuperType.computeIfAbsent( clazz, ignored -> new LinkedHashSet<>() )
.add( typeManager );
if ( !clazz.javaClass().isInterface() ) {
if ( clazz.isNamed() || !clazz.javaClass().isInterface() ) {
allByNonInterfaceSuperType.computeIfAbsent( clazz, ignored -> new LinkedHashSet<>() )
.add( typeManager );
}
Expand All @@ -168,7 +168,7 @@ public <E> void addContained(PojoRawTypeModel<E> typeModel, PojoContainedTypeMan
contained.add( typeManager );
typeModel.descendingSuperTypes()
.map( PojoRawTypeModel::typeIdentifier )
.filter( clazz -> !clazz.javaClass().isInterface() )
.filter( clazz -> clazz.isNamed() || !clazz.javaClass().isInterface() )
.forEach( clazz -> allByNonInterfaceSuperType.computeIfAbsent( clazz, ignored -> new LinkedHashSet<>() )
.add( typeManager ) );
}
Expand Down

0 comments on commit 16ed0e3

Please sign in to comment.