/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* 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>.
*/
package org.hibernate.ogm.datastore.infinispanremote.impl.schema;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.mapping.Column;
import org.hibernate.ogm.datastore.infinispanremote.impl.protobuf.CompositeProtobufCoDec;
import org.hibernate.ogm.datastore.infinispanremote.impl.protobuf.ProtofieldAccessorSet;
import org.hibernate.ogm.datastore.infinispanremote.impl.protobuf.SchemaDefinitions;
import org.hibernate.ogm.datastore.infinispanremote.impl.protobuf.TypeDeclarationsCollector;
import org.hibernate.ogm.datastore.infinispanremote.impl.protostream.OgmProtoStreamMarshaller;
import org.hibernate.ogm.datastore.infinispanremote.impl.protostream.ProtoDataMapper;
import org.hibernate.ogm.datastore.infinispanremote.impl.protostream.ProtostreamSerializerSetup;
import org.hibernate.ogm.datastore.infinispanremote.logging.impl.Log;
import org.hibernate.ogm.datastore.infinispanremote.logging.impl.LoggerFactory;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.type.Type;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.protostream.DescriptorParserException;
import org.infinispan.protostream.SerializationContext;
public final class TableDefinition implements ProtobufTypeExporter, ProtobufEntryExporter {
private static final Log log = LoggerFactory.getLogger();
private final String tableName;
private final String protobufTypeName;
private final String protobufIdTypeName;
private final String protobufPackageName;
private final ProtofieldAccessorSet keyComponents = new ProtofieldAccessorSet();
private final ProtofieldAccessorSet valueComponents = new ProtofieldAccessorSet();
private final Set<String> pkColumnNames = new HashSet<>();
public TableDefinition(String name, String protobufPackageName) {
this.tableName = name;
this.protobufTypeName = SanitationUtils.convertNameSafely( name );
this.protobufIdTypeName = SanitationUtils.toProtobufIdName( protobufTypeName );
this.protobufPackageName = protobufPackageName;
}
public void addColumnnDefinition(Column column, GridType gridType, Type ormType) {
//final boolean nullable = column.isNullable(); //Seems not reliable for FKs, don't use this to determine nullability.
final String name = column.getName();
if ( pkColumnNames.contains( name ) ) {
keyComponents.addMapping( name, gridType, ormType, false );
valueComponents.addMapping( name, gridType, ormType, false );
}
else {
valueComponents.addMapping( name, gridType, ormType, true );
}
}
@Override
public void exportProtobufEntry(StringBuilder output) {
exportProtobufEntry( protobufIdTypeName, keyComponents, output );
exportProtobufEntry( protobufTypeName, valueComponents, output );
}
private void exportProtobufEntry(String typeName, ProtofieldAccessorSet fields, StringBuilder sb) {
sb.append( "\nmessage " ).append( typeName ).append( " {" );
fields.forEachProtobufFieldExporter( v -> v.exportProtobufFieldDefinition( sb ) );
sb.append( "\n}\n" );
}
@Override
public void collectTypeDefinitions(TypeDeclarationsCollector typesDefCollector) {
keyComponents.forEach( v -> v.collectTypeDefinitions( typesDefCollector ) );
valueComponents.forEach( v -> v.collectTypeDefinitions( typesDefCollector ) );
}
public ProtoDataMapper createProtoDataMapper(RemoteCache remoteCache,
SchemaDefinitions sd, OgmProtoStreamMarshaller marshaller) {
try {
CompositeProtobufCoDec codec = new CompositeProtobufCoDec( tableName,
qualify( protobufTypeName ), qualify( protobufIdTypeName ),
keyComponents, valueComponents, remoteCache, sd );
SerializationContext serializationContext = ProtostreamSerializerSetup.buildSerializationContext( sd, codec );
return new ProtoDataMapper( codec, serializationContext, marshaller );
}
catch (DescriptorParserException | IOException e) {
throw new RuntimeException( e );
}
}
private String qualify(final String name) {
return SanitationUtils.qualify( name, protobufPackageName );
}
public String getTableName() {
return tableName;
}
public void markAsPrimaryKey(String name) {
pkColumnNames.add( name );
}
public void validate() {
//This is triggered by certain Bag collection types:
//we can't support mapping w/o a primary key
//as they can't be mapped on a K/V system.
//The user can avoid the error by picking some ordering strategy.
if ( pkColumnNames.isEmpty() ) {
throw log.tableHasNoPrimaryKey( tableName );
}
}
}