diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 3d4004a9e..1a30e3305 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -31,9 +31,9 @@ jobs: docker-img: - docker.io/arangodb:3.3.23 - docker.io/arangodb:3.4.8 - - docker.io/arangodb:3.5.0 + - docker.io/arangodb:3.5.1 - docker.io/arangodb/enterprise:3.4.8 - - docker.io/arangodb/enterprise:3.5.0 + - docker.io/arangodb/enterprise:3.5.1 topology: - single - cluster diff --git a/ChangeLog.md b/ChangeLog.md index 6d39ea2df..cfbd6e489 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +### Added + +- Stream Transactions support for graph APIs + +### Fixed + +- `catchExceptions` option in async `getEdge` and `getVertex` + ## [6.3.0] - 2019-09-16 ### Added diff --git a/docker/start_db_cluster.sh b/docker/start_db_cluster.sh index 27089565e..d7d4cf40a 100755 --- a/docker/start_db_cluster.sh +++ b/docker/start_db_cluster.sh @@ -5,7 +5,7 @@ # ./start_db_cluster.sh # EXAMPLE: -# ./start_db_cluster.sh docker.io/arangodb:3.5.0 +# ./start_db_cluster.sh docker.io/arangodb/arangodb:3.5.1 docker pull "$1" diff --git a/docker/start_db_single.sh b/docker/start_db_single.sh index 652f26d8f..cc4580067 100755 --- a/docker/start_db_single.sh +++ b/docker/start_db_single.sh @@ -5,7 +5,7 @@ # ./start_db_single.sh # EXAMPLE: -# ./start_db_single.sh docker.io/arangodb:3.5.0 +# ./start_db_single.sh docker.io/arangodb/arangodb:3.5.1 docker pull "$1" diff --git a/docs/Drivers/Java/Reference/Graph/Edges.md b/docs/Drivers/Java/Reference/Graph/Edges.md index 21673ebdb..55cb2f3e9 100644 --- a/docs/Drivers/Java/Reference/Graph/Edges.md +++ b/docs/Drivers/Java/Reference/Graph/Edges.md @@ -30,6 +30,10 @@ Retrieves the edge document with the given `key` from the collection. Whether or not catch possible thrown exceptions + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + ## ArangoEdgeCollection.insertEdge `ArangoEdgeCollection.insertEdge(T value, EdgeCreateOptions options) : EdgeEntity` @@ -88,6 +92,10 @@ a edge and no precondition is violated. Replace a document based on target revision + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + **Examples** ```Java @@ -135,6 +143,10 @@ edge and no precondition is violated. from the existing document that are contained in the patch document with an attribute value of null. + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + **Examples** ```Java @@ -169,6 +181,10 @@ Deletes the edge with the given _key_ from the collection. Remove a document based on target revision + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + **Examples** ```Java diff --git a/docs/Drivers/Java/Reference/Graph/Vertices.md b/docs/Drivers/Java/Reference/Graph/Vertices.md index 3dc5a0ba5..bf6cecd0d 100644 --- a/docs/Drivers/Java/Reference/Graph/Vertices.md +++ b/docs/Drivers/Java/Reference/Graph/Vertices.md @@ -30,6 +30,10 @@ Retrieves the vertex document with the given `key` from the collection. Whether or not catch possible thrown exceptions + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + ## ArangoVertexCollection.insertVertex `ArangoVertexCollection.insertVertex(T value, VertexCreateOptions options) : VertexEntity` @@ -48,6 +52,14 @@ Creates a new vertex in the collection. Wait until document has been synced to disk. + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + **Examples** ```Java @@ -88,6 +100,10 @@ a vertex and no precondition is violated. Replace a document based on target revision + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + **Examples** ```Java @@ -135,6 +151,10 @@ a vertex and no precondition is violated. from the existing document that are contained in the patch document with an attribute value of null. + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + **Examples** ```Java @@ -169,6 +189,10 @@ Deletes the vertex with the given _key_ from the collection. Remove a document based on target revision + - **streamTransactionId**: `String` + + If set, the operation will be executed within the transaction + **Examples** ```Java diff --git a/src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java index a4d25a4ff..4d5ffcd35 100644 --- a/src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java +++ b/src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java @@ -30,8 +30,6 @@ import java.util.Collection; import java.util.Objects; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.function.Function; /** * @author Mark Vollmary @@ -116,29 +114,7 @@ public CompletableFuture getDocument( DocumentUtil.validateDocumentKey(key); boolean isCatchException = options != null ? options.isCatchException() : new DocumentReadOptions().isCatchException(); return (CompletableFuture) executor.execute(getDocumentRequest(key, options), type) - .exceptionally(handleGetDocumentExceptions(isCatchException)); - } - - private Function handleGetDocumentExceptions(Boolean isCatchException) { - return throwable -> { - if (throwable instanceof CompletionException) { - if (throwable.getCause() instanceof ArangoDBException) { - ArangoDBException arangoDBException = (ArangoDBException) throwable.getCause(); - - // handle Response: 404, Error: 1655 - transaction not found - if (arangoDBException.getErrorNum() != null && arangoDBException.getErrorNum() == 1655) { - throw (CompletionException) throwable; - } - - if ((arangoDBException.getResponseCode() != null && (arangoDBException.getResponseCode() == 404 || arangoDBException.getResponseCode() == 304 - || arangoDBException.getResponseCode() == 412)) && isCatchException) { - return null; - } - } - throw (CompletionException) throwable; - } - throw new CompletionException(throwable); - }; + .exceptionally(ExceptionUtil.catchGetDocumentExceptions(isCatchException)); } @Override @@ -260,7 +236,7 @@ public CompletableFuture documentExists(final String key) { public CompletableFuture documentExists(final String key, final DocumentExistsOptions options) { boolean isCatchException = options != null ? options.isCatchException() : new DocumentExistsOptions().isCatchException(); return executor.execute(documentExistsRequest(key, options), response -> response) - .exceptionally(handleGetDocumentExceptions(isCatchException)) + .exceptionally(ExceptionUtil.catchGetDocumentExceptions(isCatchException)) .thenApply(Objects::nonNull); } diff --git a/src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java index 84e47b8d8..4ea3ee725 100644 --- a/src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java +++ b/src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java @@ -52,12 +52,14 @@ public CompletableFuture insertEdge(final T value, final EdgeCre @Override public CompletableFuture getEdge(final String key, final Class type) { - return executor.execute(getEdgeRequest(key, new GraphDocumentReadOptions()), getEdgeResponseDeserializer(type)); + return getEdge(key, type, null); } @Override public CompletableFuture getEdge(final String key, final Class type, final GraphDocumentReadOptions options) { - return executor.execute(getEdgeRequest(key, options), getEdgeResponseDeserializer(type)); + boolean isCatchException = options != null ? options.isCatchException() : new GraphDocumentReadOptions().isCatchException(); + return executor.execute(getEdgeRequest(key, options), getEdgeResponseDeserializer(type)) + .exceptionally(ExceptionUtil.catchGetDocumentExceptions(isCatchException)); } @Override diff --git a/src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java index 75a102eaa..e988b6436 100644 --- a/src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java +++ b/src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java @@ -57,7 +57,7 @@ public CompletableFuture insertVertex(final T value, final Ver @Override public CompletableFuture getVertex(final String key, final Class type) { - return executor.execute(getVertexRequest(key, new GraphDocumentReadOptions()), getVertexResponseDeserializer(type)); + return getVertex(key, type, null); } @Override @@ -65,7 +65,9 @@ public CompletableFuture getVertex( final String key, final Class type, final GraphDocumentReadOptions options) { - return executor.execute(getVertexRequest(key, options), getVertexResponseDeserializer(type)); + boolean isCatchException = options != null ? options.isCatchException() : new GraphDocumentReadOptions().isCatchException(); + return executor.execute(getVertexRequest(key, options), getVertexResponseDeserializer(type)) + .exceptionally(ExceptionUtil.catchGetDocumentExceptions(isCatchException)); } @Override diff --git a/src/main/java/com/arangodb/async/internal/ExceptionUtil.java b/src/main/java/com/arangodb/async/internal/ExceptionUtil.java new file mode 100644 index 000000000..b76cdc21d --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ExceptionUtil.java @@ -0,0 +1,52 @@ +package com.arangodb.async.internal;/* + * DISCLAIMER + * + * Copyright 2016 ArangoDB GmbH, Cologne, Germany + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright holder is ArangoDB GmbH, Cologne, Germany + */ + + +import com.arangodb.ArangoDBException; + +import java.util.concurrent.CompletionException; +import java.util.function.Function; + +/** + * @author Michele Rastelli + */ +class ExceptionUtil { + static Function catchGetDocumentExceptions(Boolean isCatchException) { + return throwable -> { + if (throwable instanceof CompletionException) { + if (throwable.getCause() instanceof ArangoDBException) { + ArangoDBException arangoDBException = (ArangoDBException) throwable.getCause(); + + // handle Response: 404, Error: 1655 - transaction not found + if (arangoDBException.getErrorNum() != null && arangoDBException.getErrorNum() == 1655) { + throw (CompletionException) throwable; + } + + if ((arangoDBException.getResponseCode() != null && (arangoDBException.getResponseCode() == 404 || arangoDBException.getResponseCode() == 304 + || arangoDBException.getResponseCode() == 412)) && isCatchException) { + return null; + } + } + throw (CompletionException) throwable; + } + throw new CompletionException(throwable); + }; + } +} diff --git a/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java b/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java index fb227802b..c9fb9a903 100644 --- a/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java +++ b/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java @@ -46,6 +46,8 @@ public abstract class InternalArangoEdgeCollection private static final String PATH_API_GHARIAL = "/_api/gharial"; private static final String EDGE = "edge"; + private static final String TRANSACTION_ID = "x-arango-trx-id"; + private final G graph; private final String name; @@ -67,6 +69,7 @@ protected Request insertEdgeRequest(final T value, final EdgeCreateOptions o final Request request = request(graph.db().name(), RequestType.POST, PATH_API_GHARIAL, graph.name(), EDGE, name); final EdgeCreateOptions params = (options != null ? options : new EdgeCreateOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.setBody(util(Serializer.CUSTOM).serialize(value)); return request; @@ -89,6 +92,7 @@ protected Request getEdgeRequest(final String key, final GraphDocumentReadOption final Request request = request(graph.db().name(), RequestType.GET, PATH_API_GHARIAL, graph.name(), EDGE, DocumentUtil.createDocumentHandle(name, key)); final GraphDocumentReadOptions params = (options != null ? options : new GraphDocumentReadOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putHeaderParam(ArangoRequestParam.IF_NONE_MATCH, params.getIfNoneMatch()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); if (params.getAllowDirtyRead() == Boolean.TRUE) { @@ -105,6 +109,7 @@ protected Request replaceEdgeRequest(final String key, final T value, final final Request request = request(graph.db().name(), RequestType.PUT, PATH_API_GHARIAL, graph.name(), EDGE, DocumentUtil.createDocumentHandle(name, key)); final EdgeReplaceOptions params = (options != null ? options : new EdgeReplaceOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); request.setBody(util(Serializer.CUSTOM).serialize(value)); @@ -127,6 +132,7 @@ protected Request updateEdgeRequest(final String key, final T value, final E request = request(graph.db().name(), RequestType.PATCH, PATH_API_GHARIAL, graph.name(), EDGE, DocumentUtil.createDocumentHandle(name, key)); final EdgeUpdateOptions params = (options != null ? options : new EdgeUpdateOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.KEEP_NULL, params.getKeepNull()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); @@ -150,6 +156,7 @@ protected Request deleteEdgeRequest(final String key, final EdgeDeleteOptions op final Request request = request(graph.db().name(), RequestType.DELETE, PATH_API_GHARIAL, graph.name(), EDGE, DocumentUtil.createDocumentHandle(name, key)); final EdgeDeleteOptions params = (options != null ? options : new EdgeDeleteOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); return request; diff --git a/src/main/java/com/arangodb/internal/InternalArangoGraph.java b/src/main/java/com/arangodb/internal/InternalArangoGraph.java index 6226929d0..998c56fee 100644 --- a/src/main/java/com/arangodb/internal/InternalArangoGraph.java +++ b/src/main/java/com/arangodb/internal/InternalArangoGraph.java @@ -67,7 +67,7 @@ protected Request dropRequest() { protected Request dropRequest(final boolean dropCollections) { final Request request = request(db.name(), RequestType.DELETE, PATH_API_GHARIAL, name); if (dropCollections) { - request.putQueryParam("dropCollections", dropCollections); + request.putQueryParam("dropCollections", true); } return request; } diff --git a/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java b/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java index acd922821..d0a6f9412 100644 --- a/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java +++ b/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java @@ -46,6 +46,8 @@ public abstract class InternalArangoVertexCollection Request insertVertexRequest(final T value, final VertexCreateOptio final Request request = request(graph.db().name(), RequestType.POST, PATH_API_GHARIAL, graph.name(), VERTEX, name); final VertexCreateOptions params = (options != null ? options : new VertexCreateOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.setBody(util(Serializer.CUSTOM).serialize(value)); return request; @@ -93,6 +96,7 @@ protected Request getVertexRequest(final String key, final GraphDocumentReadOpti final Request request = request(graph.db().name(), RequestType.GET, PATH_API_GHARIAL, graph.name(), VERTEX, DocumentUtil.createDocumentHandle(name, key)); final GraphDocumentReadOptions params = (options != null ? options : new GraphDocumentReadOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putHeaderParam(ArangoRequestParam.IF_NONE_MATCH, params.getIfNoneMatch()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); if (params.getAllowDirtyRead() == Boolean.TRUE) { @@ -109,6 +113,7 @@ protected Request replaceVertexRequest(final String key, final T value, fina final Request request = request(graph.db().name(), RequestType.PUT, PATH_API_GHARIAL, graph.name(), VERTEX, DocumentUtil.createDocumentHandle(name, key)); final VertexReplaceOptions params = (options != null ? options : new VertexReplaceOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); request.setBody(util(Serializer.CUSTOM).serialize(value)); @@ -131,6 +136,7 @@ protected Request updateVertexRequest(final String key, final T value, final request = request(graph.db().name(), RequestType.PATCH, PATH_API_GHARIAL, graph.name(), VERTEX, DocumentUtil.createDocumentHandle(name, key)); final VertexUpdateOptions params = (options != null ? options : new VertexUpdateOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.KEEP_NULL, params.getKeepNull()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); @@ -154,6 +160,7 @@ protected Request deleteVertexRequest(final String key, final VertexDeleteOption final Request request = request(graph.db().name(), RequestType.DELETE, PATH_API_GHARIAL, graph.name(), VERTEX, DocumentUtil.createDocumentHandle(name, key)); final VertexDeleteOptions params = (options != null ? options : new VertexDeleteOptions()); + request.putHeaderParam(TRANSACTION_ID, params.getStreamTransactionId()); request.putQueryParam(ArangoRequestParam.WAIT_FOR_SYNC, params.getWaitForSync()); request.putHeaderParam(ArangoRequestParam.IF_MATCH, params.getIfMatch()); return request; diff --git a/src/main/java/com/arangodb/model/EdgeCreateOptions.java b/src/main/java/com/arangodb/model/EdgeCreateOptions.java index 8830f92c2..5efd3811d 100644 --- a/src/main/java/com/arangodb/model/EdgeCreateOptions.java +++ b/src/main/java/com/arangodb/model/EdgeCreateOptions.java @@ -22,29 +22,42 @@ /** * @author Mark Vollmary - * * @see API Documentation */ public class EdgeCreateOptions { - private Boolean waitForSync; - - public EdgeCreateOptions() { - super(); - } - - public Boolean getWaitForSync() { - return waitForSync; - } - - /** - * @param waitForSync - * Wait until document has been synced to disk. - * @return options - */ - public EdgeCreateOptions waitForSync(final Boolean waitForSync) { - this.waitForSync = waitForSync; - return this; - } + private Boolean waitForSync; + private String streamTransactionId; + + public EdgeCreateOptions() { + super(); + } + + public Boolean getWaitForSync() { + return waitForSync; + } + + /** + * @param waitForSync Wait until document has been synced to disk. + * @return options + */ + public EdgeCreateOptions waitForSync(final Boolean waitForSync) { + this.waitForSync = waitForSync; + return this; + } + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public EdgeCreateOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } } diff --git a/src/main/java/com/arangodb/model/EdgeDeleteOptions.java b/src/main/java/com/arangodb/model/EdgeDeleteOptions.java index b57e5ba05..ff666c611 100644 --- a/src/main/java/com/arangodb/model/EdgeDeleteOptions.java +++ b/src/main/java/com/arangodb/model/EdgeDeleteOptions.java @@ -29,6 +29,7 @@ public class EdgeDeleteOptions { private Boolean waitForSync; private String ifMatch; + private String streamTransactionId; public EdgeDeleteOptions() { super(); @@ -61,4 +62,19 @@ public EdgeDeleteOptions ifMatch(final String ifMatch) { this.ifMatch = ifMatch; return this; } + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public EdgeDeleteOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } + } diff --git a/src/main/java/com/arangodb/model/EdgeReplaceOptions.java b/src/main/java/com/arangodb/model/EdgeReplaceOptions.java index 0eb16ebbe..9bf86cb82 100644 --- a/src/main/java/com/arangodb/model/EdgeReplaceOptions.java +++ b/src/main/java/com/arangodb/model/EdgeReplaceOptions.java @@ -29,6 +29,7 @@ public class EdgeReplaceOptions { private Boolean waitForSync; private String ifMatch; + private String streamTransactionId; public EdgeReplaceOptions() { super(); @@ -61,4 +62,19 @@ public EdgeReplaceOptions ifMatch(final String ifMatch) { this.ifMatch = ifMatch; return this; } + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public EdgeReplaceOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } + } diff --git a/src/main/java/com/arangodb/model/EdgeUpdateOptions.java b/src/main/java/com/arangodb/model/EdgeUpdateOptions.java index 0dac5f1b8..bd29a14d4 100644 --- a/src/main/java/com/arangodb/model/EdgeUpdateOptions.java +++ b/src/main/java/com/arangodb/model/EdgeUpdateOptions.java @@ -30,6 +30,7 @@ public class EdgeUpdateOptions { private Boolean keepNull; private Boolean waitForSync; private String ifMatch; + private String streamTransactionId; public EdgeUpdateOptions() { super(); @@ -79,4 +80,19 @@ public EdgeUpdateOptions ifMatch(final String ifMatch) { this.ifMatch = ifMatch; return this; } + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public EdgeUpdateOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } + } diff --git a/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java b/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java index aaa4ef1ba..47ddea107 100644 --- a/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java +++ b/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java @@ -32,6 +32,7 @@ public class GraphDocumentReadOptions { private boolean catchException; @Expose(serialize = false) private Boolean allowDirtyRead; + private String streamTransactionId; public GraphDocumentReadOptions() { super(); @@ -93,4 +94,18 @@ public Boolean getAllowDirtyRead() { return allowDirtyRead; } + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public GraphDocumentReadOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } + } diff --git a/src/main/java/com/arangodb/model/VertexCreateOptions.java b/src/main/java/com/arangodb/model/VertexCreateOptions.java index c0af4aece..19846a5b8 100644 --- a/src/main/java/com/arangodb/model/VertexCreateOptions.java +++ b/src/main/java/com/arangodb/model/VertexCreateOptions.java @@ -28,6 +28,7 @@ public class VertexCreateOptions { private Boolean waitForSync; + private String streamTransactionId; public VertexCreateOptions() { super(); @@ -47,4 +48,18 @@ public VertexCreateOptions waitForSync(final Boolean waitForSync) { return this; } + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public VertexCreateOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } + } diff --git a/src/main/java/com/arangodb/model/VertexDeleteOptions.java b/src/main/java/com/arangodb/model/VertexDeleteOptions.java index 19fb696d7..7f3cfcdf0 100644 --- a/src/main/java/com/arangodb/model/VertexDeleteOptions.java +++ b/src/main/java/com/arangodb/model/VertexDeleteOptions.java @@ -29,6 +29,7 @@ public class VertexDeleteOptions { private Boolean waitForSync; private String ifMatch; + private String streamTransactionId; public VertexDeleteOptions() { super(); @@ -61,4 +62,19 @@ public VertexDeleteOptions ifMatch(final String ifMatch) { this.ifMatch = ifMatch; return this; } + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public VertexDeleteOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } + } diff --git a/src/main/java/com/arangodb/model/VertexReplaceOptions.java b/src/main/java/com/arangodb/model/VertexReplaceOptions.java index b8fb6da39..e98bd2222 100644 --- a/src/main/java/com/arangodb/model/VertexReplaceOptions.java +++ b/src/main/java/com/arangodb/model/VertexReplaceOptions.java @@ -29,6 +29,7 @@ public class VertexReplaceOptions { private Boolean waitForSync; private String ifMatch; + private String streamTransactionId; public VertexReplaceOptions() { super(); @@ -61,4 +62,19 @@ public VertexReplaceOptions ifMatch(final String ifMatch) { this.ifMatch = ifMatch; return this; } + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public VertexReplaceOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } + } diff --git a/src/main/java/com/arangodb/model/VertexUpdateOptions.java b/src/main/java/com/arangodb/model/VertexUpdateOptions.java index a90fa1ac3..2f5d2fc96 100644 --- a/src/main/java/com/arangodb/model/VertexUpdateOptions.java +++ b/src/main/java/com/arangodb/model/VertexUpdateOptions.java @@ -30,6 +30,7 @@ public class VertexUpdateOptions { private Boolean keepNull; private Boolean waitForSync; private String ifMatch; + private String streamTransactionId; public VertexUpdateOptions() { super(); @@ -79,4 +80,18 @@ public VertexUpdateOptions ifMatch(final String ifMatch) { this.ifMatch = ifMatch; return this; } + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + * @since ArangoDB 3.5.1 + */ + public VertexUpdateOptions streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return this; + } } diff --git a/src/test/java/com/arangodb/ArangoCollectionTest.java b/src/test/java/com/arangodb/ArangoCollectionTest.java index bbad1ef58..900361846 100644 --- a/src/test/java/com/arangodb/ArangoCollectionTest.java +++ b/src/test/java/com/arangodb/ArangoCollectionTest.java @@ -101,6 +101,7 @@ public void insertDocumentWithArrayWithNullValues() { assertThat(insertedDoc.getKey(), is(notNullValue())); assertThat(insertedDoc.getRev(), is(notNullValue())); assertThat(insertedDoc.getId(), is(COLLECTION_NAME + "/" + insertedDoc.getKey())); + //noinspection unchecked assertThat(((List) insertedDoc.getNew().getAttribute("arr")), contains("a", null)); } diff --git a/src/test/java/com/arangodb/ArangoDatabaseTest.java b/src/test/java/com/arangodb/ArangoDatabaseTest.java index 30a924a7a..c638b2cf8 100644 --- a/src/test/java/com/arangodb/ArangoDatabaseTest.java +++ b/src/test/java/com/arangodb/ArangoDatabaseTest.java @@ -65,18 +65,16 @@ public ArangoDatabaseTest(final Builder builder) { @Before public void setUp() { - if (db.collection(COLLECTION_NAME + "2").exists()) - db.collection(COLLECTION_NAME + "2").drop(); - if (db.collection(COLLECTION_NAME + "1").exists()) - db.collection(COLLECTION_NAME + "1").drop(); - if (db.collection(COLLECTION_NAME).exists()) - db.collection(COLLECTION_NAME).drop(); - if (db.collection(COLLECTION_NAME + "edge").exists()) - db.collection(COLLECTION_NAME + "edge").drop(); - if (db.collection(COLLECTION_NAME + "from").exists()) - db.collection(COLLECTION_NAME + "from").drop(); - if (db.collection(COLLECTION_NAME + "to").exists()) - db.collection(COLLECTION_NAME + "to").drop(); + db.getCollections().stream() + .filter(it -> !it.getIsSystem()) + .map(CollectionEntity::getName) + .map(db::collection) + .forEach(ArangoCollection::drop); + + db.getGraphs().stream() + .map(GraphEntity::getName) + .map(db::graph) + .forEach(ArangoGraph::drop); } @Test diff --git a/src/test/java/com/arangodb/StreamTransactionGraphTest.java b/src/test/java/com/arangodb/StreamTransactionGraphTest.java new file mode 100644 index 000000000..fde136cbc --- /dev/null +++ b/src/test/java/com/arangodb/StreamTransactionGraphTest.java @@ -0,0 +1,396 @@ +/* + * DISCLAIMER + * + * Copyright 2016 ArangoDB GmbH, Cologne, Germany + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright holder is ArangoDB GmbH, Cologne, Germany + */ + +package com.arangodb; + +import com.arangodb.ArangoDB.Builder; +import com.arangodb.entity.*; +import com.arangodb.model.*; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Collections; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +/** + * @author Michele Rastelli + */ +@RunWith(Parameterized.class) +public class StreamTransactionGraphTest extends BaseTest { + + private static final String GRAPH_NAME = "graph_stream_transaction_graph_test"; + private static final String EDGE_COLLECTION = "edge_collection_stream_transaction_graph_test"; + private static final String VERTEX_COLLECTION_1 = "vertex_collection_1_stream_transaction_graph_test"; + private static final String VERTEX_COLLECTION_2 = "vertex_collection_2_stream_transaction_graph_test"; + + private final ArangoGraph graph; + private final ArangoVertexCollection vertexCollection1; + private final ArangoVertexCollection vertexCollection2; + private final ArangoEdgeCollection edgeCollection; + + public StreamTransactionGraphTest(final Builder builder) { + super(builder); + + graph = db.graph(GRAPH_NAME); + + if (graph.exists()) + graph.drop(); + + graph.create(Collections.singletonList(new EdgeDefinition().collection(EDGE_COLLECTION).from(VERTEX_COLLECTION_1).to(VERTEX_COLLECTION_2))); + + vertexCollection1 = graph.vertexCollection(VERTEX_COLLECTION_1); + vertexCollection2 = graph.vertexCollection(VERTEX_COLLECTION_2); + edgeCollection = graph.edgeCollection(EDGE_COLLECTION); + } + + @After + public void teardown() { + if (graph.exists()) + graph.drop(); + if (db.collection(EDGE_COLLECTION).exists()) + db.collection(EDGE_COLLECTION).drop(); + if (db.collection(VERTEX_COLLECTION_1).exists()) + db.collection(VERTEX_COLLECTION_1).drop(); + if (db.collection(VERTEX_COLLECTION_2).exists()) + db.collection(VERTEX_COLLECTION_2).drop(); + } + + private BaseEdgeDocument createEdgeValue(String streamTransactionId) { + final VertexEntity v1 = vertexCollection1.insertVertex(new BaseDocument(), new VertexCreateOptions().streamTransactionId(streamTransactionId)); + final VertexEntity v2 = vertexCollection2.insertVertex(new BaseDocument(), new VertexCreateOptions().streamTransactionId(streamTransactionId)); + final BaseEdgeDocument value = new BaseEdgeDocument(); + value.setFrom(v1.getId()); + value.setTo(v2.getId()); + return value; + } + + @Test + public void getVertex() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db + .beginStreamTransaction(new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // insert a vertex from outside the tx + VertexEntity createdVertex = vertexCollection1.insertVertex(new BaseDocument()); + + // assert that the vertex is not found from within the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())), is(nullValue())); + + db.abortStreamTransaction(tx.getId()); + } + + + @Test + public void createVertex() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // insert a vertex from within the tx + VertexEntity createdVertex = vertexCollection1.insertVertex(new BaseDocument(), new VertexCreateOptions().streamTransactionId(tx.getId())); + + // assert that the vertex is not found from outside the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null), is(nullValue())); + + // assert that the vertex is found from within the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())), is(notNullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex is found after commit + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null), is(notNullValue())); + } + + @Test + public void replaceVertex() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseDocument doc = new BaseDocument(); + doc.addAttribute("test", "foo"); + + VertexEntity createdVertex = vertexCollection1.insertVertex(doc, null); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // replace vertex from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + vertexCollection1.replaceVertex(createdVertex.getKey(), doc, + new VertexReplaceOptions().streamTransactionId(tx.getId())); + + // assert that the vertex has not been replaced from outside the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null) + .getProperties().get("test"), is("foo")); + + // assert that the vertex has been replaced from within the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex has been replaced after commit + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null) + .getProperties().get("test"), is("bar")); + } + + @Test + public void updateVertex() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseDocument doc = new BaseDocument(); + doc.addAttribute("test", "foo"); + + VertexEntity createdDoc = vertexCollection1.insertVertex(doc, null); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // update vertex from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + vertexCollection1.updateVertex(createdDoc.getKey(), doc, new VertexUpdateOptions().streamTransactionId(tx.getId())); + + // assert that the vertex has not been updated from outside the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null) + .getProperties().get("test"), is("foo")); + + // assert that the vertex has been updated from within the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex has been updated after commit + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null) + .getProperties().get("test"), is("bar")); + } + + @Test + public void deleteVertex() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + VertexEntity createdDoc = vertexCollection1.insertVertex(new BaseDocument(), null); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // delete vertex from within the tx + vertexCollection1.deleteVertex(createdDoc.getKey(), new VertexDeleteOptions().streamTransactionId(tx.getId())); + + // assert that the vertex has not been deleted from outside the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null), is(notNullValue())); + + // assert that the vertex has been deleted from within the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())), is(nullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex has been deleted after commit + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null), + is(nullValue())); + } + + + @Test + public void getEdge() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db + .beginStreamTransaction(new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // insert a edge from outside the tx + EdgeEntity createdEdge = edgeCollection.insertEdge(createEdgeValue(null)); + + // assert that the edge is not found from within the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())), is(nullValue())); + + db.abortStreamTransaction(tx.getId()); + } + + + @Test + public void createEdge() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // insert a edge from within the tx + EdgeEntity createdEdge = edgeCollection.insertEdge(createEdgeValue(tx.getId()), new EdgeCreateOptions().streamTransactionId(tx.getId())); + + // assert that the edge is not found from outside the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null), is(nullValue())); + + // assert that the edge is found from within the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())), is(notNullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge is found after commit + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null), is(notNullValue())); + } + + @Test + public void replaceEdge() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseEdgeDocument doc = createEdgeValue(null); + doc.addAttribute("test", "foo"); + + EdgeEntity createdEdge = edgeCollection.insertEdge(doc, null); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // replace edge from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + edgeCollection.replaceEdge(createdEdge.getKey(), doc, + new EdgeReplaceOptions().streamTransactionId(tx.getId())); + + // assert that the edge has not been replaced from outside the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null) + .getProperties().get("test"), is("foo")); + + // assert that the edge has been replaced from within the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge has been replaced after commit + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null) + .getProperties().get("test"), is("bar")); + } + + @Test + public void updateEdge() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseEdgeDocument doc = createEdgeValue(null); + doc.addAttribute("test", "foo"); + + EdgeEntity createdDoc = edgeCollection.insertEdge(doc, null); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // update edge from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + edgeCollection.updateEdge(createdDoc.getKey(), doc, new EdgeUpdateOptions().streamTransactionId(tx.getId())); + + // assert that the edge has not been updated from outside the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null) + .getProperties().get("test"), is("foo")); + + // assert that the edge has been updated from within the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge has been updated after commit + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null) + .getProperties().get("test"), is("bar")); + } + + @Test + public void deleteEdge() { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + EdgeEntity createdDoc = edgeCollection.insertEdge(createEdgeValue(null), null); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)); + + // delete edge from within the tx + edgeCollection.deleteEdge(createdDoc.getKey(), new EdgeDeleteOptions().streamTransactionId(tx.getId())); + + // assert that the edge has not been deleted from outside the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null), is(notNullValue())); + + // assert that the edge has been deleted from within the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())), is(nullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge has been deleted after commit + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null), + is(nullValue())); + } + +} diff --git a/src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java b/src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java index cc37bfa63..c5762e792 100644 --- a/src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java +++ b/src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java @@ -113,7 +113,7 @@ public void getEdgeIfMatch() throws InterruptedException, ExecutionException { public void getEdgeIfMatchFail() throws InterruptedException, ExecutionException { final BaseEdgeDocument value = createEdgeValue(); final EdgeEntity edge = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(value, null).get(); - final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifMatch("no"); + final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifMatch("no").catchException(false); try { db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) .getEdge(edge.getKey(), BaseEdgeDocument.class, options).get(); @@ -138,7 +138,7 @@ public void getEdgeIfNoneMatch() throws InterruptedException, ExecutionException public void getEdgeIfNoneMatchFail() throws InterruptedException, ExecutionException { final BaseEdgeDocument value = createEdgeValue(); final EdgeEntity edge = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(value, null).get(); - final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifNoneMatch(edge.getRev()); + final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifNoneMatch(edge.getRev()).catchException(false); try { db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) .getEdge(edge.getKey(), BaseEdgeDocument.class, options).get(); @@ -345,7 +345,7 @@ public void deleteEdge() throws InterruptedException, ExecutionException { db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).deleteEdge(createResult.getKey(), null).get(); try { db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) - .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + .getEdge(createResult.getKey(), BaseEdgeDocument.class, new GraphDocumentReadOptions().catchException(false)).get(); fail(); } catch (final ExecutionException e) { assertThat(e.getCause(), instanceOf(ArangoDBException.class)); @@ -361,7 +361,7 @@ public void deleteEdgeIfMatch() throws InterruptedException, ExecutionException db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).deleteEdge(createResult.getKey(), options).get(); try { db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) - .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + .getEdge(createResult.getKey(), BaseEdgeDocument.class, new GraphDocumentReadOptions().catchException(false)).get(); fail(); } catch (final ExecutionException e) { assertThat(e.getCause(), instanceOf(ArangoDBException.class)); diff --git a/src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java b/src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java index ec98ff7fd..c614bd02a 100644 --- a/src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java +++ b/src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java @@ -101,7 +101,7 @@ public void getVertexIfMatch() throws InterruptedException, ExecutionException { public void getVertexIfMatchFail() throws InterruptedException, ExecutionException { final VertexEntity vertex = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) .insertVertex(new BaseDocument(), null).get(); - final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifMatch("no"); + final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifMatch("no").catchException(false); try { db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) .getVertex(vertex.getKey(), BaseDocument.class, options).get(); @@ -126,7 +126,7 @@ public void getVertexIfNoneMatch() throws InterruptedException, ExecutionExcepti public void getVertexIfNoneMatchFail() throws InterruptedException, ExecutionException { final VertexEntity vertex = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) .insertVertex(new BaseDocument(), null).get(); - final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifNoneMatch(vertex.getRev()); + final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifNoneMatch(vertex.getRev()).catchException(false); try { db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) .getVertex(vertex.getKey(), BaseDocument.class, options).get(); @@ -333,7 +333,7 @@ public void deleteVertex() throws InterruptedException, ExecutionException { db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).deleteVertex(createResult.getKey(), null).get(); try { db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) - .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + .getVertex(createResult.getKey(), BaseDocument.class, new GraphDocumentReadOptions().catchException(false)).get(); fail(); } catch (final ExecutionException e) { assertThat(e.getCause(), instanceOf(ArangoDBException.class)); @@ -349,7 +349,7 @@ public void deleteVertexIfMatch() throws InterruptedException, ExecutionExceptio db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).deleteVertex(createResult.getKey(), options).get(); try { db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) - .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + .getVertex(createResult.getKey(), BaseDocument.class, new GraphDocumentReadOptions().catchException(false)).get(); fail(); } catch (final ExecutionException e) { assertThat(e.getCause(), instanceOf(ArangoDBException.class)); diff --git a/src/test/java/com/arangodb/async/StreamTransactionGraphTest.java b/src/test/java/com/arangodb/async/StreamTransactionGraphTest.java new file mode 100644 index 000000000..97d575ec3 --- /dev/null +++ b/src/test/java/com/arangodb/async/StreamTransactionGraphTest.java @@ -0,0 +1,393 @@ +/* + * DISCLAIMER + * + * Copyright 2016 ArangoDB GmbH, Cologne, Germany + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright holder is ArangoDB GmbH, Cologne, Germany + */ + +package com.arangodb.async; + + +import com.arangodb.entity.*; +import com.arangodb.model.*; +import org.junit.After; +import org.junit.Test; + +import java.util.Collections; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +/** + * @author Michele Rastelli + */ +public class StreamTransactionGraphTest extends BaseTest { + + private static final String GRAPH_NAME = "graph_stream_transaction_graph_test"; + private static final String EDGE_COLLECTION = "edge_collection_stream_transaction_graph_test"; + private static final String VERTEX_COLLECTION_1 = "vertex_collection_1_stream_transaction_graph_test"; + private static final String VERTEX_COLLECTION_2 = "vertex_collection_2_stream_transaction_graph_test"; + + private final ArangoGraphAsync graph; + private ArangoVertexCollectionAsync vertexCollection1; + private ArangoVertexCollectionAsync vertexCollection2; + private ArangoEdgeCollectionAsync edgeCollection; + + public StreamTransactionGraphTest() throws ExecutionException, InterruptedException { + + graph = db.graph(GRAPH_NAME); + + if (graph.exists().get()) + graph.drop().get(); + + graph.create(Collections.singletonList(new EdgeDefinition().collection(EDGE_COLLECTION).from(VERTEX_COLLECTION_1).to(VERTEX_COLLECTION_2))).get(); + + vertexCollection1 = graph.vertexCollection(VERTEX_COLLECTION_1); + vertexCollection2 = graph.vertexCollection(VERTEX_COLLECTION_2); + edgeCollection = graph.edgeCollection(EDGE_COLLECTION); + } + + @After + public void teardown() throws ExecutionException, InterruptedException { + if (graph.exists().get()) + graph.drop().get(); + if (db.collection(EDGE_COLLECTION).exists().get()) + db.collection(EDGE_COLLECTION).drop().get(); + if (db.collection(VERTEX_COLLECTION_1).exists().get()) + db.collection(VERTEX_COLLECTION_1).drop().get(); + if (db.collection(VERTEX_COLLECTION_2).exists().get()) + db.collection(VERTEX_COLLECTION_2).drop().get(); + } + + private BaseEdgeDocument createEdgeValue(String streamTransactionId) throws ExecutionException, InterruptedException { + final VertexEntity v1 = vertexCollection1.insertVertex(new BaseDocument(), new VertexCreateOptions().streamTransactionId(streamTransactionId)).get(); + final VertexEntity v2 = vertexCollection2.insertVertex(new BaseDocument(), new VertexCreateOptions().streamTransactionId(streamTransactionId)).get(); + final BaseEdgeDocument value = new BaseEdgeDocument(); + value.setFrom(v1.getId()); + value.setTo(v2.getId()); + return value; + } + + @Test + public void getVertex() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db + .beginStreamTransaction(new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // insert a vertex from outside the tx + VertexEntity createdVertex = vertexCollection1.insertVertex(new BaseDocument()).get(); + + // assert that the vertex is not found from within the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get(), is(nullValue())); + + db.abortStreamTransaction(tx.getId()); + } + + + @Test + public void createVertex() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // insert a vertex from within the tx + VertexEntity createdVertex = vertexCollection1.insertVertex(new BaseDocument(), new VertexCreateOptions().streamTransactionId(tx.getId())).get(); + + // assert that the vertex is not found from outside the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null).get(), is(nullValue())); + + // assert that the vertex is found from within the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get(), is(notNullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex is found after commit + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null).get(), is(notNullValue())); + } + + @Test + public void replaceVertex() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseDocument doc = new BaseDocument(); + doc.addAttribute("test", "foo"); + + VertexEntity createdVertex = vertexCollection1.insertVertex(doc, null).get(); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // replace vertex from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + vertexCollection1.replaceVertex(createdVertex.getKey(), doc, + new VertexReplaceOptions().streamTransactionId(tx.getId())); + + // assert that the vertex has not been replaced from outside the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null).get() + .getProperties().get("test"), is("foo")); + + // assert that the vertex has been replaced from within the tx + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get().getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex has been replaced after commit + assertThat(vertexCollection1.getVertex(createdVertex.getKey(), BaseDocument.class, null).get() + .getProperties().get("test"), is("bar")); + } + + @Test + public void updateVertex() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseDocument doc = new BaseDocument(); + doc.addAttribute("test", "foo"); + + VertexEntity createdDoc = vertexCollection1.insertVertex(doc, null).get(); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // update vertex from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + vertexCollection1.updateVertex(createdDoc.getKey(), doc, new VertexUpdateOptions().streamTransactionId(tx.getId())); + + // assert that the vertex has not been updated from outside the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null).get() + .getProperties().get("test"), is("foo")); + + // assert that the vertex has been updated from within the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get().getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex has been updated after commit + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null).get() + .getProperties().get("test"), is("bar")); + } + + @Test + public void deleteVertex() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + VertexEntity createdDoc = vertexCollection1.insertVertex(new BaseDocument(), null).get(); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // delete vertex from within the tx + vertexCollection1.deleteVertex(createdDoc.getKey(), new VertexDeleteOptions().streamTransactionId(tx.getId())); + + // assert that the vertex has not been deleted from outside the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null).get(), is(notNullValue())); + + // assert that the vertex has been deleted from within the tx + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get(), is(nullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the vertex has been deleted after commit + assertThat(vertexCollection1.getVertex(createdDoc.getKey(), BaseDocument.class, null).get(), + is(nullValue())); + } + + + @Test + public void getEdge() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db + .beginStreamTransaction(new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // insert a edge from outside the tx + EdgeEntity createdEdge = edgeCollection.insertEdge(createEdgeValue(null)).get(); + + // assert that the edge is not found from within the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get(), is(nullValue())); + + db.abortStreamTransaction(tx.getId()); + } + + + @Test + public void createEdge() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // insert a edge from within the tx + EdgeEntity createdEdge = edgeCollection.insertEdge(createEdgeValue(tx.getId()), new EdgeCreateOptions().streamTransactionId(tx.getId())).get(); + + // assert that the edge is not found from outside the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null).get(), is(nullValue())); + + // assert that the edge is found from within the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get(), is(notNullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge is found after commit + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null).get(), is(notNullValue())); + } + + @Test + public void replaceEdge() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseEdgeDocument doc = createEdgeValue(null); + doc.addAttribute("test", "foo"); + + EdgeEntity createdEdge = edgeCollection.insertEdge(doc, null).get(); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // replace edge from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + edgeCollection.replaceEdge(createdEdge.getKey(), doc, + new EdgeReplaceOptions().streamTransactionId(tx.getId())); + + // assert that the edge has not been replaced from outside the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null).get() + .getProperties().get("test"), is("foo")); + + // assert that the edge has been replaced from within the tx + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get().getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge has been replaced after commit + assertThat(edgeCollection.getEdge(createdEdge.getKey(), BaseEdgeDocument.class, null).get() + .getProperties().get("test"), is("bar")); + } + + @Test + public void updateEdge() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + BaseEdgeDocument doc = createEdgeValue(null); + doc.addAttribute("test", "foo"); + + EdgeEntity createdDoc = edgeCollection.insertEdge(doc, null).get(); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // update edge from within the tx + doc.getProperties().clear(); + doc.addAttribute("test", "bar"); + edgeCollection.updateEdge(createdDoc.getKey(), doc, new EdgeUpdateOptions().streamTransactionId(tx.getId())); + + // assert that the edge has not been updated from outside the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null).get() + .getProperties().get("test"), is("foo")); + + // assert that the edge has been updated from within the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get().getProperties().get("test"), is("bar")); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge has been updated after commit + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null).get() + .getProperties().get("test"), is("bar")); + } + + @Test + public void deleteEdge() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + EdgeEntity createdDoc = edgeCollection.insertEdge(createEdgeValue(null), null).get(); + + StreamTransactionEntity tx = db.beginStreamTransaction( + new StreamTransactionOptions() + .readCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION) + .writeCollections(VERTEX_COLLECTION_1, VERTEX_COLLECTION_2, EDGE_COLLECTION)).get(); + + // delete edge from within the tx + edgeCollection.deleteEdge(createdDoc.getKey(), new EdgeDeleteOptions().streamTransactionId(tx.getId())); + + // assert that the edge has not been deleted from outside the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null).get(), is(notNullValue())); + + // assert that the edge has been deleted from within the tx + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, + new GraphDocumentReadOptions().streamTransactionId(tx.getId())).get(), is(nullValue())); + + db.commitStreamTransaction(tx.getId()); + + // assert that the edge has been deleted after commit + assertThat(edgeCollection.getEdge(createdDoc.getKey(), BaseEdgeDocument.class, null).get(), + is(nullValue())); + } + +} diff --git a/src/test/java/com/arangodb/async/TestUtils.java b/src/test/java/com/arangodb/async/TestUtils.java index bcaf0ed78..129ebcf42 100644 --- a/src/test/java/com/arangodb/async/TestUtils.java +++ b/src/test/java/com/arangodb/async/TestUtils.java @@ -30,8 +30,8 @@ /** * @author Michele Rastelli */ -public class TestUtils { - public static TestRule acquireHostListRule = (base, description) -> { +class TestUtils { + static final TestRule acquireHostListRule = (base, description) -> { assumeTrue(!TestUtils.isAcquireHostList()); return base; };