All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hibernate.ogm.datastore.neo4j.BaseNeo4jDialect Maven / Gradle / Ivy
/*
* 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 .
*/
package org.hibernate.ogm.datastore.neo4j;
import static org.hibernate.ogm.datastore.neo4j.query.parsing.cypherdsl.impl.CypherDSL.limit;
import static org.hibernate.ogm.datastore.neo4j.query.parsing.cypherdsl.impl.CypherDSL.skip;
import static org.hibernate.ogm.util.impl.EmbeddedHelper.isPartOfEmbedded;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.ogm.datastore.neo4j.dialect.impl.BaseNeo4jAssociationQueries;
import org.hibernate.ogm.datastore.neo4j.dialect.impl.BaseNeo4jEntityQueries;
import org.hibernate.ogm.datastore.neo4j.dialect.impl.BaseNeo4jTypeConverter;
import org.hibernate.ogm.datastore.neo4j.dialect.impl.DiscriminatorAwareKeyMetadata;
import org.hibernate.ogm.datastore.neo4j.query.impl.Neo4jParameterMetadataBuilder;
import org.hibernate.ogm.dialect.multiget.spi.MultigetGridDialect;
import org.hibernate.ogm.dialect.query.spi.BackendQuery;
import org.hibernate.ogm.dialect.query.spi.ParameterMetadataBuilder;
import org.hibernate.ogm.dialect.query.spi.QueryParameters;
import org.hibernate.ogm.dialect.query.spi.QueryableGridDialect;
import org.hibernate.ogm.dialect.query.spi.TypedGridValue;
import org.hibernate.ogm.dialect.spi.AssociationContext;
import org.hibernate.ogm.dialect.spi.AssociationTypeContext;
import org.hibernate.ogm.dialect.spi.BaseGridDialect;
import org.hibernate.ogm.dialect.spi.DuplicateInsertPreventionStrategy;
import org.hibernate.ogm.dialect.spi.OperationContext;
import org.hibernate.ogm.dialect.spi.SessionFactoryLifecycleAwareDialect;
import org.hibernate.ogm.dialect.spi.TupleContext;
import org.hibernate.ogm.dialect.spi.TupleTypeContext;
import org.hibernate.ogm.model.key.spi.AssociatedEntityKeyMetadata;
import org.hibernate.ogm.model.key.spi.AssociationKey;
import org.hibernate.ogm.model.key.spi.AssociationKeyMetadata;
import org.hibernate.ogm.model.key.spi.EntityKey;
import org.hibernate.ogm.model.key.spi.EntityKeyMetadata;
import org.hibernate.ogm.model.key.spi.RowKey;
import org.hibernate.ogm.model.spi.Association;
import org.hibernate.ogm.model.spi.Tuple;
import org.hibernate.ogm.model.spi.TupleSnapshot;
import org.hibernate.ogm.persister.impl.OgmCollectionPersister;
import org.hibernate.ogm.persister.impl.OgmEntityPersister;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.ogm.util.impl.ArrayHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.type.Type;
/**
* @author Davide D'Alto
*/
public abstract class BaseNeo4jDialect extends BaseGridDialect
implements QueryableGridDialect, ServiceRegistryAwareService, SessionFactoryLifecycleAwareDialect, MultigetGridDialect {
public static final String CONSTRAINT_VIOLATION_CODE = "Neo.ClientError.Schema.ConstraintValidationFailed";
private ServiceRegistryImplementor serviceRegistry;
private final BaseNeo4jTypeConverter typeConverter;
private Map entitiesQueries;
private Map associationQueries;
public BaseNeo4jDialect(BaseNeo4jTypeConverter converter) {
this.typeConverter = converter;
}
@Override
public void sessionFactoryCreated(SessionFactoryImplementor sessionFactoryImplementor) {
this.associationQueries = Collections.unmodifiableMap( initializeAssociationQueries( sessionFactoryImplementor ) );
this.entitiesQueries = Collections.unmodifiableMap( initializeEntityWithEmbeddedQueries( sessionFactoryImplementor ) );
}
protected E getEntityQueries(EntityKeyMetadata entityKeyMetadata, OperationContext operationContext) {
return getEntityQueries( entityKeyMetadata, operationContext.getTupleTypeContext() );
}
protected E getEntityQueries(EntityKeyMetadata entityKeyMetadata, TupleTypeContext tupleTypeContext) {
return entitiesQueries.get( entityKeyMetadata( entityKeyMetadata, tupleTypeContext ) );
}
protected A getAssociationQueries(AssociationKeyMetadata associationKeyMetadata) {
return associationQueries.get( associationKeyMetadata );
}
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
public ServiceRegistryImplementor getServiceRegistry() {
return serviceRegistry;
}
@Override
public Tuple createTuple(EntityKey key, OperationContext operationContext) {
return new Tuple();
}
@Override
public Association createAssociation(AssociationKey associationKey, AssociationContext associationContext) {
return new Association();
}
@Override
public boolean isStoredInEntityStructure(AssociationKeyMetadata associationKeyMetadata, AssociationTypeContext associationTypeContext) {
return false;
}
@Override
public boolean supportsSequences() {
return true;
}
protected RowKey convert(AssociationKey associationKey, TupleSnapshot snapshot) {
String[] columnNames = associationKey.getMetadata().getRowKeyColumnNames();
Object[] values = new Object[columnNames.length];
for ( int i = 0; i < columnNames.length; i++ ) {
values[i] = snapshot.get( columnNames[i] );
}
return new RowKey( columnNames, values );
}
@Override
public GridType overrideType(Type type) {
return typeConverter.convert( type );
}
@Override
public String parseNativeQuery(String nativeQuery) {
// We return given Cypher queries as they are; Currently there is no API for validating Cypher queries without
// actually executing them (see https://github.com/neo4j/neo4j/issues/2766)
return nativeQuery;
}
protected String buildNativeQuery(BackendQuery customQuery, QueryParameters queryParameters) {
StringBuilder nativeQuery = new StringBuilder( customQuery.getQuery() );
applyFirstRow( queryParameters, nativeQuery );
applyMaxRows( queryParameters, nativeQuery );
return nativeQuery.toString();
}
private void applyFirstRow(QueryParameters queryParameters, StringBuilder nativeQuery) {
Integer firstRow = queryParameters.getRowSelection().getFirstRow();
if ( firstRow != null ) {
skip( nativeQuery, firstRow );
}
}
private void applyMaxRows(QueryParameters queryParameters, StringBuilder nativeQuery) {
Integer maxRows = queryParameters.getRowSelection().getMaxRows();
if ( maxRows != null ) {
limit( nativeQuery, maxRows );
}
}
@Override
public ParameterMetadataBuilder getParameterMetadataBuilder() {
return new Neo4jParameterMetadataBuilder();
}
/**
* Returns the key of the entity targeted by the represented association, retrieved from the given tuple.
*
* @param tuple the tuple from which to retrieve the referenced entity key
* @return the key of the entity targeted by the represented association
*/
protected EntityKey getEntityKey(Tuple tuple, AssociatedEntityKeyMetadata associatedEntityKeyMetadata) {
Object[] columnValues = new Object[ associatedEntityKeyMetadata.getAssociationKeyColumns().length];
int i = 0;
for ( String associationKeyColumn : associatedEntityKeyMetadata.getAssociationKeyColumns() ) {
columnValues[i] = tuple.get( associationKeyColumn );
i++;
}
return new EntityKey( associatedEntityKeyMetadata.getEntityKeyMetadata(), columnValues );
}
@Override
public DuplicateInsertPreventionStrategy getDuplicateInsertPreventionStrategy(EntityKeyMetadata entityKeyMetadata) {
// Only for non-composite keys (= one column) Neo4j supports unique key constraints; Hence an explicit look-up
// is required to detect duplicate insertions when using composite keys
return entityKeyMetadata.getColumnNames().length == 1 ?
DuplicateInsertPreventionStrategy.NATIVE :
DuplicateInsertPreventionStrategy.LOOK_UP;
}
/**
* A regular embedded is an element that it is embedded but it is not a key or a collection.
*
* @param keyColumnNames the column names representing the identifier of the entity
* @param column the column we want to check
* @return {@code true} if the column represent an attribute of a regular embedded element, {@code false} otherwise
*/
public static boolean isPartOfRegularEmbedded(String[] keyColumnNames, String column) {
return isPartOfEmbedded( column ) && !ArrayHelper.contains( keyColumnNames, column );
}
@Override
public int executeBackendUpdateQuery(BackendQuery query, QueryParameters queryParameters, TupleContext tupleContext) {
// TODO implement. org.hibernate.ogm.datastore.mongodb.MongoDBDialect.executeBackendUpdateQuery(BackendQuery, QueryParameters) might be helpful as a reference.
throw new UnsupportedOperationException( "Not yet implemented." );
}
protected Map getParameters(QueryParameters queryParameters) {
Map parameters = new HashMap<>( queryParameters.getNamedParameters().size() );
for ( Entry parameter : queryParameters.getNamedParameters().entrySet() ) {
parameters.put( parameter.getKey(), parameter.getValue().getValue() );
}
return parameters;
}
@Override
public boolean usesNavigationalInformationForInverseSideOfAssociations() {
return false;
}
protected EntityKeyMetadata entityKeyMetadata(OgmEntityPersister ogmEntityPersister) {
return entityKeyMetadata( ogmEntityPersister.getEntityKeyMetadata(), ogmEntityPersister.getTupleTypeContext() );
}
protected EntityKeyMetadata entityKeyMetadata(EntityKeyMetadata keyMetadata, TupleTypeContext tupleTypeContext) {
if ( tupleTypeContext.getDiscriminatorColumn() == null ) {
return keyMetadata;
}
// We only need it with column based discriminators
return new DiscriminatorAwareKeyMetadata( keyMetadata, tupleTypeContext.getDiscriminatorValue() );
}
private Map initializeEntityWithEmbeddedQueries(SessionFactoryImplementor sessionFactoryImplementor) {
Map entityQueries = initializeEntityQueries( sessionFactoryImplementor );
Collection collectionPersisters = sessionFactoryImplementor.getCollectionPersisters().values();
for ( CollectionPersister collectionPersister : collectionPersisters ) {
if ( collectionPersister instanceof OgmCollectionPersister ) {
OgmCollectionPersister ogmCollectionPersister = (OgmCollectionPersister) collectionPersister;
OgmEntityPersister ogmEntityPersister = (OgmEntityPersister) ( ogmCollectionPersister.getOwnerEntityPersister() );
EntityKeyMetadata ownerEntityKeyMetadata = ogmEntityPersister.getEntityKeyMetadata();
ownerEntityKeyMetadata = entityKeyMetadata( ogmEntityPersister );
if ( !entityQueries.containsKey( ownerEntityKeyMetadata ) ) {
// Embeddables metadata
E createNeo4jEntityQueries = createNeo4jEntityQueries( ogmEntityPersister.getEntityKeyMetadata(), null );
entityQueries.put( ownerEntityKeyMetadata, createNeo4jEntityQueries );
}
}
}
return entityQueries;
}
private Map initializeEntityQueries(SessionFactoryImplementor sessionFactoryImplementor) {
Map queryMap = new HashMap();
Collection entityPersisters = sessionFactoryImplementor.getEntityPersisters().values();
for ( EntityPersister entityPersister : entityPersisters ) {
if ( entityPersister instanceof OgmEntityPersister ) {
OgmEntityPersister ogmEntityPersister = (OgmEntityPersister) entityPersister;
E entityQueries = createNeo4jEntityQueries( ogmEntityPersister.getEntityKeyMetadata(), ogmEntityPersister.getTupleTypeContext() );
queryMap.put( entityKeyMetadata( ogmEntityPersister ), entityQueries );
}
}
return queryMap;
}
protected abstract E createNeo4jEntityQueries(EntityKeyMetadata entityKeyMetadata, TupleTypeContext tupleTypeContext);
protected Map initializeAssociationQueries( SessionFactoryImplementor sessionFactoryImplementor) {
Map queryMap = new HashMap();
Collection collectionPersisters = sessionFactoryImplementor.getCollectionPersisters().values();
for ( CollectionPersister collectionPersister : collectionPersisters ) {
if ( collectionPersister instanceof OgmCollectionPersister ) {
OgmCollectionPersister ogmCollectionPersister = (OgmCollectionPersister) collectionPersister;
OgmEntityPersister ogmEntityPersister = (OgmEntityPersister) ( ogmCollectionPersister.getOwnerEntityPersister() );
EntityKeyMetadata ownerEntityKeyMetadata = ogmEntityPersister.getEntityKeyMetadata();
ownerEntityKeyMetadata = entityKeyMetadata( ogmEntityPersister );
AssociationKeyMetadata associationKeyMetadata = ogmCollectionPersister.getAssociationKeyMetadata();
A createNeo4jAssociationQueries = createNeo4jAssociationQueries( ownerEntityKeyMetadata, associationKeyMetadata );
queryMap.put( associationKeyMetadata, createNeo4jAssociationQueries );
}
}
return queryMap;
}
protected abstract A createNeo4jAssociationQueries(EntityKeyMetadata ownerEntityKeyMetadata, AssociationKeyMetadata associationKeyMetadata);
}