diff --git a/Documentation/Books/Users/HttpBulkImports/Arangoimp.mdpp b/Documentation/Books/Users/HttpBulkImports/Arangoimp.mdpp index 2173bd62ce..f9656a9770 100644 --- a/Documentation/Books/Users/HttpBulkImports/Arangoimp.mdpp +++ b/Documentation/Books/Users/HttpBulkImports/Arangoimp.mdpp @@ -62,12 +62,16 @@ specify a password, you will be prompted for one. Note that the collection (*users* in this case) must already exist or the import will fail. If you want to create a new collection with the import data, you need -to specify the *--create-collection* option. Note that it is only possible to -create a document collection using the *--create-collection* flag, and no edge -collections. +to specify the *--create-collection* option. Note that by default it will create +a document collection and no ede collection. > arangoimp --file "data.json" --type json --collection "users" --create-collection true +To create an edge collection instead, use the *--create-collection-type* option +and set it to *edge*: + + > arangoimp --file "data.json" --collection "myedges" --create-collection true --create-collection-type edge + When importing data into an existing collection it is often convenient to first remove all data from the collection and then start the import. This can be achieved by passing the *--overwrite* parameter to _arangoimp_. If it is set to *true*, diff --git a/Documentation/Books/Users/NewFeatures/NewFeatures28.mdpp b/Documentation/Books/Users/NewFeatures/NewFeatures28.mdpp index b36419727c..2bab003446 100644 --- a/Documentation/Books/Users/NewFeatures/NewFeatures28.mdpp +++ b/Documentation/Books/Users/NewFeatures/NewFeatures28.mdpp @@ -351,3 +351,8 @@ will now fail by default when trying to dump edges that refer to already dropped collections. This can be circumvented by specifying the option `--force true` when invoking arangodump. +arangoimp now provides an option `--create-collection-type` to specify the type of +the collection to be created when `--create-collection` is set to `true`. Previously +`--create-collection` always created document collections and the creation of edge +collections was not possible. + diff --git a/UnitTests/HttpInterface/api-import-noncluster-spec.rb b/UnitTests/HttpInterface/api-import-noncluster-spec.rb index a687f5bd65..01a153d893 100644 --- a/UnitTests/HttpInterface/api-import-noncluster-spec.rb +++ b/UnitTests/HttpInterface/api-import-noncluster-spec.rb @@ -16,6 +16,7 @@ describe ArangoDB do context "import, testing createCollection:" do before do @cn = "UnitTestsImport" + ArangoDB.drop_collection(@cn) end after do @@ -43,6 +44,42 @@ describe ArangoDB do doc.parsed_response['error'].should eq(true) doc.parsed_response['errorNum'].should eq(1203) end + + it "createCollection=true&createCollectionType=document" do + cmd = api + "?collection=#{@cn}&createCollection=true&createCollectionType=document&type=array" + body = "[ { \"foo\" : true } ]"; + doc = ArangoDB.log_post("#{prefix}-create", cmd, :body => body) + + doc.code.should eq(201) + doc.parsed_response['error'].should eq(false) + doc.parsed_response['created'].should eq(1) + doc.parsed_response['errors'].should eq(0) + doc.parsed_response['empty'].should eq(0) + + cmd = "/_api/collection/#{@cn}" + doc = ArangoDB.log_get("#{prefix}-create", cmd, :body => "") + doc.code.should eq(200) + doc.parsed_response['error'].should eq(false) + doc.parsed_response['type'].should eq(2) # 2 = document + end + + it "createCollection=true&createCollectionType=edge" do + cmd = api + "?collection=#{@cn}&createCollection=true&createCollectionType=edge&type=array" + body = "[ { \"foo\" : true } ]"; + doc = ArangoDB.log_post("#{prefix}-create", cmd, :body => body) + + doc.code.should eq(201) # missing _from & _to + doc.parsed_response['error'].should eq(false) + doc.parsed_response['created'].should eq(0) + doc.parsed_response['errors'].should eq(1) + doc.parsed_response['empty'].should eq(0) + + cmd = "/_api/collection/#{@cn}" + doc = ArangoDB.log_get("#{prefix}-create", cmd, :body => "") + doc.code.should eq(200) + doc.parsed_response['error'].should eq(false) + doc.parsed_response['type'].should eq(3) # 3 = edge + end end ################################################################################ @@ -552,6 +589,25 @@ describe ArangoDB do doc.parsed_response['ignored'].should eq(0) end + it "multiple docs, creating edge collection" do + ArangoDB.drop_collection(@en) + + cmd = api + "?collection=#{@en}&createCollection=true&createCollectionType=edge&type=array" + body = "[\n" + body += "{ \"a\" : 1, \"_from\" : \"" + @vn + "/vertex1\", \"_to\" : \"" + @vn + "/vertex2\" },\n" + body += "{ \"foo\" : true, \"bar\": \"baz\", \"_from\" : \"" + @vn + "/vertex1\", \"_to\" : \"" + @vn + "/vertex2\" },\n" + body += "{ \"from\" : \"" + @vn + "/vertex1\", \"to\" : \"" + @vn + "/vertex2\" }\n" + body += "]"; + doc = ArangoDB.log_post("#{prefix}-edge-json-fromto", cmd, :body => body) + + doc.code.should eq(201) + doc.parsed_response['error'].should eq(false) + doc.parsed_response['created'].should eq(2) + doc.parsed_response['errors'].should eq(1) + doc.parsed_response['empty'].should eq(0) + doc.parsed_response['updated'].should eq(0) + doc.parsed_response['ignored'].should eq(0) + end end ################################################################################ @@ -746,7 +802,7 @@ describe ArangoDB do cmd = api + "?collection=#{@cn}&type=documents" body = "{ \"_key\" : \"test1\", \"value1\" : 1, \"value2\" : \"test\" }\n" body += "{ \"_key\" : \"test2\", \"value1\" : \"abc\", \"value2\" : 3 }\n" - doc = ArangoDB.post(cmd, :body => body) + ArangoDB.post(cmd, :body => body) end after do diff --git a/arangod/RestHandler/RestImportHandler.cpp b/arangod/RestHandler/RestImportHandler.cpp index 0c3719080b..b33fe506c4 100644 --- a/arangod/RestHandler/RestImportHandler.cpp +++ b/arangod/RestHandler/RestImportHandler.cpp @@ -125,6 +125,24 @@ HttpHandler::status_t RestImportHandler::execute () { // --SECTION-- private methods // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief determine the collection type from the request +//////////////////////////////////////////////////////////////////////////////// + +TRI_col_type_e RestImportHandler::getCollectionType () { + // extract the collection type from the request + bool found; + std::string const& collectionType = _request->value("createCollectionType", found); + + if (found && + ! collectionType.empty() && + collectionType == "edge") { + return TRI_COL_TYPE_EDGE; + } + + return TRI_COL_TYPE_DOCUMENT; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief extracts the "overwrite" value //////////////////////////////////////////////////////////////////////////////// @@ -388,6 +406,11 @@ int RestImportHandler::handleSingleDocument (RestImportTransaction& trx, /// created if it does not yet exist. Other values will be ignored so the /// collection must be present for the operation to succeed. /// +/// @RESTQUERYPARAM{createCollectionType,string,optional} +/// If this parameter has a value of `document` or `edge`, it will determine +/// the type of collection that is going to be created when the `createCollection` +/// option is set to `true`. The default value is `document`. +/// /// @RESTQUERYPARAM{overwrite,boolean,optional} /// If this parameter has a value of `true` or `yes`, then all data in the /// collection will be removed prior to the import. Note that any existing @@ -739,7 +762,7 @@ bool RestImportHandler::createFromJson (string const& type) { return false; } - if (! checkCreateCollection(collection, TRI_COL_TYPE_DOCUMENT)) { + if (! checkCreateCollection(collection, getCollectionType())) { return false; } @@ -948,6 +971,11 @@ bool RestImportHandler::createFromJson (string const& type) { /// created if it does not yet exist. Other values will be ignored so the /// collection must be present for the operation to succeed. /// +/// @RESTQUERYPARAM{createCollectionType,string,optional} +/// If this parameter has a value of `document` or `edge`, it will determine +/// the type of collection that is going to be created when the `createCollection` +/// option is set to `true`. The default value is `document`. +/// /// @RESTQUERYPARAM{overwrite,boolean,optional} /// If this parameter has a value of `true` or `yes`, then all data in the /// collection will be removed prior to the import. Note that any existing @@ -1233,7 +1261,7 @@ bool RestImportHandler::createFromKeyValueList () { return false; } - if (! checkCreateCollection(collection, TRI_COL_TYPE_DOCUMENT)) { + if (! checkCreateCollection(collection, getCollectionType())) { return false; } diff --git a/arangod/RestHandler/RestImportHandler.h b/arangod/RestHandler/RestImportHandler.h index a9ed9633ba..b5751f65e4 100644 --- a/arangod/RestHandler/RestImportHandler.h +++ b/arangod/RestHandler/RestImportHandler.h @@ -99,7 +99,7 @@ namespace triagens { /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// - status_t execute (); + status_t execute () override final; // ----------------------------------------------------------------------------- // --SECTION-- private methods @@ -107,6 +107,12 @@ namespace triagens { private: +//////////////////////////////////////////////////////////////////////////////// +/// @brief determine the collection type from the request +//////////////////////////////////////////////////////////////////////////////// + + TRI_col_type_e getCollectionType (); + //////////////////////////////////////////////////////////////////////////////// /// @brief extracts the "overwrite" value //////////////////////////////////////////////////////////////////////////////// diff --git a/arangosh/V8Client/ImportHelper.cpp b/arangosh/V8Client/ImportHelper.cpp index d7349371f7..fe057cb2c6 100644 --- a/arangosh/V8Client/ImportHelper.cpp +++ b/arangosh/V8Client/ImportHelper.cpp @@ -151,6 +151,7 @@ namespace triagens { _maxUploadSize(maxUploadSize), _separator(","), _quote("\""), + _createCollectionType("document"), _useBackslash(false), _createCollection(false), _overwrite(false), @@ -450,6 +451,10 @@ namespace triagens { part += "&createCollection=yes"; } + if (! _createCollectionType.empty()) { + part += "&createCollectionType=" + _createCollectionType; + } + if (_overwrite) { part += "&overwrite=yes"; } diff --git a/arangosh/V8Client/ImportHelper.h b/arangosh/V8Client/ImportHelper.h index d03904adc2..d3a65911c2 100644 --- a/arangosh/V8Client/ImportHelper.h +++ b/arangosh/V8Client/ImportHelper.h @@ -142,6 +142,10 @@ namespace triagens { _createCollection = value; } + void setCreateCollectionType (std::string const& value) { + _createCollectionType = value; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not to overwrite existing data in the collection //////////////////////////////////////////////////////////////////////////////// @@ -238,6 +242,7 @@ namespace triagens { std::string _separator; std::string _quote; + std::string _createCollectionType; bool _useBackslash; bool _createCollection; bool _overwrite; diff --git a/arangosh/V8Client/arangoimp.cpp b/arangosh/V8Client/arangoimp.cpp index 7fffad098d..25fce20ee4 100644 --- a/arangosh/V8Client/arangoimp.cpp +++ b/arangosh/V8Client/arangoimp.cpp @@ -112,6 +112,12 @@ static string TypeImport = "json"; static bool CreateCollection = false; +//////////////////////////////////////////////////////////////////////////////// +/// @brief collection type if collection is to be created +//////////////////////////////////////////////////////////////////////////////// + +static string CreateCollectionType = "document"; + //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not to overwrite existing data in a collection //////////////////////////////////////////////////////////////////////////////// @@ -153,6 +159,7 @@ static void ParseProgramOptions (int argc, char* argv[]) { ("batch-size", &ChunkSize, "size for individual data batches (in bytes)") ("collection", &CollectionName, "collection name") ("create-collection", &CreateCollection, "create collection if it does not yet exist") + ("create-collection-type", &CreateCollectionType, "type of collection if collection is created ('document' or 'edge')") ("type", &TypeImport, "type of file (\"csv\", \"tsv\", or \"json\")") ("overwrite", &Overwrite, "overwrite collection if it exist (WARNING: this will remove any data from the collection)") ("quote", &Quote, "quote character(s), used for csv") @@ -360,6 +367,10 @@ int main (int argc, char* argv[]) { ih.setCreateCollection(true); } + if (CreateCollectionType == "document" || CreateCollectionType == "edge") { + ih.setCreateCollectionType(CreateCollectionType); + } + ih.setOverwrite(Overwrite); ih.useBackslash(UseBackslash);