From db7fdc257c8b94ae2300e11ce8367ab8887accd2 Mon Sep 17 00:00:00 2001 From: michele Date: Wed, 4 Sep 2019 16:47:00 +0200 Subject: [PATCH 1/4] copied async driver --- .../arangodb/async/ArangoCollectionAsync.java | 686 ++++++ .../com/arangodb/async/ArangoCursorAsync.java | 34 + .../com/arangodb/async/ArangoDBAsync.java | 758 ++++++ .../arangodb/async/ArangoDatabaseAsync.java | 748 ++++++ .../async/ArangoEdgeCollectionAsync.java | 160 ++ .../com/arangodb/async/ArangoGraphAsync.java | 190 ++ .../com/arangodb/async/ArangoRouteAsync.java | 119 + .../com/arangodb/async/ArangoSearchAsync.java | 89 + .../async/ArangoVertexCollectionAsync.java | 172 ++ .../com/arangodb/async/ArangoViewAsync.java | 84 + .../internal/ArangoCollectionAsyncImpl.java | 424 ++++ .../async/internal/ArangoCursorAsyncImpl.java | 47 + .../async/internal/ArangoDBAsyncImpl.java | 192 ++ .../internal/ArangoDatabaseAsyncImpl.java | 455 ++++ .../ArangoEdgeCollectionAsyncImpl.java | 101 + .../async/internal/ArangoExecutorAsync.java | 76 + .../async/internal/ArangoGraphAsyncImpl.java | 118 + .../async/internal/ArangoRouteAsyncImpl.java | 100 + .../async/internal/ArangoSearchAsyncImpl.java | 90 + .../ArangoVertexCollectionAsyncImpl.java | 109 + .../async/internal/ArangoViewAsyncImpl.java | 60 + .../velocystream/VstCommunicationAsync.java | 175 ++ .../velocystream/VstConnectionAsync.java | 107 + .../VstConnectionFactoryAsync.java | 49 + .../arangodb/async/ArangoCollectionTest.java | 2133 +++++++++++++++++ .../java/com/arangodb/async/ArangoDBTest.java | 529 ++++ .../arangodb/async/ArangoDatabaseTest.java | 1058 ++++++++ .../async/ArangoEdgeCollectionTest.java | 384 +++ .../com/arangodb/async/ArangoGraphTest.java | 287 +++ .../com/arangodb/async/ArangoRouteTest.java | 81 + .../com/arangodb/async/ArangoSearchTest.java | 401 ++++ .../com/arangodb/async/ArangoSslTest.java | 92 + .../async/ArangoVertexCollectionTest.java | 372 +++ .../com/arangodb/async/ArangoViewTest.java | 85 + .../java/com/arangodb/async/BaseTest.java | 87 + .../com/arangodb/async/CommunicationTest.java | 46 + .../com/arangodb/async/ConcurrencyTest.java | 87 + .../ConcurrentStreamTransactionsTest.java | 125 + .../arangodb/async/StreamTransactionTest.java | 361 +++ .../debug/ConsolidationIntervalMsec.java | 75 + .../arangodb/async/example/ExampleBase.java | 60 + ...AqlQueryWithSpecialReturnTypesExample.java | 138 ++ .../example/document/GetDocumentExample.java | 94 + .../document/ImportDocumentExample.java | 84 + .../document/InsertDocumentExample.java | 72 + .../async/example/document/TestEntity.java | 48 + .../graph/AQLActorsAndMoviesExample.java | 582 +++++ .../async/example/graph/BaseGraphTest.java | 112 + .../arangodb/async/example/graph/Circle.java | 80 + .../async/example/graph/CircleEdge.java | 124 + .../graph/GraphTraversalsInAQLExample.java | 119 + .../graph/ShortestPathInAQLExample.java | 104 + .../async/example/ssl/SslExample.java | 76 + .../example/velocypack/VPackExample.java | 113 + .../arangodb/async/serde/CustomSerdeTest.java | 168 ++ 55 files changed, 13320 insertions(+) create mode 100644 src/main/java/com/arangodb/async/ArangoCollectionAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoCursorAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoDBAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoDatabaseAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoEdgeCollectionAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoGraphAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoRouteAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoSearchAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoVertexCollectionAsync.java create mode 100644 src/main/java/com/arangodb/async/ArangoViewAsync.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoDBAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoDatabaseAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoExecutorAsync.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoGraphAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoRouteAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoSearchAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/ArangoViewAsyncImpl.java create mode 100644 src/main/java/com/arangodb/async/internal/velocystream/VstCommunicationAsync.java create mode 100644 src/main/java/com/arangodb/async/internal/velocystream/VstConnectionAsync.java create mode 100644 src/main/java/com/arangodb/async/internal/velocystream/VstConnectionFactoryAsync.java create mode 100644 src/test/java/com/arangodb/async/ArangoCollectionTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoDBTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoDatabaseTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoGraphTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoRouteTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoSearchTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoSslTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java create mode 100644 src/test/java/com/arangodb/async/ArangoViewTest.java create mode 100644 src/test/java/com/arangodb/async/BaseTest.java create mode 100644 src/test/java/com/arangodb/async/CommunicationTest.java create mode 100644 src/test/java/com/arangodb/async/ConcurrencyTest.java create mode 100644 src/test/java/com/arangodb/async/ConcurrentStreamTransactionsTest.java create mode 100644 src/test/java/com/arangodb/async/StreamTransactionTest.java create mode 100644 src/test/java/com/arangodb/async/debug/ConsolidationIntervalMsec.java create mode 100644 src/test/java/com/arangodb/async/example/ExampleBase.java create mode 100644 src/test/java/com/arangodb/async/example/document/AqlQueryWithSpecialReturnTypesExample.java create mode 100644 src/test/java/com/arangodb/async/example/document/GetDocumentExample.java create mode 100644 src/test/java/com/arangodb/async/example/document/ImportDocumentExample.java create mode 100644 src/test/java/com/arangodb/async/example/document/InsertDocumentExample.java create mode 100644 src/test/java/com/arangodb/async/example/document/TestEntity.java create mode 100644 src/test/java/com/arangodb/async/example/graph/AQLActorsAndMoviesExample.java create mode 100644 src/test/java/com/arangodb/async/example/graph/BaseGraphTest.java create mode 100644 src/test/java/com/arangodb/async/example/graph/Circle.java create mode 100644 src/test/java/com/arangodb/async/example/graph/CircleEdge.java create mode 100644 src/test/java/com/arangodb/async/example/graph/GraphTraversalsInAQLExample.java create mode 100644 src/test/java/com/arangodb/async/example/graph/ShortestPathInAQLExample.java create mode 100644 src/test/java/com/arangodb/async/example/ssl/SslExample.java create mode 100644 src/test/java/com/arangodb/async/example/velocypack/VPackExample.java create mode 100644 src/test/java/com/arangodb/async/serde/CustomSerdeTest.java diff --git a/src/main/java/com/arangodb/async/ArangoCollectionAsync.java b/src/main/java/com/arangodb/async/ArangoCollectionAsync.java new file mode 100644 index 000000000..e11b028df --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoCollectionAsync.java @@ -0,0 +1,686 @@ +/* + * 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.ArangoDBException; +import com.arangodb.ArangoSerializationAccessor; +import com.arangodb.entity.*; +import com.arangodb.model.*; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +/** + * Interface for operations on ArangoDB collection level. + * + * @author Mark Vollmary + * @see Collection API Documentation + * @see Documents API Documentation + */ +@SuppressWarnings("unused") +public interface ArangoCollectionAsync extends ArangoSerializationAccessor { + + /** + * The the handler of the database the collection is within + * + * @return database handler + */ + ArangoDatabaseAsync db(); + + /** + * The name of the collection + * + * @return collection name + */ + String name(); + + /** + * Creates a new document from the given document, unless there is already a document with the _key given. If no + * _key is given, a new unique _key is generated automatically. + * + * @param value A representation of a single document (POJO, VPackSlice or String for Json) + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> insertDocument(final T value); + + /** + * Creates a new document from the given document, unless there is already a document with the _key given. If no + * _key is given, a new unique _key is generated automatically. + * + * @param value A representation of a single document (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> insertDocument(final T value, final DocumentCreateOptions options); + + /** + * Creates new documents from the given documents, unless there is already a document with the _key given. If no + * _key is given, a new unique _key is generated automatically. + * + * @param values A List of documents (POJO, VPackSlice or String for Json) + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> insertDocuments(final Collection values); + + /** + * Creates new documents from the given documents, unless there is already a document with the _key given. If no + * _key is given, a new unique _key is generated automatically. + * + * @param values A List of documents (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> insertDocuments( + final Collection values, + final DocumentCreateOptions options); + + /** + * Imports documents + * + * @param values a list of Objects that will be stored as documents + * @return information about the import + */ + CompletableFuture importDocuments(final Collection values); + + /** + * Imports documents + * + * @param values a list of Objects that will be stored as documents + * @param options Additional options, can be null + * @return information about the import + */ + CompletableFuture importDocuments( + final Collection values, + final DocumentImportOptions options); + + /** + * Imports documents + * + * @param values JSON-encoded array of objects that will be stored as documents + * @return information about the import + */ + CompletableFuture importDocuments(final String values); + + /** + * Imports documents + * + * @param values JSON-encoded array of objects that will be stored as documents + * @param options Additional options, can be null + * @return information about the import + */ + CompletableFuture importDocuments(final String values, final DocumentImportOptions options); + + /** + * Reads a single document + * + * @param key The key of the document + * @param type The type of the document (POJO class, VPackSlice or String for Json) + * @return the document identified by the key + * @see API + * Documentation + */ + CompletableFuture getDocument(final String key, final Class type) throws ArangoDBException; + + /** + * Reads a single document + * + * @param key The key of the document + * @param type The type of the document (POJO class, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return the document identified by the key + * @see API + * Documentation + */ + CompletableFuture getDocument(final String key, final Class type, final DocumentReadOptions options) + throws ArangoDBException; + + /** + * Reads multiple documents + * + * @param keys The keys of the documents + * @param type The type of the documents (POJO class, VPackSlice or String for Json) + * @return the documents and possible errors + */ + CompletableFuture> getDocuments(final Collection keys, final Class type); + + /** + * Reads multiple documents + * + * @param keys The keys of the documents + * @param type The type of the documents (POJO class, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return the documents and possible errors + */ + CompletableFuture> getDocuments( + final Collection keys, + final Class type, + DocumentReadOptions options); + + /** + * Replaces the document with key with the one in the body, provided there is such a document and no precondition is + * violated + * + * @param key The key of the document + * @param value A representation of a single document (POJO, VPackSlice or String for Json) + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> replaceDocument(final String key, final T value); + + /** + * Replaces the document with key with the one in the body, provided there is such a document and no precondition is + * violated + * + * @param key The key of the document + * @param value A representation of a single document (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> replaceDocument( + final String key, + final T value, + final DocumentReplaceOptions options); + + /** + * Replaces multiple documents in the specified collection with the ones in the values, the replaced documents are + * specified by the _key attributes in the documents in values. + * + * @param values A List of documents (POJO, VPackSlice or String for Json) + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> replaceDocuments(final Collection values); + + /** + * Replaces multiple documents in the specified collection with the ones in the values, the replaced documents are + * specified by the _key attributes in the documents in values. + * + * @param values A List of documents (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> replaceDocuments( + final Collection values, + final DocumentReplaceOptions options); + + /** + * Partially updates the document identified by document-key. The value must contain a document with the attributes + * to patch (the patch document). All attributes from the patch document will be added to the existing document if + * they do not yet exist, and overwritten in the existing document if they do exist there. + * + * @param key The key of the document + * @param value A representation of a single document (POJO, VPackSlice or String for Json) + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> updateDocument(final String key, final T value); + + /** + * Partially updates the document identified by document-key. The value must contain a document with the attributes + * to patch (the patch document). All attributes from the patch document will be added to the existing document if + * they do not yet exist, and overwritten in the existing document if they do exist there. + * + * @param key The key of the document + * @param value A representation of a single document (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> updateDocument( + final String key, + final T value, + final DocumentUpdateOptions options); + + /** + * Partially updates documents, the documents to update are specified by the _key attributes in the objects on + * values. Vales must contain a list of document updates with the attributes to patch (the patch documents). All + * attributes from the patch documents will be added to the existing documents if they do not yet exist, and + * overwritten in the existing documents if they do exist there. + * + * @param values A list of documents (POJO, VPackSlice or String for Json) + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> updateDocuments(final Collection values); + + /** + * Partially updates documents, the documents to update are specified by the _key attributes in the objects on + * values. Vales must contain a list of document updates with the attributes to patch (the patch documents). All + * attributes from the patch documents will be added to the existing documents if they do not yet exist, and + * overwritten in the existing documents if they do exist there. + * + * @param values A list of documents (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> updateDocuments( + final Collection values, + final DocumentUpdateOptions options); + + /** + * Removes a document + * + * @param key The key of the document + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> deleteDocument(final String key); + + /** + * Removes a document + * + * @param key The key of the document + * @param type The type of the document (POJO class, VPackSlice or String for Json). Only necessary if + * options.returnOld is set to true, otherwise can be null. + * @param options Additional options, can be null + * @return information about the document + * @see API + * Documentation + */ + CompletableFuture> deleteDocument( + final String key, + final Class type, + final DocumentDeleteOptions options); + + /** + * Removes multiple document + * + * @param values The keys of the documents or the documents themselves + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> deleteDocuments(final Collection values); + + /** + * Removes multiple document + * + * @param values The keys of the documents or the documents themselves + * @param type The type of the documents (POJO class, VPackSlice or String for Json). Only necessary if + * options.returnOld is set to true, otherwise can be null. + * @param options Additional options, can be null + * @return information about the documents + * @see API + * Documentation + */ + CompletableFuture>> deleteDocuments( + final Collection values, + final Class type, + final DocumentDeleteOptions options); + + /** + * Checks if the document exists by reading a single document head + * + * @param key The key of the document + * @return true if the document was found, otherwise false + * @see API + * Documentation + */ + CompletableFuture documentExists(final String key); + + /** + * Checks if the document exists by reading a single document head + * + * @param key The key of the document + * @param options Additional options, can be null + * @return true if the document was found, otherwise false + * @see API + * Documentation + */ + CompletableFuture documentExists(final String key, final DocumentExistsOptions options); + + /** + * Returns an index + * + * @param id The index-handle + * @return information about the index + * @see API Documentation + */ + CompletableFuture getIndex(final String id); + + /** + * Deletes an index + * + * @param id The index-handle + * @return the id of the index + * @see API Documentation + */ + CompletableFuture deleteIndex(final String id); + + /** + * Creates a hash index for the collection, if it does not already exist. + * + * @param fields A list of attribute paths + * @param options Additional options, can be null + * @return information about the index + * @see API Documentation + */ + CompletableFuture ensureHashIndex(final Iterable fields, final HashIndexOptions options); + + /** + * Creates a skip-list index for the collection, if it does not already exist. + * + * @param fields A list of attribute paths + * @param options Additional options, can be null + * @return information about the index + * @see API + * Documentation + */ + CompletableFuture ensureSkiplistIndex( + final Iterable fields, + final SkiplistIndexOptions options); + + /** + * Creates a persistent index for the collection, if it does not already exist. + * + * @param fields A list of attribute paths + * @param options Additional options, can be null + * @return information about the index + * @see API + * Documentation + */ + CompletableFuture ensurePersistentIndex( + final Iterable fields, + final PersistentIndexOptions options); + + /** + * Creates a geo-spatial index for the collection, if it does not already exist. + * + * @param fields A list of attribute paths + * @param options Additional options, can be null + * @return information about the index + * @see API + * Documentation + */ + CompletableFuture ensureGeoIndex(final Iterable fields, final GeoIndexOptions options); + + /** + * Creates a fulltext index for the collection, if it does not already exist. + * + * @param fields A list of attribute paths + * @param options Additional options, can be null + * @return information about the index + * @see API + * Documentation + */ + CompletableFuture ensureFulltextIndex( + final Iterable fields, + final FulltextIndexOptions options); + + /** + * Creates a ttl index for the collection, if it does not already exist. + * + * @param fields A list of attribute paths + * @param options Additional options, can be null + * @return information about the index + * @see API + * Documentation + */ + CompletableFuture ensureTtlIndex(Iterable fields, TtlIndexOptions options); + + /** + * Returns all indexes of the collection + * + * @return information about the indexes + * @see API + * Documentation + */ + CompletableFuture> getIndexes(); + + /** + * Checks whether the collection exists + * + * @return true if the collection exists, otherwise false + */ + CompletableFuture exists(); + + /** + * Removes all documents from the collection, but leaves the indexes intact + * + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture truncate(); + + /** + * Removes all documents from the collection, but leaves the indexes intact + * + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture truncate(CollectionTruncateOptions options); + + /** + * Counts the documents in a collection + * + * @return information about the collection, including the number of documents + * @see API + * Documentation + */ + CompletableFuture count(); + + /** + * Counts the documents in a collection + * + * @return information about the collection, including the number of documents + * @see API + * Documentation + */ + CompletableFuture count(CollectionCountOptions options); + + /** + * Creates the collection + * + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture create(); + + /** + * Creates the collection + * + * @param options Additional options, can be null + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture create(final CollectionCreateOptions options); + + /** + * Drops the collection + * + * @return void + * @see API + * Documentation + */ + CompletableFuture drop(); + + /** + * Drops the collection + * + * @param isSystem Whether or not the collection to drop is a system collection. This parameter must be set to true in + * order to drop a system collection. + * @return void + * @see API + * Documentation + */ + CompletableFuture drop(final boolean isSystem); + + /** + * Loads a collection into memory. + * + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture load(); + + /** + * Removes a collection from memory. This call does not delete any documents. You can use the collection afterwards; + * in which case it will be loaded into memory, again. + * + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture unload(); + + /** + * Returns information about the collection + * + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture getInfo(); + + /** + * Reads the properties of the specified collection + * + * @return properties of the collection + * @see API + * Documentation + */ + CompletableFuture getProperties(); + + /** + * Changes the properties of a collection + * + * @param options Additional options, can be null + * @return properties of the collection + * @see API + * Documentation + */ + CompletableFuture changeProperties(final CollectionPropertiesOptions options); + + /** + * Renames a collection + * + * @param newName The new name + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture rename(final String newName); + + /** + * Returns the responsible shard for the document. + * Please note that this API is only meaningful and available on a cluster coordinator. + * + * @param value A projection of the document containing at least the shard key (_key or a custom attribute) for + * which the responsible shard should be determined + * @return information about the responsible shard + * @see + * API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture getResponsibleShard(final Object value); + + /** + * Retrieve the collections revision + * + * @return information about the collection, including the collections revision + * @see API + * Documentation + */ + CompletableFuture getRevision(); + + /** + * Grants or revoke access to the collection for user user. You need permission to the _system database in order to + * execute this call. + * + * @param user The name of the user + * @param permissions The permissions the user grant + * @return void + * @see API + * Documentation + */ + CompletableFuture grantAccess(final String user, final Permissions permissions); + + /** + * Revokes access to the collection for user user. You need permission to the _system database in order to execute + * this call. + * + * @param user The name of the user + * @return void + * @see API + * Documentation + */ + CompletableFuture revokeAccess(final String user); + + /** + * Clear the collection access level, revert back to the default access level. + * + * @param user The name of the user + * @return void + * @see API + * Documentation + * @since ArangoDB 3.2.0 + */ + CompletableFuture resetAccess(final String user); + + /** + * Get the collection access level + * + * @param user The name of the user + * @return permissions of the user + * @see + * API Documentation + * @since ArangoDB 3.2.0 + */ + CompletableFuture getPermissions(final String user); +} diff --git a/src/main/java/com/arangodb/async/ArangoCursorAsync.java b/src/main/java/com/arangodb/async/ArangoCursorAsync.java new file mode 100644 index 000000000..e615bb401 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoCursorAsync.java @@ -0,0 +1,34 @@ +/* + * 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.ArangoCursor; + +import java.util.stream.Stream; + +/** + * @author Mark Vollmary + */ +public interface ArangoCursorAsync extends ArangoCursor { + + Stream streamRemaining(); + +} diff --git a/src/main/java/com/arangodb/async/ArangoDBAsync.java b/src/main/java/com/arangodb/async/ArangoDBAsync.java new file mode 100644 index 000000000..4d1767657 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoDBAsync.java @@ -0,0 +1,758 @@ +/* + * 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.ArangoDBException; +import com.arangodb.ArangoSerializationAccessor; +import com.arangodb.Protocol; +import com.arangodb.async.internal.ArangoDBAsyncImpl; +import com.arangodb.async.internal.velocystream.VstCommunicationAsync; +import com.arangodb.async.internal.velocystream.VstConnectionFactoryAsync; +import com.arangodb.entity.*; +import com.arangodb.internal.ArangoContext; +import com.arangodb.internal.ArangoDefaults; +import com.arangodb.internal.InternalArangoDBBuilder; +import com.arangodb.internal.net.ConnectionFactory; +import com.arangodb.internal.net.HostHandler; +import com.arangodb.internal.net.HostResolver; +import com.arangodb.internal.util.ArangoDeserializerImpl; +import com.arangodb.internal.util.ArangoSerializationFactory; +import com.arangodb.internal.util.ArangoSerializerImpl; +import com.arangodb.internal.util.DefaultArangoSerialization; +import com.arangodb.internal.velocystream.VstCommunicationSync; +import com.arangodb.model.LogOptions; +import com.arangodb.model.UserCreateOptions; +import com.arangodb.model.UserUpdateOptions; +import com.arangodb.util.ArangoDeserializer; +import com.arangodb.util.ArangoSerialization; +import com.arangodb.util.ArangoSerializer; +import com.arangodb.velocypack.*; +import com.arangodb.velocystream.Request; +import com.arangodb.velocystream.Response; + +import javax.net.ssl.SSLContext; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +/** + * Central access point for applications to communicate with an ArangoDB server. + * + *

+ * Will be instantiated through {@link ArangoDBAsync.Builder} + *

+ * + *
+ * ArangoDBAsync arango = new ArangoDBAsync.Builder().build();
+ * ArangoDBAsync arango = new ArangoDBAsync.Builder().host("127.0.0.1", 8529).build();
+ * 
+ * + * @author Mark Vollmary + */ +public interface ArangoDBAsync extends ArangoSerializationAccessor { + + void shutdown() throws ArangoDBException; + + /** + * Returns a handler of the system database + * + * @return database handler + */ + ArangoDatabaseAsync db(); + + /** + * Returns a handler of the database by the given name + * + * @param name Name of the database + * @return database handler + */ + ArangoDatabaseAsync db(final String name); + + /** + * Creates a new database + * + * @param name Has to contain a valid database name + * @return true if the database was created successfully. + * @see API + * Documentation + */ + CompletableFuture createDatabase(final String name); + + /** + * Retrieves a list of all existing databases + * + * @return a list of all existing databases + * @see API + * Documentation + */ + CompletableFuture> getDatabases(); + + /** + * Retrieves a list of all databases the current user can access + * + * @return a list of all databases the current user can access + * @see API + * Documentation + */ + CompletableFuture> getAccessibleDatabases(); + + /** + * List available database to the specified user + * + * @param user The name of the user for which you want to query the databases + * @return + * @see API + * Documentation + */ + CompletableFuture> getAccessibleDatabasesFor(final String user); + + /** + * Returns the server name and version number. + * + * @return the server version, number + * @see API + * Documentation + */ + CompletableFuture getVersion(); + + /** + * Returns the server role. + * + * @return the server role + */ + CompletableFuture getRole(); + + /** + * Create a new user. This user will not have access to any database. You need permission to the _system database in + * order to execute this call. + * + * @param user The name of the user + * @param passwd The user password + * @return information about the user + * @see API Documentation + */ + CompletableFuture createUser(final String user, final String passwd); + + /** + * Create a new user. This user will not have access to any database. You need permission to the _system database in + * order to execute this call. + * + * @param user The name of the user + * @param passwd The user password + * @param options Additional properties of the user, can be null + * @return information about the user + * @see API Documentation + */ + CompletableFuture createUser(final String user, final String passwd, final UserCreateOptions options); + + /** + * Removes an existing user, identified by user. You need access to the _system database. + * + * @param user The name of the user + * @return void + * @see API Documentation + */ + CompletableFuture deleteUser(final String user); + + /** + * Fetches data about the specified user. You can fetch information about yourself or you need permission to the + * _system database in order to execute this call. + * + * @param user The name of the user + * @return information about the user + * @see API Documentation + */ + CompletableFuture getUser(final String user); + + /** + * Fetches data about all users. You can only execute this call if you have access to the _system database. + * + * @return informations about all users + * @see API + * Documentation + */ + CompletableFuture> getUsers(); + + /** + * Partially updates the data of an existing user. The name of an existing user must be specified in user. You can + * only change the password of your self. You need access to the _system database to change the active flag. + * + * @param user The name of the user + * @param options Properties of the user to be changed + * @return information about the user + * @see API Documentation + */ + CompletableFuture updateUser(final String user, final UserUpdateOptions options); + + /** + * Replaces the data of an existing user. The name of an existing user must be specified in user. You can only + * change the password of your self. You need access to the _system database to change the active flag. + * + * @param user The name of the user + * @param options Additional properties of the user, can be null + * @return information about the user + * @see API + * Documentation + */ + CompletableFuture replaceUser(final String user, final UserUpdateOptions options); + + /** + * Sets the default access level for databases for the user user. You need permission to the _system + * database in order to execute this call. + * + * @param user The name of the user + * @param permissions The permissions the user grant + * @return void + * @since ArangoDB 3.2.0 + */ + CompletableFuture grantDefaultDatabaseAccess(final String user, final Permissions permissions); + + /** + * Sets the default access level for collections for the user user. You need permission to the _system + * database in order to execute this call. + * + * @param user The name of the user + * @param permissions The permissions the user grant + * @return void + * @since ArangoDB 3.2.0 + */ + CompletableFuture grantDefaultCollectionAccess(final String user, final Permissions permissions); + + /** + * Generic Execute. Use this method to execute custom FOXX services. + * + * @param request VelocyStream request + * @return VelocyStream response + */ + CompletableFuture execute(final Request request); + + /** + * Returns fatal, error, warning or info log messages from the server's global log. + * + * @param options Additional options, can be null + * @return the log messages + * @see API + * Documentation + */ + CompletableFuture getLogs(final LogOptions options); + + /** + * Returns the server's current loglevel settings. + * + * @return the server's current loglevel settings + */ + CompletableFuture getLogLevel(); + + /** + * Modifies and returns the server's current loglevel settings. + * + * @param entity loglevel settings + * @return the server's current loglevel settings + */ + CompletableFuture setLogLevel(final LogLevelEntity entity); + + /** + * Builder class to build an instance of {@link ArangoDBAsync}. + * + * @author Mark Vollmary + */ + @SuppressWarnings("unused") + class Builder extends InternalArangoDBBuilder { + + public Builder() { + super(); + } + + @Override + public Builder loadProperties(final InputStream in) throws ArangoDBException { + super.loadProperties(in); + return this; + } + + /** + * Adds a host to connect to. Multiple hosts can be added to provide fallbacks. + * + * @param host address of the host + * @param port port of the host + * @return {@link ArangoDBAsync.Builder} + */ + public Builder host(final String host, final int port) { + setHost(host, port); + return this; + } + + /** + * Sets the timeout in milliseconds. It is used as socket timeout when opening a VecloyStream. + * + * @param timeout timeout in milliseconds + * @return {@link ArangoDBAsync.Builder} + */ + public Builder timeout(final Integer timeout) { + setTimeout(timeout); + return this; + } + + /** + * Sets the username to use for authentication. + * + * @param user the user in the database (default: root) + * @return {@link ArangoDBAsync.Builder} + */ + public Builder user(final String user) { + setUser(user); + return this; + } + + /** + * Sets the password for the user for authentication. + * + * @param password the password of the user in the database (default: null) + * @return {@link ArangoDBAsync.Builder} + */ + public Builder password(final String password) { + setPassword(password); + return this; + } + + /** + * If set to true SSL will be used when connecting to an ArangoDB server. + * + * @param useSsl whether or not use SSL (default: false) + * @return {@link ArangoDBAsync.Builder} + */ + public Builder useSsl(final Boolean useSsl) { + setUseSsl(useSsl); + return this; + } + + /** + * Sets the SSL context to be used when true is passed through {@link #useSsl(Boolean)}. + * + * @param sslContext SSL context to be used + * @return {@link ArangoDBAsync.Builder} + */ + public Builder sslContext(final SSLContext sslContext) { + setSslContext(sslContext); + return this; + } + + /** + * Sets the chunk size when {@link Protocol#VST} is used. + * + * @param chunksize size of a chunk in bytes + * @return {@link ArangoDBAsync.Builder} + */ + public Builder chunksize(final Integer chunksize) { + setChunksize(chunksize); + return this; + } + + /** + * Sets the maximum number of connections the built in connection pool will open. + * + *

+ * In an ArangoDB cluster setup with {@link LoadBalancingStrategy#ROUND_ROBIN} set, this value should be at + * least as high as the number of ArangoDB coordinators in the cluster. + *

+ * + * @param maxConnections max number of connections (default: 1) + * @return {@link ArangoDBAsync.Builder} + */ + public Builder maxConnections(final Integer maxConnections) { + setMaxConnections(maxConnections); + return this; + } + + /** + * Set the maximum time to life of a connection. After this time the connection will be closed automatically. + * + * @param connectionTtl the maximum time to life of a connection. + * @return {@link ArangoDBAsync.Builder} + */ + public Builder connectionTtl(final Long connectionTtl) { + setConnectionTtl(connectionTtl); + return this; + } + + /** + * Whether or not the driver should acquire a list of available coordinators in an ArangoDB cluster or a single + * server with active failover. + * + *

+ * The host list will be used for failover and load balancing. + *

+ * + * @param acquireHostList whether or not automatically acquire a list of available hosts (default: false) + * @return {@link ArangoDBAsync.Builder} + */ + public Builder acquireHostList(final Boolean acquireHostList) { + setAcquireHostList(acquireHostList); + return this; + } + + /** + * Sets the load balancing strategy to be used in an ArangoDB cluster setup. + * + * @param loadBalancingStrategy the load balancing strategy to be used (default: {@link LoadBalancingStrategy#NONE} + * @return {@link ArangoDBAsync.Builder} + */ + public Builder loadBalancingStrategy(final LoadBalancingStrategy loadBalancingStrategy) { + setLoadBalancingStrategy(loadBalancingStrategy); + return this; + } + + /** + * Register a custom {@link VPackSerializer} for a specific type to be used within the internal serialization + * process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param clazz the type the serializer should be registered for + * @param serializer serializer to register + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerSerializer(final Class clazz, final VPackSerializer serializer) { + vpackBuilder.registerSerializer(clazz, serializer); + return this; + } + + /** + * Register a special serializer for a member class which can only be identified by its enclosing class. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param clazz the type of the enclosing class + * @param serializer serializer to register + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerEnclosingSerializer(final Class clazz, final VPackSerializer serializer) { + vpackBuilder.registerEnclosingSerializer(clazz, serializer); + return this; + } + + /** + * Register a custom {@link VPackDeserializer} for a specific type to be used within the internal serialization + * process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param clazz the type the serializer should be registered for + * @param deserializer + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerDeserializer(final Class clazz, final VPackDeserializer deserializer) { + vpackBuilder.registerDeserializer(clazz, deserializer); + return this; + } + + /** + * Register a custom {@link VPackInstanceCreator} for a specific type to be used within the internal + * serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param clazz the type the instance creator should be registered for + * @param creator + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerInstanceCreator(final Class clazz, final VPackInstanceCreator creator) { + vpackBuilder.registerInstanceCreator(clazz, creator); + return this; + } + + /** + * Register a custom {@link VPackJsonDeserializer} for a specific type to be used within the internal + * serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param type the type the serializer should be registered for + * @param deserializer + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerJsonDeserializer(final ValueType type, final VPackJsonDeserializer deserializer) { + vpackParserBuilder.registerDeserializer(type, deserializer); + return this; + } + + /** + * Register a custom {@link VPackJsonDeserializer} for a specific type and attribute name to be used within the + * internal serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param attribute + * @param type the type the serializer should be registered for + * @param deserializer + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerJsonDeserializer( + final String attribute, + final ValueType type, + final VPackJsonDeserializer deserializer) { + vpackParserBuilder.registerDeserializer(attribute, type, deserializer); + return this; + } + + /** + * Register a custom {@link VPackJsonSerializer} for a specific type to be used within the internal + * serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param clazz the type the serializer should be registered for + * @param serializer + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerJsonSerializer(final Class clazz, final VPackJsonSerializer serializer) { + vpackParserBuilder.registerSerializer(clazz, serializer); + return this; + } + + /** + * Register a custom {@link VPackJsonSerializer} for a specific type and attribute name to be used within the + * internal serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param attribute + * @param clazz the type the serializer should be registered for + * @param serializer + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerJsonSerializer( + final String attribute, + final Class clazz, + final VPackJsonSerializer serializer) { + vpackParserBuilder.registerSerializer(attribute, clazz, serializer); + return this; + } + + /** + * Register a custom {@link VPackAnnotationFieldFilter} for a specific type to be used within the internal + * serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param type the type the serializer should be registered for + * @param fieldFilter + * @return {@link ArangoDBAsync.Builder} + */ + public Builder annotationFieldFilter( + final Class type, + final VPackAnnotationFieldFilter fieldFilter) { + vpackBuilder.annotationFieldFilter(type, fieldFilter); + return this; + } + + /** + * Register a custom {@link VPackAnnotationFieldNaming} for a specific type to be used within the internal + * serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param type the type the serializer should be registered for + * @param fieldNaming + * @return {@link ArangoDBAsync.Builder} + */ + public
Builder annotationFieldNaming( + final Class type, + final VPackAnnotationFieldNaming fieldNaming) { + vpackBuilder.annotationFieldNaming(type, fieldNaming); + return this; + } + + /** + * Register a {@link VPackModule} to be used within the internal serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param module module to register + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerModule(final VPackModule module) { + vpackBuilder.registerModule(module); + return this; + } + + /** + * Register a list of {@link VPackModule} to be used within the internal serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param modules modules to register + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerModules(final VPackModule... modules) { + vpackBuilder.registerModules(modules); + return this; + } + + /** + * Register a {@link VPackParserModule} to be used within the internal serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param module module to register + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerJsonModule(final VPackParserModule module) { + vpackParserBuilder.registerModule(module); + return this; + } + + /** + * Register a list of {@link VPackParserModule} to be used within the internal serialization process. + * + *

+ * Attention:can not be used together with {@link #serializer(ArangoSerialization)} + *

+ * + * @param modules modules to register + * @return {@link ArangoDBAsync.Builder} + */ + public Builder registerJsonModules(final VPackParserModule... modules) { + vpackParserBuilder.registerModules(modules); + return this; + } + + /** + * Replace the built-in serializer with the given serializer. + *

+ *
+ * ATTENTION!: Use at your own risk + * + * @param serializer custom serializer + * @return {@link ArangoDBAsync.Builder} + * @deprecated use {@link #serializer(ArangoSerialization)} instead + */ + @Deprecated + public Builder setSerializer(final ArangoSerializer serializer) { + serializer(serializer); + return this; + } + + /** + * Replace the built-in deserializer with the given deserializer. + *

+ *
+ * ATTENTION!: Use at your own risk + * + * @param deserializer custom deserializer + * @return {@link ArangoDBAsync.Builder} + * @deprecated use {@link #serializer(ArangoSerialization)} instead + */ + @Deprecated + public Builder setDeserializer(final ArangoDeserializer deserializer) { + deserializer(deserializer); + return this; + } + + /** + * Replace the built-in serializer/deserializer with the given one. + *

+ *
+ * ATTENTION!: Any registered custom serializer/deserializer or module will be ignored. + * + * @param serialization custom serializer/deserializer + * @return {@link ArangoDBAsync.Builder} + */ + public Builder serializer(final ArangoSerialization serialization) { + setSerializer(serialization); + return this; + } + + /** + * Returns an instance of {@link ArangoDBAsync}. + * + * @return {@link ArangoDBAsync} + */ + public synchronized ArangoDBAsync build() { + if (hosts.isEmpty()) { + hosts.add(host); + } + final VPack vpacker = vpackBuilder.serializeNullValues(false).build(); + final VPack vpackerNull = vpackBuilder.serializeNullValues(true).build(); + final VPackParser vpackParser = vpackParserBuilder.build(); + final ArangoSerializer serializerTemp = serializer != null ? serializer + : new ArangoSerializerImpl(vpacker, vpackerNull, vpackParser); + final ArangoDeserializer deserializerTemp = deserializer != null ? deserializer + : new ArangoDeserializerImpl(vpackerNull, vpackParser); + final DefaultArangoSerialization internal = new DefaultArangoSerialization(serializerTemp, + deserializerTemp); + final ArangoSerialization custom = customSerializer != null ? customSerializer : internal; + final ArangoSerializationFactory util = new ArangoSerializationFactory(internal, custom); + + final int max = maxConnections != null ? Math.max(1, maxConnections) + : ArangoDefaults.MAX_CONNECTIONS_VST_DEFAULT; + final ConnectionFactory connectionFactory = new VstConnectionFactoryAsync(host, timeout, connectionTtl, + useSsl, sslContext); + final HostResolver hostResolver = createHostResolver(createHostList(max, connectionFactory), max, + connectionFactory); + final HostHandler hostHandler = createHostHandler(hostResolver); + return new ArangoDBAsyncImpl(asyncBuilder(hostHandler), util, syncBuilder(hostHandler), hostResolver, + new ArangoContext()); + } + + private VstCommunicationAsync.Builder asyncBuilder(final HostHandler hostHandler) { + return new VstCommunicationAsync.Builder(hostHandler).timeout(timeout).user(user).password(password) + .useSsl(useSsl).sslContext(sslContext).chunksize(chunksize).maxConnections(maxConnections) + .connectionTtl(connectionTtl); + } + + private VstCommunicationSync.Builder syncBuilder(final HostHandler hostHandler) { + return new VstCommunicationSync.Builder(hostHandler).timeout(timeout).user(user).password(password) + .useSsl(useSsl).sslContext(sslContext).chunksize(chunksize).maxConnections(maxConnections) + .connectionTtl(connectionTtl); + } + + } +} diff --git a/src/main/java/com/arangodb/async/ArangoDatabaseAsync.java b/src/main/java/com/arangodb/async/ArangoDatabaseAsync.java new file mode 100644 index 000000000..9a6c7a7c3 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoDatabaseAsync.java @@ -0,0 +1,748 @@ +/* + * 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.ArangoDBException; +import com.arangodb.ArangoSerializationAccessor; +import com.arangodb.entity.*; +import com.arangodb.entity.arangosearch.AnalyzerEntity; +import com.arangodb.model.*; +import com.arangodb.model.arangosearch.AnalyzerDeleteOptions; +import com.arangodb.model.arangosearch.ArangoSearchCreateOptions; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** + * Interface for operations on ArangoDB database level. + * + * @author Mark Vollmary + * @see
Databases API Documentation + * @see Query API Documentation + */ +@SuppressWarnings("unused") +public interface ArangoDatabaseAsync extends ArangoSerializationAccessor { + + /** + * Return the main entry point for the ArangoDB driver + * + * @return main entry point + */ + ArangoDBAsync arango(); + + /** + * Returns the name of the database + * + * @return database name + */ + String name(); + + /** + * Returns the server name and version number. + * + * @return the server version, number + * @see API + * Documentation + */ + CompletableFuture getVersion(); + + /** + * Returns the name of the used storage engine. + * + * @return the storage engine name + * @see API + * Documentation + */ + CompletableFuture getEngine(); + + /** + * Checks whether the database exists + * + * @return true if the database exists, otherwise false + */ + CompletableFuture exists(); + + /** + * Retrieves a list of all databases the current user can access + * + * @return a list of all databases the current user can access + * @see API + * Documentation + */ + CompletableFuture> getAccessibleDatabases(); + + /** + * Returns a handler of the collection by the given name + * + * @param name Name of the collection + * @return collection handler + */ + ArangoCollectionAsync collection(final String name); + + /** + * Creates a collection + * + * @param name The name of the collection + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture createCollection(final String name); + + /** + * Creates a collection + * + * @param name The name of the collection + * @param options Additional options, can be null + * @return information about the collection + * @see API + * Documentation + */ + CompletableFuture createCollection(final String name, final CollectionCreateOptions options); + + /** + * Returns all collections + * + * @return list of information about all collections + * @see API + * Documentation + */ + CompletableFuture> getCollections(); + + /** + * Returns all collections + * + * @param options Additional options, can be null + * @return list of information about all collections + * @see API + * Documentation + */ + CompletableFuture> getCollections(final CollectionsReadOptions options); + + /** + * Returns an index + * + * @param id The index-handle + * @return information about the index + * @see API Documentation + */ + CompletableFuture getIndex(final String id); + + /** + * Deletes an index + * + * @param id The index handle + * @return the id of the index + * @see API Documentation + */ + CompletableFuture deleteIndex(final String id); + + /** + * Creates the database + * + * @return true if the database was created successfully. + * @see API + * Documentation + */ + CompletableFuture create(); + + /** + * Drop an existing database + * + * @return true if the database was dropped successfully + * @see API + * Documentation + */ + CompletableFuture drop(); + + /** + * Grants access to the database dbname for user user. You need permission to the _system database in order to + * execute this call. + * + * @param user The name of the user + * @param permissions The permissions the user grant + * @return void + * @see + * API Documentation + */ + CompletableFuture grantAccess(final String user, final Permissions permissions); + + /** + * Grants access to the database dbname for user user. You need permission to the _system database in order to + * execute this call. + * + * @param user The name of the user + * @return void + * @see + * API Documentation + */ + CompletableFuture grantAccess(final String user); + + /** + * Revokes access to the database dbname for user user. You need permission to the _system database in order to + * execute this call. + * + * @param user The name of the user + * @return void + * @see + * API Documentation + */ + CompletableFuture revokeAccess(final String user); + + /** + * Clear the database access level, revert back to the default access level. + * + * @param user The name of the user + * @return void + * @see + * API Documentation + * @since ArangoDB 3.2.0 + */ + CompletableFuture resetAccess(final String user); + + /** + * Sets the default access level for collections within this database for the user user. You need + * permission to the _system database in order to execute this call. + * + * @param user The name of the user + * @param permissions The permissions the user grant + * @since ArangoDB 3.2.0 + */ + CompletableFuture grantDefaultCollectionAccess(final String user, final Permissions permissions); + + /** + * Get specific database access level + * + * @param user The name of the user + * @return permissions of the user + * @see API + * Documentation + * @since ArangoDB 3.2.0 + */ + CompletableFuture getPermissions(final String user); + + /** + * Performs a database query using the given {@code query} and {@code bindVars}, then returns a new + * {@code ArangoCursor} instance for the result list. + * + * @param query contains the query string to be executed + * @param bindVars key/value pairs representing the bind parameters + * @param options Additional options, can be null + * @param type The type of the result (POJO class, VPackSlice, String for Json, or Collection/List/Map) + * @return cursor of the results + * @see API + * Documentation + */ + CompletableFuture> query( + final String query, + final Map bindVars, + final AqlQueryOptions options, + final Class type); + + /** + * Performs a database query using the given {@code query}, then returns a new {@code ArangoCursor} instance for the + * result list. + * + * @param query contains the query string to be executed + * @param options Additional options, can be null + * @param type The type of the result (POJO class, VPackSlice, String for Json, or Collection/List/Map) + * @return cursor of the results + * @see API + * Documentation + */ + CompletableFuture> query( + final String query, + final AqlQueryOptions options, + final Class type); + + /** + * Performs a database query using the given {@code query} and {@code bindVars}, then returns a new + * {@code ArangoCursor} instance for the result list. + * + * @param query contains the query string to be executed + * @param bindVars key/value pairs representing the bind parameters + * @param type The type of the result (POJO class, VPackSlice, String for Json, or Collection/List/Map) + * @return cursor of the results + * @see API + * Documentation + */ + CompletableFuture> query( + final String query, + final Map bindVars, + final Class type); + + /** + * Performs a database query using the given {@code query}, then returns a new {@code ArangoCursor} instance for the + * result list. + * + * @param query contains the query string to be executed + * @param type The type of the result (POJO class, VPackSlice, String for Json, or Collection/List/Map) + * @return cursor of the results + * @see API + * Documentation + */ + CompletableFuture> query(final String query, final Class type); + + /** + * Return an cursor from the given cursor-ID if still existing + * + * @param cursorId The ID of the cursor + * @param type The type of the result (POJO class, VPackSlice, String for Json, or Collection/List/Map) + * @return cursor of the results + * @see API + * Documentation + */ + CompletableFuture> cursor(final String cursorId, final Class type); + + /** + * Explain an AQL query and return information about it + * + * @param query the query which you want explained + * @param bindVars key/value pairs representing the bind parameters + * @param options Additional options, can be null + * @return information about the query + * @see API + * Documentation + */ + CompletableFuture explainQuery( + final String query, + final Map bindVars, + final AqlQueryExplainOptions options); + + /** + * Parse an AQL query and return information about it This method is for query validation only. To actually query + * the database, see {@link ArangoDatabaseAsync#query(String, Map, AqlQueryOptions, Class)} + * + * @param query the query which you want parse + * @return imformation about the query + * @see API + * Documentation + */ + CompletableFuture parseQuery(final String query); + + /** + * Clears the AQL query cache + * + * @return void + * @see API + * Documentation + */ + CompletableFuture clearQueryCache(); + + /** + * Returns the global configuration for the AQL query cache + * + * @return configuration for the AQL query cache + * @see API + * Documentation + */ + CompletableFuture getQueryCacheProperties(); + + /** + * Changes the configuration for the AQL query cache. Note: changing the properties may invalidate all results in + * the cache. + * + * @param properties properties to be set + * @return current set of properties + * @see API + * Documentation + */ + CompletableFuture setQueryCacheProperties(final QueryCachePropertiesEntity properties); + + /** + * Returns the configuration for the AQL query tracking + * + * @return configuration for the AQL query tracking + * @see API + * Documentation + */ + CompletableFuture getQueryTrackingProperties(); + + /** + * Changes the configuration for the AQL query tracking + * + * @param properties properties to be set + * @return current set of properties + * @see API + * Documentation + */ + CompletableFuture setQueryTrackingProperties( + final QueryTrackingPropertiesEntity properties); + + /** + * Returns a list of currently running AQL queries + * + * @return a list of currently running AQL queries + * @see API + * Documentation + */ + CompletableFuture> getCurrentlyRunningQueries(); + + /** + * Returns a list of slow running AQL queries + * + * @return a list of slow running AQL queries + * @see API + * Documentation + */ + CompletableFuture> getSlowQueries(); + + /** + * Clears the list of slow AQL queries + * + * @return void + * @see API + * Documentation + */ + CompletableFuture clearSlowQueries(); + + /** + * Kills a running query. The query will be terminated at the next cancelation point. + * + * @param id The id of the query + * @return void + * @see API + * Documentation + */ + CompletableFuture killQuery(final String id); + + /** + * Create a new AQL user function + * + * @param name the fully qualified name of the user functions + * @param code a string representation of the function body + * @param options Additional options, can be null + * @return void + * @see API + * Documentation + */ + CompletableFuture createAqlFunction( + final String name, + final String code, + final AqlFunctionCreateOptions options); + + /** + * Remove an existing AQL user function + * + * @param name the name of the AQL user function + * @param options Additional options, can be null + * @return number of deleted functions (since ArangoDB 3.4.0) + * @see API + * Documentation + */ + CompletableFuture deleteAqlFunction(final String name, final AqlFunctionDeleteOptions options); + + /** + * Gets all reqistered AQL user functions + * + * @param options Additional options, can be null + * @return all reqistered AQL user functions + * @see API + * Documentation + */ + CompletableFuture> getAqlFunctions(final AqlFunctionGetOptions options); + + /** + * Returns a handler of the graph by the given name + * + * @param name Name of the graph + * @return graph handler + */ + ArangoGraphAsync graph(final String name); + + /** + * Create a new graph in the graph module. The creation of a graph requires the name of the graph and a definition + * of its edges. + * + * @param name Name of the graph + * @param edgeDefinitions An array of definitions for the edge + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture createGraph(final String name, final Collection edgeDefinitions); + + /** + * Create a new graph in the graph module. The creation of a graph requires the name of the graph and a definition + * of its edges. + * + * @param name Name of the graph + * @param edgeDefinitions An array of definitions for the edge + * @param options Additional options, can be null + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture createGraph( + final String name, + final Collection edgeDefinitions, + final GraphCreateOptions options); + + /** + * Lists all graphs known to the graph module + * + * @return graphs stored in this database + * @see API + * Documentation + */ + CompletableFuture> getGraphs(); + + /** + * Execute a server-side transaction + * + * @param action the actual transaction operations to be executed, in the form of stringified JavaScript code + * @param type The type of the result (POJO class, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return the result of the transaction if it succeeded + * @see API + * Documentation + */ + CompletableFuture transaction(final String action, final Class type, final TransactionOptions options); + + /** + * Begins a Stream Transaction. + * + * @param options Additional options, can be null + * @return information about the transaction + * @see API + * Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture beginStreamTransaction(StreamTransactionOptions options); + + /** + * Aborts a Stream Transaction. + * + * @return information about the transaction + * @see API + * Documentation + */ + CompletableFuture abortStreamTransaction(String id); + + /** + * Gets information about a Stream Transaction. + * + * @return information about the transaction + * @see + * API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture getStreamTransaction(String id); + + /** + * Gets all the currently running Stream Transactions. + * + * @return all the currently running Stream Transactions + * @see + * API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture> getStreamTransactions(); + + /** + * Commits a Stream Transaction. + * + * @return information about the transaction + * @see + * API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture commitStreamTransaction(String id); + + /** + * Retrieves information about the current database + * + * @return information about the current database + * @see API + * Documentation + */ + CompletableFuture getInfo(); + + /** + * Execute a server-side traversal + * + * @param vertexClass The type of the vertex documents (POJO class, VPackSlice or String for Json) + * @param edgeClass The type of the edge documents (POJO class, VPackSlice or String for Json) + * @param options Additional options + * @return Result of the executed traversal + * @see API + * Documentation + */ + CompletableFuture> executeTraversal( + final Class vertexClass, + final Class edgeClass, + final TraversalOptions options); + + /** + * Reads a single document + * + * @param id The id of the document + * @param type The type of the document (POJO class, VPackSlice or String for Json) + * @return the document identified by the id + * @see API + * Documentation + */ + CompletableFuture getDocument(final String id, final Class type) throws ArangoDBException; + + /** + * Reads a single document + * + * @param id The id of the document + * @param type The type of the document (POJO class, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return the document identified by the id + * @see API + * Documentation + */ + CompletableFuture getDocument(final String id, final Class type, final DocumentReadOptions options) + throws ArangoDBException; + + /** + * Reload the routing table. + * + * @return void + * @see API + * Documentation + */ + CompletableFuture reloadRouting(); + + /** + * Returns a new {@link ArangoRouteAsync} instance for the given path (relative to the database) that can be used to + * perform arbitrary requests. + * + * @param path The database-relative URL of the route + * @return {@link ArangoRouteAsync} + */ + ArangoRouteAsync route(String... path); + + /** + * Fetches all views from the database and returns an list of view descriptions. + * + * @return list of information about all views + * @see API Documentation + * @since ArangoDB 3.4.0 + */ + CompletableFuture> getViews(); + + /** + * Returns a {@code ArangoViewAsync} instance for the given view name. + * + * @param name Name of the view + * @return view handler + * @since ArangoDB 3.4.0 + */ + ArangoViewAsync view(String name); + + /** + * Returns a {@code ArangoSearchAsync} instance for the given ArangoSearch view name. + * + * @param name Name of the view + * @return ArangoSearch view handler + * @since ArangoDB 3.4.0 + */ + ArangoSearchAsync arangoSearch(String name); + + /** + * Creates a view of the given {@code type}, then returns view information from the server. + * + * @param name The name of the view + * @param type The type of the view + * @return information about the view + * @since ArangoDB 3.4.0 + */ + CompletableFuture createView(String name, ViewType type); + + /** + * Creates a ArangoSearch view with the given {@code options}, then returns view information from the server. + * + * @param name The name of the view + * @param options Additional options, can be null + * @return information about the view + * @see API + * Documentation + * @since ArangoDB 3.4.0 + */ + CompletableFuture createArangoSearch(String name, ArangoSearchCreateOptions options); + + /** + * Creates an Analyzer + * + * @param options AnalyzerEntity + * @return the created Analyzer + * @see API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture createAnalyzer(AnalyzerEntity options); + + /** + * Gets information about an Analyzer + * + * @param name of the Analyzer without database prefix + * @return information about an Analyzer + * @see API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture getAnalyzer(String name); + + /** + * Retrieves all analyzers definitions. + * + * @return collection of all analyzers definitions + * @see API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture> getAnalyzers(); + + /** + * Deletes an Analyzer + * + * @param name of the Analyzer without database prefix + * @see API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture deleteAnalyzer(String name); + + /** + * Deletes an Analyzer + * + * @param name of the Analyzer without database prefix + * @param options AnalyzerDeleteOptions + * @see API Documentation + * @since ArangoDB 3.5.0 + */ + CompletableFuture deleteAnalyzer(String name, AnalyzerDeleteOptions options); + +} diff --git a/src/main/java/com/arangodb/async/ArangoEdgeCollectionAsync.java b/src/main/java/com/arangodb/async/ArangoEdgeCollectionAsync.java new file mode 100644 index 000000000..7f7cb4585 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoEdgeCollectionAsync.java @@ -0,0 +1,160 @@ +/* + * 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.ArangoSerializationAccessor; +import com.arangodb.entity.EdgeEntity; +import com.arangodb.entity.EdgeUpdateEntity; +import com.arangodb.model.*; + +import java.util.concurrent.CompletableFuture; + +/** + * Interface for operations on ArangoDB edge collection level. + * + * @author Mark Vollmary + * @see API Documentation + */ +@SuppressWarnings("unused") +public interface ArangoEdgeCollectionAsync extends ArangoSerializationAccessor { + + /** + * The the handler of the named graph the edge collection is within + * + * @return graph handler + */ + ArangoGraphAsync graph(); + + /** + * The name of the edge collection + * + * @return collection name + */ + String name(); + + /** + * Creates a new edge in the collection + * + * @param value A representation of a single edge (POJO, VPackSlice or String for Json) + * @return information about the edge + * @see API Documentation + */ + CompletableFuture insertEdge(final T value); + + /** + * Creates a new edge in the collection + * + * @param value A representation of a single edge (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the edge + * @see API Documentation + */ + CompletableFuture insertEdge(final T value, final EdgeCreateOptions options); + + /** + * Fetches an existing edge + * + * @param key The key of the edge + * @param type The type of the edge-document (POJO class, VPackSlice or String for Json) + * @return the edge identified by the key + * @see API Documentation + */ + CompletableFuture getEdge(final String key, final Class type); + + /** + * Fetches an existing edge + * + * @param key The key of the edge + * @param type The type of the edge-document (POJO class, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return the edge identified by the key + * @see API Documentation + */ + CompletableFuture getEdge(final String key, final Class type, final GraphDocumentReadOptions options); + + /** + * Replaces the edge with key with the one in the body, provided there is such a edge and no precondition is + * violated + * + * @param key The key of the edge + * @return information about the edge + * @see API Documentation + */ + CompletableFuture replaceEdge(final String key, final T value); + + /** + * Replaces the edge with key with the one in the body, provided there is such a edge and no precondition is + * violated + * + * @param key The key of the edge + * @param options Additional options, can be null + * @return information about the edge + * @see API Documentation + */ + CompletableFuture replaceEdge( + final String key, + final T value, + final EdgeReplaceOptions options); + + /** + * Partially updates the edge identified by document-key. The value must contain a document with the attributes to + * patch (the patch document). All attributes from the patch document will be added to the existing document if they + * do not yet exist, and overwritten in the existing document if they do exist there. + * + * @param key The key of the edge + * @return information about the edge + * @see API Documentation + */ + CompletableFuture updateEdge(final String key, final T value); + + /** + * Partially updates the edge identified by document-key. The value must contain a document with the attributes to + * patch (the patch document). All attributes from the patch document will be added to the existing document if they + * do not yet exist, and overwritten in the existing document if they do exist there. + * + * @param key The key of the edge + * @param options Additional options, can be null + * @return information about the edge + * @see API Documentation + */ + CompletableFuture updateEdge( + final String key, + final T value, + final EdgeUpdateOptions options); + + /** + * Removes a edge + * + * @param key The key of the edge + * @see API Documentation + */ + CompletableFuture deleteEdge(final String key); + + /** + * Removes a edge + * + * @param key The key of the edge + * @param options Additional options, can be null + * @see API Documentation + */ + CompletableFuture deleteEdge(final String key, final EdgeDeleteOptions options); + +} diff --git a/src/main/java/com/arangodb/async/ArangoGraphAsync.java b/src/main/java/com/arangodb/async/ArangoGraphAsync.java new file mode 100644 index 000000000..9633f5c40 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoGraphAsync.java @@ -0,0 +1,190 @@ +/* + * 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.ArangoSerializationAccessor; +import com.arangodb.entity.EdgeDefinition; +import com.arangodb.entity.GraphEntity; +import com.arangodb.model.GraphCreateOptions; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +/** + * Interface for operations on ArangoDB graph level. + * + * @author Mark Vollmary + * @see API Documentation + */ +@SuppressWarnings("unused") +public interface ArangoGraphAsync extends ArangoSerializationAccessor { + + /** + * The the handler of the database the named graph is within + * + * @return database handler + */ + ArangoDatabaseAsync db(); + + /** + * The name of the collection + * + * @return collection name + */ + String name(); + + /** + * Checks whether the graph exists + * + * @return true if the graph exists, otherwise false + */ + CompletableFuture exists(); + + /** + * Creates the graph in the graph module. The creation of a graph requires the name of the graph and a definition of + * its edges. + * + * @param edgeDefinitions An array of definitions for the edge + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture create(final Collection edgeDefinitions); + + /** + * Creates the graph in the graph module. The creation of a graph requires the name of the graph and a definition of + * its edges. + * + * @param edgeDefinitions An array of definitions for the edge + * @param options Additional options, can be null + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture createGraph( + final Collection edgeDefinitions, + final GraphCreateOptions options); + + /** + * Delete an existing graph + * + * @return void + * @see API Documentation + */ + CompletableFuture drop(); + + /** + * Delete an existing graph including + * + * @param dropCollections Drop collections of this graph as well. Collections will only be dropped if they are not used in other + * graphs. + * @return void + * @see API Documentation + */ + CompletableFuture drop(boolean dropCollections); + + /** + * Get a graph from the graph module + * + * @return the definition content of this graph + * @see API Documentation + */ + CompletableFuture getInfo(); + + /** + * Lists all vertex collections used in this graph + * + * @return all vertex collections within this graph + * @see API + * Documentation + */ + CompletableFuture> getVertexCollections(); + + /** + * Adds a vertex collection to the set of collections of the graph. If the collection does not exist, it will be + * created. + * + * @param name The name of the collection + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture addVertexCollection(final String name); + + /** + * Returns a handler of the vertex collection by the given name + * + * @param name Name of the vertex collection + * @return collection handler + */ + ArangoVertexCollectionAsync vertexCollection(final String name); + + /** + * Returns a handler of the edge collection by the given name + * + * @param name Name of the edge collection + * @return collection handler + */ + ArangoEdgeCollectionAsync edgeCollection(final String name); + + /** + * Lists all edge collections used in this graph + * + * @return all edge collections within this graph + * @see API + * Documentation + */ + CompletableFuture> getEdgeDefinitions(); + + /** + * Add a new edge definition to the graph + * + * @param definition + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture addEdgeDefinition(final EdgeDefinition definition); + + /** + * Change one specific edge definition. This will modify all occurrences of this definition in all graphs known to + * your database + * + * @param definition The edge definition + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture replaceEdgeDefinition(final EdgeDefinition definition); + + /** + * Remove one edge definition from the graph. This will only remove the edge collection, the vertex collections + * remain untouched and can still be used in your queries + * + * @param definitionName The name of the edge collection used in the definition + * @return information about the graph + * @see API + * Documentation + */ + CompletableFuture removeEdgeDefinition(final String definitionName); + +} diff --git a/src/main/java/com/arangodb/async/ArangoRouteAsync.java b/src/main/java/com/arangodb/async/ArangoRouteAsync.java new file mode 100644 index 000000000..e16655e83 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoRouteAsync.java @@ -0,0 +1,119 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.ArangoSerializationAccessor; +import com.arangodb.velocypack.VPackSlice; +import com.arangodb.velocystream.Response; + +import java.util.concurrent.CompletableFuture; + +/** + * Interface for a specific path to be used to perform arbitrary requests. + * + * @author Mark Vollmary + */ +@SuppressWarnings("unused") +public interface ArangoRouteAsync extends ArangoSerializationAccessor { + + /** + * Returns a new {@link ArangoRouteAsync} instance for the given path (relative to the current route) that can be + * used to perform arbitrary requests. + * + * @param path The relative URL of the route + * @return {@link ArangoRouteAsync} + */ + ArangoRouteAsync route(String... path); + + /** + * Header that should be sent with each request to the route. + * + * @param key Header key + * @param value Header value (the toString() method will be called for the value} + * @return {@link ArangoRouteAsync} + */ + ArangoRouteAsync withHeader(String key, Object value); + + /** + * Query parameter that should be sent with each request to the route. + * + * @param key Query parameter key + * @param value Query parameter value (the toString() method will be called for the value} + * @return {@link ArangoRouteAsync} + */ + ArangoRouteAsync withQueryParam(String key, Object value); + + /** + * The response body. The body will be serialized to {@link VPackSlice}. + * + * @param body The response body + * @return {@link ArangoRouteAsync} + */ + ArangoRouteAsync withBody(Object body); + + /** + * Performs a DELETE request to the given URL and returns the server response. + * + * @return server response + */ + CompletableFuture delete(); + + /** + * Performs a GET request to the given URL and returns the server response. + * + * @return server response + */ + + CompletableFuture get(); + + /** + * Performs a HEAD request to the given URL and returns the server response. + * + * @return server response + */ + + CompletableFuture head(); + + /** + * Performs a PATCH request to the given URL and returns the server response. + * + * @return server response + */ + + CompletableFuture patch(); + + /** + * Performs a POST request to the given URL and returns the server response. + * + * @return server response + */ + + CompletableFuture post(); + + /** + * Performs a PUT request to the given URL and returns the server response. + * + * @return server response + */ + + CompletableFuture put(); + +} diff --git a/src/main/java/com/arangodb/async/ArangoSearchAsync.java b/src/main/java/com/arangodb/async/ArangoSearchAsync.java new file mode 100644 index 000000000..06899676d --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoSearchAsync.java @@ -0,0 +1,89 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.ViewEntity; +import com.arangodb.entity.arangosearch.ArangoSearchPropertiesEntity; +import com.arangodb.model.arangosearch.ArangoSearchCreateOptions; +import com.arangodb.model.arangosearch.ArangoSearchPropertiesOptions; + +import java.util.concurrent.CompletableFuture; + +/** + * Interface for operations on ArangoDB view level for ArangoSearch views. + * + * @author Mark Vollmary + * @see View API Documentation + * @since ArangoDB 3.4.0 + */ +public interface ArangoSearchAsync extends ArangoViewAsync { + + /** + * Creates a view, then returns view information from the server. + * + * @return information about the view @ + * @see API + * Documentation + */ + CompletableFuture create(); + + /** + * Creates a view with the given {@code options}, then returns view information from the server. + * + * @param options Additional options, can be null + * @return information about the view @ + * @see API + * Documentation + */ + CompletableFuture create(ArangoSearchCreateOptions options); + + /** + * Reads the properties of the specified view. + * + * @return properties of the view @ + * @see API + * Documentation + */ + CompletableFuture getProperties(); + + /** + * Partially changes properties of the view. + * + * @param options properties to change + * @return properties of the view @ + * @see API + * Documentation + */ + CompletableFuture updateProperties(ArangoSearchPropertiesOptions options); + + /** + * Changes properties of the view. + * + * @param options properties to change + * @return properties of the view @ + * @see API + * Documentation + */ + CompletableFuture replaceProperties(ArangoSearchPropertiesOptions options); + +} diff --git a/src/main/java/com/arangodb/async/ArangoVertexCollectionAsync.java b/src/main/java/com/arangodb/async/ArangoVertexCollectionAsync.java new file mode 100644 index 000000000..2f1b1af66 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoVertexCollectionAsync.java @@ -0,0 +1,172 @@ +/* + * 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.ArangoSerializationAccessor; +import com.arangodb.entity.VertexEntity; +import com.arangodb.entity.VertexUpdateEntity; +import com.arangodb.model.*; + +import java.util.concurrent.CompletableFuture; + +/** + * Interface for operations on ArangoDB vertex collection level. + * + * @author Mark Vollmary + * @see API Documentation + */ +@SuppressWarnings("unused") +public interface ArangoVertexCollectionAsync extends ArangoSerializationAccessor { + + /** + * The the handler of the named graph the edge collection is within + * + * @return graph handler + */ + ArangoGraphAsync graph(); + + /** + * The name of the edge collection + * + * @return collection name + */ + String name(); + + /** + * Removes a vertex collection from the graph and optionally deletes the collection, if it is not used in any other + * graph + * + * @return void + * @see API + * Documentation + */ + CompletableFuture drop(); + + /** + * Creates a new vertex in the collection + * + * @param value A representation of a single vertex (POJO, VPackSlice or String for Json) + * @return information about the vertex + * @see API Documentation + */ + CompletableFuture insertVertex(final T value); + + /** + * Creates a new vertex in the collection + * + * @param value A representation of a single vertex (POJO, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return information about the vertex + * @see API Documentation + */ + CompletableFuture insertVertex(final T value, final VertexCreateOptions options); + + /** + * Fetches an existing vertex + * + * @param key The key of the vertex + * @param type The type of the vertex-document (POJO class, VPackSlice or String for Json) + * @return the vertex identified by the key + * @see API Documentation + */ + CompletableFuture getVertex(final String key, final Class type); + + /** + * Fetches an existing vertex + * + * @param key The key of the vertex + * @param type The type of the vertex-document (POJO class, VPackSlice or String for Json) + * @param options Additional options, can be null + * @return the vertex identified by the key + * @see API Documentation + */ + CompletableFuture getVertex(final String key, final Class type, final GraphDocumentReadOptions options); + + /** + * Replaces the vertex with key with the one in the body, provided there is such a vertex and no precondition is + * violated + * + * @param key The key of the vertex + * @return information about the vertex + * @see API + * Documentation + */ + CompletableFuture replaceVertex(final String key, final T value); + + /** + * Replaces the vertex with key with the one in the body, provided there is such a vertex and no precondition is + * violated + * + * @param key The key of the vertex + * @param options Additional options, can be null + * @return information about the vertex + * @see API + * Documentation + */ + CompletableFuture replaceVertex( + final String key, + final T value, + final VertexReplaceOptions options); + + /** + * Partially updates the vertex identified by document-key. The value must contain a document with the attributes to + * patch (the patch document). All attributes from the patch document will be added to the existing document if they + * do not yet exist, and overwritten in the existing document if they do exist there. + * + * @param key The key of the vertex + * @return information about the vertex + * @see API Documentation + */ + CompletableFuture updateVertex(final String key, final T value); + + /** + * Partially updates the vertex identified by document-key. The value must contain a document with the attributes to + * patch (the patch document). All attributes from the patch document will be added to the existing document if they + * do not yet exist, and overwritten in the existing document if they do exist there. + * + * @param key The key of the vertex + * @param options Additional options, can be null + * @return information about the vertex + * @see API Documentation + */ + CompletableFuture updateVertex( + final String key, + final T value, + final VertexUpdateOptions options); + + /** + * Removes a vertex + * + * @param key The key of the vertex + * @see API Documentation + */ + CompletableFuture deleteVertex(final String key); + + /** + * Removes a vertex + * + * @param key The key of the vertex + * @param options Additional options, can be null + * @see API Documentation + */ + CompletableFuture deleteVertex(final String key, final VertexDeleteOptions options); + +} diff --git a/src/main/java/com/arangodb/async/ArangoViewAsync.java b/src/main/java/com/arangodb/async/ArangoViewAsync.java new file mode 100644 index 000000000..1afea0d87 --- /dev/null +++ b/src/main/java/com/arangodb/async/ArangoViewAsync.java @@ -0,0 +1,84 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.ArangoSerializationAccessor; +import com.arangodb.entity.ViewEntity; + +import java.util.concurrent.CompletableFuture; + +/** + * Interface for operations on ArangoDB view level. + * + * @author Mark Vollmary + * @see View API Documentation + * @since ArangoDB 3.4.0 + */ +@SuppressWarnings("unused") +public interface ArangoViewAsync extends ArangoSerializationAccessor { + + /** + * The the handler of the database the collection is within + * + * @return database handler + */ + ArangoDatabaseAsync db(); + + /** + * The name of the view + * + * @return view name + */ + String name(); + + /** + * Checks whether the view exists. + * + * @return true if the view exists, otherwise false + */ + CompletableFuture exists(); + + /** + * Deletes the view from the database. + * + * @see API Documentation + */ + CompletableFuture drop(); + + /** + * Renames the view. + * + * @param newName The new name + * @return information about the view + * @see API Documentation + */ + CompletableFuture rename(String newName); + + /** + * Returns information about the view. + * + * @return information about the view + * @see API + * Documentation + */ + CompletableFuture getInfo(); + +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java new file mode 100644 index 000000000..a4d25a4ff --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoCollectionAsyncImpl.java @@ -0,0 +1,424 @@ +/* + * 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.internal; + +import com.arangodb.ArangoDBException; +import com.arangodb.async.ArangoCollectionAsync; +import com.arangodb.entity.*; +import com.arangodb.internal.InternalArangoCollection; +import com.arangodb.internal.util.DocumentUtil; +import com.arangodb.model.*; + +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 + * @author Michele Rastelli + */ +public class ArangoCollectionAsyncImpl + extends InternalArangoCollection + implements ArangoCollectionAsync { + + ArangoCollectionAsyncImpl(final ArangoDatabaseAsyncImpl db, final String name) { + super(db, name); + } + + @Override + public CompletableFuture> insertDocument(final T value) { + final DocumentCreateOptions options = new DocumentCreateOptions(); + return executor.execute(insertDocumentRequest(value, options), + insertDocumentResponseDeserializer(value, options)); + } + + @Override + public CompletableFuture> insertDocument( + final T value, + final DocumentCreateOptions options) { + return executor.execute(insertDocumentRequest(value, options), + insertDocumentResponseDeserializer(value, options)); + } + + @Override + public CompletableFuture>> insertDocuments( + final Collection values) { + final DocumentCreateOptions params = new DocumentCreateOptions(); + return executor.execute(insertDocumentsRequest(values, params), + insertDocumentsResponseDeserializer(values, params)); + } + + @Override + public CompletableFuture>> insertDocuments( + final Collection values, + final DocumentCreateOptions options) { + final DocumentCreateOptions params = (options != null ? options : new DocumentCreateOptions()); + return executor.execute(insertDocumentsRequest(values, params), + insertDocumentsResponseDeserializer(values, params)); + } + + @Override + public CompletableFuture importDocuments(final Collection values) { + return importDocuments(values, new DocumentImportOptions()); + } + + @Override + public CompletableFuture importDocuments( + final Collection values, + final DocumentImportOptions options) { + return executor.execute(importDocumentsRequest(values, options), DocumentImportEntity.class); + } + + @Override + public CompletableFuture importDocuments(final String values) { + return executor.execute(importDocumentsRequest(values, new DocumentImportOptions()), + DocumentImportEntity.class); + } + + @Override + public CompletableFuture importDocuments( + final String values, + final DocumentImportOptions options) { + return executor.execute(importDocumentsRequest(values, options), DocumentImportEntity.class); + } + + @Override + public CompletableFuture getDocument(final String key, final Class type) throws ArangoDBException { + return getDocument(key, type, new DocumentReadOptions()); + } + + @Override + @SuppressWarnings("unchecked") + public CompletableFuture getDocument( + final String key, + final Class type, + final DocumentReadOptions options) throws ArangoDBException { + 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); + }; + } + + @Override + public CompletableFuture> getDocuments( + final Collection keys, + final Class type) { + return getDocuments(keys, type, new DocumentReadOptions()); + } + + @Override + public CompletableFuture> getDocuments( + final Collection keys, + final Class type, + final DocumentReadOptions options) { + return executor.execute(getDocumentsRequest(keys, options), getDocumentsResponseDeserializer(type, options)); + } + + @Override + public CompletableFuture> replaceDocument(final String key, final T value) { + final DocumentReplaceOptions options = new DocumentReplaceOptions(); + return executor.execute(replaceDocumentRequest(key, value, options), + replaceDocumentResponseDeserializer(value, options)); + } + + @Override + public CompletableFuture> replaceDocument( + final String key, + final T value, + final DocumentReplaceOptions options) { + return executor.execute(replaceDocumentRequest(key, value, options), + replaceDocumentResponseDeserializer(value, options)); + } + + @Override + public CompletableFuture>> replaceDocuments( + final Collection values) { + final DocumentReplaceOptions params = new DocumentReplaceOptions(); + return executor.execute(replaceDocumentsRequest(values, params), + replaceDocumentsResponseDeserializer(values, params)); + } + + @Override + public CompletableFuture>> replaceDocuments( + final Collection values, + final DocumentReplaceOptions options) { + final DocumentReplaceOptions params = (options != null ? options : new DocumentReplaceOptions()); + return executor.execute(replaceDocumentsRequest(values, params), + replaceDocumentsResponseDeserializer(values, params)); + } + + @Override + public CompletableFuture> updateDocument(final String key, final T value) { + final DocumentUpdateOptions options = new DocumentUpdateOptions(); + return executor.execute(updateDocumentRequest(key, value, options), + updateDocumentResponseDeserializer(value, options)); + } + + @Override + public CompletableFuture> updateDocument( + final String key, + final T value, + final DocumentUpdateOptions options) { + return executor.execute(updateDocumentRequest(key, value, options), + updateDocumentResponseDeserializer(value, options)); + } + + @Override + public CompletableFuture>> updateDocuments( + final Collection values) { + final DocumentUpdateOptions params = new DocumentUpdateOptions(); + return executor.execute(updateDocumentsRequest(values, params), + updateDocumentsResponseDeserializer(values, params)); + } + + @Override + public CompletableFuture>> updateDocuments( + final Collection values, + final DocumentUpdateOptions options) { + final DocumentUpdateOptions params = (options != null ? options : new DocumentUpdateOptions()); + return executor.execute(updateDocumentsRequest(values, params), + updateDocumentsResponseDeserializer(values, params)); + } + + @Override + public CompletableFuture> deleteDocument(final String key) { + return executor.execute(deleteDocumentRequest(key, new DocumentDeleteOptions()), + deleteDocumentResponseDeserializer(Void.class)); + } + + @Override + public CompletableFuture> deleteDocument( + final String key, + final Class type, + final DocumentDeleteOptions options) { + return executor.execute(deleteDocumentRequest(key, options), deleteDocumentResponseDeserializer(type)); + } + + @Override + public CompletableFuture>> deleteDocuments( + final Collection values) { + return executor.execute(deleteDocumentsRequest(values, new DocumentDeleteOptions()), + deleteDocumentsResponseDeserializer(Void.class)); + } + + @Override + public CompletableFuture>> deleteDocuments( + final Collection values, + final Class type, + final DocumentDeleteOptions options) { + return executor.execute(deleteDocumentsRequest(values, options), deleteDocumentsResponseDeserializer(type)); + } + + @Override + public CompletableFuture documentExists(final String key) { + return documentExists(key, new DocumentExistsOptions()); + } + + @Override + 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)) + .thenApply(Objects::nonNull); + } + + @Override + public CompletableFuture getIndex(final String id) { + return executor.execute(getIndexRequest(id), IndexEntity.class); + } + + @Override + public CompletableFuture deleteIndex(final String id) { + return executor.execute(deleteIndexRequest(id), deleteIndexResponseDeserializer()); + } + + @Override + public CompletableFuture ensureHashIndex( + final Iterable fields, + final HashIndexOptions options) { + return executor.execute(createHashIndexRequest(fields, options), IndexEntity.class); + } + + @Override + public CompletableFuture ensureSkiplistIndex( + final Iterable fields, + final SkiplistIndexOptions options) { + return executor.execute(createSkiplistIndexRequest(fields, options), IndexEntity.class); + } + + @Override + public CompletableFuture ensurePersistentIndex( + final Iterable fields, + final PersistentIndexOptions options) { + return executor.execute(createPersistentIndexRequest(fields, options), IndexEntity.class); + } + + @Override + public CompletableFuture ensureGeoIndex(final Iterable fields, final GeoIndexOptions options) { + return executor.execute(createGeoIndexRequest(fields, options), IndexEntity.class); + } + + @Override + public CompletableFuture ensureFulltextIndex( + final Iterable fields, + final FulltextIndexOptions options) { + return executor.execute(createFulltextIndexRequest(fields, options), IndexEntity.class); + } + + @Override + public CompletableFuture ensureTtlIndex(Iterable fields, TtlIndexOptions options) { + return executor.execute(createTtlIndexRequest(fields, options), IndexEntity.class); + } + + @Override + public CompletableFuture> getIndexes() { + return executor.execute(getIndexesRequest(), getIndexesResponseDeserializer()); + } + + @Override + public CompletableFuture exists() { + return getInfo().thenApply(Objects::nonNull).exceptionally(Objects::isNull); + } + + @Override + public CompletableFuture truncate() { + return truncate(null); + } + + @Override + public CompletableFuture truncate(CollectionTruncateOptions options) { + return executor.execute(truncateRequest(options), CollectionEntity.class); + } + + @Override + public CompletableFuture count() { + return count(null); + } + + @Override + public CompletableFuture count(CollectionCountOptions options) { + return executor.execute(countRequest(options), CollectionPropertiesEntity.class); + } + + @Override + public CompletableFuture create() { + return db().createCollection(name()); + } + + @Override + public CompletableFuture create(final CollectionCreateOptions options) { + return db().createCollection(name(), options); + } + + @Override + public CompletableFuture drop() { + return executor.execute(dropRequest(null), Void.class); + } + + @Override + public CompletableFuture drop(final boolean isSystem) { + return executor.execute(dropRequest(isSystem), Void.class); + } + + @Override + public CompletableFuture load() { + return executor.execute(loadRequest(), CollectionEntity.class); + } + + @Override + public CompletableFuture unload() { + return executor.execute(unloadRequest(), CollectionEntity.class); + } + + @Override + public CompletableFuture getInfo() { + return executor.execute(getInfoRequest(), CollectionEntity.class); + } + + @Override + public CompletableFuture getProperties() { + return executor.execute(getPropertiesRequest(), CollectionPropertiesEntity.class); + } + + @Override + public CompletableFuture changeProperties(final CollectionPropertiesOptions options) { + return executor.execute(changePropertiesRequest(options), CollectionPropertiesEntity.class); + } + + @Override + public CompletableFuture rename(final String newName) { + return executor.execute(renameRequest(newName), CollectionEntity.class); + } + + @Override + public CompletableFuture getResponsibleShard(Object value) { + return executor.execute(responsibleShardRequest(value), ShardEntity.class); + } + + @Override + public CompletableFuture getRevision() { + return executor.execute(getRevisionRequest(), CollectionRevisionEntity.class); + } + + @Override + public CompletableFuture grantAccess(final String user, final Permissions permissions) { + return executor.execute(grantAccessRequest(user, permissions), Void.class); + } + + @Override + public CompletableFuture revokeAccess(final String user) { + return executor.execute(grantAccessRequest(user, Permissions.NONE), Void.class); + } + + @Override + public CompletableFuture resetAccess(final String user) { + return executor.execute(resetAccessRequest(user), Void.class); + } + + @Override + public CompletableFuture getPermissions(final String user) { + return executor.execute(getPermissionsRequest(user), getPermissionsResponseDeserialzer()); + } +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java new file mode 100644 index 000000000..e21a01aa3 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java @@ -0,0 +1,47 @@ +/* + * 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.internal; + +import com.arangodb.async.ArangoCursorAsync; +import com.arangodb.entity.CursorEntity; +import com.arangodb.internal.ArangoCursorExecute; +import com.arangodb.internal.InternalArangoDatabase; +import com.arangodb.internal.cursor.ArangoCursorImpl; + +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * @author Mark Vollmary + */ +public class ArangoCursorAsyncImpl extends ArangoCursorImpl implements ArangoCursorAsync { + + ArangoCursorAsyncImpl(final InternalArangoDatabase db, final ArangoCursorExecute execute, + final Class type, final CursorEntity result) { + super(db, execute, type, result); + } + + @Override + public Stream streamRemaining() { + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); + } +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoDBAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoDBAsyncImpl.java new file mode 100644 index 000000000..2a6ad7936 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoDBAsyncImpl.java @@ -0,0 +1,192 @@ +/* + * 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.internal; + +import com.arangodb.ArangoDBException; +import com.arangodb.async.ArangoDBAsync; +import com.arangodb.async.ArangoDatabaseAsync; +import com.arangodb.async.internal.velocystream.VstCommunicationAsync; +import com.arangodb.entity.*; +import com.arangodb.internal.*; +import com.arangodb.internal.net.CommunicationProtocol; +import com.arangodb.internal.net.HostResolver; +import com.arangodb.internal.util.ArangoSerializationFactory; +import com.arangodb.internal.util.ArangoSerializationFactory.Serializer; +import com.arangodb.internal.velocystream.VstCommunication; +import com.arangodb.internal.velocystream.VstCommunicationSync; +import com.arangodb.internal.velocystream.VstProtocol; +import com.arangodb.internal.velocystream.internal.VstConnectionSync; +import com.arangodb.model.LogOptions; +import com.arangodb.model.UserCreateOptions; +import com.arangodb.model.UserUpdateOptions; +import com.arangodb.velocystream.Request; +import com.arangodb.velocystream.Response; + +import java.io.IOException; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +/** + * @author Mark Vollmary + */ +public class ArangoDBAsyncImpl extends InternalArangoDB implements ArangoDBAsync { + + private final CommunicationProtocol cp; + + public ArangoDBAsyncImpl(final VstCommunicationAsync.Builder commBuilder, final ArangoSerializationFactory util, + final VstCommunicationSync.Builder syncbuilder, final HostResolver hostResolver, final ArangoContext context) { + + super(new ArangoExecutorAsync(commBuilder.build(util.get(Serializer.INTERNAL)), util, new DocumentCache()), util, context); + + final VstCommunication cacheCom = syncbuilder.build(util.get(Serializer.INTERNAL)); + + cp = new VstProtocol(cacheCom); + + ArangoExecutorSync arangoExecutorSync = new ArangoExecutorSync(cp, util, new DocumentCache()); + hostResolver.init(arangoExecutorSync, util.get(Serializer.INTERNAL)); + + } + + @Override + protected ArangoExecutorAsync executor() { + return executor; + } + + @Override + public void shutdown() throws ArangoDBException { + try { + executor.disconnect(); + cp.close(); + } catch (final IOException e) { + throw new ArangoDBException(e); + } + } + + @Override + public ArangoDatabaseAsync db() { + return db(ArangoRequestParam.SYSTEM); + } + + @Override + public ArangoDatabaseAsync db(final String name) { + return new ArangoDatabaseAsyncImpl(this, name); + } + + @Override + public CompletableFuture createDatabase(final String name) { + return executor.execute(createDatabaseRequest(name), createDatabaseResponseDeserializer()); + } + + @Override + public CompletableFuture> getDatabases() { + return executor.execute(getDatabasesRequest(db().name()), getDatabaseResponseDeserializer()); + } + + @Override + public CompletableFuture> getAccessibleDatabases() { + return db().getAccessibleDatabases(); + } + + @Override + public CompletableFuture> getAccessibleDatabasesFor(final String user) { + return executor.execute(getAccessibleDatabasesForRequest(db().name(), user), + getAccessibleDatabasesForResponseDeserializer()); + } + + @Override + public CompletableFuture getVersion() { + return db().getVersion(); + } + + @Override + public CompletableFuture getRole() { + return executor.execute(getRoleRequest(), getRoleResponseDeserializer()); + } + + @Override + public CompletableFuture createUser(final String user, final String passwd) { + return executor.execute(createUserRequest(db().name(), user, passwd, new UserCreateOptions()), + UserEntity.class); + } + + @Override + public CompletableFuture createUser( + final String user, + final String passwd, + final UserCreateOptions options) { + return executor.execute(createUserRequest(db().name(), user, passwd, options), UserEntity.class); + } + + @Override + public CompletableFuture deleteUser(final String user) { + return executor.execute(deleteUserRequest(db().name(), user), Void.class); + } + + @Override + public CompletableFuture getUser(final String user) { + return executor.execute(getUserRequest(db().name(), user), UserEntity.class); + } + + @Override + public CompletableFuture> getUsers() { + return executor.execute(getUsersRequest(db().name()), getUsersResponseDeserializer()); + } + + @Override + public CompletableFuture updateUser(final String user, final UserUpdateOptions options) { + return executor.execute(updateUserRequest(db().name(), user, options), UserEntity.class); + } + + @Override + public CompletableFuture replaceUser(final String user, final UserUpdateOptions options) { + return executor.execute(replaceUserRequest(db().name(), user, options), UserEntity.class); + } + + @Override + public CompletableFuture grantDefaultDatabaseAccess(final String user, final Permissions permissions) { + return executor.execute(updateUserDefaultDatabaseAccessRequest(user, permissions), Void.class); + } + + @Override + public CompletableFuture grantDefaultCollectionAccess(final String user, final Permissions permissions) { + return executor.execute(updateUserDefaultCollectionAccessRequest(user, permissions), Void.class); + } + + @Override + public CompletableFuture execute(final Request request) { + return executor.execute(request, response -> response); + } + + @Override + public CompletableFuture getLogs(final LogOptions options) { + return executor.execute(getLogsRequest(options), LogEntity.class); + } + + @Override + public CompletableFuture getLogLevel() { + return executor.execute(getLogLevelRequest(), LogLevelEntity.class); + } + + @Override + public CompletableFuture setLogLevel(final LogLevelEntity entity) { + return executor.execute(setLogLevelRequest(entity), LogLevelEntity.class); + } +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoDatabaseAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoDatabaseAsyncImpl.java new file mode 100644 index 000000000..3c0c4abd5 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoDatabaseAsyncImpl.java @@ -0,0 +1,455 @@ +/* + * 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.internal; + +import com.arangodb.ArangoDBException; +import com.arangodb.async.*; +import com.arangodb.entity.*; +import com.arangodb.entity.arangosearch.AnalyzerEntity; +import com.arangodb.internal.ArangoCursorExecute; +import com.arangodb.internal.InternalArangoDatabase; +import com.arangodb.internal.net.HostHandle; +import com.arangodb.internal.util.DocumentUtil; +import com.arangodb.model.*; +import com.arangodb.model.arangosearch.AnalyzerDeleteOptions; +import com.arangodb.model.arangosearch.ArangoSearchCreateOptions; +import com.arangodb.velocypack.Type; +import com.arangodb.velocystream.Request; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * @author Mark Vollmary + * @author Michele Rastelli + */ +public class ArangoDatabaseAsyncImpl extends InternalArangoDatabase + implements ArangoDatabaseAsync { + + ArangoDatabaseAsyncImpl(final ArangoDBAsyncImpl arangoDB, final String name) { + super(arangoDB, name); + } + + @Override + public CompletableFuture getVersion() { + return executor.execute(getVersionRequest(), ArangoDBVersion.class); + } + + @Override + public CompletableFuture getEngine() { + return executor.execute(getEngineRequest(), ArangoDBEngine.class); + } + + @Override + public CompletableFuture exists() { + return getInfo().thenApply(Objects::nonNull).exceptionally(Objects::isNull); + } + + @Override + public CompletableFuture> getAccessibleDatabases() { + return executor.execute(getAccessibleDatabasesRequest(), getDatabaseResponseDeserializer()); + } + + @Override + public ArangoCollectionAsync collection(final String name) { + return new ArangoCollectionAsyncImpl(this, name); + } + + @Override + public CompletableFuture createCollection(final String name) { + return executor.execute(createCollectionRequest(name, new CollectionCreateOptions()), CollectionEntity.class); + } + + @Override + public CompletableFuture createCollection( + final String name, + final CollectionCreateOptions options) { + return executor.execute(createCollectionRequest(name, options), CollectionEntity.class); + } + + @Override + public CompletableFuture> getCollections() { + return executor.execute(getCollectionsRequest(new CollectionsReadOptions()), + getCollectionsResponseDeserializer()); + } + + @Override + public CompletableFuture> getCollections(final CollectionsReadOptions options) { + return executor.execute(getCollectionsRequest(options), getCollectionsResponseDeserializer()); + } + + @Override + public CompletableFuture getIndex(final String id) { + DocumentUtil.validateIndexId(id); + final String[] split = id.split("/"); + return collection(split[0]).getIndex(split[1]); + } + + @Override + public CompletableFuture deleteIndex(final String id) { + DocumentUtil.validateIndexId(id); + final String[] split = id.split("/"); + return collection(split[0]).deleteIndex(split[1]); + } + + @Override + public CompletableFuture create() { + return arango().createDatabase(name()); + } + + @Override + public CompletableFuture drop() { + return executor.execute(dropRequest(), createDropResponseDeserializer()); + } + + @Override + public CompletableFuture grantAccess(final String user, final Permissions permissions) { + return executor.execute(grantAccessRequest(user, permissions), Void.class); + } + + @Override + public CompletableFuture grantAccess(final String user) { + return executor.execute(grantAccessRequest(user, Permissions.RW), Void.class); + } + + @Override + public CompletableFuture revokeAccess(final String user) { + return executor.execute(grantAccessRequest(user, Permissions.NONE), Void.class); + } + + @Override + public CompletableFuture resetAccess(final String user) { + return executor.execute(resetAccessRequest(user), Void.class); + } + + @Override + public CompletableFuture grantDefaultCollectionAccess(final String user, final Permissions permissions) { + return executor.execute(updateUserDefaultCollectionAccessRequest(user, permissions), Void.class); + } + + @Override + public CompletableFuture getPermissions(final String user) { + return executor.execute(getPermissionsRequest(user), getPermissionsResponseDeserialzer()); + } + + @Override + public CompletableFuture> query( + final String query, + final Map bindVars, + final AqlQueryOptions options, + final Class type) { + final Request request = queryRequest(query, bindVars, options); + final HostHandle hostHandle = new HostHandle(); + final CompletableFuture execution = executor.execute(request, CursorEntity.class, hostHandle); + return execution.thenApply(result -> createCursor(result, type, options, hostHandle)); + } + + @Override + public CompletableFuture> query( + final String query, + final AqlQueryOptions options, + final Class type) { + return query(query, null, options, type); + } + + @Override + public CompletableFuture> query( + final String query, + final Map bindVars, + final Class type) { + return query(query, bindVars, null, type); + } + + @Override + public CompletableFuture> query(final String query, final Class type) { + return query(query, null, null, type); + } + + @Override + public CompletableFuture> cursor(final String cursorId, final Class type) { + final HostHandle hostHandle = new HostHandle(); + final CompletableFuture execution = executor.execute(queryNextRequest(cursorId, null, null), CursorEntity.class, hostHandle); + return execution.thenApply(result -> createCursor(result, type, null, hostHandle)); + } + + private ArangoCursorAsync createCursor( + final CursorEntity result, + final Class type, + final AqlQueryOptions options, + final HostHandle hostHandle) { + return new ArangoCursorAsyncImpl<>(this, new ArangoCursorExecute() { + @Override + public CursorEntity next(final String id, Map meta) { + final CompletableFuture result = executor.execute(queryNextRequest(id, options, meta), + CursorEntity.class, hostHandle); + try { + return result.get(); + } catch (InterruptedException | ExecutionException e) { + throw new ArangoDBException(e); + } + } + + @Override + public void close(final String id, Map meta) { + try { + executor.execute(queryCloseRequest(id, options, meta), Void.class, hostHandle).get(); + } catch (InterruptedException | ExecutionException e) { + throw new ArangoDBException(e); + } + } + }, type, result); + } + + @Override + public CompletableFuture explainQuery( + final String query, + final Map bindVars, + final AqlQueryExplainOptions options) { + return executor.execute(explainQueryRequest(query, bindVars, options), AqlExecutionExplainEntity.class); + } + + @Override + public CompletableFuture parseQuery(final String query) { + return executor.execute(parseQueryRequest(query), AqlParseEntity.class); + } + + @Override + public CompletableFuture clearQueryCache() { + return executor.execute(clearQueryCacheRequest(), Void.class); + } + + @Override + public CompletableFuture getQueryCacheProperties() { + return executor.execute(getQueryCachePropertiesRequest(), QueryCachePropertiesEntity.class); + } + + @Override + public CompletableFuture setQueryCacheProperties( + final QueryCachePropertiesEntity properties) { + return executor.execute(setQueryCachePropertiesRequest(properties), QueryCachePropertiesEntity.class); + } + + @Override + public CompletableFuture getQueryTrackingProperties() { + return executor.execute(getQueryTrackingPropertiesRequest(), QueryTrackingPropertiesEntity.class); + } + + @Override + public CompletableFuture setQueryTrackingProperties( + final QueryTrackingPropertiesEntity properties) { + return executor.execute(setQueryTrackingPropertiesRequest(properties), QueryTrackingPropertiesEntity.class); + } + + @Override + public CompletableFuture> getCurrentlyRunningQueries() { + return executor.execute(getCurrentlyRunningQueriesRequest(), new Type>() { + }.getType()); + } + + @Override + public CompletableFuture> getSlowQueries() { + return executor.execute(getSlowQueriesRequest(), new Type>() { + }.getType()); + } + + @Override + public CompletableFuture clearSlowQueries() { + return executor.execute(clearSlowQueriesRequest(), Void.class); + } + + @Override + public CompletableFuture killQuery(final String id) { + return executor.execute(killQueryRequest(id), Void.class); + } + + @Override + public CompletableFuture createAqlFunction( + final String name, + final String code, + final AqlFunctionCreateOptions options) { + return executor.execute(createAqlFunctionRequest(name, code, options), Void.class); + + } + + @Override + public CompletableFuture deleteAqlFunction(final String name, final AqlFunctionDeleteOptions options) { + return executor.execute(deleteAqlFunctionRequest(name, options), deleteAqlFunctionResponseDeserializer()); + } + + @Override + public CompletableFuture> getAqlFunctions(final AqlFunctionGetOptions options) { + return executor.execute(getAqlFunctionsRequest(options), getAqlFunctionsResponseDeserializer()); + } + + @Override + public ArangoGraphAsync graph(final String name) { + return new ArangoGraphAsyncImpl(this, name); + } + + @Override + public CompletableFuture createGraph( + final String name, + final Collection edgeDefinitions) { + return executor.execute(createGraphRequest(name, edgeDefinitions, new GraphCreateOptions()), + createGraphResponseDeserializer()); + } + + @Override + public CompletableFuture createGraph( + final String name, + final Collection edgeDefinitions, + final GraphCreateOptions options) { + return executor.execute(createGraphRequest(name, edgeDefinitions, options), createGraphResponseDeserializer()); + } + + @Override + public CompletableFuture> getGraphs() { + return executor.execute(getGraphsRequest(), getGraphsResponseDeserializer()); + } + + @Override + public CompletableFuture transaction( + final String action, + final Class type, + final TransactionOptions options) { + return executor.execute(transactionRequest(action, options), transactionResponseDeserializer(type)); + } + + @Override + public CompletableFuture beginStreamTransaction(StreamTransactionOptions options) { + return executor.execute(beginStreamTransactionRequest(options), streamTransactionResponseDeserializer()); + } + + @Override + public CompletableFuture abortStreamTransaction(String id) { + return executor.execute(abortStreamTransactionRequest(id), streamTransactionResponseDeserializer()); + } + + @Override + public CompletableFuture getStreamTransaction(String id) { + return executor.execute(getStreamTransactionRequest(id), streamTransactionResponseDeserializer()); + } + + @Override + public CompletableFuture> getStreamTransactions() { + return executor.execute(getStreamTransactionsRequest(), transactionsResponseDeserializer()); + } + + @Override + public CompletableFuture commitStreamTransaction(String id) { + return executor.execute(commitStreamTransactionRequest(id), streamTransactionResponseDeserializer()); + } + + @Override + public CompletableFuture getInfo() { + return executor.execute(getInfoRequest(), getInfoResponseDeserializer()); + } + + @Override + public CompletableFuture> executeTraversal( + final Class vertexClass, + final Class edgeClass, + final TraversalOptions options) { + final Request request = executeTraversalRequest(options); + return executor.execute(request, executeTraversalResponseDeserializer(vertexClass, edgeClass)); + } + + @Override + public CompletableFuture getDocument(final String id, final Class type) throws ArangoDBException { + DocumentUtil.validateDocumentId(id); + final String[] split = id.split("/"); + return collection(split[0]).getDocument(split[1], type); + } + + @Override + public CompletableFuture getDocument(final String id, final Class type, final DocumentReadOptions options) + throws ArangoDBException { + DocumentUtil.validateDocumentId(id); + final String[] split = id.split("/"); + return collection(split[0]).getDocument(split[1], type, options); + } + + @Override + public CompletableFuture reloadRouting() { + return executor.execute(reloadRoutingRequest(), Void.class); + } + + @Override + public ArangoRouteAsync route(final String... path) { + return new ArangoRouteAsyncImpl(this, createPath(path), Collections.emptyMap()); + } + + @Override + public CompletableFuture> getViews() { + return executor.execute(getViewsRequest(), getViewsResponseDeserializer()); + } + + @Override + public ArangoViewAsync view(final String name) { + return new ArangoViewAsyncImpl(this, name); + } + + @Override + public ArangoSearchAsync arangoSearch(final String name) { + return new ArangoSearchAsyncImpl(this, name); + } + + @Override + public CompletableFuture createView(final String name, final ViewType type) { + return executor.execute(createViewRequest(name, type), ViewEntity.class); + } + + @Override + public CompletableFuture createArangoSearch(final String name, final ArangoSearchCreateOptions options) { + return executor.execute(createArangoSearchRequest(name, options), ViewEntity.class); + } + + @Override + public CompletableFuture createAnalyzer(AnalyzerEntity options) { + return executor.execute(createAnalyzerRequest(options), AnalyzerEntity.class); + } + + @Override + public CompletableFuture getAnalyzer(String name) { + return executor.execute(getAnalyzerRequest(name), AnalyzerEntity.class); + } + + @Override + public CompletableFuture> getAnalyzers() { + return executor.execute(getAnalyzersRequest(), getAnalyzersResponseDeserializer()); + } + + @Override + public CompletableFuture deleteAnalyzer(String name) { + return executor.execute(deleteAnalyzerRequest(name, null), Void.class); + } + + @Override + public CompletableFuture deleteAnalyzer(String name, AnalyzerDeleteOptions options) { + return executor.execute(deleteAnalyzerRequest(name, options), Void.class); + } + + +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java new file mode 100644 index 000000000..84e47b8d8 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoEdgeCollectionAsyncImpl.java @@ -0,0 +1,101 @@ +/* + * 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.internal; + +import com.arangodb.async.ArangoEdgeCollectionAsync; +import com.arangodb.entity.EdgeEntity; +import com.arangodb.entity.EdgeUpdateEntity; +import com.arangodb.internal.InternalArangoEdgeCollection; +import com.arangodb.model.*; + +import java.util.concurrent.CompletableFuture; + +/** + * @author Mark Vollmary + */ +public class ArangoEdgeCollectionAsyncImpl extends + InternalArangoEdgeCollection + implements ArangoEdgeCollectionAsync { + + ArangoEdgeCollectionAsyncImpl(final ArangoGraphAsyncImpl graph, final String name) { + super(graph, name); + } + + @Override + public CompletableFuture insertEdge(final T value) { + return executor.execute(insertEdgeRequest(value, new EdgeCreateOptions()), + insertEdgeResponseDeserializer(value)); + } + + @Override + public CompletableFuture insertEdge(final T value, final EdgeCreateOptions options) { + return executor.execute(insertEdgeRequest(value, options), insertEdgeResponseDeserializer(value)); + } + + @Override + public CompletableFuture getEdge(final String key, final Class type) { + return executor.execute(getEdgeRequest(key, new GraphDocumentReadOptions()), getEdgeResponseDeserializer(type)); + } + + @Override + public CompletableFuture getEdge(final String key, final Class type, final GraphDocumentReadOptions options) { + return executor.execute(getEdgeRequest(key, options), getEdgeResponseDeserializer(type)); + } + + @Override + public CompletableFuture replaceEdge(final String key, final T value) { + return executor.execute(replaceEdgeRequest(key, value, new EdgeReplaceOptions()), + replaceEdgeResponseDeserializer(value)); + } + + @Override + public CompletableFuture replaceEdge( + final String key, + final T value, + final EdgeReplaceOptions options) { + return executor.execute(replaceEdgeRequest(key, value, options), replaceEdgeResponseDeserializer(value)); + } + + @Override + public CompletableFuture updateEdge(final String key, final T value) { + return executor.execute(updateEdgeRequest(key, value, new EdgeUpdateOptions()), + updateEdgeResponseDeserializer(value)); + } + + @Override + public CompletableFuture updateEdge( + final String key, + final T value, + final EdgeUpdateOptions options) { + return executor.execute(updateEdgeRequest(key, value, options), updateEdgeResponseDeserializer(value)); + } + + @Override + public CompletableFuture deleteEdge(final String key) { + return executor.execute(deleteEdgeRequest(key, new EdgeDeleteOptions()), Void.class); + } + + @Override + public CompletableFuture deleteEdge(final String key, final EdgeDeleteOptions options) { + return executor.execute(deleteEdgeRequest(key, options), Void.class); + } + +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoExecutorAsync.java b/src/main/java/com/arangodb/async/internal/ArangoExecutorAsync.java new file mode 100644 index 000000000..7aa3b49ec --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoExecutorAsync.java @@ -0,0 +1,76 @@ +/* + * 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.internal; + +import com.arangodb.async.internal.velocystream.VstCommunicationAsync; +import com.arangodb.internal.ArangoExecutor; +import com.arangodb.internal.DocumentCache; +import com.arangodb.internal.net.HostHandle; +import com.arangodb.internal.util.ArangoSerializationFactory; +import com.arangodb.velocystream.Request; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @author Mark Vollmary + * @author Michele Rastelli + */ +public class ArangoExecutorAsync extends ArangoExecutor { + + private final VstCommunicationAsync communication; + private final ExecutorService outgoingExecutor = Executors.newSingleThreadExecutor(); + + public ArangoExecutorAsync(final VstCommunicationAsync communication, final ArangoSerializationFactory util, + final DocumentCache documentCache) { + super(util, documentCache); + this.communication = communication; + } + + public CompletableFuture execute(final Request request, final Type type) { + return execute(request, (response) -> createResult(type, response)); + } + + public CompletableFuture execute(final Request request, final Type type, final HostHandle hostHandle) { + return execute(request, (response) -> createResult(type, response), hostHandle); + } + + public CompletableFuture execute(final Request request, final ResponseDeserializer responseDeserializer) { + return execute(request, responseDeserializer, null); + } + + private CompletableFuture execute( + final Request request, + final ResponseDeserializer responseDeserializer, + final HostHandle hostHandle) { + + return CompletableFuture.completedFuture(null) + .thenComposeAsync((it) -> communication.execute(request, hostHandle), outgoingExecutor) + .thenApplyAsync(responseDeserializer::deserialize); + } + + public void disconnect() throws IOException { + communication.close(); + } +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoGraphAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoGraphAsyncImpl.java new file mode 100644 index 000000000..449f55ec3 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoGraphAsyncImpl.java @@ -0,0 +1,118 @@ +/* + * 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.internal; + +import com.arangodb.async.ArangoEdgeCollectionAsync; +import com.arangodb.async.ArangoGraphAsync; +import com.arangodb.async.ArangoVertexCollectionAsync; +import com.arangodb.entity.EdgeDefinition; +import com.arangodb.entity.GraphEntity; +import com.arangodb.internal.InternalArangoGraph; +import com.arangodb.model.GraphCreateOptions; + +import java.util.Collection; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +/** + * @author Mark Vollmary + */ +public class ArangoGraphAsyncImpl + extends InternalArangoGraph + implements ArangoGraphAsync { + + ArangoGraphAsyncImpl(final ArangoDatabaseAsyncImpl db, final String name) { + super(db, name); + } + + @Override + public CompletableFuture exists() { + return getInfo().thenApply(Objects::nonNull).exceptionally(Objects::isNull); + } + + @Override + public CompletableFuture create(final Collection edgeDefinitions) { + return db().createGraph(name(), edgeDefinitions); + } + + @Override + public CompletableFuture createGraph( + final Collection edgeDefinitions, + final GraphCreateOptions options) { + return db().createGraph(name(), edgeDefinitions, options); + } + + @Override + public CompletableFuture drop() { + return executor.execute(dropRequest(), Void.class); + } + + @Override + public CompletableFuture drop(boolean dropCollections) { + return executor.execute(dropRequest(dropCollections), Void.class); + } + + @Override + public CompletableFuture getInfo() { + return executor.execute(getInfoRequest(), getInfoResponseDeserializer()); + } + + @Override + public CompletableFuture> getVertexCollections() { + return executor.execute(getVertexCollectionsRequest(), getVertexCollectionsResponseDeserializer()); + } + + @Override + public CompletableFuture addVertexCollection(final String name) { + return executor.execute(addVertexCollectionRequest(name), addVertexCollectionResponseDeserializer()); + } + + @Override + public ArangoVertexCollectionAsync vertexCollection(final String name) { + return new ArangoVertexCollectionAsyncImpl(this, name); + } + + @Override + public ArangoEdgeCollectionAsync edgeCollection(final String name) { + return new ArangoEdgeCollectionAsyncImpl(this, name); + } + + @Override + public CompletableFuture> getEdgeDefinitions() { + return executor.execute(getEdgeDefinitionsRequest(), getEdgeDefinitionsDeserializer()); + } + + @Override + public CompletableFuture addEdgeDefinition(final EdgeDefinition definition) { + return executor.execute(addEdgeDefinitionRequest(definition), addEdgeDefinitionResponseDeserializer()); + } + + @Override + public CompletableFuture replaceEdgeDefinition(final EdgeDefinition definition) { + return executor.execute(replaceEdgeDefinitionRequest(definition), replaceEdgeDefinitionResponseDeserializer()); + } + + @Override + public CompletableFuture removeEdgeDefinition(final String definitionName) { + return executor.execute(removeEdgeDefinitionRequest(definitionName), + removeEdgeDefinitionResponseDeserializer()); + } +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoRouteAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoRouteAsyncImpl.java new file mode 100644 index 000000000..44046507a --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoRouteAsyncImpl.java @@ -0,0 +1,100 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.internal; + +import com.arangodb.async.ArangoRouteAsync; +import com.arangodb.internal.InternalArangoRoute; +import com.arangodb.velocystream.RequestType; +import com.arangodb.velocystream.Response; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** + * @author Mark Vollmary + */ +public class ArangoRouteAsyncImpl + extends InternalArangoRoute + implements ArangoRouteAsync { + + ArangoRouteAsyncImpl(final ArangoDatabaseAsyncImpl db, final String path, + final Map headerParam) { + super(db, path, headerParam); + } + + @Override + public ArangoRouteAsync route(final String... path) { + return new ArangoRouteAsyncImpl(db, createPath(this.path, createPath(path)), headerParam); + } + + @Override + public ArangoRouteAsync withHeader(final String key, final Object value) { + _withHeader(key, value); + return this; + } + + @Override + public ArangoRouteAsync withQueryParam(final String key, final Object value) { + _withQueryParam(key, value); + return this; + } + + @Override + public ArangoRouteAsync withBody(final Object body) { + _withBody(body); + return this; + } + + private CompletableFuture request(final RequestType requestType) { + return executor.execute(createRequest(requestType), response -> response); + } + + @Override + public CompletableFuture delete() { + return request(RequestType.DELETE); + } + + @Override + public CompletableFuture get() { + return request(RequestType.GET); + } + + @Override + public CompletableFuture head() { + return request(RequestType.HEAD); + } + + @Override + public CompletableFuture patch() { + return request(RequestType.PATCH); + } + + @Override + public CompletableFuture post() { + return request(RequestType.POST); + } + + @Override + public CompletableFuture put() { + return request(RequestType.PUT); + } + +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoSearchAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoSearchAsyncImpl.java new file mode 100644 index 000000000..9c9740ee4 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoSearchAsyncImpl.java @@ -0,0 +1,90 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.internal; + +import com.arangodb.async.ArangoSearchAsync; +import com.arangodb.entity.ViewEntity; +import com.arangodb.entity.arangosearch.ArangoSearchPropertiesEntity; +import com.arangodb.internal.InternalArangoSearch; +import com.arangodb.model.arangosearch.ArangoSearchCreateOptions; +import com.arangodb.model.arangosearch.ArangoSearchPropertiesOptions; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +/** + * @author Mark Vollmary + */ +public class ArangoSearchAsyncImpl + extends InternalArangoSearch + implements ArangoSearchAsync { + + ArangoSearchAsyncImpl(final ArangoDatabaseAsyncImpl db, final String name) { + super(db, name); + } + + @Override + public CompletableFuture exists() { + return getInfo().thenApply(Objects::nonNull).exceptionally(Objects::isNull); + } + + @Override + public CompletableFuture drop() { + return executor.execute(dropRequest(), Void.class); + } + + @Override + public synchronized CompletableFuture rename(final String newName) { + return executor.execute(renameRequest(newName), ViewEntity.class); + } + + @Override + public CompletableFuture getInfo() { + return executor.execute(getInfoRequest(), ViewEntity.class); + } + + @Override + public CompletableFuture create() { + return create(new ArangoSearchCreateOptions()); + } + + @Override + public CompletableFuture create(final ArangoSearchCreateOptions options) { + return db().createArangoSearch(name(), options); + } + + @Override + public CompletableFuture getProperties() { + return executor.execute(getPropertiesRequest(), ArangoSearchPropertiesEntity.class); + } + + @Override + public CompletableFuture updateProperties(final ArangoSearchPropertiesOptions options) { + return executor.execute(updatePropertiesRequest(options), ArangoSearchPropertiesEntity.class); + } + + @Override + public CompletableFuture replaceProperties( + final ArangoSearchPropertiesOptions options) { + return executor.execute(replacePropertiesRequest(options), ArangoSearchPropertiesEntity.class); + } + +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java new file mode 100644 index 000000000..75a102eaa --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoVertexCollectionAsyncImpl.java @@ -0,0 +1,109 @@ +/* + * 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.internal; + +import com.arangodb.async.ArangoVertexCollectionAsync; +import com.arangodb.entity.VertexEntity; +import com.arangodb.entity.VertexUpdateEntity; +import com.arangodb.internal.InternalArangoVertexCollection; +import com.arangodb.model.*; + +import java.util.concurrent.CompletableFuture; + +/** + * @author Mark Vollmary + */ +public class ArangoVertexCollectionAsyncImpl extends + InternalArangoVertexCollection + implements ArangoVertexCollectionAsync { + + ArangoVertexCollectionAsyncImpl(final ArangoGraphAsyncImpl graph, final String name) { + super(graph, name); + } + + @Override + public CompletableFuture drop() { + return executor.execute(dropRequest(), Void.class); + } + + @Override + public CompletableFuture insertVertex(final T value) { + return executor.execute(insertVertexRequest(value, new VertexCreateOptions()), + insertVertexResponseDeserializer(value)); + } + + @Override + public CompletableFuture insertVertex(final T value, final VertexCreateOptions options) { + return executor.execute(insertVertexRequest(value, options), insertVertexResponseDeserializer(value)); + } + + @Override + public CompletableFuture getVertex(final String key, final Class type) { + return executor.execute(getVertexRequest(key, new GraphDocumentReadOptions()), getVertexResponseDeserializer(type)); + } + + @Override + public CompletableFuture getVertex( + final String key, + final Class type, + final GraphDocumentReadOptions options) { + return executor.execute(getVertexRequest(key, options), getVertexResponseDeserializer(type)); + } + + @Override + public CompletableFuture replaceVertex(final String key, final T value) { + return executor.execute(replaceVertexRequest(key, value, new VertexReplaceOptions()), + replaceVertexResponseDeserializer(value)); + } + + @Override + public CompletableFuture replaceVertex( + final String key, + final T value, + final VertexReplaceOptions options) { + return executor.execute(replaceVertexRequest(key, value, options), replaceVertexResponseDeserializer(value)); + } + + @Override + public CompletableFuture updateVertex(final String key, final T value) { + return executor.execute(updateVertexRequest(key, value, new VertexUpdateOptions()), + updateVertexResponseDeserializer(value)); + } + + @Override + public CompletableFuture updateVertex( + final String key, + final T value, + final VertexUpdateOptions options) { + return executor.execute(updateVertexRequest(key, value, options), updateVertexResponseDeserializer(value)); + } + + @Override + public CompletableFuture deleteVertex(final String key) { + return executor.execute(deleteVertexRequest(key, new VertexDeleteOptions()), Void.class); + } + + @Override + public CompletableFuture deleteVertex(final String key, final VertexDeleteOptions options) { + return executor.execute(deleteVertexRequest(key, options), Void.class); + } + +} diff --git a/src/main/java/com/arangodb/async/internal/ArangoViewAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoViewAsyncImpl.java new file mode 100644 index 000000000..a019cb721 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/ArangoViewAsyncImpl.java @@ -0,0 +1,60 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.internal; + +import com.arangodb.async.ArangoViewAsync; +import com.arangodb.entity.ViewEntity; +import com.arangodb.internal.InternalArangoView; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +/** + * @author Mark Vollmary + */ +public class ArangoViewAsyncImpl extends + InternalArangoView implements ArangoViewAsync { + + ArangoViewAsyncImpl(final ArangoDatabaseAsyncImpl db, final String name) { + super(db, name); + } + + @Override + public CompletableFuture exists() { + return getInfo().thenApply(Objects::nonNull).exceptionally(Objects::isNull); + } + + @Override + public CompletableFuture drop() { + return executor.execute(dropRequest(), Void.class); + } + + @Override + public synchronized CompletableFuture rename(final String newName) { + return executor.execute(renameRequest(newName), ViewEntity.class); + } + + @Override + public CompletableFuture getInfo() { + return executor.execute(getInfoRequest(), ViewEntity.class); + } + +} diff --git a/src/main/java/com/arangodb/async/internal/velocystream/VstCommunicationAsync.java b/src/main/java/com/arangodb/async/internal/velocystream/VstCommunicationAsync.java new file mode 100644 index 000000000..c597de11c --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/velocystream/VstCommunicationAsync.java @@ -0,0 +1,175 @@ +/* + * 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.internal.velocystream; + +import com.arangodb.ArangoDBException; +import com.arangodb.entity.ErrorEntity; +import com.arangodb.internal.net.HostHandler; +import com.arangodb.internal.velocystream.VstCommunication; +import com.arangodb.internal.velocystream.internal.AuthenticationRequest; +import com.arangodb.internal.velocystream.internal.Message; +import com.arangodb.util.ArangoSerialization; +import com.arangodb.velocypack.exception.VPackException; +import com.arangodb.velocypack.exception.VPackParserException; +import com.arangodb.velocystream.Request; +import com.arangodb.velocystream.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLContext; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * @author Mark Vollmary + */ +public class VstCommunicationAsync extends VstCommunication, VstConnectionAsync> { + + private static final Logger LOGGER = LoggerFactory.getLogger(VstCommunicationAsync.class); + + private VstCommunicationAsync(final HostHandler hostHandler, final Integer timeout, final String user, + final String password, final Boolean useSsl, final SSLContext sslContext, final ArangoSerialization util, + final Integer chunksize, final Integer maxConnections, final Long connectionTtl) { + super(timeout, user, password, useSsl, sslContext, util, chunksize, hostHandler); + } + + @Override + protected CompletableFuture execute(final Request request, final VstConnectionAsync connection) { + final CompletableFuture rfuture = new CompletableFuture<>(); + try { + final Message message = createMessage(request); + send(message, connection).whenComplete((m, ex) -> { + if (m != null) { + try { + final Response response = createResponse(m); + if (response.getResponseCode() >= 300) { + if (response.getBody() != null) { + final ErrorEntity errorEntity = util.deserialize(response.getBody(), ErrorEntity.class); + rfuture.completeExceptionally(new ArangoDBException(errorEntity)); + } else { + rfuture.completeExceptionally(new ArangoDBException( + String.format("Response Code: %s", response.getResponseCode()), response.getResponseCode())); + } + } else { + rfuture.complete(response); + } + } catch (final VPackParserException e) { + LOGGER.error(e.getMessage(), e); + rfuture.completeExceptionally(e); + } + } else if (ex != null) { + LOGGER.error(ex.getMessage(), ex); + rfuture.completeExceptionally(ex); + } else { + rfuture.cancel(true); + } + }); + } catch (final VPackException e) { + LOGGER.error(e.getMessage(), e); + rfuture.completeExceptionally(e); + } + return rfuture; + } + + private CompletableFuture send(final Message message, final VstConnectionAsync connection) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(String.format("Send Message (id=%s, head=%s, body=%s)", message.getId(), message.getHead(), + message.getBody() != null ? message.getBody() : "{}")); + } + return connection.write(message, buildChunks(message)); + } + + @Override + protected void authenticate(final VstConnectionAsync connection) { + Response response; + try { + response = execute(new AuthenticationRequest(user, password != null ? password : "", ENCRYPTION_PLAIN), + connection).get(); + } catch (final InterruptedException | ExecutionException e) { + throw new ArangoDBException(e); + } + checkError(response); + } + + public static class Builder { + + private final HostHandler hostHandler; + private Integer timeout; + private Long connectionTtl; + private String user; + private String password; + private Boolean useSsl; + private SSLContext sslContext; + private Integer chunksize; + private Integer maxConnections; + + public Builder(final HostHandler hostHandler) { + super(); + this.hostHandler = hostHandler; + } + + public Builder timeout(final Integer timeout) { + this.timeout = timeout; + return this; + } + + public Builder user(final String user) { + this.user = user; + return this; + } + + public Builder password(final String password) { + this.password = password; + return this; + } + + public Builder useSsl(final Boolean useSsl) { + this.useSsl = useSsl; + return this; + } + + public Builder sslContext(final SSLContext sslContext) { + this.sslContext = sslContext; + return this; + } + + public Builder chunksize(final Integer chunksize) { + this.chunksize = chunksize; + return this; + } + + public Builder maxConnections(final Integer maxConnections) { + this.maxConnections = maxConnections; + return this; + } + + public Builder connectionTtl(final Long connectionTtl) { + this.connectionTtl = connectionTtl; + return this; + } + + public VstCommunicationAsync build(final ArangoSerialization util) { + return new VstCommunicationAsync(hostHandler, timeout, user, password, useSsl, sslContext, util, chunksize, + maxConnections, connectionTtl); + } + } + +} diff --git a/src/main/java/com/arangodb/async/internal/velocystream/VstConnectionAsync.java b/src/main/java/com/arangodb/async/internal/velocystream/VstConnectionAsync.java new file mode 100644 index 000000000..1dbcc313b --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/velocystream/VstConnectionAsync.java @@ -0,0 +1,107 @@ +/* + * 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.internal.velocystream; + +import com.arangodb.internal.net.HostDescription; +import com.arangodb.internal.velocystream.internal.Chunk; +import com.arangodb.internal.velocystream.internal.Message; +import com.arangodb.internal.velocystream.internal.MessageStore; +import com.arangodb.internal.velocystream.internal.VstConnection; + +import javax.net.ssl.SSLContext; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.FutureTask; + +/** + * @author Mark Vollmary + */ +public class VstConnectionAsync extends VstConnection { + + private VstConnectionAsync(final HostDescription host, final Integer timeout, final Long ttl, final Boolean useSsl, + final SSLContext sslContext, final MessageStore messageStore) { + super(host, timeout, ttl, useSsl, sslContext, messageStore); + } + + public synchronized CompletableFuture write(final Message message, final Collection chunks) { + final CompletableFuture future = new CompletableFuture<>(); + final FutureTask task = new FutureTask<>(() -> { + try { + future.complete(messageStore.get(message.getId())); + } catch (final Exception e) { + future.completeExceptionally(e); + } + return null; + }); + messageStore.storeMessage(message.getId(), task); + super.writeIntern(message, chunks); + return future; + } + + public static class Builder { + + private MessageStore messageStore; + private HostDescription host; + private Integer timeout; + private Long ttl; + private Boolean useSsl; + private SSLContext sslContext; + + public Builder() { + super(); + } + + public Builder messageStore(final MessageStore messageStore) { + this.messageStore = messageStore; + return this; + } + + public Builder host(final HostDescription host) { + this.host = host; + return this; + } + + public Builder timeout(final Integer timeout) { + this.timeout = timeout; + return this; + } + + public Builder ttl(final Long ttl) { + this.ttl = ttl; + return this; + } + + public Builder useSsl(final Boolean useSsl) { + this.useSsl = useSsl; + return this; + } + + public Builder sslContext(final SSLContext sslContext) { + this.sslContext = sslContext; + return this; + } + + public VstConnectionAsync build() { + return new VstConnectionAsync(host, timeout, ttl, useSsl, sslContext, messageStore); + } + } + +} diff --git a/src/main/java/com/arangodb/async/internal/velocystream/VstConnectionFactoryAsync.java b/src/main/java/com/arangodb/async/internal/velocystream/VstConnectionFactoryAsync.java new file mode 100644 index 000000000..9a181c5a9 --- /dev/null +++ b/src/main/java/com/arangodb/async/internal/velocystream/VstConnectionFactoryAsync.java @@ -0,0 +1,49 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.internal.velocystream; + +import com.arangodb.internal.net.Connection; +import com.arangodb.internal.net.ConnectionFactory; +import com.arangodb.internal.net.HostDescription; +import com.arangodb.internal.velocystream.internal.MessageStore; + +import javax.net.ssl.SSLContext; + +/** + * @author Mark Vollmary + */ +public class VstConnectionFactoryAsync implements ConnectionFactory { + + private final VstConnectionAsync.Builder builder; + + public VstConnectionFactoryAsync(final HostDescription host, final Integer timeout, final Long connectionTtl, + final Boolean useSsl, final SSLContext sslContext) { + super(); + builder = new VstConnectionAsync.Builder().timeout(timeout).ttl(connectionTtl).useSsl(useSsl) + .sslContext(sslContext); + } + + @Override + public Connection create(final HostDescription host) { + return builder.messageStore(new MessageStore()).host(host).build(); + } + +} diff --git a/src/test/java/com/arangodb/async/ArangoCollectionTest.java b/src/test/java/com/arangodb/async/ArangoCollectionTest.java new file mode 100644 index 000000000..dbec7828b --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoCollectionTest.java @@ -0,0 +1,2133 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.*; +import com.arangodb.model.*; +import com.arangodb.model.DocumentImportOptions.OnDuplicate; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +/** + * @author Mark Vollmary + * @author Michele Rastelli + */ +public class ArangoCollectionTest extends BaseTest { + + private static final String COLLECTION_NAME = "db_collection_test"; + + public ArangoCollectionTest() throws ExecutionException, InterruptedException { + ArangoCollectionAsync collection = db.collection(COLLECTION_NAME); + if (!collection.exists().get()) { + collection.create().get(); + } + } + + @BeforeClass + public static void setup() throws InterruptedException, ExecutionException { + db.createCollection(COLLECTION_NAME, null).get(); + } + + @After + public void teardown() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void create() throws InterruptedException, ExecutionException { + final CollectionEntity result = db.collection(COLLECTION_NAME + "_1").create().get(); + assertThat(result, is(notNullValue())); + assertThat(result.getId(), is(notNullValue())); + db.collection(COLLECTION_NAME + "_1").drop().get(); + } + + @Test + public void insertDocument() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), null) + .whenComplete((doc, ex) -> { + assertThat(ex, is(nullValue())); + assertThat(doc.getId(), is(notNullValue())); + assertThat(doc.getKey(), is(notNullValue())); + assertThat(doc.getRev(), is(notNullValue())); + assertThat(doc.getNew(), is(nullValue())); + assertThat(doc.getId(), is(COLLECTION_NAME + "/" + doc.getKey())); + }) + .get(); + } + + @Test + public void insertDocumentReturnNew() throws InterruptedException, ExecutionException { + final DocumentCreateOptions options = new DocumentCreateOptions().returnNew(true); + db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), options) + .whenComplete((doc, ex) -> { + assertThat(doc, is(notNullValue())); + assertThat(doc.getId(), is(notNullValue())); + assertThat(doc.getKey(), is(notNullValue())); + assertThat(doc.getRev(), is(notNullValue())); + assertThat(doc.getNew(), is(notNullValue())); + }) + .get(); + } + + @Test + public void insertDocumentWaitForSync() throws InterruptedException, ExecutionException { + final DocumentCreateOptions options = new DocumentCreateOptions().waitForSync(true); + db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), options) + .whenComplete((doc, ex) -> { + assertThat(doc, is(notNullValue())); + assertThat(doc.getId(), is(notNullValue())); + assertThat(doc.getKey(), is(notNullValue())); + assertThat(doc.getRev(), is(notNullValue())); + assertThat(doc.getNew(), is(nullValue())); + }) + .get(); + } + + @Test + public void insertDocumentAsJson() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME) + .insertDocument("{\"_key\":\"docRaw\",\"a\":\"test\"}", null) + .whenComplete((doc, ex) -> { + assertThat(doc, is(notNullValue())); + assertThat(doc.getId(), is(notNullValue())); + assertThat(doc.getKey(), is(notNullValue())); + assertThat(doc.getRev(), is(notNullValue())); + }) + .get(); + } + + @Test + public void getDocument() throws InterruptedException, ExecutionException { + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), null).get(); + assertThat(createResult.getKey(), is(notNullValue())); + db.collection(COLLECTION_NAME).getDocument(createResult.getKey(), BaseDocument.class, null) + .whenComplete((readResult, ex) -> { + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getId(), is(COLLECTION_NAME + "/" + createResult.getKey())); + }) + .get(); + } + + @Test + public void getDocumentIfMatch() throws InterruptedException, ExecutionException { + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), null).get(); + assertThat(createResult.getKey(), is(notNullValue())); + final DocumentReadOptions options = new DocumentReadOptions().ifMatch(createResult.getRev()); + db.collection(COLLECTION_NAME).getDocument(createResult.getKey(), BaseDocument.class, options) + .whenComplete((readResult, ex) -> { + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getId(), is(COLLECTION_NAME + "/" + createResult.getKey())); + }) + .get(); + } + + @Test + public void getDocumentIfMatchFail() throws InterruptedException, ExecutionException { + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), null).get(); + assertThat(createResult.getKey(), is(notNullValue())); + final DocumentReadOptions options = new DocumentReadOptions().ifMatch("no"); + db.collection(COLLECTION_NAME).getDocument(createResult.getKey(), BaseDocument.class, options) + .whenComplete((doc, ex) -> assertThat(doc, is(nullValue()))) + .get(); + } + + @Test + public void getDocumentIfNoneMatch() throws InterruptedException, ExecutionException { + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), null).get(); + assertThat(createResult.getKey(), is(notNullValue())); + final DocumentReadOptions options = new DocumentReadOptions().ifNoneMatch("no"); + db.collection(COLLECTION_NAME).getDocument(createResult.getKey(), BaseDocument.class, options) + .whenComplete((readResult, ex) -> { + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getId(), is(COLLECTION_NAME + "/" + createResult.getKey())); + }) + .get(); + } + + @Test + public void getDocumentIfNoneMatchFail() throws InterruptedException, ExecutionException { + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), null).get(); + assertThat(createResult.getKey(), is(notNullValue())); + final DocumentReadOptions options = new DocumentReadOptions().ifNoneMatch(createResult.getRev()); + db.collection(COLLECTION_NAME).getDocument(createResult.getKey(), BaseDocument.class, options) + .whenComplete((doc, ex) -> assertThat(doc, is(nullValue()))) + .get(); + } + + @Test + public void getDocumentAsJson() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).insertDocument("{\"_key\":\"docRaw\",\"a\":\"test\"}", null).get(); + db.collection(COLLECTION_NAME).getDocument("docRaw", String.class, null) + .whenComplete((readResult, ex) -> { + assertThat(readResult.contains("\"_key\":\"docRaw\""), is(true)); + assertThat(readResult.contains("\"_id\":\"db_collection_test\\/docRaw\""), is(true)); + }) + .get(); + } + + @Test + public void getDocumentNotFound() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).getDocument("no", BaseDocument.class) + .whenComplete((doc, ex) -> assertThat(doc, is(nullValue()))) + .get(); + } + + @Test(expected = ArangoDBException.class) + public void getDocumentWrongKey() { + db.collection(COLLECTION_NAME).getDocument("no/no", BaseDocument.class); + } + + @Test + public void getDocuments() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("3")); + db.collection(COLLECTION_NAME).insertDocuments(values).get(); + final MultiDocumentEntity documents = db.collection(COLLECTION_NAME) + .getDocuments(Arrays.asList("1", "2", "3"), BaseDocument.class).get(); + assertThat(documents, is(notNullValue())); + assertThat(documents.getDocuments().size(), is(3)); + for (final BaseDocument document : documents.getDocuments()) { + assertThat(document.getId(), + isOneOf(COLLECTION_NAME + "/" + "1", COLLECTION_NAME + "/" + "2", COLLECTION_NAME + "/" + "3")); + } + } + + @Test + public void getDocumentsNotFound() throws InterruptedException, ExecutionException { + final MultiDocumentEntity readResult = db.collection(COLLECTION_NAME) + .getDocuments(Collections.singleton("no"), BaseDocument.class).get(); + assertThat(readResult, is(notNullValue())); + assertThat(readResult.getDocuments().size(), is(0)); + assertThat(readResult.getErrors().size(), is(1)); + } + + @Test + public void getDocumentsWrongKey() throws InterruptedException, ExecutionException { + final MultiDocumentEntity readResult = db.collection(COLLECTION_NAME) + .getDocuments(Collections.singleton("no/no"), BaseDocument.class).get(); + assertThat(readResult, is(notNullValue())); + assertThat(readResult.getDocuments().size(), is(0)); + assertThat(readResult.getErrors().size(), is(1)); + } + + @Test + public void updateDocument() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + + final CompletableFuture> f = db.collection(COLLECTION_NAME) + .updateDocument(createResult.getKey(), doc, null); + f.whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getNew(), is(nullValue())); + assertThat(updateResult.getOld(), is(nullValue())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + }).get(); + final DocumentUpdateEntity updateResult = f.get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("a")), is("test1")); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + assertThat(readResult.getRevision(), is(updateResult.getRev())); + assertThat(readResult.getProperties().keySet(), hasItem("c")); + } + + @Test + public void updateDocumentIfMatch() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + final DocumentUpdateOptions options = new DocumentUpdateOptions().ifMatch(createResult.getRev()); + final CompletableFuture> f = db.collection(COLLECTION_NAME) + .updateDocument(createResult.getKey(), doc, options); + assertThat(f, is(notNullValue())); + f.whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + }).get(); + final DocumentUpdateEntity updateResult = f.get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("a")), is("test1")); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + assertThat(readResult.getRevision(), is(updateResult.getRev())); + assertThat(readResult.getProperties().keySet(), hasItem("c")); + } + + @Test + public void updateDocumentIfMatchFail() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + try { + final DocumentUpdateOptions options = new DocumentUpdateOptions().ifMatch("no"); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void updateDocumentReturnNew() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + final DocumentUpdateOptions options = new DocumentUpdateOptions().returnNew(true); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + assertThat(updateResult.getNew(), is(notNullValue())); + assertThat(updateResult.getNew().getKey(), is(createResult.getKey())); + assertThat(updateResult.getNew().getRevision(), is(not(createResult.getRev()))); + assertThat(updateResult.getNew().getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(updateResult.getNew().getAttribute("a")), is("test1")); + assertThat(updateResult.getNew().getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(updateResult.getNew().getAttribute("b")), is("test")); + }) + .get(); + } + + @Test + public void updateDocumentReturnOld() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + final DocumentUpdateOptions options = new DocumentUpdateOptions().returnOld(true); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + assertThat(updateResult.getOld(), is(notNullValue())); + assertThat(updateResult.getOld().getKey(), is(createResult.getKey())); + assertThat(updateResult.getOld().getRevision(), is(createResult.getRev())); + assertThat(updateResult.getOld().getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(updateResult.getOld().getAttribute("a")), is("test")); + assertThat(updateResult.getOld().getProperties().keySet(), not(hasItem("b"))); + }) + .get(); + } + + @Test + public void updateDocumentKeepNullTrue() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", null); + final DocumentUpdateOptions options = new DocumentUpdateOptions().keepNull(true); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + }) + .get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getProperties().keySet(), hasItem("a")); + } + + @Test + public void updateDocumentKeepNullFalse() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", null); + final DocumentUpdateOptions options = new DocumentUpdateOptions().keepNull(false); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + }) + .get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getId(), is(createResult.getId())); + assertThat(readResult.getRevision(), is(notNullValue())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + } + + @SuppressWarnings("unchecked") + @Test + public void updateDocumentMergeObjectsTrue() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final Map a = new HashMap<>(); + a.put("a", "test"); + doc.addAttribute("a", a); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + a.clear(); + a.put("b", "test"); + doc.updateAttribute("a", a); + final DocumentUpdateOptions options = new DocumentUpdateOptions().mergeObjects(true); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + }) + .get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + final Object aResult = readResult.getAttribute("a"); + assertThat(aResult, instanceOf(Map.class)); + final Map aMap = (Map) aResult; + assertThat(aMap.keySet(), hasItem("a")); + assertThat(aMap.keySet(), hasItem("b")); + } + + @SuppressWarnings("unchecked") + @Test + public void updateDocumentMergeObjectsFalse() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final Map a = new HashMap<>(); + a.put("a", "test"); + doc.addAttribute("a", a); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + a.clear(); + a.put("b", "test"); + doc.updateAttribute("a", a); + final DocumentUpdateOptions options = new DocumentUpdateOptions().mergeObjects(false); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + }) + .get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + final Object aResult = readResult.getAttribute("a"); + assertThat(aResult, instanceOf(Map.class)); + final Map aMap = (Map) aResult; + assertThat(aMap.keySet(), not(hasItem("a"))); + assertThat(aMap.keySet(), hasItem("b")); + } + + @Test + public void updateDocumentIgnoreRevsFalse() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.setRevision("no"); + try { + final DocumentUpdateOptions options = new DocumentUpdateOptions().ignoreRevs(false); + db.collection(COLLECTION_NAME).updateDocument(createResult.getKey(), doc, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void replaceDocument() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final CompletableFuture> f = db.collection(COLLECTION_NAME) + .replaceDocument(createResult.getKey(), doc, null); + f.whenComplete((replaceResult, ex) -> { + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getNew(), is(nullValue())); + assertThat(replaceResult.getOld(), is(nullValue())); + assertThat(replaceResult.getRev(), is(not(replaceResult.getOldRev()))); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + }).get(); + final DocumentUpdateEntity replaceResult = f.get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getRevision(), is(replaceResult.getRev())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + } + + @Test + public void replaceDocumentIfMatch() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final DocumentReplaceOptions options = new DocumentReplaceOptions().ifMatch(createResult.getRev()); + final CompletableFuture> f = db.collection(COLLECTION_NAME) + .replaceDocument(createResult.getKey(), doc, options); + f.whenComplete((replaceResult, ex) -> { + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getRev(), is(not(replaceResult.getOldRev()))); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + }).get(); + final DocumentUpdateEntity replaceResult = f.get(); + + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getRevision(), is(replaceResult.getRev())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + } + + @Test + public void replaceDocumentIfMatchFail() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + try { + final DocumentReplaceOptions options = new DocumentReplaceOptions().ifMatch("no"); + db.collection(COLLECTION_NAME).replaceDocument(createResult.getKey(), doc, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void replaceDocumentIgnoreRevsFalse() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + doc.setRevision("no"); + try { + final DocumentReplaceOptions options = new DocumentReplaceOptions().ignoreRevs(false); + db.collection(COLLECTION_NAME).replaceDocument(createResult.getKey(), doc, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void replaceDocumentReturnNew() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final DocumentReplaceOptions options = new DocumentReplaceOptions().returnNew(true); + db.collection(COLLECTION_NAME).replaceDocument(createResult.getKey(), doc, options) + .whenComplete((replaceResult, ex) -> { + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + assertThat(replaceResult.getNew(), is(notNullValue())); + assertThat(replaceResult.getNew().getKey(), is(createResult.getKey())); + assertThat(replaceResult.getNew().getRevision(), is(not(createResult.getRev()))); + assertThat(replaceResult.getNew().getProperties().keySet(), not(hasItem("a"))); + assertThat(replaceResult.getNew().getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(replaceResult.getNew().getAttribute("b")), is("test")); + }) + .get(); + } + + @Test + public void replaceDocumentReturnOld() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final DocumentReplaceOptions options = new DocumentReplaceOptions().returnOld(true); + db.collection(COLLECTION_NAME).replaceDocument(createResult.getKey(), doc, options) + .whenComplete((replaceResult, ex) -> { + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + assertThat(replaceResult.getOld(), is(notNullValue())); + assertThat(replaceResult.getOld().getKey(), is(createResult.getKey())); + assertThat(replaceResult.getOld().getRevision(), is(createResult.getRev())); + assertThat(replaceResult.getOld().getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(replaceResult.getOld().getAttribute("a")), is("test")); + assertThat(replaceResult.getOld().getProperties().keySet(), not(hasItem("b"))); + }) + .get(); + } + + @Test + public void deleteDocument() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + db.collection(COLLECTION_NAME).deleteDocument(createResult.getKey(), null, null).get(); + db.collection(COLLECTION_NAME).getDocument(createResult.getKey(), BaseDocument.class, null) + .whenComplete((document, ex) -> assertThat(document, is(nullValue()))) + .get(); + } + + @Test + public void deleteDocumentReturnOld() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + final DocumentDeleteOptions options = new DocumentDeleteOptions().returnOld(true); + db.collection(COLLECTION_NAME).deleteDocument(createResult.getKey(), BaseDocument.class, options) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult.getOld(), is(notNullValue())); + assertThat(deleteResult.getOld(), instanceOf(BaseDocument.class)); + assertThat(deleteResult.getOld().getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(deleteResult.getOld().getAttribute("a")), is("test")); + }) + .get(); + } + + @Test + public void deleteDocumentIfMatch() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + final DocumentDeleteOptions options = new DocumentDeleteOptions().ifMatch(createResult.getRev()); + db.collection(COLLECTION_NAME).deleteDocument(createResult.getKey(), null, options).get(); + db.collection(COLLECTION_NAME).getDocument(createResult.getKey(), BaseDocument.class, null) + .whenComplete((document, ex) -> assertThat(document, is(nullValue()))) + .get(); + } + + @Test + public void deleteDocumentIfMatchFail() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME).insertDocument(doc, null) + .get(); + final DocumentDeleteOptions options = new DocumentDeleteOptions().ifMatch("no"); + try { + db.collection(COLLECTION_NAME).deleteDocument(createResult.getKey(), null, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getIndex() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("a"); + final IndexEntity createResult = db.collection(COLLECTION_NAME).ensureHashIndex(fields, null).get(); + db.collection(COLLECTION_NAME).getIndex(createResult.getId()) + .whenComplete((readResult, ex) -> { + assertThat(readResult.getId(), is(createResult.getId())); + assertThat(readResult.getType(), is(createResult.getType())); + }) + .get(); + } + + @Test + public void getIndexByKey() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("a"); + final IndexEntity createResult = db.collection(COLLECTION_NAME).ensureHashIndex(fields, null).get(); + db.collection(COLLECTION_NAME).getIndex(createResult.getId().split("/")[1]) + .whenComplete((readResult, ex) -> { + assertThat(readResult.getId(), is(createResult.getId())); + assertThat(readResult.getType(), is(createResult.getType())); + }) + .get(); + } + + @Test + public void deleteIndex() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("deleteIndexField"); + final IndexEntity createResult = db.collection(COLLECTION_NAME).ensureHashIndex(fields, null).get(); + db.getIndex(createResult.getId()).get(); + db.collection(COLLECTION_NAME).deleteIndex(createResult.getId()) + .whenComplete((id, ex) -> { + assertThat(id, is(createResult.getId())); + try { + db.getIndex(id).get(); + fail(); + } catch (final InterruptedException exception) { + exception.printStackTrace(); + fail(); + } catch (final ExecutionException exception) { + assertThat(exception.getCause(), instanceOf(ArangoDBException.class)); + } + }) + .get(); + } + + @Test + public void deleteIndexByKey() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("deleteIndexByKeyField"); + final IndexEntity createResult = db.collection(COLLECTION_NAME).ensureHashIndex(fields, null).get(); + db.getIndex(createResult.getId()).get(); + db.collection(COLLECTION_NAME).deleteIndex(createResult.getId().split("/")[1]) + .whenComplete((id, ex) -> { + assertThat(id, is(createResult.getId())); + try { + db.getIndex(id).get(); + fail(); + } catch (final InterruptedException exception) { + exception.printStackTrace(); + fail(); + } catch (final ExecutionException exception) { + assertThat(exception.getCause(), instanceOf(ArangoDBException.class)); + } + }) + .get(); + } + + @Test + public void createHashIndex() throws InterruptedException, ExecutionException { + final boolean singleServer = isSingleServer(); + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + db.collection(COLLECTION_NAME).ensureHashIndex(fields, null) + .whenComplete((indexResult, ex) -> { + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getGeoJson(), is(nullValue())); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + if (singleServer) { + assertThat(indexResult.getSelectivityEstimate(), is(1.0)); + } + assertThat(indexResult.getSparse(), is(false)); + assertThat(indexResult.getType(), is(IndexType.hash)); + assertThat(indexResult.getUnique(), is(false)); + }) + .get(); + } + + @Test + public void createHashIndexWithOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final HashIndexOptions options = new HashIndexOptions(); + options.name("myHashIndex"); + + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureHashIndex(fields, options).get(); + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + if (isSingleServer()) { + assertThat(indexResult.getSelectivityEstimate(), is(1.)); + } + assertThat(indexResult.getSparse(), is(false)); + assertThat(indexResult.getType(), is(IndexType.hash)); + assertThat(indexResult.getUnique(), is(false)); + assertThat(indexResult.getName(), is("myHashIndex")); + } + + @Test + public void createGeoIndex() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("a"); + db.collection(COLLECTION_NAME).ensureGeoIndex(fields, null) + .whenComplete((indexResult, ex) -> { + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getGeoJson(), is(false)); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSelectivityEstimate(), is(nullValue())); + assertThat(indexResult.getSparse(), is(true)); + assertThat(indexResult.getType(), anyOf(is(IndexType.geo), is(IndexType.geo1))); + assertThat(indexResult.getUnique(), is(false)); + }) + .get(); + } + + @Test + public void createGeoIndexWithOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final GeoIndexOptions options = new GeoIndexOptions(); + options.name("myGeoIndex1"); + + final Collection fields = new ArrayList<>(); + fields.add("a"); + final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureGeoIndex(fields, options).get(); + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSparse(), is(true)); + assertThat(indexResult.getUnique(), is(false)); + if (isAtLeastVersion(3, 4)) { + assertThat(indexResult.getType(), is(IndexType.geo)); + } else { + assertThat(indexResult.getType(), is(IndexType.geo1)); + } + assertThat(indexResult.getName(), is("myGeoIndex1")); + } + + @Test + public void createGeo2Index() throws ExecutionException, InterruptedException { + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + db.collection(COLLECTION_NAME).ensureGeoIndex(fields, null).whenComplete((indexResult, ex) -> { + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSparse(), is(true)); + assertThat(indexResult.getUnique(), is(false)); + try { + if (isAtLeastVersion(3, 4)) { + assertThat(indexResult.getType(), is(IndexType.geo)); + } else { + assertThat(indexResult.getType(), is(IndexType.geo2)); + } + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + }).get(); + } + + @Test + public void createGeo2IndexWithOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final GeoIndexOptions options = new GeoIndexOptions(); + options.name("myGeoIndex2"); + + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureGeoIndex(fields, options).get(); + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSparse(), is(true)); + assertThat(indexResult.getUnique(), is(false)); + if (isAtLeastVersion(3, 4)) { + assertThat(indexResult.getType(), is(IndexType.geo)); + } else { + assertThat(indexResult.getType(), is(IndexType.geo2)); + } + assertThat(indexResult.getName(), is("myGeoIndex2")); + } + + @Test + public void createSkiplistIndex() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + db.collection(COLLECTION_NAME).ensureSkiplistIndex(fields, null) + .whenComplete((indexResult, ex) -> { + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getGeoJson(), is(nullValue())); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSparse(), is(false)); + assertThat(indexResult.getType(), is(IndexType.skiplist)); + assertThat(indexResult.getUnique(), is(false)); + }) + .get(); + } + + @Test + public void createSkiplistIndexWithOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final SkiplistIndexOptions options = new SkiplistIndexOptions(); + options.name("mySkiplistIndex"); + + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureSkiplistIndex(fields, options).get(); + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSparse(), is(false)); + assertThat(indexResult.getType(), is(IndexType.skiplist)); + assertThat(indexResult.getUnique(), is(false)); + assertThat(indexResult.getName(), is("mySkiplistIndex")); + } + + @Test + public void createPersistentIndex() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + db.collection(COLLECTION_NAME).ensurePersistentIndex(fields, null) + .whenComplete((indexResult, ex) -> { + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getGeoJson(), is(nullValue())); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSparse(), is(false)); + assertThat(indexResult.getType(), is(IndexType.persistent)); + assertThat(indexResult.getUnique(), is(false)); + }) + .get(); + } + + @Test + public void createPersistentIndexWithOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final PersistentIndexOptions options = new PersistentIndexOptions(); + options.name("myPersistentIndex"); + + final Collection fields = new ArrayList<>(); + fields.add("a"); + fields.add("b"); + final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensurePersistentIndex(fields, options).get(); + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getFields(), hasItem("b")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getMinLength(), is(nullValue())); + assertThat(indexResult.getSparse(), is(false)); + assertThat(indexResult.getType(), is(IndexType.persistent)); + assertThat(indexResult.getUnique(), is(false)); + assertThat(indexResult.getName(), is("myPersistentIndex")); + } + + @Test + public void createFulltextIndex() throws InterruptedException, ExecutionException { + final Collection fields = new ArrayList<>(); + fields.add("a"); + db.collection(COLLECTION_NAME).ensureFulltextIndex(fields, null) + .whenComplete((indexResult, ex) -> { + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getGeoJson(), is(nullValue())); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getSelectivityEstimate(), is(nullValue())); + assertThat(indexResult.getSparse(), is(true)); + assertThat(indexResult.getType(), is(IndexType.fulltext)); + assertThat(indexResult.getUnique(), is(false)); + }) + .get(); + } + + @Test + public void createFulltextIndexWithOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final FulltextIndexOptions options = new FulltextIndexOptions(); + options.name("myFulltextIndex"); + + final Collection fields = new ArrayList<>(); + fields.add("a"); + final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureFulltextIndex(fields, options).get(); + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getConstraint(), is(nullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getSparse(), is(true)); + assertThat(indexResult.getType(), is(IndexType.fulltext)); + assertThat(indexResult.getUnique(), is(false)); + assertThat(indexResult.getName(), is("myFulltextIndex")); + } + + @Test + public void createTtlIndexWithoutOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final Collection fields = new ArrayList<>(); + fields.add("a"); + try { + db.collection(COLLECTION_NAME).ensureTtlIndex(fields, null).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + assertThat(e.getCause().getMessage(), containsString("expireAfter attribute must be a number")); + assertThat(((ArangoDBException) e.getCause()).getResponseCode(), is(400)); + assertThat(((ArangoDBException) e.getCause()).getErrorNum(), is(10)); + } + } + + @Test + public void createTtlIndexWithOptions() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final Collection fields = new ArrayList<>(); + fields.add("a"); + + final TtlIndexOptions options = new TtlIndexOptions(); + options.name("myTtlIndex"); + options.expireAfter(3600); + + final IndexEntity indexResult = db.collection(COLLECTION_NAME).ensureTtlIndex(fields, options).get(); + assertThat(indexResult, is(notNullValue())); + assertThat(indexResult.getFields(), hasItem("a")); + assertThat(indexResult.getId(), startsWith(COLLECTION_NAME)); + assertThat(indexResult.getIsNewlyCreated(), is(true)); + assertThat(indexResult.getType(), is(IndexType.ttl)); + assertThat(indexResult.getExpireAfter(), is(3600)); + assertThat(indexResult.getName(), is("myTtlIndex")); + } + + @Test + public void getIndexes() throws InterruptedException, ExecutionException { + final int initialIndexCount = db.collection(COLLECTION_NAME).getIndexes().get().size(); + final Collection fields = new ArrayList<>(); + fields.add("a"); + db.collection(COLLECTION_NAME).ensureHashIndex(fields, null).get(); + db.collection(COLLECTION_NAME).getIndexes() + .whenComplete((indexes, ex) -> { + assertThat(indexes, is(notNullValue())); + assertThat(indexes.size(), is(initialIndexCount + 1)); + for (final IndexEntity i : indexes) { + if (i.getType() == IndexType.hash) { + assertThat(i.getFields().size(), is(1)); + assertThat(i.getFields(), hasItem("a")); + } + } + }) + .get(); + } + + @Test + public void exists() throws InterruptedException, ExecutionException { + assertThat(db.collection(COLLECTION_NAME).exists().get(), is(true)); + assertThat(db.collection(COLLECTION_NAME + "no").exists().get(), is(false)); + } + + @Test + public void truncate() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + db.collection(COLLECTION_NAME).insertDocument(doc, null).get(); + final BaseDocument readResult = db.collection(COLLECTION_NAME) + .getDocument(doc.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(doc.getKey())); + db.collection(COLLECTION_NAME).truncate() + .whenComplete((truncateResult, ex) -> { + assertThat(truncateResult, is(notNullValue())); + assertThat(truncateResult.getId(), is(notNullValue())); + }) + .get(); + final BaseDocument document = db.collection(COLLECTION_NAME).getDocument(doc.getKey(), BaseDocument.class, null) + .get(); + assertThat(document, is(nullValue())); + } + + @Test + public void getCount() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).count() + .whenComplete((countEmpty, ex) -> { + assertThat(countEmpty, is(notNullValue())); + assertThat(countEmpty.getCount(), is(0L)); + }) + .get(); + + db.collection(COLLECTION_NAME).insertDocument("{}", null).get(); + + db.collection(COLLECTION_NAME).count() + .whenComplete((count, ex) -> assertThat(count.getCount(), is(1L))) + .get(); + } + + @Test + public void documentExists() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).documentExists("no", null) + .whenComplete((existsNot, ex) -> assertThat(existsNot, is(false))) + .get(); + + db.collection(COLLECTION_NAME).insertDocument("{\"_key\":\"abc\"}", null).get(); + + db.collection(COLLECTION_NAME).documentExists("abc", null) + .whenComplete((exists, ex) -> assertThat(exists, is(true))) + .get(); + } + + @Test + public void documentExistsIfMatch() throws InterruptedException, ExecutionException { + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME) + .insertDocument("{\"_key\":\"abc\"}", null).get(); + final DocumentExistsOptions options = new DocumentExistsOptions().ifMatch(createResult.getRev()); + db.collection(COLLECTION_NAME).documentExists("abc", options) + .whenComplete((exists, ex) -> assertThat(exists, is(true))) + .get(); + } + + @Test + public void documentExistsIfMatchFail() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).insertDocument("{\"_key\":\"abc\"}", null).get(); + final DocumentExistsOptions options = new DocumentExistsOptions().ifMatch("no"); + db.collection(COLLECTION_NAME).documentExists("abc", options) + .whenComplete((exists, ex) -> assertThat(exists, is(false))) + .get(); + } + + @Test + public void documentExistsIfNoneMatch() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).insertDocument("{\"_key\":\"abc\"}", null).get(); + final DocumentExistsOptions options = new DocumentExistsOptions().ifNoneMatch("no"); + db.collection(COLLECTION_NAME).documentExists("abc", options) + .whenComplete((exists, ex) -> assertThat(exists, is(true))) + .get(); + } + + @Test + public void documentExistsIfNoneMatchFail() throws InterruptedException, ExecutionException { + final DocumentCreateEntity createResult = db.collection(COLLECTION_NAME) + .insertDocument("{\"_key\":\"abc\"}", null).get(); + final DocumentExistsOptions options = new DocumentExistsOptions().ifNoneMatch(createResult.getRev()); + db.collection(COLLECTION_NAME).documentExists("abc", options) + .whenComplete((exists, ex) -> assertThat(exists, is(false))) + .get(); + } + + @Test + public void insertDocuments() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + db.collection(COLLECTION_NAME).insertDocuments(values, null) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getDocuments(), is(notNullValue())); + assertThat(docs.getDocuments().size(), is(3)); + assertThat(docs.getErrors(), is(notNullValue())); + assertThat(docs.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void insertDocumentsOne() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument()); + db.collection(COLLECTION_NAME).insertDocuments(values, null) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getDocuments(), is(notNullValue())); + assertThat(docs.getDocuments().size(), is(1)); + assertThat(docs.getErrors(), is(notNullValue())); + assertThat(docs.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void insertDocumentsEmpty() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + db.collection(COLLECTION_NAME).insertDocuments(values, null) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getDocuments(), is(notNullValue())); + assertThat(docs.getDocuments().size(), is(0)); + assertThat(docs.getErrors(), is(notNullValue())); + assertThat(docs.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void insertDocumentsReturnNew() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + final DocumentCreateOptions options = new DocumentCreateOptions().returnNew(true); + db.collection(COLLECTION_NAME).insertDocuments(values, options) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getDocuments(), is(notNullValue())); + assertThat(docs.getDocuments().size(), is(3)); + assertThat(docs.getErrors(), is(notNullValue())); + assertThat(docs.getErrors().size(), is(0)); + for (final DocumentCreateEntity doc : docs.getDocuments()) { + assertThat(doc.getNew(), is(notNullValue())); + final BaseDocument baseDocument = doc.getNew(); + assertThat(baseDocument.getKey(), is(notNullValue())); + } + }) + .get(); + } + + @Test + public void insertDocumentsFail() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + db.collection(COLLECTION_NAME).insertDocuments(values) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getDocuments(), is(notNullValue())); + assertThat(docs.getDocuments().size(), is(2)); + assertThat(docs.getErrors(), is(notNullValue())); + assertThat(docs.getErrors().size(), is(1)); + assertThat(docs.getErrors().iterator().next().getErrorNum(), is(1210)); + }) + .get(); + } + + @Test + public void importDocuments() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + db.collection(COLLECTION_NAME).importDocuments(values) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(values.size())); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsDuplicateDefaultError() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + db.collection(COLLECTION_NAME).importDocuments(values) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(1)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsDuplicateError() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.error)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(1)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsDuplicateIgnore() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.ignore)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(1)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsDuplicateReplace() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.replace)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(1)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsDuplicateUpdate() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.update)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(1)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsCompleteFail() throws InterruptedException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + try { + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().complete(true)).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + assertThat(((ArangoDBException) e.getCause()).getErrorNum(), is(1210)); + } + } + + @Test + public void importDocumentsDetails() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + values.add(new BaseDocument("2")); + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().details(true)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(1)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails().size(), is(1)); + assertThat(docs.getDetails().iterator().next(), containsString("unique constraint violated")); + }) + .get(); + } + + @Test + public void importDocumentsOverwriteFalse() throws InterruptedException, ExecutionException { + final ArangoCollectionAsync collection = db.collection(COLLECTION_NAME); + collection.insertDocument(new BaseDocument()).get(); + assertThat(collection.count().get().getCount(), is(1L)); + + final Collection values = new ArrayList<>(); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + collection.importDocuments(values, new DocumentImportOptions().overwrite(false)).get(); + assertThat(collection.count().get().getCount(), is(3L)); + } + + @Test + public void importDocumentsOverwriteTrue() throws InterruptedException, ExecutionException { + final ArangoCollectionAsync collection = db.collection(COLLECTION_NAME); + collection.insertDocument(new BaseDocument()).get(); + assertThat(collection.count().get().getCount(), is(1L)); + + final Collection values = new ArrayList<>(); + values.add(new BaseDocument()); + values.add(new BaseDocument()); + collection.importDocuments(values, new DocumentImportOptions().overwrite(true)).get(); + assertThat(collection.count().get().getCount(), is(2L)); + } + + @Test + public void importDocumentsFromToPrefix() throws InterruptedException, ExecutionException { + db.createCollection(COLLECTION_NAME + "_edge", new CollectionCreateOptions().type(CollectionType.EDGES)).get(); + final ArangoCollectionAsync collection = db.collection(COLLECTION_NAME + "_edge"); + try { + final Collection values = new ArrayList<>(); + final String[] keys = {"1", "2"}; + for (String s : keys) { + values.add(new BaseEdgeDocument(s, "from", "to")); + } + assertThat(values.size(), is(keys.length)); + + final DocumentImportEntity importResult = collection + .importDocuments(values, new DocumentImportOptions().fromPrefix("foo").toPrefix("bar")).get(); + assertThat(importResult, is(notNullValue())); + assertThat(importResult.getCreated(), is(values.size())); + for (String key : keys) { + BaseEdgeDocument doc; + doc = collection.getDocument(key, BaseEdgeDocument.class).get(); + assertThat(doc, is(notNullValue())); + assertThat(doc.getFrom(), is("foo/from")); + assertThat(doc.getTo(), is("bar/to")); + } + } finally { + collection.drop().get(); + } + } + + @Test + public void importDocumentsJson() throws InterruptedException, ExecutionException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"}]"; + db.collection(COLLECTION_NAME).importDocuments(values) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsJsonDuplicateDefaultError() throws InterruptedException, ExecutionException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"},{\"_key\":\"2\"}]"; + db.collection(COLLECTION_NAME).importDocuments(values) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(1)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsJsonDuplicateError() throws InterruptedException, ExecutionException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"},{\"_key\":\"2\"}]"; + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.error)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(1)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsJsonDuplicateIgnore() throws InterruptedException, ExecutionException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"},{\"_key\":\"2\"}]"; + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.ignore)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(1)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsJsonDuplicateReplace() throws InterruptedException, ExecutionException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"},{\"_key\":\"2\"}]"; + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.replace)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(1)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsJsonDuplicateUpdate() throws InterruptedException, ExecutionException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"},{\"_key\":\"2\"}]"; + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().onDuplicate(OnDuplicate.update)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(0)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(1)); + assertThat(docs.getDetails(), is(empty())); + }) + .get(); + } + + @Test + public void importDocumentsJsonCompleteFail() throws InterruptedException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"},{\"_key\":\"2\"}]"; + try { + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().complete(true)).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + assertThat(((ArangoDBException) e.getCause()).getErrorNum(), is(1210)); + } + } + + @Test + public void importDocumentsJsonDetails() throws InterruptedException, ExecutionException { + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"},{\"_key\":\"2\"}]"; + db.collection(COLLECTION_NAME).importDocuments(values, new DocumentImportOptions().details(true)) + .whenComplete((docs, ex) -> { + assertThat(docs, is(notNullValue())); + assertThat(docs.getCreated(), is(2)); + assertThat(docs.getEmpty(), is(0)); + assertThat(docs.getErrors(), is(1)); + assertThat(docs.getIgnored(), is(0)); + assertThat(docs.getUpdated(), is(0)); + assertThat(docs.getDetails().size(), is(1)); + assertThat(docs.getDetails().iterator().next(), containsString("unique constraint violated")); + }) + .get(); + } + + @Test + public void importDocumentsJsonOverwriteFalse() throws InterruptedException, ExecutionException { + final ArangoCollectionAsync collection = db.collection(COLLECTION_NAME); + collection.insertDocument(new BaseDocument()).get(); + assertThat(collection.count().get().getCount(), is(1L)); + + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"}]"; + collection.importDocuments(values, new DocumentImportOptions().overwrite(false)).get(); + assertThat(collection.count().get().getCount(), is(3L)); + } + + @Test + public void importDocumentsJsonOverwriteTrue() throws InterruptedException, ExecutionException { + final ArangoCollectionAsync collection = db.collection(COLLECTION_NAME); + collection.insertDocument(new BaseDocument()).get(); + assertThat(collection.count().get().getCount(), is(1L)); + + final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"}]"; + collection.importDocuments(values, new DocumentImportOptions().overwrite(true)).get(); + assertThat(collection.count().get().getCount(), is(2L)); + } + + @Test + public void importDocumentsJsonFromToPrefix() throws InterruptedException, ExecutionException { + db.createCollection(COLLECTION_NAME + "_edge", new CollectionCreateOptions().type(CollectionType.EDGES)).get(); + final ArangoCollectionAsync collection = db.collection(COLLECTION_NAME + "_edge"); + try { + final String[] keys = {"1", "2"}; + final String values = "[{\"_key\":\"1\",\"_from\":\"from\",\"_to\":\"to\"},{\"_key\":\"2\",\"_from\":\"from\",\"_to\":\"to\"}]"; + + final DocumentImportEntity importResult = collection + .importDocuments(values, new DocumentImportOptions().fromPrefix("foo").toPrefix("bar")).get(); + assertThat(importResult, is(notNullValue())); + assertThat(importResult.getCreated(), is(2)); + for (String key : keys) { + BaseEdgeDocument doc; + doc = collection.getDocument(key, BaseEdgeDocument.class).get(); + assertThat(doc, is(notNullValue())); + assertThat(doc.getFrom(), is("foo/from")); + assertThat(doc.getTo(), is("bar/to")); + } + } finally { + collection.drop().get(); + } + } + + @Test + public void deleteDocumentsByKey() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + { + final BaseDocument e = new BaseDocument(); + e.setKey("2"); + values.add(e); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection keys = new ArrayList<>(); + keys.add("1"); + keys.add("2"); + db.collection(COLLECTION_NAME).deleteDocuments(keys, null, null) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult, is(notNullValue())); + assertThat(deleteResult.getDocuments().size(), is(2)); + for (final DocumentDeleteEntity i : deleteResult.getDocuments()) { + assertThat(i.getKey(), anyOf(is("1"), is("2"))); + } + assertThat(deleteResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void deleteDocumentsByDocuments() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + { + final BaseDocument e = new BaseDocument(); + e.setKey("2"); + values.add(e); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + db.collection(COLLECTION_NAME).deleteDocuments(values, null, null) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult, is(notNullValue())); + assertThat(deleteResult.getDocuments().size(), is(2)); + for (final DocumentDeleteEntity i : deleteResult.getDocuments()) { + assertThat(i.getKey(), anyOf(is("1"), is("2"))); + } + assertThat(deleteResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void deleteDocumentsByKeyOne() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection keys = new ArrayList<>(); + keys.add("1"); + db.collection(COLLECTION_NAME).deleteDocuments(keys, null, null) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult, is(notNullValue())); + assertThat(deleteResult.getDocuments().size(), is(1)); + for (final DocumentDeleteEntity i : deleteResult.getDocuments()) { + assertThat(i.getKey(), is("1")); + } + assertThat(deleteResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void deleteDocumentsByDocumentOne() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + db.collection(COLLECTION_NAME).deleteDocuments(values, null, null) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult, is(notNullValue())); + assertThat(deleteResult.getDocuments().size(), is(1)); + for (final DocumentDeleteEntity i : deleteResult.getDocuments()) { + assertThat(i.getKey(), is("1")); + } + assertThat(deleteResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void deleteDocumentsEmpty() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection keys = new ArrayList<>(); + db.collection(COLLECTION_NAME).deleteDocuments(keys, null, null) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult, is(notNullValue())); + assertThat(deleteResult.getDocuments().size(), is(0)); + assertThat(deleteResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void deleteDocumentsByKeyNotExisting() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection keys = new ArrayList<>(); + keys.add("1"); + keys.add("2"); + db.collection(COLLECTION_NAME).deleteDocuments(keys, null, null) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult, is(notNullValue())); + assertThat(deleteResult.getDocuments().size(), is(0)); + assertThat(deleteResult.getErrors().size(), is(2)); + }) + .get(); + } + + @Test + public void deleteDocumentsByDocumentsNotExisting() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + { + final BaseDocument e = new BaseDocument(); + e.setKey("2"); + values.add(e); + } + db.collection(COLLECTION_NAME).deleteDocuments(values, null, null) + .whenComplete((deleteResult, ex) -> { + assertThat(deleteResult, is(notNullValue())); + assertThat(deleteResult.getDocuments().size(), is(0)); + assertThat(deleteResult.getErrors().size(), is(2)); + }) + .get(); + } + + @Test + public void updateDocuments() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + { + final BaseDocument e = new BaseDocument(); + e.setKey("2"); + values.add(e); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection updatedValues = new ArrayList<>(); + for (final BaseDocument i : values) { + i.addAttribute("a", "test"); + updatedValues.add(i); + } + db.collection(COLLECTION_NAME).updateDocuments(updatedValues, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(2)); + assertThat(updateResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void updateDocumentsOne() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection updatedValues = new ArrayList<>(); + final BaseDocument first = values.iterator().next(); + first.addAttribute("a", "test"); + updatedValues.add(first); + db.collection(COLLECTION_NAME).updateDocuments(updatedValues, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(1)); + assertThat(updateResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void updateDocumentsEmpty() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + db.collection(COLLECTION_NAME).updateDocuments(values, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(0)); + assertThat(updateResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void updateDocumentsWithoutKey() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + values.add(new BaseDocument("1")); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection updatedValues = new ArrayList<>(); + for (final BaseDocument i : values) { + i.addAttribute("a", "test"); + updatedValues.add(i); + } + updatedValues.add(new BaseDocument()); + db.collection(COLLECTION_NAME).updateDocuments(updatedValues, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(1)); + assertThat(updateResult.getErrors().size(), is(1)); + }) + .get(); + } + + @Test + public void replaceDocuments() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + values.add(new BaseDocument("1")); + values.add(new BaseDocument("2")); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection updatedValues = new ArrayList<>(); + for (final BaseDocument i : values) { + i.addAttribute("a", "test"); + updatedValues.add(i); + } + db.collection(COLLECTION_NAME).replaceDocuments(updatedValues, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(2)); + assertThat(updateResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void replaceDocumentsOne() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + final BaseDocument e = new BaseDocument(); + e.setKey("1"); + values.add(e); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection updatedValues = new ArrayList<>(); + final BaseDocument first = values.iterator().next(); + first.addAttribute("a", "test"); + updatedValues.add(first); + db.collection(COLLECTION_NAME).updateDocuments(updatedValues, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(1)); + assertThat(updateResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void replaceDocumentsEmpty() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + db.collection(COLLECTION_NAME).updateDocuments(values, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(0)); + assertThat(updateResult.getErrors().size(), is(0)); + }) + .get(); + } + + @Test + public void replaceDocumentsWithoutKey() throws InterruptedException, ExecutionException { + final Collection values = new ArrayList<>(); + { + values.add(new BaseDocument("1")); + } + db.collection(COLLECTION_NAME).insertDocuments(values, null).get(); + final Collection updatedValues = new ArrayList<>(); + for (final BaseDocument i : values) { + i.addAttribute("a", "test"); + updatedValues.add(i); + } + updatedValues.add(new BaseDocument()); + db.collection(COLLECTION_NAME).updateDocuments(updatedValues, null) + .whenComplete((updateResult, ex) -> { + assertThat(updateResult.getDocuments().size(), is(1)); + assertThat(updateResult.getErrors().size(), is(1)); + }) + .get(); + } + + @Test + public void load() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).load() + .whenComplete((result, ex) -> assertThat(result.getName(), is(COLLECTION_NAME))) + .get(); + } + + @Test + public void unload() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).unload() + .whenComplete((result, ex) -> assertThat(result.getName(), is(COLLECTION_NAME))) + .get(); + } + + @Test + public void getInfo() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).getInfo() + .whenComplete((result, ex) -> assertThat(result.getName(), is(COLLECTION_NAME))) + .get(); + } + + @Test + public void getPropeties() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).getProperties() + .whenComplete((result, ex) -> { + assertThat(result.getName(), is(COLLECTION_NAME)); + assertThat(result.getCount(), is(nullValue())); + }) + .get(); + } + + @Test + public void changeProperties() throws InterruptedException, ExecutionException { + final String collection = COLLECTION_NAME + "_prop"; + try { + db.createCollection(collection).get(); + final CollectionPropertiesEntity properties = db.collection(collection).getProperties().get(); + assertThat(properties.getWaitForSync(), is(notNullValue())); + final CollectionPropertiesOptions options = new CollectionPropertiesOptions(); + options.waitForSync(!properties.getWaitForSync()); + options.journalSize(2000000L); + db.collection(collection).changeProperties(options) + .whenComplete((changedProperties, ex) -> { + assertThat(changedProperties.getWaitForSync(), is(notNullValue())); + assertThat(changedProperties.getWaitForSync(), is(not(properties.getWaitForSync()))); + }) + .get(); + } finally { + db.collection(collection).drop().get(); + } + } + + @Test + public void rename() throws InterruptedException, ExecutionException { + assumeTrue(isSingleServer()); + db.collection(COLLECTION_NAME).rename(COLLECTION_NAME + "1") + .whenComplete((result, ex) -> { + assertThat(result, is(notNullValue())); + assertThat(result.getName(), is(COLLECTION_NAME + "1")); + }) + .get(); + final CollectionEntity info = db.collection(COLLECTION_NAME + "1").getInfo().get(); + assertThat(info.getName(), is(COLLECTION_NAME + "1")); + try { + db.collection(COLLECTION_NAME).getInfo().get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + db.collection(COLLECTION_NAME + "1").rename(COLLECTION_NAME).get(); + } + + @Test + public void responsibleShard() throws ExecutionException, InterruptedException { + assumeTrue(isCluster()); + assumeTrue(isAtLeastVersion(3, 5)); + ShardEntity shard = db.collection(COLLECTION_NAME).getResponsibleShard(new BaseDocument("testKey")).get(); + assertThat(shard, is(notNullValue())); + assertThat(shard.getShardId(), is(notNullValue())); + } + + @Test + public void getRevision() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).getRevision() + .whenComplete((result, ex) -> { + assertThat(result, is(notNullValue())); + assertThat(result.getName(), is(COLLECTION_NAME)); + assertThat(result.getRevision(), is(notNullValue())); + }) + .get(); + } + + @Test + public void grantAccessRW() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.collection(COLLECTION_NAME).grantAccess("user1", Permissions.RW).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test + public void grantAccessRO() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.collection(COLLECTION_NAME).grantAccess("user1", Permissions.RO).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test + public void grantAccessNONE() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.collection(COLLECTION_NAME).grantAccess("user1", Permissions.NONE).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test(expected = ExecutionException.class) + public void grantAccessUserNotFound() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).grantAccess("user1", Permissions.RW).get(); + } + + @Test + public void revokeAccess() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.collection(COLLECTION_NAME).grantAccess("user1", Permissions.NONE).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test(expected = ExecutionException.class) + public void revokeAccessUserNotFound() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).grantAccess("user1", Permissions.NONE).get(); + } + + @Test + public void resetAccess() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.collection(COLLECTION_NAME).resetAccess("user1").get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test(expected = ExecutionException.class) + public void resetAccessUserNotFound() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).resetAccess("user1").get(); + } + + @Test + public void getPermissions() throws InterruptedException, ExecutionException { + assertThat(Permissions.RW, is(db.collection(COLLECTION_NAME).getPermissions("root").get())); + } +} diff --git a/src/test/java/com/arangodb/async/ArangoDBTest.java b/src/test/java/com/arangodb/async/ArangoDBTest.java new file mode 100644 index 000000000..e7fd42603 --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoDBTest.java @@ -0,0 +1,529 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.*; +import com.arangodb.model.LogOptions; +import com.arangodb.model.LogOptions.SortOrder; +import com.arangodb.model.UserCreateOptions; +import com.arangodb.model.UserUpdateOptions; +import com.arangodb.velocypack.exception.VPackException; +import com.arangodb.velocystream.Request; +import com.arangodb.velocystream.RequestType; +import org.junit.Test; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * @author Mark Vollmary + * @author Michele Rastelli + */ +public class ArangoDBTest { + + private static final String ROOT = "root"; + private static final String USER = "mit dem mund"; + private static final String PW = "machts der hund"; + + @Test + public void getVersion() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getVersion() + .whenComplete((version, ex) -> { + assertThat(version, is(notNullValue())); + assertThat(version.getServer(), is(notNullValue())); + assertThat(version.getVersion(), is(notNullValue())); + }) + .get(); + } + + @Test(timeout = 2000) + public void nestedGetVersion() { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + for (int i = 0; i < 100; i++) { + try { + arangoDB.getVersion() + .whenComplete((v1, ex1) -> { + assertThat(v1, is(notNullValue())); + assertThat(v1.getServer(), is(notNullValue())); + assertThat(v1.getVersion(), is(notNullValue())); + try { + arangoDB.getVersion() + .whenComplete((v2, ex2) -> { + assertThat(v2, is(notNullValue())); + assertThat(v2.getServer(), is(notNullValue())); + assertThat(v2.getVersion(), is(notNullValue())); + try { + arangoDB.getVersion() + .whenComplete((v3, ex3) -> { + assertThat(v3, is(notNullValue())); + assertThat(v3.getServer(), is(notNullValue())); + assertThat(v3.getVersion(), is(notNullValue())); + }) + .get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + fail(); + } + }) + .get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + fail(); + } + }) + .get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + fail(); + } + } + } + + @Test + public void createDatabase() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.createDatabase(BaseTest.TEST_DB) + .whenComplete((result, ex) -> assertThat(result, is(true))) + .get(); + arangoDB.db(BaseTest.TEST_DB).drop().get(); + } + + @Test + public void deleteDatabase() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final Boolean resultCreate = arangoDB.createDatabase(BaseTest.TEST_DB).get(); + assertThat(resultCreate, is(true)); + arangoDB.db(BaseTest.TEST_DB).drop() + .whenComplete((resultDelete, ex) -> assertThat(resultDelete, is(true))) + .get(); + } + + @Test + public void getDatabases() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + Collection dbs = arangoDB.getDatabases().get(); + assertThat(dbs, is(notNullValue())); + assertThat(dbs.size(), is(greaterThan(0))); + final int dbCount = dbs.size(); + assertThat(dbs.iterator().next(), is("_system")); + arangoDB.createDatabase(BaseTest.TEST_DB).get(); + dbs = arangoDB.getDatabases().get(); + assertThat(dbs.size(), is(greaterThan(dbCount))); + assertThat(dbs, hasItem("_system")); + assertThat(dbs, hasItem(BaseTest.TEST_DB)); + } finally { + arangoDB.db(BaseTest.TEST_DB).drop().get(); + } + } + + @Test + public void getAccessibleDatabases() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getAccessibleDatabases() + .whenComplete((dbs, ex) -> { + assertThat(dbs, is(notNullValue())); + assertThat(dbs.size(), greaterThan(0)); + assertThat(dbs, hasItem("_system")); + }) + .get(); + } + + @Test + public void getAccessibleDatabasesFor() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getAccessibleDatabasesFor("root") + .whenComplete((dbs, ex) -> { + assertThat(dbs, is(notNullValue())); + assertThat(dbs, is(notNullValue())); + assertThat(dbs.size(), greaterThan(0)); + assertThat(dbs, hasItem("_system")); + }) + .get(); + } + + @Test + public void createUser() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + arangoDB.createUser(USER, PW, null) + .whenComplete((result, ex) -> { + assertThat(result, is(notNullValue())); + assertThat(result.getUser(), is(USER)); + }) + .get(); + } finally { + arangoDB.deleteUser(USER).get(); + } + } + + @Test + public void deleteUser() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.createUser(USER, PW, null).get(); + arangoDB.deleteUser(USER).get(); + } + + @Test + public void getUserRoot() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getUser(ROOT) + .whenComplete((user, ex) -> { + assertThat(user, is(notNullValue())); + assertThat(user.getUser(), is(ROOT)); + }) + .get(); + } + + @Test + public void getUser() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + arangoDB.createUser(USER, PW, null).get(); + arangoDB.getUser(USER) + .whenComplete((user, ex) -> assertThat(user.getUser(), is(USER))) + .get(); + } finally { + arangoDB.deleteUser(USER).get(); + } + + } + + @Test + public void getUsersOnlyRoot() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getUsers() + .whenComplete((users, ex) -> { + assertThat(users, is(notNullValue())); + assertThat(users.size(), greaterThan(0)); + }) + .get(); + } + + @Test + public void getUsers() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + arangoDB.createUser(USER, PW, null).get(); + arangoDB.getUsers() + .whenComplete((users, ex) -> { + assertThat(users, is(notNullValue())); + assertThat(users.size(), is(2)); + for (final UserEntity user : users) { + assertThat(user.getUser(), anyOf(is(ROOT), is(USER))); + } + }) + .get(); + } finally { + arangoDB.deleteUser(USER).get(); + } + } + + @Test + public void updateUserNoOptions() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + arangoDB.createUser(USER, PW, null).get(); + arangoDB.updateUser(USER, null).get(); + } finally { + arangoDB.deleteUser(USER).get(); + } + } + + @Test + public void updateUser() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + final Map extra = new HashMap<>(); + extra.put("hund", false); + arangoDB.createUser(USER, PW, new UserCreateOptions().extra(extra)).get(); + extra.put("hund", true); + extra.put("mund", true); + { + arangoDB.updateUser(USER, new UserUpdateOptions().extra(extra)) + .whenComplete((user, ex) -> { + assertThat(user, is(notNullValue())); + assertThat(user.getExtra().size(), is(2)); + assertThat(user.getExtra().get("hund"), is(notNullValue())); + assertThat(Boolean.valueOf(String.valueOf(user.getExtra().get("hund"))), is(true)); + }) + .get(); + } + arangoDB.getUser(USER) + .whenComplete((user2, ex) -> { + assertThat(user2.getExtra().size(), is(2)); + assertThat(user2.getExtra().get("hund"), is(notNullValue())); + assertThat(Boolean.valueOf(String.valueOf(user2.getExtra().get("hund"))), is(true)); + }) + .get(); + } finally { + arangoDB.deleteUser(USER).get(); + } + } + + @Test + public void replaceUser() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + final Map extra = new HashMap<>(); + extra.put("hund", false); + arangoDB.createUser(USER, PW, new UserCreateOptions().extra(extra)).get(); + extra.remove("hund"); + extra.put("mund", true); + { + arangoDB.replaceUser(USER, new UserUpdateOptions().extra(extra)) + .whenComplete((user, ex) -> { + assertThat(user, is(notNullValue())); + assertThat(user.getExtra().size(), is(1)); + assertThat(user.getExtra().get("mund"), is(notNullValue())); + assertThat(Boolean.valueOf(String.valueOf(user.getExtra().get("mund"))), is(true)); + }) + .get(); + } + { + arangoDB.getUser(USER) + .whenComplete((user2, ex) -> { + assertThat(user2.getExtra().size(), is(1)); + assertThat(user2.getExtra().get("mund"), is(notNullValue())); + assertThat(Boolean.valueOf(String.valueOf(user2.getExtra().get("mund"))), is(true)); + }) + .get(); + } + } finally { + arangoDB.deleteUser(USER).get(); + } + } + + @Test + public void updateUserDefaultDatabaseAccess() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + arangoDB.createUser(USER, PW).get(); + arangoDB.grantDefaultDatabaseAccess(USER, Permissions.RW).get(); + } finally { + arangoDB.deleteUser(USER).get(); + } + } + + @Test + public void updateUserDefaultCollectionAccess() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + try { + arangoDB.createUser(USER, PW).get(); + arangoDB.grantDefaultCollectionAccess(USER, Permissions.RW).get(); + } finally { + arangoDB.deleteUser(USER).get(); + } + } + + @Test + public void authenticationFailPassword() throws InterruptedException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().password("no").build(); + try { + arangoDB.getVersion().get(); + fail(); + } catch (final ExecutionException exception) { + assertThat(exception.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void authenticationFailUser() throws InterruptedException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().user("no").build(); + try { + arangoDB.getVersion().get(); + fail(); + } catch (final ExecutionException exception) { + assertThat(exception.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void execute() throws VPackException, InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB + .execute(new Request("_system", RequestType.GET, "/_api/version")) + .whenComplete((response, ex) -> { + assertThat(response.getBody(), is(notNullValue())); + assertThat(response.getBody().get("version").isString(), is(true)); + }) + .get(); + } + + @Test + public void getLogs() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getLogs(null) + .whenComplete((logs, ex) -> { + assertThat(logs, is(notNullValue())); + assertThat(logs.getTotalAmount(), greaterThan(0L)); + assertThat((long) logs.getLid().size(), is(logs.getTotalAmount())); + assertThat((long) logs.getLevel().size(), is(logs.getTotalAmount())); + assertThat((long) logs.getTimestamp().size(), is(logs.getTotalAmount())); + assertThat((long) logs.getText().size(), is(logs.getTotalAmount())); + }) + .get(); + } + + @Test + public void getLogsUpto() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final LogEntity logs = arangoDB.getLogs(null).get(); + arangoDB.getLogs(new LogOptions().upto(LogLevel.WARNING)) + .whenComplete((logsUpto, ex) -> { + assertThat(logsUpto, is(notNullValue())); + assertThat(logs.getTotalAmount() >= logsUpto.getTotalAmount(), is(true)); + assertThat(logsUpto.getLevel(), not(contains(LogLevel.INFO))); + }) + .get(); + } + + @Test + public void getLogsLevel() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final LogEntity logs = arangoDB.getLogs(null).get(); + arangoDB.getLogs(new LogOptions().level(LogLevel.INFO)) + .whenComplete((logsInfo, ex) -> { + assertThat(logsInfo, is(notNullValue())); + assertThat(logs.getTotalAmount() >= logsInfo.getTotalAmount(), is(true)); + assertThat(logsInfo.getLevel(), everyItem(is(LogLevel.INFO))); + }) + .get(); + } + + @Test + public void getLogsStart() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final LogEntity logs = arangoDB.getLogs(null).get(); + assertThat(logs.getLid(), not(empty())); + arangoDB.getLogs(new LogOptions().start(logs.getLid().get(0) + 1)) + .whenComplete((logsStart, ex) -> { + assertThat(logsStart, is(notNullValue())); + assertThat(logsStart.getLid(), not(contains(logs.getLid().get(0)))); + }) + .get(); + } + + @Test + public void getLogsSize() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final LogEntity logs = arangoDB.getLogs(null).get(); + assertThat(logs.getLid().size(), greaterThan(0)); + arangoDB.getLogs(new LogOptions().size(logs.getLid().size() - 1)) + .whenComplete((logsSize, ex) -> { + assertThat(logsSize, is(notNullValue())); + assertThat(logsSize.getLid().size(), is(logs.getLid().size() - 1)); + }) + .get(); + } + + @Test + public void getLogsOffset() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final LogEntity logs = arangoDB.getLogs(null).get(); + assertThat(logs.getTotalAmount(), greaterThan(0L)); + arangoDB.getLogs(new LogOptions().offset((int) (logs.getTotalAmount() - 1))) + .whenComplete((logsOffset, ex) -> { + assertThat(logsOffset, is(notNullValue())); + assertThat(logsOffset.getLid().size(), is(1)); + }) + .get(); + } + + @Test + public void getLogsSearch() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final LogEntity logs = arangoDB.getLogs(null).get(); + arangoDB.getLogs(new LogOptions().search(BaseTest.TEST_DB)) + .whenComplete((logsSearch, ex) -> { + assertThat(logsSearch, is(notNullValue())); + assertThat(logs.getTotalAmount(), greaterThan(logsSearch.getTotalAmount())); + }) + .get(); + } + + @Test + public void getLogsSortAsc() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getLogs(new LogOptions().sort(SortOrder.asc)) + .whenComplete((logs, ex) -> { + assertThat(logs, is(notNullValue())); + long lastId = -1; + for (final Long id : logs.getLid()) { + assertThat(id, greaterThan(lastId)); + lastId = id; + } + }) + .get(); + } + + @Test + public void getLogsSortDesc() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getLogs(new LogOptions().sort(SortOrder.desc)) + .whenComplete((logs, ex) -> { + assertThat(logs, is(notNullValue())); + long lastId = Long.MAX_VALUE; + for (final Long id : logs.getLid()) { + assertThat(lastId, greaterThan(id)); + lastId = id; + } + }) + .get(); + } + + @Test + public void getLogLevel() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + arangoDB.getLogLevel() + .whenComplete((logLevel, ex) -> { + assertThat(logLevel, is(notNullValue())); + assertThat(logLevel.getAgency(), is(LogLevelEntity.LogLevel.INFO)); + }) + .get(); + } + + @Test + public void setLogLevel() throws InterruptedException, ExecutionException { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final LogLevelEntity entity = new LogLevelEntity(); + try { + entity.setAgency(LogLevelEntity.LogLevel.ERROR); + arangoDB.setLogLevel(entity) + .whenComplete((logLevel, ex) -> { + assertThat(logLevel, is(notNullValue())); + assertThat(logLevel.getAgency(), is(LogLevelEntity.LogLevel.ERROR)); + }) + .get(); + } finally { + entity.setAgency(LogLevelEntity.LogLevel.INFO); + arangoDB.setLogLevel(entity).get(); + } + } +} diff --git a/src/test/java/com/arangodb/async/ArangoDatabaseTest.java b/src/test/java/com/arangodb/async/ArangoDatabaseTest.java new file mode 100644 index 000000000..7e5bed0a3 --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoDatabaseTest.java @@ -0,0 +1,1058 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.AqlExecutionExplainEntity.ExecutionPlan; +import com.arangodb.entity.*; +import com.arangodb.entity.AqlParseEntity.AstNode; +import com.arangodb.entity.QueryCachePropertiesEntity.CacheMode; +import com.arangodb.model.*; +import com.arangodb.model.TraversalOptions.Direction; +import com.arangodb.velocypack.VPackBuilder; +import com.arangodb.velocypack.VPackSlice; +import com.arangodb.velocypack.exception.VPackException; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +/** + * @author Mark Vollmary + * @author Michele Rastelli + */ +public class ArangoDatabaseTest extends BaseTest { + + private static final String COLLECTION_NAME = "db_test"; + private static final String GRAPH_NAME = "graph_test"; + + @Test + public void create() throws InterruptedException, ExecutionException { + try { + final Boolean result = arangoDB.db(BaseTest.TEST_DB + "_1").create().get(); + assertThat(result, is(true)); + } finally { + arangoDB.db(BaseTest.TEST_DB + "_1").drop().get(); + } + } + + @Test + public void getVersion() throws InterruptedException, ExecutionException { + db.getVersion() + .whenComplete((version, ex) -> { + assertThat(version, is(notNullValue())); + assertThat(version.getServer(), is(notNullValue())); + assertThat(version.getVersion(), is(notNullValue())); + }) + .get(); + } + + @Test + public void getEngine() throws ExecutionException, InterruptedException { + final ArangoDBEngine engine = db.getEngine().get(); + assertThat(engine, is(notNullValue())); + assertThat(engine.getName(), is(notNullValue())); + } + + @Test + public void exists() throws InterruptedException, ExecutionException { + assertThat(db.exists().get(), is(true)); + assertThat(arangoDB.db("no").exists().get(), is(false)); + } + + @Test + public void getAccessibleDatabases() throws InterruptedException, ExecutionException { + db.getAccessibleDatabases() + .whenComplete((dbs, ex) -> { + assertThat(dbs, is(notNullValue())); + assertThat(dbs.size(), greaterThan(0)); + assertThat(dbs, hasItem("_system")); + }) + .get(); + } + + @Test + public void createCollection() throws InterruptedException, ExecutionException { + db.createCollection(COLLECTION_NAME, null) + .whenComplete((result, ex) -> { + assertThat(result, is(notNullValue())); + assertThat(result.getId(), is(notNullValue())); + }) + .get(); + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void createCollectionWithReplicationFactor() throws InterruptedException, ExecutionException { + assumeTrue(isCluster()); + final CollectionEntity result = db + .createCollection(COLLECTION_NAME, new CollectionCreateOptions().replicationFactor(2)).get(); + assertThat(result, is(notNullValue())); + assertThat(result.getId(), is(notNullValue())); + assertThat(db.collection(COLLECTION_NAME).getProperties().get().getReplicationFactor(), is(2)); + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void createCollectionWithMinReplicationFactor() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isCluster()); + + final CollectionEntity result = db.createCollection(COLLECTION_NAME, + new CollectionCreateOptions().replicationFactor(2).minReplicationFactor(2)).get(); + assertThat(result, is(notNullValue())); + assertThat(result.getId(), is(notNullValue())); + assertThat(db.collection(COLLECTION_NAME).getProperties().get().getReplicationFactor(), is(2)); + assertThat(db.collection(COLLECTION_NAME).getProperties().get().getMinReplicationFactor(), is(2)); + assertThat(db.collection(COLLECTION_NAME).getProperties().get().getSatellite(), is(nullValue())); + db.collection(COLLECTION_NAME).drop(); + } + + @Test + public void createCollectionWithNumberOfShards() throws InterruptedException, ExecutionException { + assumeTrue(isCluster()); + final CollectionEntity result = db + .createCollection(COLLECTION_NAME, new CollectionCreateOptions().numberOfShards(2)).get(); + assertThat(result, is(notNullValue())); + assertThat(result.getId(), is(notNullValue())); + assertThat(db.collection(COLLECTION_NAME).getProperties().get().getNumberOfShards(), is(2)); + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void createCollectionWithNumberOfShardsAndShardKey() throws InterruptedException, ExecutionException { + assumeTrue(isCluster()); + final CollectionEntity result = db + .createCollection(COLLECTION_NAME, new CollectionCreateOptions().numberOfShards(2).shardKeys("a")) + .get(); + assertThat(result, is(notNullValue())); + assertThat(result.getId(), is(notNullValue())); + final CollectionPropertiesEntity properties = db.collection(COLLECTION_NAME).getProperties().get(); + assertThat(properties.getNumberOfShards(), is(2)); + assertThat(properties.getShardKeys().size(), is(1)); + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void createCollectionWithNumberOfShardsAndShardKeys() throws InterruptedException, ExecutionException { + assumeTrue(isCluster()); + final CollectionEntity result = db.createCollection(COLLECTION_NAME, + new CollectionCreateOptions().numberOfShards(2).shardKeys("a", "b")).get(); + assertThat(result, is(notNullValue())); + assertThat(result.getId(), is(notNullValue())); + final CollectionPropertiesEntity properties = db.collection(COLLECTION_NAME).getProperties().get(); + assertThat(properties.getNumberOfShards(), is(2)); + assertThat(properties.getShardKeys().size(), is(2)); + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void deleteCollection() throws InterruptedException, ExecutionException { + db.createCollection(COLLECTION_NAME, null).get(); + db.collection(COLLECTION_NAME).drop().get(); + try { + db.collection(COLLECTION_NAME).getInfo().get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void deleteSystemCollection() throws InterruptedException, ExecutionException { + final String name = "_system_test"; + db.createCollection(name, new CollectionCreateOptions().isSystem(true)).get(); + db.collection(name).drop(true).get(); + try { + db.collection(name).getInfo().get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void deleteSystemCollectionFail() throws InterruptedException, ExecutionException { + final String name = "_system_test"; + db.createCollection(name, new CollectionCreateOptions().isSystem(true)).get(); + try { + db.collection(name).drop().get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + db.collection(name).drop(true).get(); + try { + db.collection(name).getInfo().get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getIndex() throws InterruptedException, ExecutionException { + db.createCollection(COLLECTION_NAME, null).get(); + final Collection fields = new ArrayList<>(); + fields.add("a"); + final IndexEntity createResult = db.collection(COLLECTION_NAME).ensureHashIndex(fields, null).get(); + db.getIndex(createResult.getId()) + .whenComplete((readResult, ex) -> { + assertThat(readResult.getId(), is(createResult.getId())); + assertThat(readResult.getType(), is(createResult.getType())); + }) + .get(); + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void deleteIndex() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + final Collection fields = new ArrayList<>(); + fields.add("a"); + final IndexEntity createResult = db.collection(COLLECTION_NAME).ensureHashIndex(fields, null).get(); + db.deleteIndex(createResult.getId()) + .whenComplete((id, ex) -> { + assertThat(id, is(createResult.getId())); + try { + db.getIndex(id).get(); + fail(); + } catch (InterruptedException e) { + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + }) + .get(); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void getCollections() throws InterruptedException, ExecutionException { + try { + final Collection systemCollections = db.getCollections(null).get(); + db.createCollection(COLLECTION_NAME + "1", null).get(); + db.createCollection(COLLECTION_NAME + "2", null).get(); + db.getCollections(null) + .whenComplete((collections, ex) -> { + assertThat(collections.size(), is(2 + systemCollections.size())); + assertThat(collections, is(notNullValue())); + }) + .get(); + } finally { + db.collection(COLLECTION_NAME + "1").drop().get(); + db.collection(COLLECTION_NAME + "2").drop().get(); + } + } + + @Test + public void getCollectionsExcludeSystem() throws InterruptedException, ExecutionException { + try { + final CollectionsReadOptions options = new CollectionsReadOptions().excludeSystem(true); + final Collection systemCollections = db.getCollections(options).get(); + assertThat(systemCollections.size(), is(0)); + db.createCollection(COLLECTION_NAME + "1", null).get(); + db.createCollection(COLLECTION_NAME + "2", null).get(); + db.getCollections(options) + .whenComplete((collections, ex) -> { + assertThat(collections.size(), is(2)); + assertThat(collections, is(notNullValue())); + }) + .get(); + } finally { + db.collection(COLLECTION_NAME + "1").drop().get(); + db.collection(COLLECTION_NAME + "2").drop().get(); + } + } + + @Test + public void grantAccess() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.grantAccess("user1").get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test + public void grantAccessRW() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.grantAccess("user1", Permissions.RW).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test + public void grantAccessRO() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.grantAccess("user1", Permissions.RO).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test + public void grantAccessNONE() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.grantAccess("user1", Permissions.NONE).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test(expected = ExecutionException.class) + public void grantAccessUserNotFound() throws InterruptedException, ExecutionException { + db.grantAccess("user1", Permissions.RW).get(); + } + + @Test + public void revokeAccess() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.revokeAccess("user1").get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test(expected = ExecutionException.class) + public void revokeAccessUserNotFound() throws InterruptedException, ExecutionException { + db.revokeAccess("user1").get(); + } + + @Test + public void resetAccess() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234", null).get(); + db.resetAccess("user1").get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test(expected = ExecutionException.class) + public void resetAccessUserNotFound() throws InterruptedException, ExecutionException { + db.resetAccess("user1").get(); + } + + @Test + public void grantDefaultCollectionAccess() throws InterruptedException, ExecutionException { + try { + arangoDB.createUser("user1", "1234").get(); + db.grantDefaultCollectionAccess("user1", Permissions.RW).get(); + } finally { + arangoDB.deleteUser("user1").get(); + } + } + + @Test + public void getPermissions() throws InterruptedException, ExecutionException { + assertThat(Permissions.RW, is(db.getPermissions("root").get())); + } + + @Test + public void query() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + db.query("for i in db_test return i._id", null, null, String.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + for (int i = 0; i < 10; i++, cursor.next()) { + assertThat(cursor.hasNext(), is(true)); + } + }) + .get(); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void queryForEach() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + db.query("for i in db_test return i._id", null, null, String.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + final AtomicInteger i = new AtomicInteger(0); + cursor.forEachRemaining(e -> i.incrementAndGet()); + assertThat(i.get(), is(10)); + }) + .get(); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void queryStream() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + db.query("for i in db_test return i._id", null, null, String.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + final AtomicInteger i = new AtomicInteger(0); + cursor.forEachRemaining(e -> i.incrementAndGet()); + assertThat(i.get(), is(10)); + }) + .get(); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void queryWithCount() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + + db.query("for i in db_test Limit 6 return i._id", null, new AqlQueryOptions().count(true), String.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + for (int i = 0; i < 6; i++, cursor.next()) { + assertThat(cursor.hasNext(), is(true)); + } + assertThat(cursor.getCount(), is(6)); + }) + .get(); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void queryWithLimitAndFullCount() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + + db.query("for i in db_test Limit 5 return i._id", null, new AqlQueryOptions().fullCount(true), String.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + for (int i = 0; i < 5; i++, cursor.next()) { + assertThat(cursor.hasNext(), is(true)); + } + assertThat(cursor.getStats(), is(notNullValue())); + assertThat(cursor.getStats().getFullCount(), is(10L)); + }) + .get(); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void queryWithBatchSize() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + final ArangoCursorAsync cursor = db.query("for i in db_test return i._id", null, + new AqlQueryOptions().batchSize(5).count(true), String.class).get(); + assertThat(cursor, is(notNullValue())); + for (int i = 0; i < 10; i++, cursor.next()) { + assertThat(cursor.hasNext(), is(true)); + } + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void queryStreamWithBatchSize() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + final ArangoCursorAsync cursor = db.query("for i in db_test return i._id", null, + new AqlQueryOptions().batchSize(5).count(true), String.class).get(); + assertThat(cursor, is(notNullValue())); + final AtomicInteger i = new AtomicInteger(0); + cursor.streamRemaining().forEach(e -> i.incrementAndGet()); + assertThat(i.get(), is(10)); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + /** + * ignored. takes to long + */ + @Test + @Ignore + public void queryWithTTL() throws InterruptedException, ExecutionException { + // set TTL to 1 seconds and get the second batch after 2 seconds! + final int ttl = 1; + final int wait = 2; + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + final ArangoCursorAsync cursor = db.query("for i in db_test return i._id", null, + new AqlQueryOptions().batchSize(5).ttl(ttl), String.class).get(); + assertThat(cursor, is(notNullValue())); + for (int i = 0; i < 10; i++, cursor.next()) { + assertThat(cursor.hasNext(), is(true)); + if (i == 1) { + Thread.sleep(wait * 1000); + } + } + fail(); + } catch (final ArangoDBException ex) { + assertThat(ex.getResponseCode(), is(404)); + assertThat(ex.getErrorNum(), is(1600)); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void changeQueryCache() throws InterruptedException, ExecutionException { + try { + QueryCachePropertiesEntity properties = db.getQueryCacheProperties().get(); + assertThat(properties, is(notNullValue())); + assertThat(properties.getMode(), is(CacheMode.off)); + assertThat(properties.getMaxResults(), greaterThan(0L)); + + properties.setMode(CacheMode.on); + properties = db.setQueryCacheProperties(properties).get(); + assertThat(properties, is(notNullValue())); + assertThat(properties.getMode(), is(CacheMode.on)); + + properties = db.getQueryCacheProperties().get(); + assertThat(properties.getMode(), is(CacheMode.on)); + } finally { + final QueryCachePropertiesEntity properties = new QueryCachePropertiesEntity(); + properties.setMode(CacheMode.off); + db.setQueryCacheProperties(properties).get(); + } + } + + @Test + public void queryWithCache() throws InterruptedException, ExecutionException { + assumeTrue(isSingleServer()); + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + + final QueryCachePropertiesEntity properties = new QueryCachePropertiesEntity(); + properties.setMode(CacheMode.on); + db.setQueryCacheProperties(properties).get(); + + final ArangoCursorAsync cursor = db + .query("FOR t IN db_test FILTER t.age >= 10 SORT t.age RETURN t._id", null, + new AqlQueryOptions().cache(true), String.class) + .get(); + + assertThat(cursor, is(notNullValue())); + assertThat(cursor.isCached(), is(false)); + + final ArangoCursorAsync cachedCursor = db + .query("FOR t IN db_test FILTER t.age >= 10 SORT t.age RETURN t._id", null, + new AqlQueryOptions().cache(true), String.class) + .get(); + + assertThat(cachedCursor, is(notNullValue())); + assertThat(cachedCursor.isCached(), is(true)); + + } finally { + db.collection(COLLECTION_NAME).drop().get(); + final QueryCachePropertiesEntity properties = new QueryCachePropertiesEntity(); + properties.setMode(CacheMode.off); + db.setQueryCacheProperties(properties).get(); + } + } + + @Test + public void queryCursor() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + final int numbDocs = 10; + for (int i = 0; i < numbDocs; i++) { + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(), null).get(); + } + + final int batchSize = 5; + final ArangoCursorAsync cursor = db.query("for i in db_test return i._id", null, + new AqlQueryOptions().batchSize(batchSize).count(true), String.class).get(); + assertThat(cursor, is(notNullValue())); + assertThat(cursor.getCount(), is(numbDocs)); + + final ArangoCursorAsync cursor2 = db.cursor(cursor.getId(), String.class).get(); + assertThat(cursor2, is(notNullValue())); + assertThat(cursor2.getCount(), is(numbDocs)); + assertThat(cursor2.hasNext(), is(true)); + + for (int i = 0; i < batchSize; i++, cursor.next()) { + assertThat(cursor.hasNext(), is(true)); + } + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void changeQueryTrackingProperties() throws InterruptedException, ExecutionException { + try { + QueryTrackingPropertiesEntity properties = db.getQueryTrackingProperties().get(); + assertThat(properties, is(notNullValue())); + assertThat(properties.getEnabled(), is(true)); + assertThat(properties.getTrackSlowQueries(), is(true)); + assertThat(properties.getMaxQueryStringLength(), greaterThan(0L)); + assertThat(properties.getMaxSlowQueries(), greaterThan(0L)); + assertThat(properties.getSlowQueryThreshold(), greaterThan(0L)); + properties.setEnabled(false); + properties = db.setQueryTrackingProperties(properties).get(); + assertThat(properties, is(notNullValue())); + assertThat(properties.getEnabled(), is(false)); + properties = db.getQueryTrackingProperties().get(); + assertThat(properties.getEnabled(), is(false)); + } finally { + final QueryTrackingPropertiesEntity properties = new QueryTrackingPropertiesEntity(); + properties.setEnabled(true); + db.setQueryTrackingProperties(properties).get(); + } + } + + @Test + public void queryWithBindVars() throws InterruptedException, ExecutionException { + try { + db.createCollection(COLLECTION_NAME, null).get(); + for (int i = 0; i < 10; i++) { + final BaseDocument baseDocument = new BaseDocument(); + baseDocument.addAttribute("age", 20 + i); + db.collection(COLLECTION_NAME).insertDocument(baseDocument, null).get(); + } + final Map bindVars = new HashMap<>(); + bindVars.put("@coll", COLLECTION_NAME); + bindVars.put("age", 25); + db.query("FOR t IN @@coll FILTER t.age >= @age SORT t.age RETURN t._id", bindVars, null, String.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + for (int i = 0; i < 5; i++, cursor.next()) { + assertThat(cursor.hasNext(), is(true)); + } + }) + .get(); + } finally { + db.collection(COLLECTION_NAME).drop().get(); + } + } + + @Test + public void queryWithWarning() throws InterruptedException, ExecutionException { + arangoDB.db().query("return 1/0", null, null, String.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + assertThat(cursor.getWarnings(), is(notNullValue())); + assertThat(cursor.getWarnings(), is(not(empty()))); + }) + .get(); + } + + @Test + public void queryClose() throws IOException, InterruptedException, ExecutionException { + final ArangoCursorAsync cursor = arangoDB.db() + .query("for i in 1..2 return i", null, new AqlQueryOptions().batchSize(1), String.class).get(); + cursor.close(); + int count = 0; + try { + for (; cursor.hasNext(); cursor.next(), count++) { + } + fail(); + } catch (final ArangoDBException e) { + assertThat(count, is(1)); + } + + } + + @Test + public void explainQuery() throws InterruptedException, ExecutionException { + arangoDB.db().explainQuery("for i in 1..1 return i", null, null) + .whenComplete((explain, ex) -> { + assertThat(explain, is(notNullValue())); + assertThat(explain.getPlan(), is(notNullValue())); + assertThat(explain.getPlans(), is(nullValue())); + final ExecutionPlan plan = explain.getPlan(); + assertThat(plan.getCollections().size(), is(0)); + assertThat(plan.getEstimatedCost(), greaterThan(0)); + assertThat(plan.getEstimatedNrItems(), greaterThan(0)); + assertThat(plan.getVariables().size(), is(2)); + assertThat(plan.getNodes().size(), is(greaterThan(0))); + }) + .get(); + } + + @Test + public void parseQuery() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + arangoDB.db().parseQuery("for i in _apps return i") + .whenComplete((parse, ex) -> { + assertThat(parse, is(notNullValue())); + assertThat(parse.getBindVars(), is(empty())); + assertThat(parse.getCollections().size(), is(1)); + assertThat(parse.getCollections().iterator().next(), is("_apps")); + assertThat(parse.getAst().size(), is(1)); + final AstNode root = parse.getAst().iterator().next(); + assertThat(root.getType(), is("root")); + assertThat(root.getName(), is(nullValue())); + assertThat(root.getSubNodes(), is(notNullValue())); + assertThat(root.getSubNodes().size(), is(2)); + final Iterator iterator = root.getSubNodes().iterator(); + final AstNode for_ = iterator.next(); + assertThat(for_.getType(), is("for")); + assertThat(for_.getSubNodes(), is(notNullValue())); + assertThat(for_.getSubNodes().size(), is(3)); + final Iterator iterator2 = for_.getSubNodes().iterator(); + final AstNode first = iterator2.next(); + assertThat(first.getType(), is("variable")); + assertThat(first.getName(), is("i")); + final AstNode second = iterator2.next(); + assertThat(second.getType(), is("collection")); + assertThat(second.getName(), is("_apps")); + final AstNode return_ = iterator.next(); + assertThat(return_.getType(), is("return")); + assertThat(return_.getSubNodes(), is(notNullValue())); + assertThat(return_.getSubNodes().size(), is(1)); + assertThat(return_.getSubNodes().iterator().next().getType(), is("reference")); + assertThat(return_.getSubNodes().iterator().next().getName(), is("i")); + }) + .get(); + } + + @Test + @Ignore + public void getAndClearSlowQueries() throws InterruptedException, ExecutionException { + final QueryTrackingPropertiesEntity properties = db.getQueryTrackingProperties().get(); + final Long slowQueryThreshold = properties.getSlowQueryThreshold(); + try { + properties.setSlowQueryThreshold(1L); + db.setQueryTrackingProperties(properties); + + db.query("return sleep(1.1)", null, null, Void.class); + final Collection slowQueries = db.getSlowQueries().get(); + assertThat(slowQueries, is(notNullValue())); + assertThat(slowQueries.size(), is(1)); + final QueryEntity queryEntity = slowQueries.iterator().next(); + assertThat(queryEntity.getQuery(), is("return sleep(1.1)")); + + db.clearSlowQueries().get(); + assertThat(db.getSlowQueries().get().size(), is(0)); + } finally { + properties.setSlowQueryThreshold(slowQueryThreshold); + db.setQueryTrackingProperties(properties); + } + } + + @Test + public void createGetDeleteAqlFunction() throws InterruptedException, ExecutionException { + final Collection aqlFunctionsInitial = db.getAqlFunctions(null).get(); + assertThat(aqlFunctionsInitial, is(empty())); + try { + db.createAqlFunction("myfunctions::temperature::celsiustofahrenheit", + "function (celsius) { return celsius * 1.8 + 32; }", null).get(); + + final Collection aqlFunctions = db.getAqlFunctions(null).get(); + assertThat(aqlFunctions.size(), is(greaterThan(aqlFunctionsInitial.size()))); + } finally { + final Integer deleteCount = db.deleteAqlFunction("myfunctions::temperature::celsiustofahrenheit", null) + .get(); + // compatibility with ArangoDB < 3.4 + if (isAtLeastVersion(3, 4)) { + assertThat(deleteCount, is(1)); + } else { + assertThat(deleteCount, is(nullValue())); + } + + final Collection aqlFunctions = db.getAqlFunctions(null).get(); + assertThat(aqlFunctions.size(), is(aqlFunctionsInitial.size())); + } + } + + @Test + public void createGetDeleteAqlFunctionWithNamespace() throws InterruptedException, ExecutionException { + final Collection aqlFunctionsInitial = db.getAqlFunctions(null).get(); + assertThat(aqlFunctionsInitial, is(empty())); + try { + db.createAqlFunction("myfunctions::temperature::celsiustofahrenheit1", + "function (celsius) { return celsius * 1.8 + 32; }", null).get(); + db.createAqlFunction("myfunctions::temperature::celsiustofahrenheit2", + "function (celsius) { return celsius * 1.8 + 32; }", null).get(); + + } finally { + db.deleteAqlFunction("myfunctions::temperature", new AqlFunctionDeleteOptions().group(true)).get(); + + final Collection aqlFunctions = db.getAqlFunctions(null).get(); + assertThat(aqlFunctions.size(), is(aqlFunctionsInitial.size())); + } + } + + @Test + public void createGraph() throws InterruptedException, ExecutionException { + try { + db.createGraph(GRAPH_NAME, null, null) + .whenComplete((result, ex) -> { + assertThat(result, is(notNullValue())); + assertThat(result.getName(), is(GRAPH_NAME)); + }) + .get(); + } finally { + db.graph(GRAPH_NAME).drop().get(); + } + } + + @Test + public void getGraphs() throws InterruptedException, ExecutionException { + try { + db.createGraph(GRAPH_NAME, null, null).get(); + db.getGraphs() + .whenComplete((graphs, ex) -> { + assertThat(graphs, is(notNullValue())); + assertThat(graphs.size(), is(1)); + }) + .get(); + } finally { + db.graph(GRAPH_NAME).drop().get(); + } + } + + @Test + public void transactionString() throws InterruptedException, ExecutionException { + final TransactionOptions options = new TransactionOptions().params("test"); + db.transaction("function (params) {return params;}", String.class, options) + .whenComplete((result, ex) -> assertThat(result, is("test"))) + .get(); + } + + @Test + public void transactionNumber() throws InterruptedException, ExecutionException { + final TransactionOptions options = new TransactionOptions().params(5); + db.transaction("function (params) {return params;}", Integer.class, options) + .whenComplete((result, ex) -> assertThat(result, is(5))) + .get(); + } + + @Test + public void transactionVPack() throws VPackException, InterruptedException, ExecutionException { + final TransactionOptions options = new TransactionOptions().params(new VPackBuilder().add("test").slice()); + db.transaction("function (params) {return params;}", VPackSlice.class, options) + .whenComplete((result, ex) -> { + assertThat(result.isString(), is(true)); + assertThat(result.getAsString(), is("test")); + }) + .get(); + } + + @Test + public void transactionEmpty() throws InterruptedException, ExecutionException { + db.transaction("function () {}", null, null).get(); + } + + @Test + public void transactionallowImplicit() throws InterruptedException, ExecutionException { + try { + db.createCollection("someCollection", null).get(); + db.createCollection("someOtherCollection", null).get(); + final String action = "function (params) {" + "var db = require('internal').db;" + + "return {'a':db.someCollection.all().toArray()[0], 'b':db.someOtherCollection.all().toArray()[0]};" + + "}"; + final TransactionOptions options = new TransactionOptions().readCollections("someCollection"); + db.transaction(action, VPackSlice.class, options).get(); + try { + options.allowImplicit(false); + db.transaction(action, VPackSlice.class, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } finally { + db.collection("someCollection").drop().get(); + db.collection("someOtherCollection").drop().get(); + } + } + + @Test + public void transactionPojoReturn() throws ExecutionException, InterruptedException { + final String action = "function() { return {'value':'hello world'}; }"; + db.transaction(action, TransactionTestEntity.class, new TransactionOptions()) + .whenComplete((res, ex) -> { + assertThat(res, is(notNullValue())); + assertThat(res.value, is("hello world")); + }) + .get(); + } + + @Test + public void getInfo() throws InterruptedException, ExecutionException { + final CompletableFuture f = db.getInfo(); + assertThat(f, is(notNullValue())); + f.whenComplete((info, ex) -> { + assertThat(info, is(notNullValue())); + assertThat(info.getId(), is(notNullValue())); + assertThat(info.getName(), is(TEST_DB)); + assertThat(info.getPath(), is(notNullValue())); + assertThat(info.getIsSystem(), is(false)); + }); + f.get(); + } + + @Test + public void executeTraversal() throws InterruptedException, ExecutionException { + try { + db.createCollection("person", null).get(); + db.createCollection("knows", new CollectionCreateOptions().type(CollectionType.EDGES)).get(); + for (final String e : new String[]{"Alice", "Bob", "Charlie", "Dave", "Eve"}) { + final BaseDocument doc = new BaseDocument(); + doc.setKey(e); + db.collection("person").insertDocument(doc, null).get(); + } + for (final String[] e : new String[][]{new String[]{"Alice", "Bob"}, new String[]{"Bob", "Charlie"}, + new String[]{"Bob", "Dave"}, new String[]{"Eve", "Alice"}, new String[]{"Eve", "Bob"}}) { + final BaseEdgeDocument edge = new BaseEdgeDocument(); + edge.setKey(e[0] + "_knows_" + e[1]); + edge.setFrom("person/" + e[0]); + edge.setTo("person/" + e[1]); + db.collection("knows").insertDocument(edge, null).get(); + } + final TraversalOptions options = new TraversalOptions().edgeCollection("knows").startVertex("person/Alice") + .direction(Direction.outbound); + db.executeTraversal(BaseDocument.class, BaseEdgeDocument.class, options) + .whenComplete((traversal, ex) -> { + assertThat(traversal, is(notNullValue())); + + final Collection vertices = traversal.getVertices(); + assertThat(vertices, is(notNullValue())); + assertThat(vertices.size(), is(4)); + + final Iterator verticesIterator = vertices.iterator(); + final Collection v = Arrays.asList("Alice", "Bob", "Charlie", "Dave"); + for (; verticesIterator.hasNext(); ) { + assertThat(v.contains(verticesIterator.next().getKey()), is(true)); + } + + final Collection> paths = traversal.getPaths(); + assertThat(paths, is(notNullValue())); + assertThat(paths.size(), is(4)); + + assertThat(paths.iterator().hasNext(), is(true)); + final PathEntity first = paths.iterator().next(); + assertThat(first, is(notNullValue())); + assertThat(first.getEdges().size(), is(0)); + assertThat(first.getVertices().size(), is(1)); + assertThat(first.getVertices().iterator().next().getKey(), is("Alice")); + }) + .get(); + } finally { + db.collection("person").drop().get(); + db.collection("knows").drop().get(); + } + } + + @Test + public void getDocument() throws InterruptedException, ExecutionException { + String collectionName = COLLECTION_NAME + "getDocument"; + db.createCollection(collectionName).get(); + final BaseDocument value = new BaseDocument(); + value.setKey("123"); + db.collection(collectionName).insertDocument(value).get(); + db.getDocument(collectionName + "/123", BaseDocument.class) + .whenComplete((document, ex) -> { + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is("123")); + }) + .get(); + db.collection(collectionName).drop().get(); + } + + @Test + public void shouldIncludeExceptionMessage() throws InterruptedException, ExecutionException { + final String exceptionMessage = "My error context"; + final String action = "function (params) {" + "throw '" + exceptionMessage + "';" + "}"; + try { + db.transaction(action, VPackSlice.class, null).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + ArangoDBException cause = ((ArangoDBException) e.getCause()); + assertThat(cause.getErrorNum(), is(1650)); + if (isAtLeastVersion(3, 4)) { + assertThat(cause.getErrorMessage(), is(exceptionMessage)); + } + } + } + + @Test(expected = ArangoDBException.class) + public void getDocumentWrongId() throws InterruptedException, ExecutionException { + db.getDocument("123", BaseDocument.class).get(); + } + + @Test + public void reloadRouting() throws InterruptedException, ExecutionException { + db.reloadRouting().get(); + } + + @SuppressWarnings({"WeakerAccess", "unused"}) + protected static class TransactionTestEntity { + private String value; + + public TransactionTestEntity() { + super(); + } + } +} diff --git a/src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java b/src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java new file mode 100644 index 000000000..cc37bfa63 --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoEdgeCollectionTest.java @@ -0,0 +1,384 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.*; +import com.arangodb.model.*; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * @author Mark Vollmary + */ +public class ArangoEdgeCollectionTest extends BaseTest { + + private static final String GRAPH_NAME = "db_collection_test"; + private static final String EDGE_COLLECTION_NAME = "db_edge_collection_test"; + private static final String VERTEX_COLLECTION_NAME = "db_vertex_collection_test"; + + @BeforeClass + public static void setup() throws InterruptedException, ExecutionException { + if (!db.collection(VERTEX_COLLECTION_NAME).exists().get()) { + db.createCollection(VERTEX_COLLECTION_NAME, null).get(); + } + if (!db.collection(EDGE_COLLECTION_NAME).exists().get()) { + db.createCollection(EDGE_COLLECTION_NAME, new CollectionCreateOptions().type(CollectionType.EDGES)).get(); + } + final Collection edgeDefinitions = new ArrayList<>(); + edgeDefinitions.add(new EdgeDefinition().collection(EDGE_COLLECTION_NAME).from(VERTEX_COLLECTION_NAME) + .to(VERTEX_COLLECTION_NAME)); + db.createGraph(GRAPH_NAME, edgeDefinitions, null).get(); + } + + @After + public void teardown() throws InterruptedException, ExecutionException { + for (final String collection : new String[]{VERTEX_COLLECTION_NAME, EDGE_COLLECTION_NAME}) { + db.collection(collection).truncate().get(); + } + } + + private BaseEdgeDocument createEdgeValue() throws InterruptedException, ExecutionException { + final VertexEntity v1 = db.graph(GRAPH_NAME).vertexCollection(VERTEX_COLLECTION_NAME) + .insertVertex(new BaseDocument(), null).get(); + final VertexEntity v2 = db.graph(GRAPH_NAME).vertexCollection(VERTEX_COLLECTION_NAME) + .insertVertex(new BaseDocument(), null).get(); + + final BaseEdgeDocument value = new BaseEdgeDocument(); + value.setFrom(v1.getId()); + value.setTo(v2.getId()); + return value; + } + + @Test + public void insertEdge() throws InterruptedException, ExecutionException { + final BaseEdgeDocument value = createEdgeValue(); + final EdgeEntity edge = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(value, null).get(); + assertThat(edge, is(notNullValue())); + final BaseEdgeDocument document = db.collection(EDGE_COLLECTION_NAME) + .getDocument(edge.getKey(), BaseEdgeDocument.class, null).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(edge.getKey())); + } + + @Test + public void getEdge() throws InterruptedException, ExecutionException { + final BaseEdgeDocument value = createEdgeValue(); + final EdgeEntity edge = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(value, null).get(); + final BaseDocument document = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(edge.getKey(), BaseDocument.class, null).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(edge.getKey())); + } + + @Test + public void getEdgeIfMatch() 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(edge.getRev()); + final BaseDocument document = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(edge.getKey(), BaseDocument.class, options).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(edge.getKey())); + } + + @Test + 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"); + try { + db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(edge.getKey(), BaseEdgeDocument.class, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getEdgeIfNoneMatch() 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("no"); + final BaseDocument document = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(edge.getKey(), BaseDocument.class, options).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(edge.getKey())); + } + + @Test + 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()); + try { + db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(edge.getKey(), BaseEdgeDocument.class, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void replaceEdge() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final EdgeUpdateEntity replaceResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .replaceEdge(createResult.getKey(), doc, null).get(); + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getRev(), is(not(replaceResult.getOldRev()))); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + + final BaseEdgeDocument readResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getRevision(), is(replaceResult.getRev())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + } + + @Test + public void replaceEdgeIfMatch() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final EdgeReplaceOptions options = new EdgeReplaceOptions().ifMatch(createResult.getRev()); + final EdgeUpdateEntity replaceResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .replaceEdge(createResult.getKey(), doc, options).get(); + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getRev(), is(not(replaceResult.getOldRev()))); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + + final BaseEdgeDocument readResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getRevision(), is(replaceResult.getRev())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + } + + @Test + public void replaceEdgeIfMatchFail() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + try { + final EdgeReplaceOptions options = new EdgeReplaceOptions().ifMatch("no"); + db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).replaceEdge(createResult.getKey(), doc, options) + .get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void updateEdge() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + final EdgeUpdateEntity updateResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .updateEdge(createResult.getKey(), doc, null).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseEdgeDocument readResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("a")), is("test1")); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + assertThat(readResult.getRevision(), is(updateResult.getRev())); + assertThat(readResult.getProperties().keySet(), hasItem("c")); + } + + @Test + public void updateEdgeIfMatch() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + final EdgeUpdateOptions options = new EdgeUpdateOptions().ifMatch(createResult.getRev()); + final EdgeUpdateEntity updateResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .updateEdge(createResult.getKey(), doc, options).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseEdgeDocument readResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("a")), is("test1")); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + assertThat(readResult.getRevision(), is(updateResult.getRev())); + assertThat(readResult.getProperties().keySet(), hasItem("c")); + } + + @Test + public void updateEdgeIfMatchFail() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + try { + final EdgeUpdateOptions options = new EdgeUpdateOptions().ifMatch("no"); + db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).updateEdge(createResult.getKey(), doc, options) + .get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void updateEdgeKeepNullTrue() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.updateAttribute("a", null); + final EdgeUpdateOptions options = new EdgeUpdateOptions().keepNull(true); + final EdgeUpdateEntity updateResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .updateEdge(createResult.getKey(), doc, options).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseEdgeDocument readResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getProperties().keySet().size(), is(1)); + assertThat(readResult.getProperties().keySet(), hasItem("a")); + } + + @Test + public void updateEdgeKeepNullFalse() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + doc.addAttribute("a", "test"); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + doc.updateAttribute("a", null); + final EdgeUpdateOptions options = new EdgeUpdateOptions().keepNull(false); + final EdgeUpdateEntity updateResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .updateEdge(createResult.getKey(), doc, options).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseEdgeDocument readResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME) + .getEdge(createResult.getKey(), BaseEdgeDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getId(), is(createResult.getId())); + assertThat(readResult.getRevision(), is(notNullValue())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + } + + @Test + public void deleteEdge() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + 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(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void deleteEdgeIfMatch() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + final EdgeDeleteOptions options = new EdgeDeleteOptions().ifMatch(createResult.getRev()); + 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(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void deleteEdgeIfMatchFail() throws InterruptedException, ExecutionException { + final BaseEdgeDocument doc = createEdgeValue(); + final EdgeEntity createResult = db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(doc, null) + .get(); + final EdgeDeleteOptions options = new EdgeDeleteOptions().ifMatch("no"); + try { + db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).deleteEdge(createResult.getKey(), options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } +} diff --git a/src/test/java/com/arangodb/async/ArangoGraphTest.java b/src/test/java/com/arangodb/async/ArangoGraphTest.java new file mode 100644 index 000000000..833fba4d3 --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoGraphTest.java @@ -0,0 +1,287 @@ +/* + * 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.CollectionPropertiesEntity; +import com.arangodb.entity.EdgeDefinition; +import com.arangodb.entity.GraphEntity; +import com.arangodb.entity.ServerRole; +import com.arangodb.model.GraphCreateOptions; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +/** + * @author Mark Vollmary + */ +public class ArangoGraphTest extends BaseTest { + + private static final String GRAPH_NAME = "db_collection_test"; + private static final String EDGE_COL_1 = "db_edge1_collection_test"; + private static final String EDGE_COL_2 = "db_edge2_collection_test"; + private static final String EDGE_COL_3 = "db_edge3_collection_test"; + private static final String VERTEX_COL_1 = "db_vertex1_collection_test"; + private static final String VERTEX_COL_2 = "db_vertex2_collection_test"; + private static final String VERTEX_COL_3 = "db_vertex3_collection_test"; + private static final String VERTEX_COL_4 = "db_vertex4_collection_test"; + private static final Integer REPLICATION_FACTOR = 2; + private static final Integer NUMBER_OF_SHARDS = 2; + + @BeforeClass + public static void setup() throws InterruptedException, ExecutionException { + if (db.graph(GRAPH_NAME).exists().get()) { + db.graph(GRAPH_NAME).drop().get(); + } + final Collection edgeDefinitions = new ArrayList<>(); + edgeDefinitions.add(new EdgeDefinition().collection(EDGE_COL_1).from(VERTEX_COL_1).to(VERTEX_COL_2)); + edgeDefinitions + .add(new EdgeDefinition().collection(EDGE_COL_2).from(VERTEX_COL_2).to(VERTEX_COL_1, VERTEX_COL_3)); + final GraphCreateOptions options = new GraphCreateOptions(); + if (arangoDB.getRole().get() != ServerRole.SINGLE) { + options.replicationFactor(REPLICATION_FACTOR).numberOfShards(NUMBER_OF_SHARDS); + } + db.createGraph(GRAPH_NAME, edgeDefinitions, options).get(); + } + + @After + public void teardown() throws InterruptedException, ExecutionException { + for (final String collection : new String[]{EDGE_COL_1, EDGE_COL_2, VERTEX_COL_1, VERTEX_COL_2, VERTEX_COL_3, + VERTEX_COL_4}) { + final ArangoCollectionAsync c = db.collection(collection); + if (c.exists().get()) { + c.truncate().get(); + } + } + } + + @Test + public void create() throws InterruptedException, ExecutionException { + try { + final GraphEntity result = db.graph(GRAPH_NAME + "_1").create(null).get(); + assertThat(result, is(notNullValue())); + assertThat(result.getName(), is(GRAPH_NAME + "_1")); + } finally { + db.graph(GRAPH_NAME + "_1").drop().get(); + } + } + + @Test + public void createWithReplicationAndMinReplicationFactor() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isCluster()); + final Collection edgeDefinitions = new ArrayList<>(); + final GraphEntity graph = db.createGraph(GRAPH_NAME + "_1", edgeDefinitions, new GraphCreateOptions().isSmart(true).replicationFactor(2).minReplicationFactor(2)).get(); + assertThat(graph, is(notNullValue())); + assertThat(graph.getName(), is(GRAPH_NAME + "_1")); + assertThat(graph.getMinReplicationFactor(), is(2)); + assertThat(graph.getReplicationFactor(), is(2)); + db.graph(GRAPH_NAME + "_1").drop(); + } + + @Test + public void getGraphs() throws InterruptedException, ExecutionException { + final Collection graphs = db.getGraphs().get(); + assertThat(graphs, is(notNullValue())); + assertThat(graphs.size(), greaterThanOrEqualTo(1)); + } + + @Test + public void getInfo() throws InterruptedException, ExecutionException { + final GraphEntity info = db.graph(GRAPH_NAME).getInfo().get(); + assertThat(info, is(notNullValue())); + assertThat(info.getName(), is(GRAPH_NAME)); + assertThat(info.getEdgeDefinitions().size(), is(2)); + final Iterator iterator = info.getEdgeDefinitions().iterator(); + final EdgeDefinition e1 = iterator.next(); + assertThat(e1.getCollection(), is(EDGE_COL_1)); + assertThat(e1.getFrom(), hasItem(VERTEX_COL_1)); + assertThat(e1.getTo(), hasItem(VERTEX_COL_2)); + final EdgeDefinition e2 = iterator.next(); + assertThat(e2.getCollection(), is(EDGE_COL_2)); + assertThat(e2.getFrom(), hasItem(VERTEX_COL_2)); + assertThat(e2.getTo(), hasItems(VERTEX_COL_1, VERTEX_COL_3)); + assertThat(info.getOrphanCollections(), is(empty())); + + if (isCluster()) { + for (final String collection : new String[]{VERTEX_COL_1, VERTEX_COL_2}) { + final CollectionPropertiesEntity properties = db.collection(collection).getProperties().get(); + assertThat(properties.getReplicationFactor(), is(REPLICATION_FACTOR)); + assertThat(properties.getNumberOfShards(), is(NUMBER_OF_SHARDS)); + } + for (final String collection : new String[]{EDGE_COL_1, EDGE_COL_2}) { + final CollectionPropertiesEntity properties = db.collection(collection).getProperties().get(); + assertThat(properties.getReplicationFactor(), is(REPLICATION_FACTOR)); + } + } + } + + @Test + public void getVertexCollections() throws InterruptedException, ExecutionException { + final Collection vertexCollections = db.graph(GRAPH_NAME).getVertexCollections().get(); + assertThat(vertexCollections, is(notNullValue())); + assertThat(vertexCollections.size(), is(3)); + assertThat(vertexCollections, hasItems(VERTEX_COL_1, VERTEX_COL_2, VERTEX_COL_3)); + } + + @Test + public void addVertexCollection() throws InterruptedException, ExecutionException { + final GraphEntity graph = db.graph(GRAPH_NAME).addVertexCollection(VERTEX_COL_4).get(); + assertThat(graph, is(notNullValue())); + final Collection vertexCollections = db.graph(GRAPH_NAME).getVertexCollections().get(); + assertThat(vertexCollections, hasItems(VERTEX_COL_1, VERTEX_COL_2, VERTEX_COL_3, VERTEX_COL_4)); + setup(); + } + + @Test + public void getEdgeCollections() throws InterruptedException, ExecutionException { + final Collection edgeCollections = db.graph(GRAPH_NAME).getEdgeDefinitions().get(); + assertThat(edgeCollections, is(notNullValue())); + assertThat(edgeCollections.size(), is(2)); + assertThat(edgeCollections, hasItems(EDGE_COL_1, EDGE_COL_2)); + } + + @Test + public void addEdgeDefinition() throws InterruptedException, ExecutionException { + final GraphEntity graph = db.graph(GRAPH_NAME) + .addEdgeDefinition(new EdgeDefinition().collection(EDGE_COL_3).from(VERTEX_COL_1).to(VERTEX_COL_2)) + .get(); + assertThat(graph, is(notNullValue())); + final Collection edgeDefinitions = graph.getEdgeDefinitions(); + assertThat(edgeDefinitions.size(), is(3)); + int count = 0; + for (final EdgeDefinition e : edgeDefinitions) { + if (e.getCollection().equals(EDGE_COL_3)) { + count++; + } + } + assertThat(count, is(1)); + for (final EdgeDefinition e : edgeDefinitions) { + if (e.getCollection().equals(EDGE_COL_3)) { + assertThat(e.getFrom(), hasItem(VERTEX_COL_1)); + assertThat(e.getTo(), hasItem(VERTEX_COL_2)); + } + } + if (isCluster()) { + final CollectionPropertiesEntity properties = db.collection(EDGE_COL_3).getProperties().get(); + assertThat(properties.getReplicationFactor(), is(REPLICATION_FACTOR)); + assertThat(properties.getNumberOfShards(), is(NUMBER_OF_SHARDS)); + } + setup(); + } + + @Test + public void replaceEdgeDefinition() throws InterruptedException, ExecutionException { + final GraphEntity graph = db.graph(GRAPH_NAME) + .replaceEdgeDefinition(new EdgeDefinition().collection(EDGE_COL_1).from(VERTEX_COL_3).to(VERTEX_COL_4)) + .get(); + final Collection edgeDefinitions = graph.getEdgeDefinitions(); + assertThat(edgeDefinitions.size(), is(2)); + int count = 0; + for (final EdgeDefinition e : edgeDefinitions) { + if (e.getCollection().equals(EDGE_COL_1)) { + count++; + } + } + assertThat(count, is(1)); + for (final EdgeDefinition e : edgeDefinitions) { + if (e.getCollection().equals(EDGE_COL_1)) { + assertThat(e.getFrom(), hasItem(VERTEX_COL_3)); + assertThat(e.getTo(), hasItem(VERTEX_COL_4)); + } + } + setup(); + } + + @Test + public void removeEdgeDefinition() throws InterruptedException, ExecutionException { + final GraphEntity graph = db.graph(GRAPH_NAME).removeEdgeDefinition(EDGE_COL_1).get(); + final Collection edgeDefinitions = graph.getEdgeDefinitions(); + assertThat(edgeDefinitions.size(), is(1)); + assertThat(edgeDefinitions.iterator().next().getCollection(), is(EDGE_COL_2)); + setup(); + } + + @Test + public void smartGraph() throws InterruptedException, ExecutionException { + assumeTrue(isCluster()); + assumeTrue(isEnterprise()); + for (final String collection : new String[]{EDGE_COL_1, EDGE_COL_2, VERTEX_COL_1, VERTEX_COL_2, + VERTEX_COL_3, VERTEX_COL_4}) { + if (db.collection(collection).exists().get()) { + db.collection(collection).drop().get(); + } + } + final Collection edgeDefinitions = new ArrayList<>(); + edgeDefinitions.add(new EdgeDefinition().collection(EDGE_COL_1).from(VERTEX_COL_1).to(VERTEX_COL_2)); + edgeDefinitions + .add(new EdgeDefinition().collection(EDGE_COL_2).from(VERTEX_COL_2).to(VERTEX_COL_1, VERTEX_COL_3)); + final GraphEntity graph = db.createGraph(GRAPH_NAME + "_smart", edgeDefinitions, + new GraphCreateOptions().isSmart(true).smartGraphAttribute("test").replicationFactor(REPLICATION_FACTOR) + .numberOfShards(NUMBER_OF_SHARDS)) + .get(); + assertThat(graph, is(notNullValue())); + assertThat(graph.getIsSmart(), is(true)); + assertThat(graph.getSmartGraphAttribute(), is("test")); + assertThat(graph.getNumberOfShards(), is(2)); + if (db.graph(GRAPH_NAME + "_smart").exists().get()) { + db.graph(GRAPH_NAME + "_smart").drop().get(); + } + } + + @Test + public void drop() throws InterruptedException, ExecutionException { + final String edgeCollection = "edge_drop"; + final String vertexCollection = "vertex_drop"; + final String graph = GRAPH_NAME + "_drop"; + final GraphEntity result = db.graph(graph).create(Collections + .singleton(new EdgeDefinition().collection(edgeCollection).from(vertexCollection).to(vertexCollection))) + .get(); + assertThat(result, is(notNullValue())); + db.graph(graph).drop().get(); + assertThat(db.collection(edgeCollection).exists().get(), is(true)); + assertThat(db.collection(vertexCollection).exists().get(), is(true)); + } + + @Test + public void dropPlusDropCollections() throws InterruptedException, ExecutionException { + final String edgeCollection = "edge_dropC"; + final String vertexCollection = "vertex_dropC"; + final String graph = GRAPH_NAME + "_dropC"; + final GraphEntity result = db.graph(graph).create(Collections + .singleton(new EdgeDefinition().collection(edgeCollection).from(vertexCollection).to(vertexCollection))) + .get(); + assertThat(result, is(notNullValue())); + db.graph(graph).drop(true).get(); + assertThat(db.collection(edgeCollection).exists().get(), is(false)); + assertThat(db.collection(vertexCollection).exists().get(), is(false)); + } +} diff --git a/src/test/java/com/arangodb/async/ArangoRouteTest.java b/src/test/java/com/arangodb/async/ArangoRouteTest.java new file mode 100644 index 000000000..f0c5f609e --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoRouteTest.java @@ -0,0 +1,81 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.ArangoDBException; +import com.arangodb.entity.BaseDocument; +import com.arangodb.internal.ArangoRequestParam; +import org.junit.Test; + +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * @author Mark Vollmary + */ +public class ArangoRouteTest extends BaseTest { + + /* + @Test + public void get() throws InterruptedException, ExecutionException { + final Response res = db.route("/_api/version").get().get(); + assertThat(res.getBody().get("version").isString(), is(true)); + }*/ + + /* + @Test + public void withHeader() throws InterruptedException, ExecutionException { + final ArangoCollectionAsync collection = db.collection("route-test-col"); + try { + collection.create(); + final BaseDocument doc = new BaseDocument(); + collection.insertDocument(doc).get(); + db.route("/_api/document", doc.getId()).withHeader(ArangoRequestParam.IF_NONE_MATCH, doc.getRevision()) + .get().get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause() instanceof ArangoDBException, is(true)); + } finally { + collection.drop(); + } + } + */ + + @Test + public void withParentHeader() throws InterruptedException, ExecutionException { + final ArangoCollectionAsync collection = db.collection("route-test-col"); + try { + collection.create().get(); + final BaseDocument doc = new BaseDocument(); + collection.insertDocument(doc).get(); + db.route("/_api/document").withHeader(ArangoRequestParam.IF_NONE_MATCH, doc.getRevision()) + .route(doc.getId()).get().get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + collection.drop().get(); + } + +} diff --git a/src/test/java/com/arangodb/async/ArangoSearchTest.java b/src/test/java/com/arangodb/async/ArangoSearchTest.java new file mode 100644 index 000000000..78355797e --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoSearchTest.java @@ -0,0 +1,401 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.ArangoDBException; +import com.arangodb.entity.ViewEntity; +import com.arangodb.entity.ViewType; +import com.arangodb.entity.arangosearch.*; +import com.arangodb.model.arangosearch.AnalyzerDeleteOptions; +import com.arangodb.model.arangosearch.ArangoSearchCreateOptions; +import com.arangodb.model.arangosearch.ArangoSearchPropertiesOptions; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.*; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +/** + * @author Mark Vollmary + */ + +public class ArangoSearchTest extends BaseTest { + + private static final String VIEW_NAME = "view_test"; + + @BeforeClass + public static void setup() throws InterruptedException, ExecutionException { + db.createArangoSearch(VIEW_NAME, new ArangoSearchCreateOptions()).get(); + } + + @Test + public void exists() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + assertThat(db.arangoSearch(VIEW_NAME).exists().get(), is(true)); + } + + @Test + public void getInfo() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + final ViewEntity info = db.arangoSearch(VIEW_NAME).getInfo().get(); + assertThat(info, is(not(nullValue()))); + assertThat(info.getId(), is(not(nullValue()))); + assertThat(info.getName(), is(VIEW_NAME)); + assertThat(info.getType(), is(ViewType.ARANGO_SEARCH)); + } + + @Test + public void drop() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + final String name = VIEW_NAME + "_droptest"; + db.createArangoSearch(name, new ArangoSearchCreateOptions()).get(); + final ArangoViewAsync view = db.arangoSearch(name); + view.drop().get(); + assertThat(view.exists().get(), is(false)); + } + + @Test + public void rename() throws InterruptedException, ExecutionException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 4)); + final String name = VIEW_NAME + "_renametest"; + final String newName = name + "_new"; + db.createArangoSearch(name, new ArangoSearchCreateOptions()).get(); + db.arangoSearch(name).rename(newName).get(); + assertThat(db.arangoSearch(name).exists().get(), is(false)); + assertThat(db.arangoSearch(newName).exists().get(), is(true)); + } + + @Test + public void create() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + final String name = VIEW_NAME + "_createtest"; + final ViewEntity info = db.arangoSearch(name).create().get(); + assertThat(info, is(not(nullValue()))); + assertThat(info.getId(), is(not(nullValue()))); + assertThat(info.getName(), is(name)); + assertThat(info.getType(), is(ViewType.ARANGO_SEARCH)); + assertThat(db.arangoSearch(name).exists().get(), is(true)); + } + + @Test + public void createWithOptions() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + final String name = VIEW_NAME + "_createtest_withotpions"; + final ViewEntity info = db.arangoSearch(name).create(new ArangoSearchCreateOptions()).get(); + assertThat(info, is(not(nullValue()))); + assertThat(info.getId(), is(not(nullValue()))); + assertThat(info.getName(), is(name)); + assertThat(info.getType(), is(ViewType.ARANGO_SEARCH)); + assertThat(db.arangoSearch(name).exists().get(), is(true)); + } + + @Test + public void createWithPrimarySort() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final String name = "createWithPrimarySort"; + final ArangoSearchCreateOptions options = new ArangoSearchCreateOptions(); + + final PrimarySort primarySort = PrimarySort.on("myFieldName"); + primarySort.ascending(true); + options.primarySort(primarySort); + options.consolidationIntervalMsec(666666L); + + final ViewEntity info = db.arangoSearch(name).create(options).get(); + assertThat(info, is(not(nullValue()))); + assertThat(info.getId(), is(not(nullValue()))); + assertThat(info.getName(), is(name)); + assertThat(info.getType(), is(ViewType.ARANGO_SEARCH)); + assertThat(db.arangoSearch(name).exists().get(), is(true)); + } + + @Test + public void createWithCommitIntervalMsec() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + final String name = "createWithCommitIntervalMsec"; + final ArangoSearchCreateOptions options = new ArangoSearchCreateOptions(); + options.commitIntervalMsec(666666L); + + final ViewEntity info = db.arangoSearch(name).create(options).get(); + assertThat(info, is(not(nullValue()))); + assertThat(info.getId(), is(not(nullValue()))); + assertThat(info.getName(), is(name)); + assertThat(info.getType(), is(ViewType.ARANGO_SEARCH)); + assertThat(db.arangoSearch(name).exists().get(), is(true)); + + // check commit interval msec property + final ArangoSearchAsync view = db.arangoSearch(name); + final ArangoSearchPropertiesEntity properties = view.getProperties().get(); + assertThat(properties.getCommitIntervalMsec(), is(666666L)); + } + + @Test + public void getProperties() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + final String name = VIEW_NAME + "_getpropertiestest"; + final ArangoSearchAsync view = db.arangoSearch(name); + view.create(new ArangoSearchCreateOptions()).get(); + final ArangoSearchPropertiesEntity properties = view.getProperties().get(); + assertThat(properties, is(not(nullValue()))); + assertThat(properties.getId(), is(not(nullValue()))); + assertThat(properties.getName(), is(name)); + assertThat(properties.getType(), is(ViewType.ARANGO_SEARCH)); + assertThat(properties.getConsolidationIntervalMsec(), is(not(nullValue()))); + assertThat(properties.getCleanupIntervalStep(), is(not(nullValue()))); + final ConsolidationPolicy consolidate = properties.getConsolidationPolicy(); + assertThat(consolidate, is(is(not(nullValue())))); + final Collection links = properties.getLinks(); + assertThat(links.isEmpty(), is(true)); + } + + @Test + public void updateProperties() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + db.createCollection("view_update_prop_test_collection").get(); + final String name = VIEW_NAME + "_updatepropertiestest"; + final ArangoSearchAsync view = db.arangoSearch(name); + view.create(new ArangoSearchCreateOptions()).get(); + final ArangoSearchPropertiesOptions options = new ArangoSearchPropertiesOptions(); + options.cleanupIntervalStep(15L); + options.consolidationIntervalMsec(65000L); + options.consolidationPolicy(ConsolidationPolicy.of(ConsolidationType.BYTES_ACCUM).threshold(1.)); + options.link( + CollectionLink.on("view_update_prop_test_collection").fields(FieldLink.on("value").analyzers("identity") + .trackListPositions(true).includeAllFields(true).storeValues(StoreValuesType.ID))); + final ArangoSearchPropertiesEntity properties = view.updateProperties(options).get(); + assertThat(properties, is(not(nullValue()))); + assertThat(properties.getCleanupIntervalStep(), is(15L)); + assertThat(properties.getConsolidationIntervalMsec(), is(65000L)); + final ConsolidationPolicy consolidate = properties.getConsolidationPolicy(); + assertThat(consolidate, is(not(nullValue()))); + assertThat(consolidate.getType(), is(ConsolidationType.BYTES_ACCUM)); + assertThat(consolidate.getThreshold(), is(1.)); + assertThat(properties.getLinks().size(), is(1)); + final CollectionLink link = properties.getLinks().iterator().next(); + assertThat(link.getName(), is("view_update_prop_test_collection")); + assertThat(link.getFields().size(), is(1)); + final FieldLink next = link.getFields().iterator().next(); + assertThat(next.getName(), is("value")); + assertThat(next.getIncludeAllFields(), is(true)); + assertThat(next.getTrackListPositions(), is(true)); + assertThat(next.getStoreValues(), is(StoreValuesType.ID)); + } + + @Test + public void replaceProperties() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + db.createCollection("view_replace_prop_test_collection").get(); + final String name = VIEW_NAME + "_replacepropertiestest"; + final ArangoSearchAsync view = db.arangoSearch(name); + view.create(new ArangoSearchCreateOptions()).get(); + final ArangoSearchPropertiesOptions options = new ArangoSearchPropertiesOptions(); + options.link( + CollectionLink.on("view_replace_prop_test_collection").fields(FieldLink.on("value").analyzers("identity"))); + final ArangoSearchPropertiesEntity properties = view.replaceProperties(options).get(); + assertThat(properties, is(not(nullValue()))); + assertThat(properties.getLinks().size(), is(1)); + final CollectionLink link = properties.getLinks().iterator().next(); + assertThat(link.getName(), is("view_replace_prop_test_collection")); + assertThat(link.getFields().size(), is(1)); + assertThat(link.getFields().iterator().next().getName(), is("value")); + } + + private void createGetAndDeleteAnalyzer(AnalyzerEntity options) throws ExecutionException, InterruptedException { + + String fullyQualifiedName = db.name() + "::" + options.getName(); + + // createAnalyzer + AnalyzerEntity createdAnalyzer = db.createAnalyzer(options).get(); + + assertThat(createdAnalyzer.getName(), is(fullyQualifiedName)); + assertThat(createdAnalyzer.getType(), is(options.getType())); + assertThat(createdAnalyzer.getFeatures(), is(options.getFeatures())); + assertThat(createdAnalyzer.getProperties(), is(options.getProperties())); + + // getAnalyzer + AnalyzerEntity gotAnalyzer = db.getAnalyzer(options.getName()).get(); + assertThat(gotAnalyzer.getName(), is(fullyQualifiedName)); + assertThat(gotAnalyzer.getType(), is(options.getType())); + assertThat(gotAnalyzer.getFeatures(), is(options.getFeatures())); + assertThat(gotAnalyzer.getProperties(), is(options.getProperties())); + + // getAnalyzers + @SuppressWarnings("OptionalGetWithoutIsPresent") + AnalyzerEntity foundAnalyzer = db.getAnalyzers().get().stream().filter(it -> it.getName().equals(fullyQualifiedName)) + .findFirst().get(); + + assertThat(foundAnalyzer.getName(), is(fullyQualifiedName)); + assertThat(foundAnalyzer.getType(), is(options.getType())); + assertThat(foundAnalyzer.getFeatures(), is(options.getFeatures())); + assertThat(foundAnalyzer.getProperties(), is(options.getProperties())); + + AnalyzerDeleteOptions deleteOptions = new AnalyzerDeleteOptions(); + deleteOptions.setForce(true); + + // deleteAnalyzer + db.deleteAnalyzer(options.getName(), deleteOptions).get(); + + try { + db.getAnalyzer(options.getName()).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + assertThat(((ArangoDBException) e.getCause()).getResponseCode(), is(404)); + } + } + + @Test + public void identityAnalyzer() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + String name = "test-" + UUID.randomUUID().toString(); + + Set features = new HashSet<>(); + features.add(AnalyzerFeature.frequency); + features.add(AnalyzerFeature.norm); + features.add(AnalyzerFeature.position); + + AnalyzerEntity options = new AnalyzerEntity(); + options.setFeatures(features); + options.setName(name); + options.setType(AnalyzerType.identity); + options.setProperties(Collections.emptyMap()); + + createGetAndDeleteAnalyzer(options); + } + + @Test + public void delimiterAnalyzer() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + String name = "test-" + UUID.randomUUID().toString(); + + Set features = new HashSet<>(); + features.add(AnalyzerFeature.frequency); + features.add(AnalyzerFeature.norm); + features.add(AnalyzerFeature.position); + + AnalyzerEntity options = new AnalyzerEntity(); + options.setFeatures(features); + options.setName(name); + options.setType(AnalyzerType.delimiter); + options.setProperties(Collections.singletonMap("delimiter", "-")); + + createGetAndDeleteAnalyzer(options); + } + + @Test + public void stemAnalyzer() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + String name = "test-" + UUID.randomUUID().toString(); + + Set features = new HashSet<>(); + features.add(AnalyzerFeature.frequency); + features.add(AnalyzerFeature.norm); + features.add(AnalyzerFeature.position); + + AnalyzerEntity options = new AnalyzerEntity(); + options.setFeatures(features); + options.setName(name); + options.setType(AnalyzerType.stem); + options.setProperties(Collections.singletonMap("locale", "ru.utf-8")); + + createGetAndDeleteAnalyzer(options); + } + + @Test + public void normAnalyzer() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + String name = "test-" + UUID.randomUUID().toString(); + + Set features = new HashSet<>(); + features.add(AnalyzerFeature.frequency); + features.add(AnalyzerFeature.norm); + features.add(AnalyzerFeature.position); + + Map properties = new HashMap<>(); + properties.put("locale", "ru.utf-8"); + properties.put("case", "lower"); + properties.put("accent", true); + + AnalyzerEntity options = new AnalyzerEntity(); + options.setFeatures(features); + options.setName(name); + options.setType(AnalyzerType.norm); + options.setProperties(properties); + + createGetAndDeleteAnalyzer(options); + } + + @Test + public void ngramAnalyzer() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + String name = "test-" + UUID.randomUUID().toString(); + + Set features = new HashSet<>(); + features.add(AnalyzerFeature.frequency); + features.add(AnalyzerFeature.norm); + features.add(AnalyzerFeature.position); + + Map properties = new HashMap<>(); + properties.put("max", 6L); + properties.put("min", 3L); + properties.put("preserveOriginal", true); + + AnalyzerEntity options = new AnalyzerEntity(); + options.setFeatures(features); + options.setName(name); + options.setType(AnalyzerType.ngram); + options.setProperties(properties); + + createGetAndDeleteAnalyzer(options); + } + + @Test + public void textAnalyzer() throws ExecutionException, InterruptedException { + assumeTrue(isAtLeastVersion(3, 5)); + String name = "test-" + UUID.randomUUID().toString(); + + Set features = new HashSet<>(); + features.add(AnalyzerFeature.frequency); + features.add(AnalyzerFeature.norm); + features.add(AnalyzerFeature.position); + + Map properties = new HashMap<>(); + properties.put("locale", "ru.utf-8"); + properties.put("case", "lower"); + properties.put("stopwords", Collections.emptyList()); + properties.put("accent", true); + properties.put("stemming", true); + + AnalyzerEntity options = new AnalyzerEntity(); + options.setFeatures(features); + options.setName(name); + options.setType(AnalyzerType.text); + options.setProperties(properties); + + createGetAndDeleteAnalyzer(options); + } + +} diff --git a/src/test/java/com/arangodb/async/ArangoSslTest.java b/src/test/java/com/arangodb/async/ArangoSslTest.java new file mode 100644 index 000000000..f02c30581 --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoSslTest.java @@ -0,0 +1,92 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.ArangoDBVersion; +import org.junit.Ignore; +import org.junit.Test; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; +import java.security.KeyStore; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * @author Mark Vollmary + */ +public class ArangoSslTest { + + /*- + * a SSL trust store + * + * create the trust store for the self signed certificate: + * keytool -import -alias "my arangodb server cert" -file UnitTests/server.pem -keystore example.truststore + * + * Documentation: + * https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ssl/SSLSocketFactory.html + */ + private static final String SSL_TRUSTSTORE = "/example.truststore"; + private static final String SSL_TRUSTSTORE_PASSWORD = "12345678"; + + @Test + @Ignore + public void connect() throws Exception { + final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + ks.load(this.getClass().getResourceAsStream(SSL_TRUSTSTORE), SSL_TRUSTSTORE_PASSWORD.toCharArray()); + + final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, SSL_TRUSTSTORE_PASSWORD.toCharArray()); + + final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + + final SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder() + .loadProperties(ArangoSslTest.class.getResourceAsStream("/arangodb-ssl.properties")).useSsl(true) + .sslContext(sc).build(); + final ArangoDBVersion version = arangoDB.getVersion().get(); + assertThat(version, is(notNullValue())); + } + + @Test + @Ignore + public void connectWithoutValidSslContext() throws Exception { + try { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder() + .loadProperties(ArangoSslTest.class.getResourceAsStream("/arangodb-ssl.properties")).useSsl(true) + .build(); + arangoDB.getVersion().get(); + fail("this should fail"); + } catch (final ArangoDBException ex) { + assertThat(ex.getCause() instanceof SSLHandshakeException, is(true)); + } + } + +} diff --git a/src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java b/src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java new file mode 100644 index 000000000..ec98ff7fd --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoVertexCollectionTest.java @@ -0,0 +1,372 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.BaseDocument; +import com.arangodb.entity.VertexEntity; +import com.arangodb.entity.VertexUpdateEntity; +import com.arangodb.model.*; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Collection; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * @author Mark Vollmary + */ +public class ArangoVertexCollectionTest extends BaseTest { + + private static final String GRAPH_NAME = "db_collection_test"; + private static final String COLLECTION_NAME = "db_vertex_collection_test"; + + @BeforeClass + public static void setup() throws InterruptedException, ExecutionException { + if (!db.collection(COLLECTION_NAME).exists().get()) { + db.createCollection(COLLECTION_NAME, null).get(); + } + final GraphCreateOptions options = new GraphCreateOptions().orphanCollections(COLLECTION_NAME); + db.createGraph(GRAPH_NAME, null, options).get(); + } + + @After + public void teardown() throws InterruptedException, ExecutionException { + db.collection(COLLECTION_NAME).truncate().get(); + } + + @Test + public void dropVertexCollection() throws InterruptedException, ExecutionException { + db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).drop().get(); + final Collection vertexCollections = db.graph(GRAPH_NAME).getVertexCollections().get(); + assertThat(vertexCollections, not(hasItem(COLLECTION_NAME))); + } + + @Test + public void insertVertex() throws InterruptedException, ExecutionException { + final VertexEntity vertex = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .insertVertex(new BaseDocument(), null).get(); + assertThat(vertex, is(notNullValue())); + final BaseDocument document = db.collection(COLLECTION_NAME) + .getDocument(vertex.getKey(), BaseDocument.class, null).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(vertex.getKey())); + } + + @Test + public void getVertex() throws InterruptedException, ExecutionException { + final VertexEntity vertex = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .insertVertex(new BaseDocument(), null).get(); + final BaseDocument document = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(vertex.getKey(), BaseDocument.class, null).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(vertex.getKey())); + } + + @Test + public void getVertexIfMatch() throws InterruptedException, ExecutionException { + final VertexEntity vertex = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .insertVertex(new BaseDocument(), null).get(); + final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifMatch(vertex.getRev()); + final BaseDocument document = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(vertex.getKey(), BaseDocument.class, options).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(vertex.getKey())); + } + + @Test + 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"); + try { + db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(vertex.getKey(), BaseDocument.class, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getVertexIfNoneMatch() throws InterruptedException, ExecutionException { + final VertexEntity vertex = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .insertVertex(new BaseDocument(), null).get(); + final GraphDocumentReadOptions options = new GraphDocumentReadOptions().ifNoneMatch("no"); + final BaseDocument document = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(vertex.getKey(), BaseDocument.class, options).get(); + assertThat(document, is(notNullValue())); + assertThat(document.getKey(), is(vertex.getKey())); + } + + @Test + 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()); + try { + db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(vertex.getKey(), BaseDocument.class, options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void replaceVertex() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final VertexUpdateEntity replaceResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .replaceVertex(createResult.getKey(), doc, null).get(); + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getRev(), is(not(replaceResult.getOldRev()))); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + + final BaseDocument readResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getRevision(), is(replaceResult.getRev())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + } + + @Test + public void replaceVertexIfMatch() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + final VertexReplaceOptions options = new VertexReplaceOptions().ifMatch(createResult.getRev()); + final VertexUpdateEntity replaceResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .replaceVertex(createResult.getKey(), doc, options).get(); + assertThat(replaceResult, is(notNullValue())); + assertThat(replaceResult.getId(), is(createResult.getId())); + assertThat(replaceResult.getRev(), is(not(replaceResult.getOldRev()))); + assertThat(replaceResult.getOldRev(), is(createResult.getRev())); + + final BaseDocument readResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getRevision(), is(replaceResult.getRev())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + } + + @Test + public void replaceVertexIfMatchFail() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.getProperties().clear(); + doc.addAttribute("b", "test"); + try { + final VertexReplaceOptions options = new VertexReplaceOptions().ifMatch("no"); + db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).replaceVertex(createResult.getKey(), doc, options) + .get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void updateVertex() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + final VertexUpdateEntity updateResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .updateVertex(createResult.getKey(), doc, null).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseDocument readResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("a")), is("test1")); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + assertThat(readResult.getRevision(), is(updateResult.getRev())); + assertThat(readResult.getProperties().keySet(), hasItem("c")); + } + + @Test + public void updateVertexIfMatch() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + final VertexUpdateOptions options = new VertexUpdateOptions().ifMatch(createResult.getRev()); + final VertexUpdateEntity updateResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .updateVertex(createResult.getKey(), doc, options).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseDocument readResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getAttribute("a"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("a")), is("test1")); + assertThat(readResult.getAttribute("b"), is(notNullValue())); + assertThat(String.valueOf(readResult.getAttribute("b")), is("test")); + assertThat(readResult.getRevision(), is(updateResult.getRev())); + assertThat(readResult.getProperties().keySet(), hasItem("c")); + } + + @Test + public void updateVertexIfMatchFail() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + doc.addAttribute("c", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.updateAttribute("a", "test1"); + doc.addAttribute("b", "test"); + doc.updateAttribute("c", null); + try { + final VertexUpdateOptions options = new VertexUpdateOptions().ifMatch("no"); + db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).updateVertex(createResult.getKey(), doc, options) + .get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void updateVertexKeepNullTrue() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.updateAttribute("a", null); + final VertexUpdateOptions options = new VertexUpdateOptions().keepNull(true); + final VertexUpdateEntity updateResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .updateVertex(createResult.getKey(), doc, options).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseDocument readResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getProperties().keySet().size(), is(1)); + assertThat(readResult.getProperties().keySet(), hasItem("a")); + } + + @Test + public void updateVertexKeepNullFalse() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + doc.addAttribute("a", "test"); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + doc.updateAttribute("a", null); + final VertexUpdateOptions options = new VertexUpdateOptions().keepNull(false); + final VertexUpdateEntity updateResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .updateVertex(createResult.getKey(), doc, options).get(); + assertThat(updateResult, is(notNullValue())); + assertThat(updateResult.getId(), is(createResult.getId())); + assertThat(updateResult.getRev(), is(not(updateResult.getOldRev()))); + assertThat(updateResult.getOldRev(), is(createResult.getRev())); + + final BaseDocument readResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME) + .getVertex(createResult.getKey(), BaseDocument.class, null).get(); + assertThat(readResult.getKey(), is(createResult.getKey())); + assertThat(readResult.getId(), is(createResult.getId())); + assertThat(readResult.getRevision(), is(notNullValue())); + assertThat(readResult.getProperties().keySet(), not(hasItem("a"))); + } + + @Test + public void deleteVertex() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + 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(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void deleteVertexIfMatch() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + final VertexDeleteOptions options = new VertexDeleteOptions().ifMatch(createResult.getRev()); + 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(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void deleteVertexIfMatchFail() throws InterruptedException, ExecutionException { + final BaseDocument doc = new BaseDocument(); + final VertexEntity createResult = db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).insertVertex(doc, null) + .get(); + final VertexDeleteOptions options = new VertexDeleteOptions().ifMatch("no"); + try { + db.graph(GRAPH_NAME).vertexCollection(COLLECTION_NAME).deleteVertex(createResult.getKey(), options).get(); + fail(); + } catch (final ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } +} diff --git a/src/test/java/com/arangodb/async/ArangoViewTest.java b/src/test/java/com/arangodb/async/ArangoViewTest.java new file mode 100644 index 000000000..259b1b24b --- /dev/null +++ b/src/test/java/com/arangodb/async/ArangoViewTest.java @@ -0,0 +1,85 @@ +/* + * DISCLAIMER + * + * Copyright 2018 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.ViewEntity; +import com.arangodb.entity.ViewType; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +/** + * @author Mark Vollmary + */ + +public class ArangoViewTest extends BaseTest { + + private static final String VIEW_NAME = "view_test"; + + @BeforeClass + public static void setup() throws InterruptedException, ExecutionException { + db.createView(VIEW_NAME, ViewType.ARANGO_SEARCH).get(); + } + + @Test + public void exists() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + assertThat(db.view(VIEW_NAME).exists().get(), is(true)); + } + + @Test + public void getInfo() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + final ViewEntity info = db.view(VIEW_NAME).getInfo().get(); + assertThat(info, is(not(nullValue()))); + assertThat(info.getId(), is(not(nullValue()))); + assertThat(info.getName(), is(VIEW_NAME)); + assertThat(info.getType(), is(ViewType.ARANGO_SEARCH)); + } + + @Test + public void drop() throws InterruptedException, ExecutionException { + assumeTrue(isAtLeastVersion(3, 4)); + final String name = VIEW_NAME + "_droptest"; + db.createView(name, ViewType.ARANGO_SEARCH).get(); + final ArangoViewAsync view = db.view(name); + view.drop().get(); + assertThat(view.exists().get(), is(false)); + } + + @Test + public void rename() throws InterruptedException, ExecutionException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 4)); + final String name = VIEW_NAME + "_renametest"; + final String newName = name + "_new"; + db.createView(name, ViewType.ARANGO_SEARCH).get(); + db.view(name).rename(newName).get(); + assertThat(db.view(name).exists().get(), is(false)); + assertThat(db.view(newName).exists().get(), is(true)); + } + +} diff --git a/src/test/java/com/arangodb/async/BaseTest.java b/src/test/java/com/arangodb/async/BaseTest.java new file mode 100644 index 000000000..1da3f080b --- /dev/null +++ b/src/test/java/com/arangodb/async/BaseTest.java @@ -0,0 +1,87 @@ +/* + * 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.ArangoDBEngine; +import com.arangodb.entity.License; +import com.arangodb.entity.ServerRole; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import java.util.concurrent.ExecutionException; + +/** + * @author Mark Vollmary + */ +public abstract class BaseTest { + + static final String TEST_DB = "java_driver_test_db"; + static ArangoDBAsync arangoDB; + static ArangoDatabaseAsync db; + + @BeforeClass + public static void init() throws InterruptedException, ExecutionException { + if (arangoDB == null) { + arangoDB = new ArangoDBAsync.Builder().build(); + } + + if (arangoDB.db(TEST_DB).exists().get()) { + arangoDB.db(TEST_DB).drop().get(); + } + + arangoDB.createDatabase(TEST_DB).get(); + BaseTest.db = arangoDB.db(TEST_DB); + } + + @AfterClass + public static void shutdown() throws InterruptedException, ExecutionException { + arangoDB.db(TEST_DB).drop().get(); + arangoDB.shutdown(); + arangoDB = null; + } + + private static boolean isAtLeastVersion(final ArangoDBAsync arangoDB, final int major, final int minor) + throws InterruptedException, ExecutionException { + final String[] split = arangoDB.getVersion().get().getVersion().split("\\."); + return Integer.parseInt(split[0]) >= major && Integer.parseInt(split[1]) >= minor; + } + + boolean isAtLeastVersion(final int major, final int minor) throws InterruptedException, ExecutionException { + return isAtLeastVersion(arangoDB, major, minor); + } + + boolean isStorageEngine(ArangoDBEngine.StorageEngineName name) throws ExecutionException, InterruptedException { + return name.equals(db.getEngine().get().getName()); + } + + boolean isSingleServer() throws ExecutionException, InterruptedException { + return (arangoDB.getRole().get() == ServerRole.SINGLE); + } + + boolean isCluster() throws ExecutionException, InterruptedException { + return arangoDB.getRole().get() == ServerRole.COORDINATOR; + } + + boolean isEnterprise() throws ExecutionException, InterruptedException { + return arangoDB.getVersion().get().getLicense() == License.ENTERPRISE; + } + +} diff --git a/src/test/java/com/arangodb/async/CommunicationTest.java b/src/test/java/com/arangodb/async/CommunicationTest.java new file mode 100644 index 000000000..cb22f17c2 --- /dev/null +++ b/src/test/java/com/arangodb/async/CommunicationTest.java @@ -0,0 +1,46 @@ +/* + * 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 org.junit.Ignore; +import org.junit.Test; + +import java.util.concurrent.CompletableFuture; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author Mark Vollmary + */ +public class CommunicationTest { + + @Test + @Ignore + public void disconnect() { + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); + final CompletableFuture> result = arangoDB.db().query("return sleep(1)", null, null, + null); + arangoDB.shutdown(); + assertThat(result.isCompletedExceptionally(), is(true)); + } + +} diff --git a/src/test/java/com/arangodb/async/ConcurrencyTest.java b/src/test/java/com/arangodb/async/ConcurrencyTest.java new file mode 100644 index 000000000..07bcbe4b5 --- /dev/null +++ b/src/test/java/com/arangodb/async/ConcurrencyTest.java @@ -0,0 +1,87 @@ +/* + * 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.async.internal.ArangoExecutorAsync; +import com.arangodb.entity.ArangoDBVersion; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * @author Michele Rastelli + */ +public class ConcurrencyTest { + + private ArangoDBAsync arangoDB; + + @Before + public void initialize() { + arangoDB = new ArangoDBAsync.Builder().build(); + } + + /** + * FIXME: make the user executor configurable in com.arangodb.internal.ArangoExecutorAsync::execute + * (eg. this test passes using a CachedThreadPool) + */ + @Ignore + @Test(timeout = 2000) + public void executorLimit() { + List> futures = IntStream.range(0, 20) + .mapToObj(i -> arangoDB.getVersion() + .whenComplete((dbVersion, ex) -> { + System.out.println(Thread.currentThread().getName()); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + })) + .collect(Collectors.toList()); + + futures.forEach(future -> { + try { + future.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + }); + } + + + /** + * outgoing requests should be queued in the {@link ArangoExecutorAsync} outgoingExecutor + */ + @Ignore + @Test(timeout = 1000) + public void outgoingRequestsParallelismTest() { + for (int i = 0; i < 50_000; i++) { + arangoDB.getVersion(); + } + } +} diff --git a/src/test/java/com/arangodb/async/ConcurrentStreamTransactionsTest.java b/src/test/java/com/arangodb/async/ConcurrentStreamTransactionsTest.java new file mode 100644 index 000000000..fd329f382 --- /dev/null +++ b/src/test/java/com/arangodb/async/ConcurrentStreamTransactionsTest.java @@ -0,0 +1,125 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.ArangoDBEngine; +import com.arangodb.entity.BaseDocument; +import com.arangodb.entity.StreamTransactionEntity; +import com.arangodb.model.DocumentCreateOptions; +import com.arangodb.model.StreamTransactionOptions; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Test; + +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +/** + * @author Michele Rastelli + */ +public class ConcurrentStreamTransactionsTest extends BaseTest { + + private static final String COLLECTION_NAME = "db_concurrent_stream_transactions_test"; + + public ConcurrentStreamTransactionsTest() throws ExecutionException, InterruptedException { + if (db.collection(COLLECTION_NAME).exists().get()) + db.collection(COLLECTION_NAME).drop().get(); + + db.createCollection(COLLECTION_NAME, null).get(); + } + + @After + public void teardown() throws ExecutionException, InterruptedException { + if (db.collection(COLLECTION_NAME).exists().get()) + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void conflictOnInsertDocumentWithNotYetCommittedTx() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx1 = db.beginStreamTransaction( + new StreamTransactionOptions().readCollections(COLLECTION_NAME).writeCollections(COLLECTION_NAME)).get(); + + StreamTransactionEntity tx2 = db.beginStreamTransaction( + new StreamTransactionOptions().readCollections(COLLECTION_NAME).writeCollections(COLLECTION_NAME)).get(); + + String key = UUID.randomUUID().toString(); + + // insert a document from within tx1 + db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(key), new DocumentCreateOptions().streamTransactionId(tx1.getId())).get(); + + try { + // insert conflicting document from within tx2 + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(key), + new DocumentCreateOptions().streamTransactionId(tx2.getId())).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), Matchers.instanceOf(ArangoDBException.class)); + e.getCause().printStackTrace(); + } + + db.abortStreamTransaction(tx1.getId()).get(); + db.abortStreamTransaction(tx2.getId()).get(); + } + + @Test + public void conflictOnInsertDocumentWithAlreadyCommittedTx() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx1 = db.beginStreamTransaction( + new StreamTransactionOptions().readCollections(COLLECTION_NAME).writeCollections(COLLECTION_NAME)).get(); + + StreamTransactionEntity tx2 = db.beginStreamTransaction( + new StreamTransactionOptions().readCollections(COLLECTION_NAME).writeCollections(COLLECTION_NAME)).get(); + + String key = UUID.randomUUID().toString(); + + // insert a document from within tx1 + db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(key), new DocumentCreateOptions().streamTransactionId(tx1.getId())).get(); + + // commit tx1 + db.commitStreamTransaction(tx1.getId()).get(); + + try { + // insert conflicting document from within tx2 + db.collection(COLLECTION_NAME).insertDocument(new BaseDocument(key), + new DocumentCreateOptions().streamTransactionId(tx2.getId())).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), Matchers.instanceOf(ArangoDBException.class)); + e.getCause().printStackTrace(); + } + + db.abortStreamTransaction(tx2.getId()).get(); + } +} diff --git a/src/test/java/com/arangodb/async/StreamTransactionTest.java b/src/test/java/com/arangodb/async/StreamTransactionTest.java new file mode 100644 index 000000000..91e9b0eaa --- /dev/null +++ b/src/test/java/com/arangodb/async/StreamTransactionTest.java @@ -0,0 +1,361 @@ +/* + * 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.ArangoDBException; +import com.arangodb.entity.*; +import com.arangodb.model.DocumentCreateOptions; +import com.arangodb.model.DocumentReadOptions; +import com.arangodb.model.StreamTransactionOptions; +import org.junit.After; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +/** + * @author Michele Rastelli + */ +public class StreamTransactionTest extends BaseTest { + + private static final String COLLECTION_NAME = "db_stream_transaction_test"; + + public StreamTransactionTest() throws ExecutionException, InterruptedException { + if (db.collection(COLLECTION_NAME).exists().get()) + db.collection(COLLECTION_NAME).drop().get(); + + db.createCollection(COLLECTION_NAME, null).get(); + } + + @After + public void teardown() throws ExecutionException, InterruptedException { + if (db.collection(COLLECTION_NAME).exists().get()) + db.collection(COLLECTION_NAME).drop().get(); + } + + @Test + public void beginStreamTransaction() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db.beginStreamTransaction(null).get(); + assertThat(tx.getId(), is(notNullValue())); + assertThat(tx.getStatus(), is(StreamTransactionStatus.running)); + db.abortStreamTransaction(tx.getId()).get(); + } + + @Test + public void beginStreamTransactionWithNonExistingCollectionsShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.beginStreamTransaction(new StreamTransactionOptions().writeCollections("notExistingCollection")).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void abortStreamTransaction() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity begunTx = db.beginStreamTransaction(null).get(); + StreamTransactionEntity abortedTx = db.abortStreamTransaction(begunTx.getId()).get(); + + assertThat(abortedTx.getId(), is(notNullValue())); + assertThat(abortedTx.getId(), is(begunTx.getId())); + assertThat(abortedTx.getStatus(), is(StreamTransactionStatus.aborted)); + } + + @Test + public void abortStreamTransactionTwice() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity begunTx = db.beginStreamTransaction(null).get(); + db.abortStreamTransaction(begunTx.getId()).get(); + db.abortStreamTransaction(begunTx.getId()).get(); + } + + @Test + public void abortStreamTransactionWhenTransactionIdDoesNotExistsShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.abortStreamTransaction("000000").get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void abortStreamTransactionWithInvalidTransactionIdShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.abortStreamTransaction("invalidTransactionId").get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void abortCommittedStreamTransactionShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity createdTx = db.beginStreamTransaction(null).get(); + db.commitStreamTransaction(createdTx.getId()).get(); + + try { + db.abortStreamTransaction(createdTx.getId()).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getStreamTransaction() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity createdTx = db.beginStreamTransaction(null).get(); + StreamTransactionEntity gotTx = db.getStreamTransaction(createdTx.getId()).get(); + + assertThat(gotTx.getId(), is(notNullValue())); + assertThat(gotTx.getId(), is(createdTx.getId())); + assertThat(gotTx.getStatus(), is(StreamTransactionStatus.running)); + + db.abortStreamTransaction(createdTx.getId()).get(); + } + + @Test + public void getStreamTransactionWhenTransactionIdDoesNotExistsShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.getStreamTransaction("000000").get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getStreamTransactionWithInvalidTransactionIdShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.getStreamTransaction("invalidTransactionId").get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void commitStreamTransaction() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity createdTx = db.beginStreamTransaction(null).get(); + StreamTransactionEntity committedTx = db.commitStreamTransaction(createdTx.getId()).get(); + + assertThat(committedTx.getId(), is(notNullValue())); + assertThat(committedTx.getId(), is(createdTx.getId())); + assertThat(committedTx.getStatus(), is(StreamTransactionStatus.committed)); + } + + @Test + public void commitStreamTransactionTwice() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity createdTx = db.beginStreamTransaction(null).get(); + db.commitStreamTransaction(createdTx.getId()).get(); + db.commitStreamTransaction(createdTx.getId()).get(); + } + + @Test + public void commitStreamTransactionWhenTransactionIdDoesNotExistsShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.commitStreamTransaction("000000").get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void commitStreamTransactionWithInvalidTransactionIdShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.commitStreamTransaction("invalidTransactionId").get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void commitAbortedStreamTransactionShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity createdTx = db.beginStreamTransaction(null).get(); + db.abortStreamTransaction(createdTx.getId()).get(); + + try { + db.commitStreamTransaction(createdTx.getId()).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getDocument() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx = db + .beginStreamTransaction(new StreamTransactionOptions().readCollections(COLLECTION_NAME)).get(); + + // insert a document from outside the tx + DocumentCreateEntity externalDoc = db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), null).get(); + + // assert that the document is not found from within the tx + assertThat(db.collection(COLLECTION_NAME).getDocument(externalDoc.getKey(), BaseDocument.class, + new DocumentReadOptions().streamTransactionId(tx.getId())).get(), is(nullValue())); + + db.abortStreamTransaction(tx.getId()).get(); + } + + @Test + public void getDocumentWithNonExistingTransactionIdShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.collection(COLLECTION_NAME) + .getDocument("docId", BaseDocument.class, new DocumentReadOptions().streamTransactionId("123456")) + .get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void insertDocumentWithNonExistingTransactionIdShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.collection(COLLECTION_NAME) + .insertDocument(new BaseDocument(), new DocumentCreateOptions().streamTransactionId("123456")).get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getDocumentWithInvalidTransactionIdShouldThrow() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + try { + db.collection(COLLECTION_NAME) + .getDocument("docId", BaseDocument.class, new DocumentReadOptions().streamTransactionId("abcde")) + .get(); + fail(); + } catch (ExecutionException e) { + assertThat(e.getCause(), instanceOf(ArangoDBException.class)); + } + } + + @Test + public void getStreamTransactions() throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); + assumeTrue(isAtLeastVersion(3, 5)); + assumeTrue(isStorageEngine(ArangoDBEngine.StorageEngineName.rocksdb)); + + StreamTransactionEntity tx1 = db.beginStreamTransaction(null).get(); + StreamTransactionEntity tx2 = db.beginStreamTransaction(null).get(); + + List createdIds = Arrays.asList(tx1.getId(), tx2.getId()); + Set gotTxs = db.getStreamTransactions().get().stream(). + filter(it -> createdIds.contains(it.getId())).collect(Collectors.toSet()); + + assertThat(gotTxs.size(), is(createdIds.size())); + assertThat(gotTxs.stream() + .allMatch(it -> it.getStatus() == StreamTransactionStatus.running), is(true)); + + db.abortStreamTransaction(tx1.getId()).get(); + db.abortStreamTransaction(tx2.getId()).get(); + } + +} diff --git a/src/test/java/com/arangodb/async/debug/ConsolidationIntervalMsec.java b/src/test/java/com/arangodb/async/debug/ConsolidationIntervalMsec.java new file mode 100644 index 000000000..5ec5027f8 --- /dev/null +++ b/src/test/java/com/arangodb/async/debug/ConsolidationIntervalMsec.java @@ -0,0 +1,75 @@ +/* + * 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.debug; + +import com.arangodb.async.ArangoDBAsync; +import com.arangodb.async.ArangoDatabaseAsync; +import com.arangodb.entity.ViewEntity; +import com.arangodb.entity.ViewType; +import com.arangodb.entity.arangosearch.ArangoSearchPropertiesEntity; +import com.arangodb.entity.arangosearch.CollectionLink; +import com.arangodb.entity.arangosearch.FieldLink; +import com.arangodb.model.arangosearch.ArangoSearchCreateOptions; +import org.junit.Test; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author Michele Rastelli + *

+ * https://github.com/arangodb/arangodb-java-driver-async/issues/15 + */ +public class ConsolidationIntervalMsec { + + @Test + public void consolidationIntervalMsec() { + ArangoDBAsync arango = new ArangoDBAsync.Builder() + .user("root") + .password("test") + .build(); + + ArangoDatabaseAsync db = arango.db("database_of_things"); + if (db.exists().join()) { + db.drop().join(); + } + + db.create().join(); + db.collection("Thing").create().join(); + + ViewEntity result = db.createArangoSearch("ThingsSearchView", new ArangoSearchCreateOptions() + .consolidationIntervalMsec(60000L) //<== This line breaks it + .link(CollectionLink.on("Thing") + .fields(FieldLink.on("name") + .analyzers("identity")))) + .join(); + + assertThat(result.getName(), is("ThingsSearchView")); + assertThat(result.getType(), is(ViewType.ARANGO_SEARCH)); + + ArangoSearchPropertiesEntity props = db.arangoSearch("ThingsSearchView").getProperties().join(); + assertThat(props.getName(), is("ThingsSearchView")); + assertThat(props.getConsolidationIntervalMsec(), is(60000L)); + assertThat(props.getLinks().iterator().hasNext(), is(true)); + assertThat(props.getLinks().iterator().next().getName(), is("Thing")); + } + +} diff --git a/src/test/java/com/arangodb/async/example/ExampleBase.java b/src/test/java/com/arangodb/async/example/ExampleBase.java new file mode 100644 index 000000000..abf1ffaaa --- /dev/null +++ b/src/test/java/com/arangodb/async/example/ExampleBase.java @@ -0,0 +1,60 @@ +/* + * 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.example; + +import com.arangodb.async.ArangoCollectionAsync; +import com.arangodb.async.ArangoDBAsync; +import com.arangodb.async.ArangoDatabaseAsync; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import java.util.concurrent.ExecutionException; + +/** + * @author Mark Vollmary + */ +public class ExampleBase { + + protected static final String COLLECTION_NAME = "json_example_collection"; + private static final String DB_NAME = "json_example_db"; + protected static ArangoDatabaseAsync db; + protected static ArangoCollectionAsync collection; + private static ArangoDBAsync arangoDB; + + @BeforeClass + public static void setUp() throws InterruptedException, ExecutionException { + arangoDB = new ArangoDBAsync.Builder().build(); + if (arangoDB.db(DB_NAME).exists().get()) { + arangoDB.db(DB_NAME).drop().get(); + } + arangoDB.createDatabase(DB_NAME).get(); + db = arangoDB.db(DB_NAME); + db.createCollection(COLLECTION_NAME).get(); + collection = db.collection(COLLECTION_NAME); + } + + @AfterClass + public static void tearDown() throws InterruptedException, ExecutionException { + db.drop().get(); + arangoDB.shutdown(); + } + +} diff --git a/src/test/java/com/arangodb/async/example/document/AqlQueryWithSpecialReturnTypesExample.java b/src/test/java/com/arangodb/async/example/document/AqlQueryWithSpecialReturnTypesExample.java new file mode 100644 index 000000000..0afa6ad81 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/document/AqlQueryWithSpecialReturnTypesExample.java @@ -0,0 +1,138 @@ +/* + * 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.example.document; + +import com.arangodb.async.example.ExampleBase; +import com.arangodb.entity.BaseDocument; +import com.arangodb.util.MapBuilder; +import com.arangodb.velocypack.VPackSlice; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * @author Mark Vollmary + */ +public class AqlQueryWithSpecialReturnTypesExample extends ExampleBase { + + @BeforeClass + public static void before() throws InterruptedException, ExecutionException { + createExamples(); + } + + private static void createExamples() throws InterruptedException, ExecutionException { + for (int i = 0; i < 100; i++) { + final BaseDocument value = new BaseDocument(); + value.addAttribute("name", "TestUser" + i); + value.addAttribute("gender", (i % 2) == 0 ? Gender.MALE : Gender.FEMALE); + value.addAttribute("age", i + 10); + db.collection(COLLECTION_NAME).insertDocument(value).get(); + } + } + + @Test + public void aqlWithLimitQueryAsVPackObject() throws InterruptedException, ExecutionException { + final String query = "FOR t IN " + COLLECTION_NAME + + " FILTER t.age >= 20 && t.age < 30 && t.gender == @gender RETURN t"; + final Map bindVars = new MapBuilder().put("gender", Gender.FEMALE).get(); + db.query(query, bindVars, null, VPackSlice.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + cursor.forEachRemaining(vpack -> { + assertThat(vpack.get("name").getAsString(), + isOneOf("TestUser11", "TestUser13", "TestUser15", "TestUser17", "TestUser19")); + assertThat(vpack.get("gender").getAsString(), is(Gender.FEMALE.name())); + assertThat(vpack.get("age").getAsInt(), isOneOf(21, 23, 25, 27, 29)); + }); + }) + .get(); + } + + @Test + public void aqlWithLimitQueryAsVPackArray() throws InterruptedException, ExecutionException { + final String query = "FOR t IN " + COLLECTION_NAME + + " FILTER t.age >= 20 && t.age < 30 && t.gender == @gender RETURN [t.name, t.gender, t.age]"; + final Map bindVars = new MapBuilder().put("gender", Gender.FEMALE).get(); + db.query(query, bindVars, null, VPackSlice.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + cursor.forEachRemaining(vpack -> { + assertThat(vpack.get(0).getAsString(), + isOneOf("TestUser11", "TestUser13", "TestUser15", "TestUser17", "TestUser19")); + assertThat(vpack.get(1).getAsString(), is(Gender.FEMALE.name())); + assertThat(vpack.get(2).getAsInt(), isOneOf(21, 23, 25, 27, 29)); + }); + }) + .get(); + } + + @Test + public void aqlWithLimitQueryAsMap() throws InterruptedException, ExecutionException { + final String query = "FOR t IN " + COLLECTION_NAME + + " FILTER t.age >= 20 && t.age < 30 && t.gender == @gender RETURN t"; + final Map bindVars = new MapBuilder().put("gender", Gender.FEMALE).get(); + db.query(query, bindVars, null, Map.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + cursor.forEachRemaining(map -> { + assertThat(map.get("name"), is(notNullValue())); + assertThat(String.valueOf(map.get("name")), + isOneOf("TestUser11", "TestUser13", "TestUser15", "TestUser17", "TestUser19")); + assertThat(map.get("gender"), is(notNullValue())); + assertThat(String.valueOf(map.get("gender")), is(Gender.FEMALE.name())); + assertThat(map.get("age"), is(notNullValue())); + assertThat(Long.valueOf(map.get("age").toString()), isOneOf(21L, 23L, 25L, 27L, 29L)); + }); + }) + .get(); + } + + @Test + public void aqlWithLimitQueryAsList() throws InterruptedException, ExecutionException { + final String query = "FOR t IN " + COLLECTION_NAME + + " FILTER t.age >= 20 && t.age < 30 && t.gender == @gender RETURN [t.name, t.gender, t.age]"; + final Map bindVars = new MapBuilder().put("gender", Gender.FEMALE).get(); + db.query(query, bindVars, null, List.class) + .whenComplete((cursor, ex) -> { + assertThat(cursor, is(notNullValue())); + cursor.forEachRemaining(list -> { + assertThat(list.get(0), is(notNullValue())); + assertThat(String.valueOf(list.get(0)), + isOneOf("TestUser11", "TestUser13", "TestUser15", "TestUser17", "TestUser19")); + assertThat(list.get(1), is(notNullValue())); + assertThat(Gender.valueOf(String.valueOf(list.get(1))), is(Gender.FEMALE)); + assertThat(list.get(2), is(notNullValue())); + assertThat(Long.valueOf(String.valueOf(list.get(2))), isOneOf(21L, 23L, 25L, 27L, 29L)); + }); + }) + .get(); + } + + public enum Gender { + MALE, FEMALE + } +} diff --git a/src/test/java/com/arangodb/async/example/document/GetDocumentExample.java b/src/test/java/com/arangodb/async/example/document/GetDocumentExample.java new file mode 100644 index 000000000..e23623e6e --- /dev/null +++ b/src/test/java/com/arangodb/async/example/document/GetDocumentExample.java @@ -0,0 +1,94 @@ +/* + * 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.example.document; + +import com.arangodb.async.example.ExampleBase; +import com.arangodb.entity.BaseDocument; +import com.arangodb.entity.DocumentCreateEntity; +import com.arangodb.velocypack.VPackSlice; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +/** + * @author Mark Vollmary + */ +public class GetDocumentExample extends ExampleBase { + + private static String key = null; + + @BeforeClass + public static void before() throws InterruptedException, ExecutionException { + final BaseDocument value = new BaseDocument(); + value.addAttribute("foo", "bar"); + final DocumentCreateEntity doc = collection.insertDocument(value).get(); + key = doc.getKey(); + } + + @Test + public void getAsBean() throws InterruptedException, ExecutionException { + collection.getDocument(key, TestEntity.class) + .whenComplete((doc, ex) -> { + assertThat(doc, is(notNullValue())); + assertThat(doc.getFoo(), is("bar")); + }) + .get(); + } + + @Test + public void getAsBaseDocument() throws InterruptedException, ExecutionException { + collection.getDocument(key, BaseDocument.class) + .whenComplete((doc, ex) -> { + assertThat(doc, is(notNullValue())); + assertThat(doc.getAttribute("foo"), is(notNullValue())); + assertThat(String.valueOf(doc.getAttribute("foo")), is("bar")); + }) + .get(); + } + + @Test + public void getAsVPack() throws InterruptedException, ExecutionException { + collection.getDocument(key, VPackSlice.class) + .whenComplete((doc, ex) -> { + assertThat(doc, is(notNullValue())); + assertThat(doc.get("foo").isString(), is(true)); + assertThat(doc.get("foo").getAsString(), is("bar")); + }) + .get(); + } + + @Test + public void getAsJson() throws InterruptedException, ExecutionException { + collection.getDocument(key, String.class) + .whenComplete((doc, ex) -> { + assertThat(doc, is(notNullValue())); + assertThat(doc.contains("foo"), is(true)); + assertThat(doc.contains("bar"), is(true)); + }) + .get(); + } + +} diff --git a/src/test/java/com/arangodb/async/example/document/ImportDocumentExample.java b/src/test/java/com/arangodb/async/example/document/ImportDocumentExample.java new file mode 100644 index 000000000..e320d15e6 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/document/ImportDocumentExample.java @@ -0,0 +1,84 @@ +/* + * 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.example.document; + +import com.arangodb.async.example.ExampleBase; +import com.arangodb.entity.DocumentImportEntity; +import com.arangodb.model.DocumentImportOptions; +import org.junit.Test; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +/** + * @author Michele Rastelli + */ +public class ImportDocumentExample extends ExampleBase { + + private static final int MAX_PENDING_REQUESTS = 10; + + @Test + public void importDocument() { + AtomicLong pendingReqsCount = new AtomicLong(); + + Stream> chunks = IntStream.range(0, 100) + .mapToObj(i -> IntStream.range(0, 500) + .mapToObj(it -> new TestEntity(UUID.randomUUID().toString())).collect(Collectors.toList()) + ); + + List> completableFutures = chunks + .map(p -> { + // wait for pending requests + while (pendingReqsCount.get() > MAX_PENDING_REQUESTS) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + pendingReqsCount.incrementAndGet(); + return collection.importDocuments(p, new DocumentImportOptions()) + .thenApply(it -> { + pendingReqsCount.decrementAndGet(); + return it; + }); + } + ) + .collect(Collectors.toList()); + + completableFutures.forEach(cf -> { + try { + cf.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + }); + + } + +} diff --git a/src/test/java/com/arangodb/async/example/document/InsertDocumentExample.java b/src/test/java/com/arangodb/async/example/document/InsertDocumentExample.java new file mode 100644 index 000000000..55a1dd5f2 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/document/InsertDocumentExample.java @@ -0,0 +1,72 @@ +/* + * 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.example.document; + +import com.arangodb.async.example.ExampleBase; +import com.arangodb.entity.BaseDocument; +import com.arangodb.velocypack.VPackBuilder; +import com.arangodb.velocypack.ValueType; +import org.junit.Test; + +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +/** + * @author Mark Vollmary + */ +public class InsertDocumentExample extends ExampleBase { + + @Test + public void insertBean() throws ExecutionException, InterruptedException { + collection.insertDocument(new TestEntity("bar")) + .whenComplete((doc, ex) -> assertThat(doc.getKey(), is(notNullValue()))) + .get(); + } + + @Test + public void insertBaseDocument() throws ExecutionException, InterruptedException { + final BaseDocument value = new BaseDocument(); + value.addAttribute("foo", "bar"); + collection.insertDocument(value) + .whenComplete((doc, ex) -> assertThat(doc.getKey(), is(notNullValue()))) + .get(); + } + + @Test + public void insertVPack() throws ExecutionException, InterruptedException { + final VPackBuilder builder = new VPackBuilder(); + builder.add(ValueType.OBJECT).add("foo", "bar").close(); + collection.insertDocument(builder.slice()) + .whenComplete((doc, ex) -> assertThat(doc.getKey(), is(notNullValue()))) + .get(); + } + + @Test + public void insertJson() throws ExecutionException, InterruptedException { + collection.insertDocument("{\"foo\":\"bar\"}") + .whenComplete((doc, ex) -> assertThat(doc.getKey(), is(notNullValue()))) + .get(); + } + +} diff --git a/src/test/java/com/arangodb/async/example/document/TestEntity.java b/src/test/java/com/arangodb/async/example/document/TestEntity.java new file mode 100644 index 000000000..2e1330b97 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/document/TestEntity.java @@ -0,0 +1,48 @@ +/* + * 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.example.document; + +/** + * @author Mark Vollmary + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class TestEntity { + + private String foo; + + public TestEntity() { + super(); + } + + public TestEntity(final String foo) { + super(); + this.foo = foo; + } + + public String getFoo() { + return foo; + } + + public void setFoo(final String foo) { + this.foo = foo; + } + +} diff --git a/src/test/java/com/arangodb/async/example/graph/AQLActorsAndMoviesExample.java b/src/test/java/com/arangodb/async/example/graph/AQLActorsAndMoviesExample.java new file mode 100644 index 000000000..8f369ff0c --- /dev/null +++ b/src/test/java/com/arangodb/async/example/graph/AQLActorsAndMoviesExample.java @@ -0,0 +1,582 @@ +/* + * 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.example.graph; + +import com.arangodb.async.ArangoCollectionAsync; +import com.arangodb.async.ArangoCursorAsync; +import com.arangodb.async.ArangoDBAsync; +import com.arangodb.async.ArangoDatabaseAsync; +import com.arangodb.entity.BaseDocument; +import com.arangodb.entity.BaseEdgeDocument; +import com.arangodb.entity.CollectionType; +import com.arangodb.entity.DocumentCreateEntity; +import com.arangodb.model.CollectionCreateOptions; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.hasItems; +import static org.junit.Assert.assertThat; + +/** + * @author Mark Vollmary + * @see AQL Example Queries on an + * Actors and Movies Database + */ +@SuppressWarnings("JavaDoc") +public class AQLActorsAndMoviesExample { + + private static final String TEST_DB = "actors_movies_test_db"; + private static ArangoDBAsync arangoDB; + private static ArangoDatabaseAsync db; + + @BeforeClass + public static void setUp() throws InterruptedException, ExecutionException { + arangoDB = new ArangoDBAsync.Builder().build(); + if (arangoDB.db(TEST_DB).exists().get()) { + arangoDB.db(TEST_DB).drop().get(); + } + arangoDB.createDatabase(TEST_DB).get(); + db = arangoDB.db(TEST_DB); + createData(); + } + + @AfterClass + public static void tearDown() throws InterruptedException, ExecutionException { + db.drop().get(); + arangoDB.shutdown(); + } + + private static DocumentCreateEntity saveMovie( + final ArangoCollectionAsync movies, + final String key, + final String title, + final int released, + final String tagline) throws InterruptedException, ExecutionException { + final BaseDocument value = new BaseDocument(); + value.setKey(key); + value.addAttribute("title", title); + value.addAttribute("released", released); + value.addAttribute("tagline", tagline); + return movies.insertDocument(value).get(); + } + + private static DocumentCreateEntity saveActor( + final ArangoCollectionAsync actors, + final String key, + final String name, + final int born) throws InterruptedException, ExecutionException { + final BaseDocument value = new BaseDocument(); + value.setKey(key); + value.addAttribute("name", name); + value.addAttribute("born", born); + return actors.insertDocument(value).get(); + } + + private static void saveActsIn( + final ArangoCollectionAsync actsIn, + final String actor, + final String movie, + final String[] roles, + final int year) throws InterruptedException, ExecutionException { + final BaseEdgeDocument value = new BaseEdgeDocument(); + value.setFrom(actor); + value.setTo(movie); + value.addAttribute("roles", roles); + value.addAttribute("year", year); + actsIn.insertDocument(value).get(); + } + + private static void createData() throws InterruptedException, ExecutionException { + db.createCollection("actors").get(); + final ArangoCollectionAsync actors = db.collection("actors"); + db.createCollection("movies").get(); + final ArangoCollectionAsync movies = db.collection("movies"); + db.createCollection("actsIn", new CollectionCreateOptions().type(CollectionType.EDGES)).get(); + final ArangoCollectionAsync actsIn = db.collection("actsIn"); + + final String theMatrix = saveMovie(movies, "TheMatrix", "The Matrix", 1999, "Welcome to the Real World") + .getId(); + final String keanu = saveActor(actors, "Keanu", "Keanu Reeves", 1964).getId(); + final String carrie = saveActor(actors, "Carrie", "Carrie-Anne Moss", 1967).getId(); + final String laurence = saveActor(actors, "Laurence", "Laurence Fishburne", 1961).getId(); + final String hugo = saveActor(actors, "Hugo", "Hugo Weaving", 1960).getId(); + final String emil = saveActor(actors, "Emil", "Emil Eifrem", 1978).getId(); + + saveActsIn(actsIn, keanu, theMatrix, new String[]{"Neo"}, 1999); + saveActsIn(actsIn, carrie, theMatrix, new String[]{"Trinity"}, 1999); + saveActsIn(actsIn, laurence, theMatrix, new String[]{"Morpheus"}, 1999); + saveActsIn(actsIn, hugo, theMatrix, new String[]{"Agent Smith"}, 1999); + saveActsIn(actsIn, emil, theMatrix, new String[]{"Emil"}, 1999); + + final String theMatrixReloaded = saveMovie(movies, "TheMatrixReloaded", "The Matrix Reloaded", 2003, + "Free your mind").getId(); + saveActsIn(actsIn, keanu, theMatrixReloaded, new String[]{"Neo"}, 2003); + saveActsIn(actsIn, carrie, theMatrixReloaded, new String[]{"Trinity"}, 2003); + saveActsIn(actsIn, laurence, theMatrixReloaded, new String[]{"Morpheus"}, 2003); + saveActsIn(actsIn, hugo, theMatrixReloaded, new String[]{"Agent Smith"}, 2003); + + final String theMatrixRevolutions = saveMovie(movies, "TheMatrixRevolutions", "The Matrix Revolutions", 2003, + "Everything that has a beginning has an end").getId(); + saveActsIn(actsIn, keanu, theMatrixRevolutions, new String[]{"Neo"}, 2003); + saveActsIn(actsIn, carrie, theMatrixRevolutions, new String[]{"Trinity"}, 2003); + saveActsIn(actsIn, laurence, theMatrixRevolutions, new String[]{"Morpheus"}, 2003); + saveActsIn(actsIn, hugo, theMatrixRevolutions, new String[]{"Agent Smith"}, 2003); + + final String theDevilsAdvocate = saveMovie(movies, "TheDevilsAdvocate", "The Devil's Advocate", 1997, + "Evil has its winning ways").getId(); + final String charlize = saveActor(actors, "Charlize", "Charlize Theron", 1975).getId(); + final String al = saveActor(actors, "Al", "Al Pacino", 1940).getId(); + saveActsIn(actsIn, keanu, theDevilsAdvocate, new String[]{"Kevin Lomax"}, 1997); + saveActsIn(actsIn, charlize, theDevilsAdvocate, new String[]{"Mary Ann Lomax"}, 1997); + saveActsIn(actsIn, al, theDevilsAdvocate, new String[]{"John Milton"}, 1997); + + final String AFewGoodMen = saveMovie(movies, "AFewGoodMen", "A Few Good Men", 1992, + "In the heart of the nation's capital, in a courthouse of the U.S. government, one man will stop at nothing to keep his honor, and one will stop at nothing to find the truth.") + .getId(); + final String tomC = saveActor(actors, "TomC", "Tom Cruise", 1962).getId(); + final String jackN = saveActor(actors, "JackN", "Jack Nicholson", 1937).getId(); + final String demiM = saveActor(actors, "DemiM", "Demi Moore", 1962).getId(); + final String kevinB = saveActor(actors, "KevinB", "Kevin Bacon", 1958).getId(); + final String kieferS = saveActor(actors, "KieferS", "Kiefer Sutherland", 1966).getId(); + final String noahW = saveActor(actors, "NoahW", "Noah Wyle", 1971).getId(); + final String cubaG = saveActor(actors, "CubaG", "Cuba Gooding Jr.", 1968).getId(); + final String kevinP = saveActor(actors, "KevinP", "Kevin Pollak", 1957).getId(); + final String jTW = saveActor(actors, "JTW", "J.T. Walsh", 1943).getId(); + final String jamesM = saveActor(actors, "JamesM", "James Marshall", 1967).getId(); + final String christopherG = saveActor(actors, "ChristopherG", "Christopher Guest", 1948).getId(); + saveActsIn(actsIn, tomC, AFewGoodMen, new String[]{"Lt. Daniel Kaffee"}, 1992); + saveActsIn(actsIn, jackN, AFewGoodMen, new String[]{"Col. Nathan R. Jessup"}, 1992); + saveActsIn(actsIn, demiM, AFewGoodMen, new String[]{"Lt. Cdr. JoAnne Galloway"}, 1992); + saveActsIn(actsIn, kevinB, AFewGoodMen, new String[]{"Capt. Jack Ross"}, 1992); + saveActsIn(actsIn, kieferS, AFewGoodMen, new String[]{"Lt. Jonathan Kendrick"}, 1992); + saveActsIn(actsIn, noahW, AFewGoodMen, new String[]{"Cpl. Jeffrey Barnes"}, 1992); + saveActsIn(actsIn, cubaG, AFewGoodMen, new String[]{"Cpl. Carl Hammaker"}, 1992); + saveActsIn(actsIn, kevinP, AFewGoodMen, new String[]{"Lt. Sam Weinberg"}, 1992); + saveActsIn(actsIn, jTW, AFewGoodMen, new String[]{"Lt. Col. Matthew Andrew Markinson"}, 1992); + saveActsIn(actsIn, jamesM, AFewGoodMen, new String[]{"Pfc. Louden Downey"}, 1992); + saveActsIn(actsIn, christopherG, AFewGoodMen, new String[]{"Dr. Stone"}, 1992); + + final String topGun = saveMovie(movies, "TopGun", "Top Gun", 1986, "I feel the need, the need for speed.") + .getId(); + final String kellyM = saveActor(actors, "KellyM", "Kelly McGillis", 1957).getId(); + final String valK = saveActor(actors, "ValK", "Val Kilmer", 1959).getId(); + final String anthonyE = saveActor(actors, "AnthonyE", "Anthony Edwards", 1962).getId(); + final String tomS = saveActor(actors, "TomS", "Tom Skerritt", 1933).getId(); + final String megR = saveActor(actors, "MegR", "Meg Ryan", 1961).getId(); + saveActsIn(actsIn, tomC, topGun, new String[]{"Maverick"}, 1986); + saveActsIn(actsIn, kellyM, topGun, new String[]{"Charlie"}, 1986); + saveActsIn(actsIn, valK, topGun, new String[]{"Iceman"}, 1986); + saveActsIn(actsIn, anthonyE, topGun, new String[]{"Goose"}, 1986); + saveActsIn(actsIn, tomS, topGun, new String[]{"Viper"}, 1986); + saveActsIn(actsIn, megR, topGun, new String[]{"Carole"}, 1986); + + final String jerryMaguire = saveMovie(movies, "JerryMaguire", "Jerry Maguire", 2000, + "The rest of his life begins now.").getId(); + final String reneeZ = saveActor(actors, "ReneeZ", "Renee Zellweger", 1969).getId(); + final String kellyP = saveActor(actors, "KellyP", "Kelly Preston", 1962).getId(); + final String jerryO = saveActor(actors, "JerryO", "Jerry O'Connell", 1974).getId(); + final String jayM = saveActor(actors, "JayM", "Jay Mohr", 1970).getId(); + final String bonnieH = saveActor(actors, "BonnieH", "Bonnie Hunt", 1961).getId(); + final String reginaK = saveActor(actors, "ReginaK", "Regina King", 1971).getId(); + final String jonathanL = saveActor(actors, "JonathanL", "Jonathan Lipnicki", 1996).getId(); + saveActsIn(actsIn, tomC, jerryMaguire, new String[]{"Jerry Maguire"}, 2000); + saveActsIn(actsIn, cubaG, jerryMaguire, new String[]{"Rod Tidwell"}, 2000); + saveActsIn(actsIn, reneeZ, jerryMaguire, new String[]{"Dorothy Boyd"}, 2000); + saveActsIn(actsIn, kellyP, jerryMaguire, new String[]{"Avery Bishop"}, 2000); + saveActsIn(actsIn, jerryO, jerryMaguire, new String[]{"Frank Cushman"}, 2000); + saveActsIn(actsIn, jayM, jerryMaguire, new String[]{"Bob Sugar"}, 2000); + saveActsIn(actsIn, bonnieH, jerryMaguire, new String[]{"Laurel Boyd"}, 2000); + saveActsIn(actsIn, reginaK, jerryMaguire, new String[]{"Marcee Tidwell"}, 2000); + saveActsIn(actsIn, jonathanL, jerryMaguire, new String[]{"Ray Boyd"}, 2000); + + final String standByMe = saveMovie(movies, "StandByMe", "Stand By Me", 1986, + "For some, it's the last real taste of innocence, and the first real taste of life. But for everyone, it's the time that memories are made of.") + .getId(); + final String riverP = saveActor(actors, "RiverP", "River Phoenix", 1970).getId(); + final String coreyF = saveActor(actors, "CoreyF", "Corey Feldman", 1971).getId(); + final String wilW = saveActor(actors, "WilW", "Wil Wheaton", 1972).getId(); + final String johnC = saveActor(actors, "JohnC", "John Cusack", 1966).getId(); + final String marshallB = saveActor(actors, "MarshallB", "Marshall Bell", 1942).getId(); + saveActsIn(actsIn, wilW, standByMe, new String[]{"Gordie Lachance"}, 1986); + saveActsIn(actsIn, riverP, standByMe, new String[]{"Chris Chambers"}, 1986); + saveActsIn(actsIn, jerryO, standByMe, new String[]{"Vern Tessio"}, 1986); + saveActsIn(actsIn, coreyF, standByMe, new String[]{"Teddy Duchamp"}, 1986); + saveActsIn(actsIn, johnC, standByMe, new String[]{"Denny Lachance"}, 1986); + saveActsIn(actsIn, kieferS, standByMe, new String[]{"Ace Merrill"}, 1986); + saveActsIn(actsIn, marshallB, standByMe, new String[]{"Mr. Lachance"}, 1986); + + final String asGoodAsItGets = saveMovie(movies, "AsGoodAsItGets", "As Good as It Gets", 1997, + "A comedy from the heart that goes for the throat.").getId(); + final String helenH = saveActor(actors, "HelenH", "Helen Hunt", 1963).getId(); + final String gregK = saveActor(actors, "GregK", "Greg Kinnear", 1963).getId(); + saveActsIn(actsIn, jackN, asGoodAsItGets, new String[]{"Melvin Udall"}, 1997); + saveActsIn(actsIn, helenH, asGoodAsItGets, new String[]{"Carol Connelly"}, 1997); + saveActsIn(actsIn, gregK, asGoodAsItGets, new String[]{"Simon Bishop"}, 1997); + saveActsIn(actsIn, cubaG, asGoodAsItGets, new String[]{"Frank Sachs"}, 1997); + + final String whatDreamsMayCome = saveMovie(movies, "WhatDreamsMayCome", "What Dreams May Come", 1998, + "After life there is more. The end is just the beginning.").getId(); + final String annabellaS = saveActor(actors, "AnnabellaS", "Annabella Sciorra", 1960).getId(); + final String maxS = saveActor(actors, "MaxS", "Max von Sydow", 1929).getId(); + final String wernerH = saveActor(actors, "WernerH", "Werner Herzog", 1942).getId(); + final String robin = saveActor(actors, "Robin", "Robin Williams", 1951).getId(); + saveActsIn(actsIn, robin, whatDreamsMayCome, new String[]{"Chris Nielsen"}, 1998); + saveActsIn(actsIn, cubaG, whatDreamsMayCome, new String[]{"Albert Lewis"}, 1998); + saveActsIn(actsIn, annabellaS, whatDreamsMayCome, new String[]{"Annie Collins-Nielsen"}, 1998); + saveActsIn(actsIn, maxS, whatDreamsMayCome, new String[]{"The Tracker"}, 1998); + saveActsIn(actsIn, wernerH, whatDreamsMayCome, new String[]{"The Face"}, 1998); + + final String snowFallingonCedars = saveMovie(movies, "SnowFallingonCedars", "Snow Falling on Cedars", 1999, + "First loves last. Forever.").getId(); + final String ethanH = saveActor(actors, "EthanH", "Ethan Hawke", 1970).getId(); + final String rickY = saveActor(actors, "RickY", "Rick Yune", 1971).getId(); + final String jamesC = saveActor(actors, "JamesC", "James Cromwell", 1940).getId(); + saveActsIn(actsIn, ethanH, snowFallingonCedars, new String[]{"Ishmael Chambers"}, 1999); + saveActsIn(actsIn, rickY, snowFallingonCedars, new String[]{"Kazuo Miyamoto"}, 1999); + saveActsIn(actsIn, maxS, snowFallingonCedars, new String[]{"Nels Gudmundsson"}, 1999); + saveActsIn(actsIn, jamesC, snowFallingonCedars, new String[]{"Judge Fielding"}, 1999); + + final String youveGotMail = saveMovie(movies, "YouveGotMail", "You've Got Mail", 1998, + "At odds in life... in love on-line.").getId(); + final String parkerP = saveActor(actors, "ParkerP", "Parker Posey", 1968).getId(); + final String daveC = saveActor(actors, "DaveC", "Dave Chappelle", 1973).getId(); + final String steveZ = saveActor(actors, "SteveZ", "Steve Zahn", 1967).getId(); + final String tomH = saveActor(actors, "TomH", "Tom Hanks", 1956).getId(); + saveActsIn(actsIn, tomH, youveGotMail, new String[]{"Joe Fox"}, 1998); + saveActsIn(actsIn, megR, youveGotMail, new String[]{"Kathleen Kelly"}, 1998); + saveActsIn(actsIn, gregK, youveGotMail, new String[]{"Frank Navasky"}, 1998); + saveActsIn(actsIn, parkerP, youveGotMail, new String[]{"Patricia Eden"}, 1998); + saveActsIn(actsIn, daveC, youveGotMail, new String[]{"Kevin Jackson"}, 1998); + saveActsIn(actsIn, steveZ, youveGotMail, new String[]{"George Pappas"}, 1998); + + final String sleeplessInSeattle = saveMovie(movies, "SleeplessInSeattle", "Sleepless in Seattle", 1993, + "What if someone you never met, someone you never saw, someone you never knew was the only someone for you?") + .getId(); + final String ritaW = saveActor(actors, "RitaW", "Rita Wilson", 1956).getId(); + final String billPull = saveActor(actors, "BillPull", "Bill Pullman", 1953).getId(); + final String victorG = saveActor(actors, "VictorG", "Victor Garber", 1949).getId(); + final String rosieO = saveActor(actors, "RosieO", "Rosie O'Donnell", 1962).getId(); + saveActsIn(actsIn, tomH, sleeplessInSeattle, new String[]{"Sam Baldwin"}, 1993); + saveActsIn(actsIn, megR, sleeplessInSeattle, new String[]{"Annie Reed"}, 1993); + saveActsIn(actsIn, ritaW, sleeplessInSeattle, new String[]{"Suzy"}, 1993); + saveActsIn(actsIn, billPull, sleeplessInSeattle, new String[]{"Walter"}, 1993); + saveActsIn(actsIn, victorG, sleeplessInSeattle, new String[]{"Greg"}, 1993); + saveActsIn(actsIn, rosieO, sleeplessInSeattle, new String[]{"Becky"}, 1993); + + final String joeVersustheVolcano = saveMovie(movies, "JoeVersustheVolcano", "Joe Versus the Volcano", 1990, + "A story of love, lava and burning desire.").getId(); + final String nathan = saveActor(actors, "Nathan", "Nathan Lane", 1956).getId(); + saveActsIn(actsIn, tomH, joeVersustheVolcano, new String[]{"Joe Banks"}, 1990); + saveActsIn(actsIn, megR, joeVersustheVolcano, + new String[]{"DeDe', 'Angelica Graynamore', 'Patricia Graynamore"}, 1990); + saveActsIn(actsIn, nathan, joeVersustheVolcano, new String[]{"Baw"}, 1990); + + final String whenHarryMetSally = saveMovie(movies, "WhenHarryMetSally", "When Harry Met Sally", 1998, + "At odds in life... in love on-line.").getId(); + final String billyC = saveActor(actors, "BillyC", "Billy Crystal", 1948).getId(); + final String carrieF = saveActor(actors, "CarrieF", "Carrie Fisher", 1956).getId(); + final String brunoK = saveActor(actors, "BrunoK", "Bruno Kirby", 1949).getId(); + saveActsIn(actsIn, billyC, whenHarryMetSally, new String[]{"Harry Burns"}, 1998); + saveActsIn(actsIn, megR, whenHarryMetSally, new String[]{"Sally Albright"}, 1998); + saveActsIn(actsIn, carrieF, whenHarryMetSally, new String[]{"Marie"}, 1998); + saveActsIn(actsIn, brunoK, whenHarryMetSally, new String[]{"Jess"}, 1998); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void allActorsActsInMovie1or2() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "WITH actors FOR x IN ANY 'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN x._id", + null, null, String.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), + hasItems("actors/Keanu", "actors/Hugo", "actors/Emil", "actors/Carrie", "actors/Laurence"))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void allActorsActsInMovie1or2UnionDistinct() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "WITH actors FOR x IN UNION_DISTINCT ((FOR y IN ANY 'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id)) RETURN x", + null, null, String.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), hasItems("actors/Emil", "actors/Hugo", "actors/Carrie", + "actors/Laurence", "actors/Keanu", "actors/Al", "actors/Charlize"))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void allActorsActsInMovie1and2() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "WITH actors FOR x IN INTERSECTION ((FOR y IN ANY 'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id)) RETURN x", + null, null, String.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), hasItems("actors/Keanu"))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void allMoviesBetweenActor1andActor2() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "WITH movies FOR x IN INTERSECTION ((FOR y IN ANY 'actors/Hugo' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id), (FOR y IN ANY 'actors/Keanu' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id)) RETURN x", + null, null, String.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), + hasItems("movies/TheMatrixRevolutions", "movies/TheMatrixReloaded", "movies/TheMatrix"))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void allActorsWhoActedIn3orMoreMovies() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "FOR x IN actsIn COLLECT actor = x._from WITH COUNT INTO counter FILTER counter >= 3 RETURN {actor: actor, movies: counter}", + null, null, Actor.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), + hasItems(new Actor("actors/Carrie", 3), new Actor("actors/CubaG", 4), new Actor("actors/Hugo", 3), + new Actor("actors/Keanu", 4), new Actor("actors/Laurence", 3), new Actor("actors/MegR", 5), + new Actor("actors/TomC", 3), new Actor("actors/TomH", 3)))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void allMoviesWhereExactly6ActorsActedIn() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter FILTER counter == 6 RETURN movie", null, + null, String.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), + hasItems("movies/SleeplessInSeattle", "movies/TopGun", "movies/YouveGotMail"))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void theNumberOfActorsByMovie() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN {movie: movie, actors: counter}", + null, null, Movie.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), + hasItems(new Movie("movies/AFewGoodMen", 11), new Movie("movies/AsGoodAsItGets", 4), + new Movie("movies/JerryMaguire", 9), new Movie("movies/JoeVersustheVolcano", 3), + new Movie("movies/SleeplessInSeattle", 6), new Movie("movies/SnowFallingonCedars", 4), + new Movie("movies/StandByMe", 7), new Movie("movies/TheDevilsAdvocate", 3), + new Movie("movies/TheMatrix", 5), new Movie("movies/TheMatrixReloaded", 4), + new Movie("movies/TheMatrixRevolutions", 4), new Movie("movies/TopGun", 6), + new Movie("movies/WhatDreamsMayCome", 5), new Movie("movies/WhenHarryMetSally", 4), + new Movie("movies/YouveGotMail", 6)))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void theNumberOfMoviesByActor() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "FOR x IN actsIn COLLECT actor = x._from WITH COUNT INTO counter RETURN {actor: actor, movies: counter}", + null, null, Actor.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), + hasItems(new Actor("actors/Al", 1), new Actor("actors/AnnabellaS", 1), new Actor("actors/AnthonyE", 1), + new Actor("actors/BillPull", 1), new Actor("actors/BillyC", 1), new Actor("actors/BonnieH", 1), + new Actor("actors/BrunoK", 1), new Actor("actors/Carrie", 3), new Actor("actors/CarrieF", 1), + new Actor("actors/Charlize", 1), new Actor("actors/ChristopherG", 1), new Actor("actors/CoreyF", 1), + new Actor("actors/CubaG", 4), new Actor("actors/DaveC", 1), new Actor("actors/DemiM", 1), + new Actor("actors/Emil", 1), new Actor("actors/EthanH", 1), new Actor("actors/GregK", 2), + new Actor("actors/HelenH", 1), new Actor("actors/Hugo", 3), new Actor("actors/JackN", 2), + new Actor("actors/JamesC", 1), new Actor("actors/JamesM", 1), new Actor("actors/JayM", 1), + new Actor("actors/JerryO", 2), new Actor("actors/JohnC", 1), new Actor("actors/JonathanL", 1), + new Actor("actors/JTW", 1), new Actor("actors/Keanu", 4), new Actor("actors/KellyM", 1), + new Actor("actors/KellyP", 1), new Actor("actors/KevinB", 1), new Actor("actors/KevinP", 1), + new Actor("actors/KieferS", 2), new Actor("actors/Laurence", 3), new Actor("actors/MarshallB", 1), + new Actor("actors/MaxS", 2), new Actor("actors/MegR", 5), new Actor("actors/Nathan", 1), + new Actor("actors/NoahW", 1), new Actor("actors/ParkerP", 1), new Actor("actors/ReginaK", 1), + new Actor("actors/ReneeZ", 1), new Actor("actors/RickY", 1), new Actor("actors/RitaW", 1), + new Actor("actors/RiverP", 1), new Actor("actors/Robin", 1), new Actor("actors/RosieO", 1), + new Actor("actors/SteveZ", 1), new Actor("actors/TomC", 3), new Actor("actors/TomH", 3), + new Actor("actors/TomS", 1), new Actor("actors/ValK", 1), new Actor("actors/VictorG", 1), + new Actor("actors/WernerH", 1), new Actor("actors/WilW", 1)))).get(); + } + + /** + * @throws ExecutionException + * @throws InterruptedException + * @see AQL + * Example Queries on an Actors and Movies Database + */ + @Test + public void theNumberOfMoviesActedInBetween2005and2010byActor() throws InterruptedException, ExecutionException { + final CompletableFuture> f = db.query( + "FOR x IN actsIn FILTER x.year >= 1990 && x.year <= 1995 COLLECT actor = x._from WITH COUNT INTO counter RETURN {actor: actor, movies: counter}", + null, null, Actor.class); + f.whenComplete((cursor, ex) -> assertThat(cursor.asListRemaining(), + hasItems(new Actor("actors/BillPull", 1), new Actor("actors/ChristopherG", 1), + new Actor("actors/CubaG", 1), new Actor("actors/DemiM", 1), new Actor("actors/JackN", 1), + new Actor("actors/JamesM", 1), new Actor("actors/JTW", 1), new Actor("actors/KevinB", 1), + new Actor("actors/KieferS", 1), new Actor("actors/MegR", 2), new Actor("actors/Nathan", 1), + new Actor("actors/NoahW", 1), new Actor("actors/RitaW", 1), new Actor("actors/RosieO", 1), + new Actor("actors/TomC", 1), new Actor("actors/TomH", 2), new Actor("actors/VictorG", 1)))).get(); + } + + @SuppressWarnings("WeakerAccess") + public static class Actor { + private String actor; + private Integer movies; + + public Actor() { + super(); + } + + public Actor(final String actor, final Integer movies) { + super(); + this.actor = actor; + this.movies = movies; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((actor == null) ? 0 : actor.hashCode()); + result = prime * result + ((movies == null) ? 0 : movies.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Actor other = (Actor) obj; + if (actor == null) { + if (other.actor != null) { + return false; + } + } else if (!actor.equals(other.actor)) { + return false; + } + if (movies == null) { + return other.movies == null; + } else return movies.equals(other.movies); + } + + } + + @SuppressWarnings("WeakerAccess") + public static class Movie { + private String movie; + private Integer actors; + + public Movie() { + super(); + } + + public Movie(final String movie, final Integer actors) { + super(); + this.movie = movie; + this.actors = actors; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((actors == null) ? 0 : actors.hashCode()); + result = prime * result + ((movie == null) ? 0 : movie.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Movie other = (Movie) obj; + if (actors == null) { + if (other.actors != null) { + return false; + } + } else if (!actors.equals(other.actors)) { + return false; + } + if (movie == null) { + return other.movie == null; + } else return movie.equals(other.movie); + } + + } + +} diff --git a/src/test/java/com/arangodb/async/example/graph/BaseGraphTest.java b/src/test/java/com/arangodb/async/example/graph/BaseGraphTest.java new file mode 100644 index 000000000..ac5621891 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/graph/BaseGraphTest.java @@ -0,0 +1,112 @@ +/* + * 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.example.graph; + +import com.arangodb.async.ArangoDBAsync; +import com.arangodb.async.ArangoDatabaseAsync; +import com.arangodb.entity.EdgeDefinition; +import com.arangodb.entity.VertexEntity; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.ExecutionException; + +/** + * @author Mark Vollmary + */ +public abstract class BaseGraphTest { + + private static final String TEST_DB = "java_driver_graph_test_db"; + private static final String GRAPH_NAME = "traversalGraph"; + private static final String EDGE_COLLECTION_NAME = "edges"; + private static final String VERTEXT_COLLECTION_NAME = "circles"; + static ArangoDatabaseAsync db; + private static ArangoDBAsync arangoDB; + + @BeforeClass + public static void init() throws InterruptedException, ExecutionException { + if (arangoDB == null) { + arangoDB = new ArangoDBAsync.Builder().build(); + } + if (arangoDB.db(TEST_DB).exists().get()) { + arangoDB.db(TEST_DB).drop().get(); + } + arangoDB.createDatabase(TEST_DB).get(); + BaseGraphTest.db = arangoDB.db(TEST_DB); + + final Collection edgeDefinitions = new ArrayList<>(); + final EdgeDefinition edgeDefinition = new EdgeDefinition().collection(EDGE_COLLECTION_NAME) + .from(VERTEXT_COLLECTION_NAME).to(VERTEXT_COLLECTION_NAME); + edgeDefinitions.add(edgeDefinition); + db.createGraph(GRAPH_NAME, edgeDefinitions, null).get(); + addExampleElements(); + } + + @AfterClass + public static void shutdown() throws InterruptedException, ExecutionException { + arangoDB.db(TEST_DB).drop().get(); + arangoDB.shutdown(); + arangoDB = null; + } + + private static void addExampleElements() throws InterruptedException, ExecutionException { + + // Add circle circles + final VertexEntity vA = createVertex(new Circle("A", "1")); + final VertexEntity vB = createVertex(new Circle("B", "2")); + final VertexEntity vC = createVertex(new Circle("C", "3")); + final VertexEntity vD = createVertex(new Circle("D", "4")); + final VertexEntity vE = createVertex(new Circle("E", "5")); + final VertexEntity vF = createVertex(new Circle("F", "6")); + final VertexEntity vG = createVertex(new Circle("G", "7")); + final VertexEntity vH = createVertex(new Circle("H", "8")); + final VertexEntity vI = createVertex(new Circle("I", "9")); + final VertexEntity vJ = createVertex(new Circle("J", "10")); + final VertexEntity vK = createVertex(new Circle("K", "11")); + + // Add relevant edges - left branch: + saveEdge(new CircleEdge(vA.getId(), vB.getId(), false, true, "left_bar")); + saveEdge(new CircleEdge(vB.getId(), vC.getId(), false, true, "left_blarg")); + saveEdge(new CircleEdge(vC.getId(), vD.getId(), false, true, "left_blorg")); + saveEdge(new CircleEdge(vB.getId(), vE.getId(), false, true, "left_blub")); + saveEdge(new CircleEdge(vE.getId(), vF.getId(), false, true, "left_schubi")); + + // Add relevant edges - right branch: + saveEdge(new CircleEdge(vA.getId(), vG.getId(), false, true, "right_foo")); + saveEdge(new CircleEdge(vG.getId(), vH.getId(), false, true, "right_blob")); + saveEdge(new CircleEdge(vH.getId(), vI.getId(), false, true, "right_blub")); + saveEdge(new CircleEdge(vG.getId(), vJ.getId(), false, true, "right_zip")); + saveEdge(new CircleEdge(vJ.getId(), vK.getId(), false, true, "right_zup")); + } + + private static void saveEdge(final CircleEdge edge) + throws InterruptedException, ExecutionException { + db.graph(GRAPH_NAME).edgeCollection(EDGE_COLLECTION_NAME).insertEdge(edge).get(); + } + + private static VertexEntity createVertex(final Circle vertex) + throws InterruptedException, ExecutionException { + return db.graph(GRAPH_NAME).vertexCollection(VERTEXT_COLLECTION_NAME).insertVertex(vertex).get(); + } + +} diff --git a/src/test/java/com/arangodb/async/example/graph/Circle.java b/src/test/java/com/arangodb/async/example/graph/Circle.java new file mode 100644 index 000000000..b37714386 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/graph/Circle.java @@ -0,0 +1,80 @@ +/* + * 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.example.graph; + +import com.arangodb.entity.DocumentField; +import com.arangodb.entity.DocumentField.Type; + +/** + * @author a-brandt + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class Circle { + + @DocumentField(Type.ID) + private String id; + + @DocumentField(Type.KEY) + private String key; + + @DocumentField(Type.REV) + private String revision; + + private String label; + + public Circle(String key, String label) { + this.key = key; + this.label = label; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getRevision() { + return revision; + } + + public void setRevision(String revision) { + this.revision = revision; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + +} diff --git a/src/test/java/com/arangodb/async/example/graph/CircleEdge.java b/src/test/java/com/arangodb/async/example/graph/CircleEdge.java new file mode 100644 index 000000000..970809116 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/graph/CircleEdge.java @@ -0,0 +1,124 @@ +/* + * 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.example.graph; + +import com.arangodb.entity.DocumentField; +import com.arangodb.entity.DocumentField.Type; + +/** + * @author a-brandt + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class CircleEdge { + + @DocumentField(Type.ID) + private String id; + + @DocumentField(Type.KEY) + private String key; + + @DocumentField(Type.REV) + private String revision; + + @DocumentField(Type.FROM) + private String from; + + @DocumentField(Type.TO) + private String to; + + private Boolean theFalse; + private Boolean theTruth; + private String label; + + public CircleEdge(final String from, final String to, final Boolean theFalse, final Boolean theTruth, + final String label) { + this.from = from; + this.to = to; + this.theFalse = theFalse; + this.theTruth = theTruth; + this.label = label; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getRevision() { + return revision; + } + + public void setRevision(String revision) { + this.revision = revision; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public Boolean getTheFalse() { + return theFalse; + } + + public void setTheFalse(Boolean theFalse) { + this.theFalse = theFalse; + } + + public Boolean getTheTruth() { + return theTruth; + } + + public void setTheTruth(Boolean theTruth) { + this.theTruth = theTruth; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + +} diff --git a/src/test/java/com/arangodb/async/example/graph/GraphTraversalsInAQLExample.java b/src/test/java/com/arangodb/async/example/graph/GraphTraversalsInAQLExample.java new file mode 100644 index 000000000..cd9ac367f --- /dev/null +++ b/src/test/java/com/arangodb/async/example/graph/GraphTraversalsInAQLExample.java @@ -0,0 +1,119 @@ +/* + * 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.example.graph; + +import com.arangodb.async.ArangoCursorAsync; +import org.junit.Test; + +import java.util.Collection; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Graph traversals in AQL + * + * @author a-brandt + * @see Graph traversals in AQL + */ +public class GraphTraversalsInAQLExample extends BaseGraphTest { + + @Test + public void queryAllVertices() throws InterruptedException, ExecutionException { + String queryString = "FOR v IN 1..3 OUTBOUND 'circles/A' GRAPH 'traversalGraph' RETURN v._key"; + ArangoCursorAsync cursor = db.query(queryString, null, null, String.class).get(); + Collection result = cursor.asListRemaining(); + assertThat(result.size(), is(10)); + + queryString = "WITH circles FOR v IN 1..3 OUTBOUND 'circles/A' edges RETURN v._key"; + cursor = db.query(queryString, null, null, String.class).get(); + result = cursor.asListRemaining(); + assertThat(result.size(), is(10)); + } + + @Test + public void queryDepthTwo() throws InterruptedException, ExecutionException { + String queryString = "FOR v IN 2..2 OUTBOUND 'circles/A' GRAPH 'traversalGraph' return v._key"; + ArangoCursorAsync cursor = db.query(queryString, null, null, String.class).get(); + Collection result = cursor.asListRemaining(); + assertThat(result.size(), is(4)); + assertThat(result, hasItems("C", "E", "H", "J")); + + queryString = "FOR v IN 2 OUTBOUND 'circles/A' GRAPH 'traversalGraph' return v._key"; + cursor = db.query(queryString, null, null, String.class).get(); + result = cursor.asListRemaining(); + assertThat(result.size(), is(4)); + assertThat(result, hasItems("C", "E", "H", "J")); + } + + @Test + public void queryWithFilter() throws InterruptedException, ExecutionException { + String queryString = "FOR v, e, p IN 1..3 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.vertices[1]._key != 'G' RETURN v._key"; + ArangoCursorAsync cursor = db.query(queryString, null, null, String.class).get(); + Collection result = cursor.asListRemaining(); + assertThat(result.size(), is(5)); + assertThat(result, hasItems("B", "C", "D", "E", "F")); + + queryString = "FOR v, e, p IN 1..3 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.edges[0].label != 'right_foo' RETURN v._key"; + cursor = db.query(queryString, null, null, String.class).get(); + result = cursor.asListRemaining(); + assertThat(result.size(), is(5)); + assertThat(result, hasItems("B", "C", "D", "E", "F")); + + queryString = "FOR v,e,p IN 1..3 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.vertices[1]._key != 'G' FILTER p.edges[1].label != 'left_blub' return v._key"; + cursor = db.query(queryString, null, null, String.class).get(); + + result = cursor.asListRemaining(); + assertThat(result.size(), is(3)); + assertThat(result, hasItems("B", "C", "D")); + + queryString = "FOR v,e,p IN 1..3 OUTBOUND 'circles/A' GRAPH 'traversalGraph' FILTER p.vertices[1]._key != 'G' AND p.edges[1].label != 'left_blub' return v._key"; + cursor = db.query(queryString, null, null, String.class).get(); + result = cursor.asListRemaining(); + assertThat(result.size(), is(3)); + assertThat(result, hasItems("B", "C", "D")); + } + + @Test + public void queryOutboundInbound() throws InterruptedException, ExecutionException { + String queryString = "FOR v IN 1..3 OUTBOUND 'circles/E' GRAPH 'traversalGraph' return v._key"; + ArangoCursorAsync cursor = db.query(queryString, null, null, String.class).get(); + Collection result = cursor.asListRemaining(); + assertThat(result.size(), is(1)); + assertThat(result, hasItems("F")); + + queryString = "FOR v IN 1..3 INBOUND 'circles/E' GRAPH 'traversalGraph' return v._key"; + cursor = db.query(queryString, null, null, String.class).get(); + result = cursor.asListRemaining(); + assertThat(result.size(), is(2)); + assertThat(result, hasItems("B", "A")); + + queryString = "FOR v IN 1..3 ANY 'circles/E' GRAPH 'traversalGraph' return v._key"; + cursor = db.query(queryString, null, null, String.class).get(); + + result = cursor.asListRemaining(); + assertThat(result.size(), is(6)); + assertThat(result, hasItems("F", "B", "C", "D", "A", "G")); + } + +} diff --git a/src/test/java/com/arangodb/async/example/graph/ShortestPathInAQLExample.java b/src/test/java/com/arangodb/async/example/graph/ShortestPathInAQLExample.java new file mode 100644 index 000000000..021ae91bb --- /dev/null +++ b/src/test/java/com/arangodb/async/example/graph/ShortestPathInAQLExample.java @@ -0,0 +1,104 @@ +/* + * 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.example.graph; + +import com.arangodb.async.ArangoCursorAsync; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Shortest Path in AQL + * + * @author a-brandt + * @see Shortest Path in AQL + */ +public class ShortestPathInAQLExample extends BaseGraphTest { + + @Test + public void queryShortestPathFromAToD() throws InterruptedException, ExecutionException { + String queryString = "FOR v, e IN OUTBOUND SHORTEST_PATH 'circles/A' TO 'circles/D' GRAPH 'traversalGraph' RETURN {'vertex': v._key, 'edge': e._key}"; + ArangoCursorAsync cursor = db.query(queryString, null, null, Pair.class).get(); + final Collection collection = toVertexCollection(cursor); + assertThat(collection.size(), is(4)); + assertThat(collection, hasItems("A", "B", "C", "D")); + + queryString = "WITH circles FOR v, e IN OUTBOUND SHORTEST_PATH 'circles/A' TO 'circles/D' edges RETURN {'vertex': v._key, 'edge': e._key}"; + db.query(queryString, null, null, Pair.class).get(); + assertThat(collection.size(), is(4)); + assertThat(collection, hasItems("A", "B", "C", "D")); + } + + @Test + public void queryShortestPathByFilter() throws InterruptedException, ExecutionException { + String queryString = "FOR a IN circles FILTER a._key == 'A' FOR d IN circles FILTER d._key == 'D' FOR v, e IN OUTBOUND SHORTEST_PATH a TO d GRAPH 'traversalGraph' RETURN {'vertex':v._key, 'edge':e._key}"; + ArangoCursorAsync cursor = db.query(queryString, null, null, Pair.class).get(); + final Collection collection = toVertexCollection(cursor); + assertThat(collection.size(), is(4)); + assertThat(collection, hasItems("A", "B", "C", "D")); + + queryString = "FOR a IN circles FILTER a._key == 'A' FOR d IN circles FILTER d._key == 'D' FOR v, e IN OUTBOUND SHORTEST_PATH a TO d edges RETURN {'vertex': v._key, 'edge': e._key}"; + db.query(queryString, null, null, Pair.class).get(); + assertThat(collection.size(), is(4)); + assertThat(collection, hasItems("A", "B", "C", "D")); + } + + private Collection toVertexCollection(final ArangoCursorAsync cursor) { + final List result = new ArrayList<>(); + for (; cursor.hasNext(); ) { + final Pair pair = cursor.next(); + result.add(pair.getVertex()); + } + return result; + } + + @SuppressWarnings({"WeakerAccess", "unused"}) + public static class Pair { + + private String vertex; + private String edge; + + public String getVertex() { + return vertex; + } + + public void setVertex(final String vertex) { + this.vertex = vertex; + } + + public String getEdge() { + return edge; + } + + public void setEdge(final String edge) { + this.edge = edge; + } + + } + +} diff --git a/src/test/java/com/arangodb/async/example/ssl/SslExample.java b/src/test/java/com/arangodb/async/example/ssl/SslExample.java new file mode 100644 index 000000000..16f19e3bb --- /dev/null +++ b/src/test/java/com/arangodb/async/example/ssl/SslExample.java @@ -0,0 +1,76 @@ +/* + * 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.example.ssl; + +import com.arangodb.async.ArangoDBAsync; +import com.arangodb.entity.ArangoDBVersion; +import org.junit.Ignore; +import org.junit.Test; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.security.KeyStore; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +/** + * @author Mark Vollmary + */ +public class SslExample { + + /*- + * a SSL trust store + * + * create the trust store for the self signed certificate: + * keytool -import -alias "my arangodb server cert" -file UnitTests/server.pem -keystore example.truststore + * + * Documentation: + * https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ssl/SSLSocketFactory.html + */ + private static final String SSL_TRUSTSTORE = "/example.truststore"; + private static final String SSL_TRUSTSTORE_PASSWORD = "12345678"; + + @Test + @Ignore + public void connect() throws Exception { + final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + ks.load(this.getClass().getResourceAsStream(SSL_TRUSTSTORE), SSL_TRUSTSTORE_PASSWORD.toCharArray()); + + final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, SSL_TRUSTSTORE_PASSWORD.toCharArray()); + + final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + + final SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + final ArangoDBAsync arangoDB = new ArangoDBAsync.Builder() + .loadProperties(SslExample.class.getResourceAsStream("/arangodb-ssl.properties")).useSsl(true) + .sslContext(sc).build(); + final ArangoDBVersion version = arangoDB.getVersion().get(); + assertThat(version, is(notNullValue())); + } + +} diff --git a/src/test/java/com/arangodb/async/example/velocypack/VPackExample.java b/src/test/java/com/arangodb/async/example/velocypack/VPackExample.java new file mode 100644 index 000000000..5eb76c232 --- /dev/null +++ b/src/test/java/com/arangodb/async/example/velocypack/VPackExample.java @@ -0,0 +1,113 @@ +/* + * 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.example.velocypack; + +import com.arangodb.velocypack.VPackBuilder; +import com.arangodb.velocypack.VPackSlice; +import com.arangodb.velocypack.ValueType; +import com.arangodb.velocypack.exception.VPackException; +import org.junit.Test; + +import java.util.Iterator; +import java.util.Map.Entry; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author Mark Vollmary + */ +public class VPackExample { + + @Test + public void buildObject() throws VPackException { + final VPackBuilder builder = new VPackBuilder(); + builder.add(ValueType.OBJECT);// object start + builder.add("foo", 1); // add field "foo" with value 1 + builder.add("bar", 2); // add field "bar" with value 2 + builder.close();// object end + + final VPackSlice slice = builder.slice(); // create slice + assertThat(slice.isObject(), is(true)); + assertThat(slice.size(), is(2)); // number of fields + + final VPackSlice foo = slice.get("foo"); // get field "foo" + assertThat(foo.isInteger(), is(true)); + assertThat(foo.getAsInt(), is(1)); + + final VPackSlice bar = slice.get("bar"); // get field "bar" + assertThat(bar.isInteger(), is(true)); + assertThat(bar.getAsInt(), is(2)); + + // iterate over the fields + for (final Iterator> iterator = slice.objectIterator(); iterator.hasNext(); ) { + final Entry field = iterator.next(); + assertThat(field.getValue().isInteger(), is(true)); + } + } + + @Test + public void buildArray() throws VPackException { + final VPackBuilder builder = new VPackBuilder(); + builder.add(ValueType.ARRAY); // array start + builder.add(1);// add value 1 + builder.add(2);// add value 2 + builder.add(3);// add value 3 + builder.close(); // array end + + final VPackSlice slice = builder.slice();// create slice + assertThat(slice.isArray(), is(true)); + assertThat(slice.size(), is(3));// number of values + + // iterate over values + for (int i = 0; i < slice.size(); i++) { + final VPackSlice value = slice.get(i); + assertThat(value.isInteger(), is(true)); + assertThat(value.getAsInt(), is(i + 1)); + } + + // iterate over values with Iterator + for (final Iterator iterator = slice.arrayIterator(); iterator.hasNext(); ) { + final VPackSlice value = iterator.next(); + assertThat(value.isInteger(), is(true)); + } + } + + @Test + public void buildObjectInObject() throws VPackException { + final VPackBuilder builder = new VPackBuilder(); + builder.add(ValueType.OBJECT);// object start + builder.add("foo", ValueType.OBJECT); // add object in field "foo" + builder.add("bar", 2); // add field "bar" with value 2 to object "foo" + builder.close();// object "foo" end + builder.close();// object end + + final VPackSlice slice = builder.slice(); // create slice + assertThat(slice.isObject(), is(true)); + + final VPackSlice foo = slice.get("foo"); + assertThat(foo.isObject(), is(true)); + + final VPackSlice bar = foo.get("bar"); // get field "bar" from "foo" + assertThat(bar.isInteger(), is(true)); + } + +} diff --git a/src/test/java/com/arangodb/async/serde/CustomSerdeTest.java b/src/test/java/com/arangodb/async/serde/CustomSerdeTest.java new file mode 100644 index 000000000..ae733b326 --- /dev/null +++ b/src/test/java/com/arangodb/async/serde/CustomSerdeTest.java @@ -0,0 +1,168 @@ +/* + * 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.serde; + + +import com.arangodb.VelocyJack; +import com.arangodb.async.ArangoCollectionAsync; +import com.arangodb.async.ArangoDBAsync; +import com.arangodb.async.ArangoDatabaseAsync; +import com.arangodb.entity.BaseDocument; +import com.arangodb.model.DocumentCreateOptions; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.HashMap; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import static com.fasterxml.jackson.databind.DeserializationFeature.USE_BIG_INTEGER_FOR_INTS; +import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author Michele Rastelli + */ +public class CustomSerdeTest { + + private static final String COLLECTION_NAME = "collection"; + + private ArangoDatabaseAsync db; + private ArangoCollectionAsync collection; + + @Before + public void init() throws ExecutionException, InterruptedException { + VelocyJack velocyJack = new VelocyJack(); + velocyJack.configure((mapper) -> { + mapper.configure(WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, true); + mapper.configure(USE_BIG_INTEGER_FOR_INTS, true); + }); + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().serializer(velocyJack).build(); + + String TEST_DB = "custom-serde-test"; + db = arangoDB.db(TEST_DB); + if (!db.exists().get()) { + db.create().get(); + } + + collection = db.collection(COLLECTION_NAME); + if (!collection.exists().get()) { + collection.create().get(); + } + } + + @After + public void shutdown() throws ExecutionException, InterruptedException { + db.drop().get(); + } + + @Test + public void aqlSerialization() throws ExecutionException, InterruptedException { + String key = "test-" + UUID.randomUUID().toString(); + + BaseDocument doc = new BaseDocument(key); + doc.addAttribute("arr", Collections.singletonList("hello")); + doc.addAttribute("int", 10); + + HashMap params = new HashMap<>(); + params.put("doc", doc); + params.put("@collection", COLLECTION_NAME); + + BaseDocument result = db.query( + "INSERT @doc INTO @@collection RETURN NEW", + params, + BaseDocument.class + ).get().first(); + + assertThat(result.getAttribute("arr"), instanceOf(String.class)); + assertThat(result.getAttribute("arr"), is("hello")); + assertThat(result.getAttribute("int"), instanceOf(BigInteger.class)); + assertThat(result.getAttribute("int"), is(BigInteger.valueOf(10))); + } + + @Test + public void aqlDeserialization() throws ExecutionException, InterruptedException { + String key = "test-" + UUID.randomUUID().toString(); + + BaseDocument doc = new BaseDocument(key); + doc.addAttribute("arr", Collections.singletonList("hello")); + doc.addAttribute("int", 10); + + collection.insertDocument(doc, null).get(); + + final BaseDocument result = db.query( + "RETURN DOCUMENT(@docId)", + Collections.singletonMap("docId", COLLECTION_NAME + "/" + key), + BaseDocument.class + ).get().first(); + + assertThat(result.getAttribute("arr"), instanceOf(String.class)); + assertThat(result.getAttribute("arr"), is("hello")); + assertThat(result.getAttribute("int"), instanceOf(BigInteger.class)); + assertThat(result.getAttribute("int"), is(BigInteger.valueOf(10))); + } + + @Test + public void insertDocument() throws ExecutionException, InterruptedException { + String key = "test-" + UUID.randomUUID().toString(); + + BaseDocument doc = new BaseDocument(key); + doc.addAttribute("arr", Collections.singletonList("hello")); + doc.addAttribute("int", 10); + + BaseDocument result = collection.insertDocument( + doc, + new DocumentCreateOptions().returnNew(true) + ).get().getNew(); + + assertThat(result.getAttribute("arr"), instanceOf(String.class)); + assertThat(result.getAttribute("arr"), is("hello")); + assertThat(result.getAttribute("int"), instanceOf(BigInteger.class)); + assertThat(result.getAttribute("int"), is(BigInteger.valueOf(10))); + } + + @Test + public void getDocument() throws ExecutionException, InterruptedException { + String key = "test-" + UUID.randomUUID().toString(); + + BaseDocument doc = new BaseDocument(key); + doc.addAttribute("arr", Collections.singletonList("hello")); + doc.addAttribute("int", 10); + + collection.insertDocument(doc, null).get(); + + final BaseDocument result = db.collection(COLLECTION_NAME).getDocument( + key, + BaseDocument.class, + null).get(); + + assertThat(result.getAttribute("arr"), instanceOf(String.class)); + assertThat(result.getAttribute("arr"), is("hello")); + assertThat(result.getAttribute("int"), instanceOf(BigInteger.class)); + assertThat(result.getAttribute("int"), is(BigInteger.valueOf(10))); + } + +} From eb3f7cb2921ab93bf579b17c4ce781e87f6ce01b Mon Sep 17 00:00:00 2001 From: michele Date: Thu, 5 Sep 2019 09:30:12 +0200 Subject: [PATCH 2/4] cursor streamRemaining ordered --- .../com/arangodb/async/internal/ArangoCursorAsyncImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java b/src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java index e21a01aa3..14988eca3 100644 --- a/src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java +++ b/src/main/java/com/arangodb/async/internal/ArangoCursorAsyncImpl.java @@ -26,6 +26,7 @@ import com.arangodb.internal.InternalArangoDatabase; import com.arangodb.internal.cursor.ArangoCursorImpl; +import java.util.Spliterator; import java.util.Spliterators; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -42,6 +43,6 @@ public class ArangoCursorAsyncImpl extends ArangoCursorImpl implements Ara @Override public Stream streamRemaining() { - return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false); } } From f01a15ad559a83b539c371b4cf7c4ec7f42fad21 Mon Sep 17 00:00:00 2001 From: michele Date: Thu, 5 Sep 2019 09:31:03 +0200 Subject: [PATCH 3/4] v6.1.1 --- ChangeLog.md | 4 ++++ pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 2ba89704f..60cde489c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +## [6.1.1] - 2019-09-05 + +- merged async driver + ## [6.1.0] - 2019-08-29 ### Added diff --git a/pom.xml b/pom.xml index caa72b093..93c993061 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.arangodb arangodb-java-driver - 6.1.0 + 6.1.1 2016 jar From 6f59340339c20178471964a4858d116cba145ae1 Mon Sep 17 00:00:00 2001 From: michele Date: Thu, 5 Sep 2019 11:57:37 +0200 Subject: [PATCH 4/4] bugfix method chaining in IndexOptions --- ChangeLog.md | 1 + .../arangodb/model/FulltextIndexOptions.java | 7 ++- .../com/arangodb/model/GeoIndexOptions.java | 7 ++- .../com/arangodb/model/HashIndexOptions.java | 7 ++- .../java/com/arangodb/model/IndexOptions.java | 62 +++++++++---------- .../model/PersistentIndexOptions.java | 7 ++- .../arangodb/model/SkiplistIndexOptions.java | 7 ++- .../com/arangodb/model/TtlIndexOptions.java | 7 ++- 8 files changed, 68 insertions(+), 37 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 60cde489c..5df8f75a5 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [6.1.1] - 2019-09-05 - merged async driver +- bugfix method chaining in IndexOptions ## [6.1.0] - 2019-08-29 diff --git a/src/main/java/com/arangodb/model/FulltextIndexOptions.java b/src/main/java/com/arangodb/model/FulltextIndexOptions.java index 81a56cc0d..b636b31b7 100644 --- a/src/main/java/com/arangodb/model/FulltextIndexOptions.java +++ b/src/main/java/com/arangodb/model/FulltextIndexOptions.java @@ -28,7 +28,7 @@ * @see API * Documentation */ -public class FulltextIndexOptions extends IndexOptions { +public class FulltextIndexOptions extends IndexOptions { private Iterable fields; private final IndexType type = IndexType.fulltext; @@ -38,6 +38,11 @@ public FulltextIndexOptions() { super(); } + @Override + protected FulltextIndexOptions getThis() { + return null; + } + protected Iterable getFields() { return fields; } diff --git a/src/main/java/com/arangodb/model/GeoIndexOptions.java b/src/main/java/com/arangodb/model/GeoIndexOptions.java index 68be48a6c..423262651 100644 --- a/src/main/java/com/arangodb/model/GeoIndexOptions.java +++ b/src/main/java/com/arangodb/model/GeoIndexOptions.java @@ -27,7 +27,7 @@ * * @see API Documentation */ -public class GeoIndexOptions extends IndexOptions { +public class GeoIndexOptions extends IndexOptions { private Iterable fields; private final IndexType type = IndexType.geo; @@ -37,6 +37,11 @@ public GeoIndexOptions() { super(); } + @Override + protected GeoIndexOptions getThis() { + return null; + } + protected Iterable getFields() { return fields; } diff --git a/src/main/java/com/arangodb/model/HashIndexOptions.java b/src/main/java/com/arangodb/model/HashIndexOptions.java index 8c6ecd159..99ddc27bc 100644 --- a/src/main/java/com/arangodb/model/HashIndexOptions.java +++ b/src/main/java/com/arangodb/model/HashIndexOptions.java @@ -27,7 +27,7 @@ * * @see API Documentation */ -public class HashIndexOptions extends IndexOptions { +public class HashIndexOptions extends IndexOptions { private Iterable fields; private final IndexType type = IndexType.hash; @@ -39,6 +39,11 @@ public HashIndexOptions() { super(); } + @Override + protected HashIndexOptions getThis() { + return this; + } + protected Iterable getFields() { return fields; } diff --git a/src/main/java/com/arangodb/model/IndexOptions.java b/src/main/java/com/arangodb/model/IndexOptions.java index 1d2a956dd..512f7d2b6 100644 --- a/src/main/java/com/arangodb/model/IndexOptions.java +++ b/src/main/java/com/arangodb/model/IndexOptions.java @@ -22,44 +22,44 @@ /** * @author Heiko Kernbach - * + *

* This class is used for all index similarities */ -public class IndexOptions { +public abstract class IndexOptions { - private Boolean inBackground; - private String name; + private Boolean inBackground; + private String name; - public IndexOptions() { + public IndexOptions() { super(); - } + } + + protected abstract T getThis(); - /** - * @param inBackground - * create the the index in the background - * this is a RocksDB only flag. - * @return options - */ - public IndexOptions inBackground(final Boolean inBackground) { - this.inBackground = inBackground; - return this; - } + /** + * @param inBackground create the the index in the background + * this is a RocksDB only flag. + * @return options + */ + public T inBackground(final Boolean inBackground) { + this.inBackground = inBackground; + return getThis(); + } - public Boolean getInBackground() { - return inBackground; - } + public Boolean getInBackground() { + return inBackground; + } - /** - * @param name - * the name of the index - * @return options - */ - public IndexOptions name(final String name) { - this.name = name; - return this; - } + /** + * @param name the name of the index + * @return options + */ + public T name(final String name) { + this.name = name; + return getThis(); + } - protected String getName() { - return name; - } + protected String getName() { + return name; + } } diff --git a/src/main/java/com/arangodb/model/PersistentIndexOptions.java b/src/main/java/com/arangodb/model/PersistentIndexOptions.java index 5cedf6901..e0bdf649f 100644 --- a/src/main/java/com/arangodb/model/PersistentIndexOptions.java +++ b/src/main/java/com/arangodb/model/PersistentIndexOptions.java @@ -28,7 +28,7 @@ * @see API * Documentation */ -public class PersistentIndexOptions extends IndexOptions { +public class PersistentIndexOptions extends IndexOptions { private Iterable fields; protected final IndexType type = IndexType.persistent; @@ -39,6 +39,11 @@ public PersistentIndexOptions() { super(); } + @Override + protected PersistentIndexOptions getThis() { + return null; + } + protected Iterable getFields() { return fields; } diff --git a/src/main/java/com/arangodb/model/SkiplistIndexOptions.java b/src/main/java/com/arangodb/model/SkiplistIndexOptions.java index e77c3cca0..aa6a650c0 100644 --- a/src/main/java/com/arangodb/model/SkiplistIndexOptions.java +++ b/src/main/java/com/arangodb/model/SkiplistIndexOptions.java @@ -27,7 +27,7 @@ * * @see API Documentation */ -public class SkiplistIndexOptions extends IndexOptions { +public class SkiplistIndexOptions extends IndexOptions { private Iterable fields; private final IndexType type = IndexType.skiplist; @@ -39,6 +39,11 @@ public SkiplistIndexOptions() { super(); } + @Override + protected SkiplistIndexOptions getThis() { + return null; + } + protected Iterable getFields() { return fields; } diff --git a/src/main/java/com/arangodb/model/TtlIndexOptions.java b/src/main/java/com/arangodb/model/TtlIndexOptions.java index 45a8ff3e9..7ca2c28c6 100644 --- a/src/main/java/com/arangodb/model/TtlIndexOptions.java +++ b/src/main/java/com/arangodb/model/TtlIndexOptions.java @@ -26,7 +26,7 @@ * @author Heiko Kernbach * @see API Documentation */ -public class TtlIndexOptions extends IndexOptions { +public class TtlIndexOptions extends IndexOptions { private Iterable fields; private final IndexType type = IndexType.ttl; @@ -36,6 +36,11 @@ public TtlIndexOptions() { super(); } + @Override + protected TtlIndexOptions getThis() { + return null; + } + protected Iterable getFields() { return fields; }