Skip to content

Commit

Permalink
#50 - Pre-process and categorize id mappings from EntityHierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
sebersole committed Oct 24, 2023
1 parent 1e4cce3 commit 89a2a01
Show file tree
Hide file tree
Showing 15 changed files with 743 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.internal;

/**
* A consumer, like {@link java.util.function.Consumer}, accepting a key and a value (Map entry e.g.)
*
* @author Christian Beikov
* @author Steve Ebersole
*/
@FunctionalInterface
public interface KeyedConsumer<K,V> {
void accept(K key, V value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.orm.bind.internal;

import java.util.function.Supplier;

import org.hibernate.mapping.Column;
import org.hibernate.models.orm.spi.OrmModelBuildingContext;
import org.hibernate.models.source.spi.AnnotationUsage;

import static org.hibernate.internal.util.NullnessHelper.nullif;

/**
* @author Steve Ebersole
*/
public class ColumnBinder {
public static Column bindColumn(
AnnotationUsage<?> annotationUsage,
Supplier<String> defaultNameSupplier,
OrmModelBuildingContext modelBuildingContext) {
return bindColumn(
annotationUsage,
defaultNameSupplier,
false,
true,
255,
0,
0,
modelBuildingContext
);
}

public static Column bindColumn(
AnnotationUsage<?> annotationUsage,
Supplier<String> defaultNameSupplier,
boolean uniqueByDefault,
boolean nullableByDefault,
long lengthByDefault,
int precisionByDefault,
int scaleByDefault,
OrmModelBuildingContext modelBuildingContext) {
final Column result = new Column();
result.setName( columnName( annotationUsage, defaultNameSupplier, modelBuildingContext ) );

result.setUnique( annotationUsage.getBoolean( "unique", uniqueByDefault ) );
result.setNullable( annotationUsage.getBoolean( "nullable", nullableByDefault ) );
result.setSqlType( annotationUsage.getString( "columnDefinition" ) );
result.setLength( annotationUsage.getLong( "length", lengthByDefault ) );
result.setPrecision( annotationUsage.getInteger( "precision", precisionByDefault ) );
result.setScale( annotationUsage.getInteger( "scale", scaleByDefault ) );
return result;
}


private static String columnName(
AnnotationUsage<?> columnAnnotation,
Supplier<String> defaultNameSupplier,
OrmModelBuildingContext modelBuildingContext) {
return nullif( columnAnnotation.getAttributeValue( "name" ), defaultNameSupplier );
}

private ColumnBinder() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.orm.bind.internal;

/**
* @author Steve Ebersole
*/
public class EntityBinder {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.orm.bind.internal;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.hibernate.annotations.TenantId;
import org.hibernate.models.ModelsException;
import org.hibernate.models.internal.CollectionHelper;
import org.hibernate.models.orm.spi.AttributeMetadata;
import org.hibernate.models.orm.spi.EntityHierarchy;
import org.hibernate.models.orm.spi.EntityTypeMetadata;
import org.hibernate.models.orm.spi.OrmModelBuildingContext;
import org.hibernate.models.orm.spi.ProcessResult;
import org.hibernate.models.source.spi.AnnotationUsage;
import org.hibernate.models.source.spi.MemberDetails;

import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Id;
import jakarta.persistence.Version;

/**
* Processes attributes which are conceptually at the level of the hierarchy - id, version, tenant-id
*
* @author Steve Ebersole
*/
public class HierarchyAttributeProcessor {
public static List<HierarchyAttributeDescriptor> preBindHierarchyAttributes(
ProcessResult processResult,
OrmModelBuildingContext modelBuildingContext) {
final Set<EntityHierarchy> entityHierarchies = processResult.getEntityHierarchies();
final List<HierarchyAttributeDescriptor> hierarchyIdMembers = CollectionHelper.arrayList( entityHierarchies.size() );

for ( EntityHierarchy hierarchy : entityHierarchies ) {
final HierarchyAttributeDescriptor hierarchyAttributeDescriptor = new HierarchyAttributeDescriptor( hierarchy );
hierarchyIdMembers.add( hierarchyAttributeDescriptor );

final EntityTypeMetadata hierarchyRoot = hierarchy.getRoot();
for ( AttributeMetadata attr : hierarchyRoot.getAttributes() ) {
final MemberDetails attrMember = attr.getMember();
final AnnotationUsage<EmbeddedId> eIdAnn = attrMember.getAnnotationUsage( EmbeddedId.class );
if ( eIdAnn != null ) {
hierarchyAttributeDescriptor.collectIdAttribute( attr );
}

final AnnotationUsage<Id> idAnn = attrMember.getAnnotationUsage( Id.class );
if ( idAnn != null ) {
hierarchyAttributeDescriptor.collectIdAttribute( attr );
}

final AnnotationUsage<Version> versionAnn = attrMember.getAnnotationUsage( Version.class );
if ( versionAnn != null ) {
hierarchyAttributeDescriptor.collectVersionAttribute( attr );
}

final AnnotationUsage<TenantId> tenantIdAnn = attrMember.getAnnotationUsage( TenantId.class );
if ( tenantIdAnn != null ) {
hierarchyAttributeDescriptor.collectTenantIdAttribute( attr );
}
}
}

return hierarchyIdMembers;
}

public static class HierarchyAttributeDescriptor {
private final EntityHierarchy entityHierarchy;

private Object collectedIdAttributes;
private AttributeMetadata versionAttribute;
private AttributeMetadata tenantIdAttribute;

public HierarchyAttributeDescriptor(EntityHierarchy entityHierarchy) {
this.entityHierarchy = entityHierarchy;
}

public EntityHierarchy getEntityHierarchy() {
return entityHierarchy;
}

public Object getCollectedIdAttributes() {
return collectedIdAttributes;
}

public void collectIdAttribute(AttributeMetadata member) {
assert member != null;

if ( collectedIdAttributes == null ) {
collectedIdAttributes = member;
}
else if ( collectedIdAttributes instanceof List ) {
//noinspection unchecked,rawtypes
final List<AttributeMetadata> membersList = (List) collectedIdAttributes;
membersList.add( member );
}
else if ( collectedIdAttributes instanceof AttributeMetadata ) {
final ArrayList<AttributeMetadata> combined = new ArrayList<>();
combined.add( (AttributeMetadata) collectedIdAttributes );
combined.add( member );
collectedIdAttributes = combined;
}
}

public AttributeMetadata getVersionAttribute() {
return versionAttribute;
}

public void collectVersionAttribute(AttributeMetadata member) {
if ( versionAttribute != null ) {
throw new ModelsException( "Encountered multiple @Version attributes for hierarchy " + getEntityHierarchy().getRoot().getEntityName() );
}
versionAttribute = member;
}

public AttributeMetadata getTenantIdAttribute() {
return tenantIdAttribute;
}

public void collectTenantIdAttribute(AttributeMetadata member) {
if ( tenantIdAttribute != null ) {
throw new ModelsException( "Encountered multiple @TenantId attributes for hierarchy " + getEntityHierarchy().getRoot().getEntityName() );
}
tenantIdAttribute = member;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.orm.bind.internal;

import java.util.function.Supplier;

import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.Table;
import org.hibernate.models.orm.spi.OrmModelBuildingContext;
import org.hibernate.models.source.spi.AnnotationUsage;

import static org.hibernate.internal.util.NullnessHelper.nullif;

/**
* @author Steve Ebersole
*/
public class TableBinder {
public static Table bindTable(
AnnotationUsage<?> tableAnnotation,
Supplier<String> implicitTableNameSupplier,
boolean isAbstract,
MetadataBuildingContext metadataBuildingContext,
OrmModelBuildingContext modelBuildingContext) {
final InFlightMetadataCollector metadataCollector = metadataBuildingContext.getMetadataCollector();
return metadataCollector.addTable(
schemaName( tableAnnotation, metadataBuildingContext, modelBuildingContext ),
catalogName( tableAnnotation, metadataBuildingContext, modelBuildingContext ),
nullif( tableAnnotation.getString( "name" ), implicitTableNameSupplier ),
null,
isAbstract,
metadataBuildingContext
);
}

public static String catalogName(
AnnotationUsage<?> tableAnnotation,
MetadataBuildingContext metadataBuildingContext,
OrmModelBuildingContext modelBuildingContext) {
if ( tableAnnotation != null ) {
return tableAnnotation.getString( "catalog", metadataBuildingContext.getMappingDefaults().getImplicitCatalogName() );
}

return metadataBuildingContext.getMappingDefaults().getImplicitCatalogName();
}

public static String schemaName(
AnnotationUsage<?> tableAnnotation,
MetadataBuildingContext metadataBuildingContext,
OrmModelBuildingContext modelBuildingContext) {
if ( tableAnnotation != null ) {
return tableAnnotation.getString( "schema", metadataBuildingContext.getMappingDefaults().getImplicitSchemaName() );
}
return metadataBuildingContext.getMappingDefaults().getImplicitSchemaName();
}

private TableBinder() {
}
}
Loading

0 comments on commit 89a2a01

Please sign in to comment.