From c6c4299402c4939c950a7605914a8ab57f86de61 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 18 Oct 2016 15:54:13 +0100 Subject: [PATCH] OGM-1111 Implements foreach method in Neo4j remote dialects --- .../ogm/datastore/neo4j/BoltNeo4jDialect.java | 46 ++++++++++++++++++- .../ogm/datastore/neo4j/HttpNeo4jDialect.java | 41 +++++++++++------ .../dialect/impl/BoltNeo4jEntityQueries.java | 5 ++ .../impl/BoltNeo4jNodesTupleIterator.java | 24 +++++++++- .../dialect/impl/HttpNeo4jEntityQueries.java | 4 +- .../impl/HttpNeo4jNodesTupleIterator.java | 2 - 6 files changed, 103 insertions(+), 19 deletions(-) diff --git a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/BoltNeo4jDialect.java b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/BoltNeo4jDialect.java index e2b58cb59e..06bfef6200 100644 --- a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/BoltNeo4jDialect.java +++ b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/BoltNeo4jDialect.java @@ -31,23 +31,26 @@ import org.hibernate.ogm.datastore.neo4j.remote.bolt.dialect.impl.BoltNeo4jTupleSnapshot; import org.hibernate.ogm.datastore.neo4j.remote.bolt.dialect.impl.BoltNeo4jTypeConverter; import org.hibernate.ogm.datastore.neo4j.remote.bolt.dialect.impl.NodeWithEmbeddedNodes; +import org.hibernate.ogm.datastore.neo4j.remote.bolt.impl.BoltNeo4jClient; import org.hibernate.ogm.datastore.neo4j.remote.bolt.impl.BoltNeo4jDatastoreProvider; import org.hibernate.ogm.datastore.neo4j.remote.common.dialect.impl.RemoteNeo4jAssociationPropertiesRow; import org.hibernate.ogm.datastore.neo4j.remote.common.dialect.impl.RemoteNeo4jAssociationSnapshot; import org.hibernate.ogm.datastore.neo4j.remote.common.util.impl.RemoteNeo4jHelper; +import org.hibernate.ogm.datastore.spi.DatastoreProvider; import org.hibernate.ogm.dialect.query.spi.BackendQuery; import org.hibernate.ogm.dialect.query.spi.ClosableIterator; import org.hibernate.ogm.dialect.query.spi.QueryParameters; import org.hibernate.ogm.dialect.spi.AssociationContext; import org.hibernate.ogm.dialect.spi.ModelConsumer; +import org.hibernate.ogm.dialect.spi.ModelConsumerWithSupplier; import org.hibernate.ogm.dialect.spi.NextValueRequest; import org.hibernate.ogm.dialect.spi.OperationContext; import org.hibernate.ogm.dialect.spi.TransactionContext; import org.hibernate.ogm.dialect.spi.TupleAlreadyExistsException; import org.hibernate.ogm.dialect.spi.TupleContext; +import org.hibernate.ogm.dialect.spi.TupleSupplier; import org.hibernate.ogm.dialect.spi.TupleTypeContext; import org.hibernate.ogm.entityentry.impl.TuplePointer; -import org.hibernate.ogm.exception.NotSupportedException; import org.hibernate.ogm.model.key.spi.AssociatedEntityKeyMetadata; import org.hibernate.ogm.model.key.spi.AssociationKey; import org.hibernate.ogm.model.key.spi.AssociationKeyMetadata; @@ -65,6 +68,7 @@ import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.neo4j.driver.v1.Record; +import org.neo4j.driver.v1.Session; import org.neo4j.driver.v1.Statement; import org.neo4j.driver.v1.StatementResult; import org.neo4j.driver.v1.Transaction; @@ -599,6 +603,44 @@ public Number nextValue(NextValueRequest request) { @Override public void forEachTuple(ModelConsumer consumer, TupleTypeContext tupleTypeContext, EntityKeyMetadata entityKeyMetadata) { - throw new NotSupportedException( "OGM-1111", "This is not supported yet for Neo4j remote" ); + DatastoreProvider datastoreProvider = getServiceRegistry().getService( DatastoreProvider.class ); + BoltNeo4jDatastoreProvider neo4jProvider = (BoltNeo4jDatastoreProvider) datastoreProvider; + BoltNeo4jClient client = neo4jProvider.getClient(); + BoltTupleSupplier tupleSupplier = new BoltTupleSupplier( entitiesQueries.get( entityKeyMetadata ), entityKeyMetadata, tupleTypeContext, client ); + ( (ModelConsumerWithSupplier) consumer ).consume( tupleSupplier ); + } + + private static class BoltTupleSupplier implements TupleSupplier { + + private final BoltNeo4jEntityQueries entityQueries; + private final EntityKeyMetadata entityKeyMetadata; + private final TupleTypeContext tupleTypeContext; + private final BoltNeo4jClient boltClient; + + public BoltTupleSupplier( + BoltNeo4jEntityQueries entityQueries, + EntityKeyMetadata entityKeyMetadata, + TupleTypeContext tupleTypeContext, + BoltNeo4jClient boltClient) { + this.entityQueries = entityQueries; + this.entityKeyMetadata = entityKeyMetadata; + this.tupleTypeContext = tupleTypeContext; + this.boltClient = boltClient; + } + + public ClosableIterator get(TransactionContext transactionContext) { + boolean shouldCloseTransaction = transactionContext == null; + Transaction tx = transaction( transactionContext ); + ClosableIterator entities = entityQueries.findEntitiesWithEmbedded( tx ); + return new BoltNeo4jNodesTupleIterator( tx, entityQueries, entityKeyMetadata, tupleTypeContext, entities, shouldCloseTransaction ); + } + + private Transaction transaction(TransactionContext transactionContext) { + if ( transactionContext == null ) { + Session session = boltClient.getDriver().session(); + return session.beginTransaction(); + } + return (Transaction) transactionContext.getTransactionId(); + } } } diff --git a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/HttpNeo4jDialect.java b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/HttpNeo4jDialect.java index b9204f0765..b03b55fc40 100644 --- a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/HttpNeo4jDialect.java +++ b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/HttpNeo4jDialect.java @@ -48,11 +48,13 @@ import org.hibernate.ogm.dialect.query.spi.QueryParameters; import org.hibernate.ogm.dialect.spi.AssociationContext; import org.hibernate.ogm.dialect.spi.ModelConsumer; +import org.hibernate.ogm.dialect.spi.ModelConsumerWithSupplier; import org.hibernate.ogm.dialect.spi.NextValueRequest; import org.hibernate.ogm.dialect.spi.OperationContext; import org.hibernate.ogm.dialect.spi.TransactionContext; import org.hibernate.ogm.dialect.spi.TupleAlreadyExistsException; import org.hibernate.ogm.dialect.spi.TupleContext; +import org.hibernate.ogm.dialect.spi.TupleSupplier; import org.hibernate.ogm.dialect.spi.TupleTypeContext; import org.hibernate.ogm.entityentry.impl.TuplePointer; import org.hibernate.ogm.model.key.spi.AssociatedEntityKeyMetadata; @@ -513,18 +515,31 @@ private void putOneToOneAssociation(EntityKey ownerKey, Tuple tuple, Map queryNodes = entityQueries.get( entityKeyMetadata ).findEntitiesWithEmbedded( client, txId ); - while ( queryNodes.hasNext() ) { - NodeWithEmbeddedNodes next = queryNodes.next(); - Map associatedEntities = HttpNeo4jAssociatedNodesHelper.findAssociatedNodes( client, txId, next, entityKeyMetadata, tupleTypeContext, - queries ); - Tuple tuple = new Tuple( new HttpNeo4jTupleSnapshot( next, entityKeyMetadata, associatedEntities, tupleTypeContext ), SnapshotType.UPDATE ); - consumer.consume( tuple ); + HttpTupleSupplier tupleSupplier = new HttpTupleSupplier( entityQueries.get( entityKeyMetadata ), entityKeyMetadata, tupleTypeContext, client ); + ( (ModelConsumerWithSupplier) consumer ).consume( tupleSupplier ); + } + + private static class HttpTupleSupplier implements TupleSupplier { + + private final HttpNeo4jEntityQueries entityQueries; + private final EntityKeyMetadata entityKeyMetadata; + private final TupleTypeContext tupleTypeContext; + private final HttpNeo4jClient httpClient; + + public HttpTupleSupplier(HttpNeo4jEntityQueries entityQueries, + EntityKeyMetadata entityKeyMetadata, + TupleTypeContext tupleTypeContext, + HttpNeo4jClient httpClient) { + this.entityQueries = entityQueries; + this.entityKeyMetadata = entityKeyMetadata; + this.tupleTypeContext = tupleTypeContext; + this.httpClient = httpClient; + } + + public ClosableIterator get(TransactionContext transactionContext) { + Long txId = transactionContext == null ? null : (Long) transactionContext.getTransactionId(); + ClosableIterator entities = entityQueries.findEntitiesWithEmbedded( httpClient, txId ); + return new HttpNeo4jNodesTupleIterator( httpClient, txId, entityQueries, entityKeyMetadata, tupleTypeContext, entities ); } } @@ -553,7 +568,7 @@ public ClosableIterator executeBackendQuery(BackendQuery backendQ keys[i] = new EntityKey( entityKeyMetadata, values ); } ClosableIterator entities = entityQueries.get( entityKeyMetadata ).findEntities( client, keys, txId ); - return new HttpNeo4jNodesTupleIterator( client, txId, queries, response, entityKeyMetadata, tupleContext.getTupleTypeContext(), entities ); + return new HttpNeo4jNodesTupleIterator( client, txId, queries, entityKeyMetadata, tupleContext.getTupleTypeContext(), entities ); } else { statement.setResultDataContents( Arrays.asList( Statement.AS_ROW ) ); diff --git a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jEntityQueries.java b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jEntityQueries.java index a9865919eb..cd059b4d29 100644 --- a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jEntityQueries.java +++ b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jEntityQueries.java @@ -73,6 +73,11 @@ private void close(ClosableIterator closableIterator) { } } + public ClosableIterator findEntitiesWithEmbedded(Transaction tx) { + StatementResult results = tx.run( getFindEntitiesQuery() ); + return closableIterator( results ); + } + public ClosableIterator findEntities(EntityKey[] keys, Transaction tx) { if ( singlePropertyKey ) { return singlePropertyIdFindEntities( keys, tx ); diff --git a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jNodesTupleIterator.java b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jNodesTupleIterator.java index 584cb16696..712c86400e 100644 --- a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jNodesTupleIterator.java +++ b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/bolt/dialect/impl/BoltNeo4jNodesTupleIterator.java @@ -29,6 +29,7 @@ public class BoltNeo4jNodesTupleIterator implements ClosableIterator { private final TupleTypeContext tupleTypeContext; private final ClosableIterator entities; private final Transaction tx; + private final boolean closeTransaction; public BoltNeo4jNodesTupleIterator( Transaction tx, @@ -36,11 +37,22 @@ public BoltNeo4jNodesTupleIterator( EntityKeyMetadata entityKeyMetadata, TupleTypeContext tupleTypeContext, ClosableIterator entities) { + this( tx, entityQueries, entityKeyMetadata, tupleTypeContext, entities, false ); + } + + public BoltNeo4jNodesTupleIterator( + Transaction tx, + BoltNeo4jEntityQueries entityQueries, + EntityKeyMetadata entityKeyMetadata, + TupleTypeContext tupleTypeContext, + ClosableIterator entities, + boolean closeTransaction) { this.tx = tx; this.entityQueries = entityQueries; this.entityKeyMetadata = entityKeyMetadata; this.tupleTypeContext = tupleTypeContext; this.entities = entities; + this.closeTransaction = closeTransaction; } private Tuple createTuple(NodeWithEmbeddedNodes node) { @@ -66,6 +78,16 @@ public void remove() { @Override public void close() { - entities.close(); + try { + entities.close(); + if ( closeTransaction ) { + tx.success(); + } + } + finally { + if ( closeTransaction ) { + tx.close(); + } + } } } diff --git a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jEntityQueries.java b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jEntityQueries.java index 08ce63b7a6..2d6a706264 100644 --- a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jEntityQueries.java +++ b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jEntityQueries.java @@ -314,7 +314,9 @@ private List executeQuery(HttpNeo4jClient executionEngine, Long } private List executeQuery(HttpNeo4jClient executionEngine, Long txId, Statements statements) { - StatementsResponse statementsResponse = executionEngine.executeQueriesInOpenTransaction( txId, statements ); + StatementsResponse statementsResponse = txId == null + ? executionEngine.executeQueriesInNewTransaction( statements ) + : executionEngine.executeQueriesInOpenTransaction( txId, statements ); validate( statementsResponse ); List results = statementsResponse.getResults(); if ( results == null || results.isEmpty() ) { diff --git a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jNodesTupleIterator.java b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jNodesTupleIterator.java index 8b3a1f43c7..ff520dc488 100644 --- a/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jNodesTupleIterator.java +++ b/neo4j/src/main/java/org/hibernate/ogm/datastore/neo4j/remote/http/dialect/impl/HttpNeo4jNodesTupleIterator.java @@ -10,7 +10,6 @@ import org.hibernate.ogm.datastore.neo4j.remote.http.impl.HttpNeo4jClient; import org.hibernate.ogm.datastore.neo4j.remote.http.json.impl.Graph.Node; -import org.hibernate.ogm.datastore.neo4j.remote.http.json.impl.StatementsResponse; import org.hibernate.ogm.dialect.query.spi.ClosableIterator; import org.hibernate.ogm.dialect.spi.TupleTypeContext; import org.hibernate.ogm.model.key.spi.EntityKeyMetadata; @@ -36,7 +35,6 @@ public HttpNeo4jNodesTupleIterator( HttpNeo4jClient client, Long txId, HttpNeo4jEntityQueries entityQueries, - StatementsResponse response, EntityKeyMetadata entityKeyMetadata, TupleTypeContext tupleTypeContext, ClosableIterator entities) {