/* * 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.neo4j.embedded.impl; import java.util.List; import java.util.Set; import org.hibernate.boot.model.relational.Sequence; import org.hibernate.cfg.Environment; import org.hibernate.ogm.datastore.neo4j.impl.BaseNeo4jSchemaDefiner; import org.hibernate.ogm.datastore.neo4j.logging.impl.Log; import org.hibernate.ogm.datastore.neo4j.logging.impl.LoggerFactory; import org.hibernate.ogm.datastore.spi.DatastoreProvider; import org.hibernate.ogm.model.key.spi.IdSourceKeyMetadata; import org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.schema.ConstraintDefinition; import org.neo4j.graphdb.schema.ConstraintType; /** * Initialize the schema for the Neo4j database: * <ol> * <li>create sequences;</li> * <li>create unique constraints on identifiers, natural ids and unique columns</li> * </ol> * <p> * Note that unique constraints involving multiple columns won't be applied because Neo4j does not support it. * <p> * The creation of unique constraints can be skipped setting the property * {@link Environment#UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY} to the value * {@link UniqueConstraintSchemaUpdateStrategy#SKIP}. Because in Neo4j unique constraints don't have a name, setting the * value to {@link UniqueConstraintSchemaUpdateStrategy#RECREATE_QUIETLY} or * {@link UniqueConstraintSchemaUpdateStrategy#DROP_RECREATE_QUIETLY} will have the same effect: keep the existing * constraints and create the missing one. * * @author Davide D'Alto * @author Gunnar Morling */ public class EmbeddedNeo4jSchemaDefiner extends BaseNeo4jSchemaDefiner { private static final Log log = LoggerFactory.getLogger(); @Override protected void createSequences(List<Sequence> sequences, Set<IdSourceKeyMetadata> allIdSourceKeyMetadata, DatastoreProvider provider) { EmbeddedNeo4jDatastoreProvider neo4jProvider = (EmbeddedNeo4jDatastoreProvider) provider; neo4jProvider.getSequenceGenerator().createSequences( sequences ); neo4jProvider.getSequenceGenerator().createUniqueConstraintsForTableSequences( allIdSourceKeyMetadata ); } @Override protected void createUniqueConstraintsIfMissing(DatastoreProvider provider, List<UniqueConstraintDetails> constraints) { EmbeddedNeo4jDatastoreProvider neo4jProvider = (EmbeddedNeo4jDatastoreProvider) provider; GraphDatabaseService neo4jDb = neo4jProvider.getDatabase(); Transaction tx = neo4jDb.beginTx(); try { for ( UniqueConstraintDetails constraint : constraints ) { createUniqueConstraint( neo4jDb, constraint ); } tx.success(); } finally { if ( tx != null ) { tx.close(); } } } private void createUniqueConstraint(GraphDatabaseService neo4jDb, UniqueConstraintDetails constraint) { Label label = constraint.getLabel(); String property = constraint.getProperty(); if ( isMissingUniqueConstraint( neo4jDb, constraint ) ) { log.tracef( "Creating unique constraint for nodes labeled as %1$s on property %2$s", label, property ); neo4jDb.schema().constraintFor( constraint.getLabel() ).assertPropertyIsUnique( constraint.getProperty() ).create(); } else { log.tracef( "Unique constraint already exists for nodes labeled as %1$s on property %2$s", label, property ); } } private boolean isMissingUniqueConstraint(GraphDatabaseService neo4jDb, UniqueConstraintDetails constraintDetails) { Iterable<ConstraintDefinition> constraints = neo4jDb.schema().getConstraints( constraintDetails.getLabel() ); for ( ConstraintDefinition constraint : constraints ) { if ( constraint.isConstraintType( ConstraintType.UNIQUENESS ) ) { for ( String propertyKey : constraint.getPropertyKeys() ) { if ( propertyKey.equals( constraintDetails.getProperty() ) ) { return false; } } } } return true; } }