diff --git a/UnitTests/HttpInterface/api-document-create-noncluster-spec.rb b/UnitTests/HttpInterface/api-document-create-noncluster-spec.rb deleted file mode 100644 index 2429310cd1..0000000000 --- a/UnitTests/HttpInterface/api-document-create-noncluster-spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# coding: utf-8 - -require 'rspec' -require 'arangodb.rb' - -describe ArangoDB do - prefix = "rest-create-document" - didRegex = /^([0-9a-zA-Z]+)\/([0-9a-zA-Z\-_]+)/ - - context "creating a document:" do - -################################################################################ -## unknown collection name -################################################################################ - - context "unknown collection name:" do - before do - @cn = "UnitTestsCollectionNamed#{Time.now.to_i}" - end - - after do - ArangoDB.drop_collection(@cn) - end - - it "create the collection and the document" do - cmd = "/_api/document?collection=#{@cn}&createCollection=true" - body = "{ \"Hallo\" : \"World\" }" - doc = ArangoDB.log_post("#{prefix}-create-collection", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) - - doc.code.should eq(202) - doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) - - etag = doc.headers['etag'] - etag.should be_kind_of(String) - - location = doc.headers['location'] - location.should be_kind_of(String) - - rev = doc.parsed_response['_rev'] - rev.should be_kind_of(String) - - did = doc.parsed_response['_id'] - did.should be_kind_of(String) - - etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") - - ArangoDB.delete(location) - - ArangoDB.size_collection(@cn).should eq(0) - end - - it "create the collection and the document, setting compatibility header" do - cmd = "/_api/document?collection=#{@cn}&createCollection=true" - body = "{ \"Hallo\" : \"World\" }" - doc = ArangoDB.log_post("#{prefix}-create-collection", cmd, :body => body, :headers => { "x-arango-version" => "1.4" }) - - doc.code.should eq(202) - doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) - - etag = doc.headers['etag'] - etag.should be_kind_of(String) - - location = doc.headers['location'] - location.should be_kind_of(String) - - rev = doc.parsed_response['_rev'] - rev.should be_kind_of(String) - - did = doc.parsed_response['_id'] - did.should be_kind_of(String) - - etag.should eq("\"#{rev}\"") - location.should eq("/_db/_system/_api/document/#{did}") - - ArangoDB.delete(location) - - ArangoDB.size_collection(@cn).should eq(0) - end - end - - end -end diff --git a/UnitTests/HttpInterface/api-document-create-spec.rb b/UnitTests/HttpInterface/api-document-create-spec.rb index c336f31aff..14f771af29 100644 --- a/UnitTests/HttpInterface/api-document-create-spec.rb +++ b/UnitTests/HttpInterface/api-document-create-spec.rb @@ -14,18 +14,6 @@ describe ArangoDB do ################################################################################ context "error handling:" do - it "returns an error if url contains a suffix" do - cmd = "/_api/document/123456" - body = "{}" - doc = ArangoDB.log_post("#{prefix}-superfluous-suffix", cmd, :body => body) - - doc.code.should eq(400) - doc.parsed_response['error'].should eq(true) - doc.parsed_response['errorNum'].should eq(601) - doc.parsed_response['code'].should eq(400) - doc.headers['content-type'].should eq("application/json; charset=utf-8") - end - it "returns an error if collection idenifier is missing" do cmd = "/_api/document" body = "{}" @@ -139,11 +127,10 @@ describe ArangoDB do it "creating a new document" do cmd = "/_api/document?collection=#{@cn}" body = "{ \"Hallo\" : \"World\" }" - doc = ArangoDB.log_post("#{prefix}", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}", cmd, :body => body, :headers => {}) doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -162,7 +149,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") ArangoDB.delete(location) @@ -176,7 +163,6 @@ describe ArangoDB do doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -205,11 +191,10 @@ describe ArangoDB do it "creating a new document complex body" do cmd = "/_api/document?collection=#{@cn}" body = "{ \"Hallo\" : \"Wo\\\"rld\" }" - doc = ArangoDB.log_post("#{prefix}", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}", cmd, :body => body, :headers => {}) doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -228,7 +213,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") cmd = "/_api/document/#{did}" doc = ArangoDB.log_get("#{prefix}-complex", cmd) @@ -249,7 +234,6 @@ describe ArangoDB do doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -285,11 +269,10 @@ describe ArangoDB do it "creating a new umlaut document" do cmd = "/_api/document?collection=#{@cn}" body = "{ \"Hallo\" : \"öäüÖÄÜßあ寿司\" }" - doc = ArangoDB.log_post("#{prefix}-umlaut", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}-umlaut", cmd, :body => body, :headers => {}) doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -308,7 +291,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") cmd = "/_api/document/#{did}" doc = ArangoDB.log_get("#{prefix}-umlaut", cmd) @@ -319,7 +302,7 @@ describe ArangoDB do newBody = doc.body() newBody = newBody.sub!(/^.*"Hallo":"([^"]*)".*$/, '\1') - newBody.should eq("\\u00F6\\u00E4\\u00FC\\u00D6\\u00C4\\u00DC\\u00DF\\u3042\\u5BFF\\u53F8") + newBody.should eq("öäüÖÄÜßあ寿司") doc.parsed_response['Hallo'].should eq('öäüÖÄÜßあ寿司') @@ -335,7 +318,6 @@ describe ArangoDB do doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -365,7 +347,7 @@ describe ArangoDB do newBody = doc.body() newBody = newBody.sub!(/^.*"Hallo":"([^"]*)".*$/, '\1') - newBody.should eq("\\u00F6\\u00E4\\u00FC\\u00D6\\u00C4\\u00DC\\u00DF\\u3042\\u5BFF\\u53F8") + newBody.should eq("öäüÖÄÜßあ寿司") doc.parsed_response['Hallo'].should eq('öäüÖÄÜßあ寿司') @@ -376,58 +358,11 @@ describe ArangoDB do it "creating a new not normalized umlaut document" do cmd = "/_api/document?collection=#{@cn}" - body = "{ \"Hallo\" : \"Gru\\u0308\\u00DF Gott.\" }" - doc = ArangoDB.log_post("#{prefix}-umlaut", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + body = "{ \"Hallo\" : \"Grüß Gott.\" }" + doc = ArangoDB.log_post("#{prefix}-umlaut", cmd, :body => body, :headers => {}) doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) - - etag = doc.headers['etag'] - etag.should be_kind_of(String) - - location = doc.headers['location'] - location.should be_kind_of(String) - - rev = doc.parsed_response['_rev'] - rev.should be_kind_of(String) - - did = doc.parsed_response['_id'] - did.should be_kind_of(String) - - match = didRegex.match(did) - - match[1].should eq("#{@cn}") - - etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") - - cmd = "/_api/document/#{did}" - doc = ArangoDB.log_get("#{prefix}-umlaut", cmd) - - doc.code.should eq(200) - doc.headers['content-type'].should eq("application/json; charset=utf-8") - - newBody = doc.body() - newBody = newBody.sub!(/^.*"Hallo":"([^"]*)".*$/, '\1') - - newBody.should eq("Gr\\u00FC\\u00DF Gott.") - - doc.parsed_response['Hallo'].should eq('Grüß Gott.') - - ArangoDB.delete(location) - - ArangoDB.size_collection(@cn).should eq(0) - end - - it "creating a new not normalized umlaut document, setting compatibility header" do - cmd = "/_api/document?collection=#{@cn}" - body = "{ \"Hallo\" : \"Gru\\u0308\\u00DF Gott.\" }" - doc = ArangoDB.log_post("#{prefix}-umlaut", cmd, :body => body, :headers => { "x-arango-version" => "1.4" }) - - doc.code.should eq(201) - doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -457,7 +392,52 @@ describe ArangoDB do newBody = doc.body() newBody = newBody.sub!(/^.*"Hallo":"([^"]*)".*$/, '\1') - newBody.should eq("Gr\\u00FC\\u00DF Gott.") + newBody.should eq("Grüß Gott.") + + doc.parsed_response['Hallo'].should eq('Grüß Gott.') + + ArangoDB.delete(location) + + ArangoDB.size_collection(@cn).should eq(0) + end + + it "creating a new not normalized umlaut document, setting compatibility header" do + cmd = "/_api/document?collection=#{@cn}" + body = "{ \"Hallo\" : \"Grüß Gott.\" }" + doc = ArangoDB.log_post("#{prefix}-umlaut", cmd, :body => body, :headers => { "x-arango-version" => "1.4" }) + + doc.code.should eq(201) + doc.headers['content-type'].should eq("application/json; charset=utf-8") + + etag = doc.headers['etag'] + etag.should be_kind_of(String) + + location = doc.headers['location'] + location.should be_kind_of(String) + + rev = doc.parsed_response['_rev'] + rev.should be_kind_of(String) + + did = doc.parsed_response['_id'] + did.should be_kind_of(String) + + match = didRegex.match(did) + + match[1].should eq("#{@cn}") + + etag.should eq("\"#{rev}\"") + location.should eq("/_db/_system/_api/document/#{did}") + + cmd = "/_api/document/#{did}" + doc = ArangoDB.log_get("#{prefix}-umlaut", cmd) + + doc.code.should eq(200) + doc.headers['content-type'].should eq("application/json; charset=utf-8") + + newBody = doc.body() + newBody = newBody.sub!(/^.*"Hallo":"([^"]*)".*$/, '\1') + + newBody.should eq("Grüß Gott.") doc.parsed_response['Hallo'].should eq('Grüß Gott.') @@ -473,11 +453,10 @@ describe ArangoDB do cmd = "/_api/document?collection=#{@cn}" body = "{ \"some stuff\" : \"goes here\", \"_key\" : \"#{@key}\" }" - doc = ArangoDB.log_post("#{prefix}-existing-id", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}-existing-id", cmd, :body => body, :headers => {}) doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -496,7 +475,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") ArangoDB.delete("/_api/document/#{@cn}/#{@key}") end @@ -512,7 +491,6 @@ describe ArangoDB do doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -575,11 +553,10 @@ describe ArangoDB do it "creating a new document" do cmd = "/_api/document?collection=#{@cn}" body = "{ \"Hallo\" : \"World\" }" - doc = ArangoDB.log_post("#{prefix}-accept", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}-accept", cmd, :body => body, :headers => {}) doc.code.should eq(202) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -598,7 +575,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") ArangoDB.delete(location) @@ -612,7 +589,6 @@ describe ArangoDB do doc.code.should eq(202) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -641,11 +617,10 @@ describe ArangoDB do it "creating a new document, waitForSync URL param = false" do cmd = "/_api/document?collection=#{@cn}&waitForSync=false" body = "{ \"Hallo\" : \"World\" }" - doc = ArangoDB.log_post("#{prefix}-accept-sync-false", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}-accept-sync-false", cmd, :body => body, :headers => {}) doc.code.should eq(202) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -664,7 +639,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") ArangoDB.delete(location) @@ -678,7 +653,6 @@ describe ArangoDB do doc.code.should eq(202) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -707,11 +681,10 @@ describe ArangoDB do it "creating a new document, waitForSync URL param = true" do cmd = "/_api/document?collection=#{@cn}&waitForSync=true" body = "{ \"Hallo\" : \"World\" }" - doc = ArangoDB.log_post("#{prefix}-accept-sync-true", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}-accept-sync-true", cmd, :body => body, :headers => {}) doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -730,7 +703,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") ArangoDB.delete(location) @@ -744,7 +717,6 @@ describe ArangoDB do doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -788,11 +760,10 @@ describe ArangoDB do it "creating a new document" do cmd = "/_api/document?collection=#{@cn}" body = "{ \"Hallo\" : \"World\" }" - doc = ArangoDB.log_post("#{prefix}-named-collection", cmd, :body => body, :headers => { "x-arango-version" => "1.3" }) + doc = ArangoDB.log_post("#{prefix}-named-collection", cmd, :body => body, :headers => {}) doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) @@ -811,7 +782,7 @@ describe ArangoDB do match[1].should eq("#{@cn}") etag.should eq("\"#{rev}\"") - location.should eq("/_api/document/#{did}") + location.should eq("/_db/_system/_api/document/#{did}") ArangoDB.delete(location) @@ -825,7 +796,6 @@ describe ArangoDB do doc.code.should eq(201) doc.headers['content-type'].should eq("application/json; charset=utf-8") - doc.parsed_response['error'].should eq(false) etag = doc.headers['etag'] etag.should be_kind_of(String) diff --git a/UnitTests/HttpInterface/api-document-key-spec.rb b/UnitTests/HttpInterface/api-document-key-spec.rb index d2fbb806c8..b1c4022b0a 100644 --- a/UnitTests/HttpInterface/api-document-key-spec.rb +++ b/UnitTests/HttpInterface/api-document-key-spec.rb @@ -236,7 +236,6 @@ describe ArangoDB do doc = ArangoDB.log_post("#{prefix}-valid", cmd, :body => body) doc.code.should eq(201) - doc.parsed_response['error'].should eq(false) doc.parsed_response['_key'].should eq(key) doc.headers['content-type'].should eq("application/json; charset=utf-8") end @@ -264,7 +263,6 @@ describe ArangoDB do doc = ArangoDB.log_post("#{prefix}-valid", cmd, :body => body) doc.code.should eq(201) - doc.parsed_response['error'].should eq(false) doc.parsed_response['_key'].should eq(key) doc.headers['content-type'].should eq("application/json; charset=utf-8") diff --git a/UnitTests/HttpInterface/api-document-read-spec.rb b/UnitTests/HttpInterface/api-document-read-spec.rb index 5a43b470c2..71a4c64a63 100644 --- a/UnitTests/HttpInterface/api-document-read-spec.rb +++ b/UnitTests/HttpInterface/api-document-read-spec.rb @@ -32,10 +32,10 @@ describe ArangoDB do cmd = "/_api/document/123456" doc = ArangoDB.log_get("#{prefix}-bad-handle", cmd) - doc.code.should eq(400) + doc.code.should eq(404) doc.parsed_response['error'].should eq(true) - doc.parsed_response['errorNum'].should eq(1205) - doc.parsed_response['code'].should eq(400) + doc.parsed_response['errorNum'].should eq(1203) + doc.parsed_response['code'].should eq(404) doc.headers['content-type'].should eq("application/json; charset=utf-8") end @@ -552,10 +552,10 @@ describe ArangoDB do doc.code.should eq(200) doc.headers['content-type'].should eq("application/json; charset=utf-8") - # get the document head + # get the document head, withdrawn for 3.0 doc = ArangoDB.head(cmd + "?rev=abcd") - doc.code.should eq(400) + doc.code.should eq(200) hdr = { "if-match" => "'abcd'" } doc = ArangoDB.log_head("#{prefix}-head-rev-invalid", cmd, :headers => hdr) diff --git a/UnitTests/HttpInterface/api-documents-spec.rb b/UnitTests/HttpInterface/api-documents-spec.rb index 493bbcdb7d..fba8d0092c 100644 --- a/UnitTests/HttpInterface/api-documents-spec.rb +++ b/UnitTests/HttpInterface/api-documents-spec.rb @@ -26,7 +26,7 @@ describe ArangoDB do it "creates a document with an invalid type" do cmd = api + "?collection=" + @cn - body = "[ ]"; + body = "[ [] ]"; doc = ArangoDB.log_post("#{prefix}-create-list1", cmd, :body => body) doc.code.should eq(400) diff --git a/arangod/Aql/Functions.cpp b/arangod/Aql/Functions.cpp index a7b8fbc8bb..2ad878c7ae 100644 --- a/arangod/Aql/Functions.cpp +++ b/arangod/Aql/Functions.cpp @@ -66,6 +66,17 @@ using VertexId = arangodb::traverser::VertexId; thread_local std::unordered_map* RegexCache = nullptr; +//////////////////////////////////////////////////////////////////////////////// +/// @brief Insert a mptr into the result +//////////////////////////////////////////////////////////////////////////////// + +static void InsertMasterPointer(TRI_doc_mptr_t const* mptr, VPackBuilder& builder) { + //builder.add(VPackValue(static_cast(mptr->vpack()), + // VPackValueType::External)); + // This is the future, for now we have to copy: + builder.add(VPackSlice(mptr->vpack())); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief clear the regex cache in a thread //////////////////////////////////////////////////////////////////////////////// @@ -436,116 +447,6 @@ static bool SortNumberList(VPackSlice const& values, return true; } -static inline void ExpandShapedJson( - VocShaper* shaper, CollectionNameResolver const* resolver, - TRI_voc_cid_t const& cid, TRI_doc_mptr_t const* mptr, VPackBuilder& b, - bool keepTopLevelOpen, - std::unordered_set const& forbidden) { - b.add(VPackValue(VPackValueType::Object)); - - TRI_df_marker_t const* marker = - static_cast(mptr->getDataPtr()); - - TRI_shaped_json_t shaped; - TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, marker); - std::shared_ptr tmp = TRI_VelocyPackShapedJson(shaper, &shaped); - // Copy the shaped into our local builder - for (auto const& it : VPackObjectIterator(tmp->slice())) { - std::string key = it.key.copyString(); - if (forbidden.count(key) == 0) { - b.add(it.key.copyString(), it.value); - } - } - - char const* key = TRI_EXTRACT_MARKER_KEY(marker); - std::string id(resolver->getCollectionName(cid)); - id.push_back('/'); - id.append(key); - if (forbidden.count(TRI_VOC_ATTRIBUTE_ID) == 0) { - b.add(TRI_VOC_ATTRIBUTE_ID, VPackValue(id)); - } - if (forbidden.count(TRI_VOC_ATTRIBUTE_REV) == 0) { - b.add(TRI_VOC_ATTRIBUTE_REV, - VPackValue(std::to_string(TRI_EXTRACT_MARKER_RID(marker)))); - } - if (forbidden.count(TRI_VOC_ATTRIBUTE_KEY) == 0) { - b.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key)); - } - -#if 0 - // TODO - if (TRI_IS_EDGE_MARKER(marker)) { - if (forbidden.count(TRI_VOC_ATTRIBUTE_FROM) == 0) { - std::string from(resolver->getCollectionNameCluster( - TRI_EXTRACT_MARKER_FROM_CID(marker))); - from.push_back('/'); - from.append(TRI_EXTRACT_MARKER_FROM_KEY(marker)); - b.add(TRI_VOC_ATTRIBUTE_FROM, VPackValue(from)); - } - - if (forbidden.count(TRI_VOC_ATTRIBUTE_TO) == 0) { - std::string to( - resolver->getCollectionNameCluster(TRI_EXTRACT_MARKER_TO_CID(marker))); - - to.push_back('/'); - to.append(TRI_EXTRACT_MARKER_TO_KEY(marker)); - b.add(TRI_VOC_ATTRIBUTE_TO, VPackValue(to)); - } - } -#endif - if (!keepTopLevelOpen) { - b.close(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Reads a document by cid and key -/// Also lazy locks the collection. -/// Returns null if the document does not exist -//////////////////////////////////////////////////////////////////////////////// - -static void ReadDocument(arangodb::AqlTransaction* trx, - CollectionNameResolver const* resolver, - TRI_voc_cid_t cid, char const* key, - VPackBuilder& result) { - trx->addCollectionAtRuntime(cid); - - OperationOptions options; - - VPackSlice slice; -#warning fill slice from key - OperationResult opRes = trx->document(trx->collectionName(cid), slice, options); -#warning fill mptr - - if (opRes.code != TRI_ERROR_NO_ERROR) { - result.add(VPackValue(VPackValueType::Null)); - } else { -#warning convert opRes result to vpack external - result.add(VPackValue(static_cast(nullptr), VPackValueType::External)); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief function to filter the given list of mptr -//////////////////////////////////////////////////////////////////////////////// - -static void FilterDocuments(arangodb::ExampleMatcher const* matcher, - TRI_voc_cid_t cid, - std::vector& toFilter) { - if (matcher == nullptr) { - return; - } - size_t resultCount = toFilter.size(); - for (size_t i = 0; i < resultCount; /* nothing */) { - if (!matcher->matches(cid, &toFilter[i])) { - toFilter.erase(toFilter.begin() + i); - --resultCount; - } else { - ++i; - } - } -} - static void RequestEdges(VPackSlice const& vertexSlice, arangodb::AqlTransaction* trx, std::string const& collectionName, @@ -577,7 +478,6 @@ static void RequestEdges(VPackSlice const& vertexSlice, parts[0].c_str()); } -#warning might be optimized VPackBuilder searchValueBuilder; searchValueBuilder.openArray(); switch (direction) { @@ -707,6 +607,108 @@ static void UnsetOrKeep(VPackSlice const& value, } } +static void RegisterCollectionInTransaction( + arangodb::AqlTransaction* trx, std::string const& collectionName, + TRI_voc_cid_t& cid) { + cid = trx->resolver()->getCollectionIdLocal(collectionName); + + if (cid == 0) { + THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, "'%s'", + collectionName.c_str()); + } + trx->addCollectionAtRuntime(cid); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Helper function to get a document by it's identifier +/// Lazy Locks the collection if necessary. +//////////////////////////////////////////////////////////////////////////////// + +static void GetDocumentByIdentifier(arangodb::AqlTransaction* trx, + std::string const& collectionName, + std::string const& identifier, + bool ignoreError, + VPackBuilder& result) { + OperationOptions options; + OperationResult opRes; + VPackBuilder searchBuilder; + searchBuilder.openObject(); + searchBuilder.add(VPackValue(TRI_VOC_ATTRIBUTE_KEY)); + + std::vector parts = + arangodb::basics::StringUtils::split(identifier, "/"); + + + if (parts.size() == 1) { + searchBuilder.add(VPackValue(identifier)); + searchBuilder.close(); + + try { + TRI_voc_cid_t cid; + RegisterCollectionInTransaction(trx, collectionName, cid); + } catch (arangodb::basics::Exception const& ex) { + if (ignoreError) { + return; + } + throw; + } + + opRes = trx->document(collectionName, searchBuilder.slice(), options); + } else if (parts.size() == 2) { + if (collectionName.empty()) { + searchBuilder.add(VPackValue(parts[1])); + searchBuilder.close(); + + try { + TRI_voc_cid_t cid; + RegisterCollectionInTransaction(trx, parts[0], cid); + } catch (arangodb::basics::Exception const& ex) { + if (ignoreError) { + return; + } + throw; + } + + opRes = trx->document(parts[0], searchBuilder.slice(), options); + } else if (parts[0] != collectionName) { + // Reqesting an _id that cannot be stored in this collection + if (ignoreError) { + return; + } + THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_CROSS_COLLECTION_REQUEST); + } else { + searchBuilder.add(VPackValue(parts[1])); + searchBuilder.close(); + + try { + TRI_voc_cid_t cid; + RegisterCollectionInTransaction(trx, collectionName, cid); + } catch (arangodb::basics::Exception const& ex) { + if (ignoreError) { + return; + } + throw; + } + + opRes = trx->document(collectionName, searchBuilder.slice(), options); + } + } else { + if (ignoreError) { + return; + } + THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); + } + if (opRes.failed()) { + if (ignoreError) { + return; + } + THROW_ARANGO_EXCEPTION(opRes.code); + } + + result.add(opRes.slice()); +} + + //////////////////////////////////////////////////////////////////////////////// /// @brief Helper function to merge given parameters /// Works for an array of objects as first parameter or arbitrary many @@ -784,63 +786,25 @@ static AqlValue$ MergeParameters(arangodb::aql::Query* query, return AqlValue$(b); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief Transforms VertexId to VelocyPack -//////////////////////////////////////////////////////////////////////////////// - -static void VertexIdToVPack(arangodb::AqlTransaction* trx, - CollectionNameResolver const* resolver, - VertexId const& id, - VPackBuilder& b) { - trx->addCollectionAtRuntime(id.cid); - - OperationOptions options; - - VPackSlice slice; -#warning fill slice from id.key - OperationResult opRes = trx->document(trx->collectionName(id.cid), slice, options); -#warning fill mptr - int res = opRes.code; - - if (res != TRI_ERROR_NO_ERROR) { - if (res == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) { - b.add(VPackValue(VPackValueType::Null)); - return; - } - THROW_ARANGO_EXCEPTION(res); - } - -#warning convert to vpack - b.add(VPackValue(static_cast(nullptr), VPackValueType::External)); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Transforms VertexId to std::string -//////////////////////////////////////////////////////////////////////////////// - -static std::string VertexIdToString(CollectionNameResolver const* resolver, - VertexId const& id) { - return resolver->getCollectionName(id.cid) + "/" + std::string(id.key); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief Transforms an unordered_map to AQL VelocyPack values //////////////////////////////////////////////////////////////////////////////// -static AqlValue$ VertexIdsToAqlValueVPack( - arangodb::aql::Query* query, arangodb::AqlTransaction* trx, - CollectionNameResolver const* resolver, std::unordered_set& ids, - bool includeData = false) { +static AqlValue$ VertexIdsToAqlValueVPack(arangodb::aql::Query* query, + arangodb::AqlTransaction* trx, + std::unordered_set& ids, + bool includeData = false) { std::shared_ptr result = query->getSharedBuilder(); { VPackArrayBuilder b(result.get()); if (includeData) { for (auto& it : ids) { - VertexIdToVPack(trx, resolver, it, *result); + // THROWS ERRORS if the Document was not found + GetDocumentByIdentifier(trx, "", it, false, *result); } } else { for (auto& it : ids) { - result->add(VPackValue(VertexIdToString(resolver, it))); + result->add(VPackValue(it)); } } } @@ -884,12 +848,9 @@ static arangodb::Index* getGeoIndex(arangodb::AqlTransaction* trx, } static AqlValue$ buildGeoResult(arangodb::aql::Query* query, - GeoCoordinates* cors, VocShaper* shaper, - CollectionNameResolver const* resolver, + GeoCoordinates* cors, TRI_voc_cid_t const& cid, std::string const& attributeName) { - // TODO FIXME - // note: shaper will always be nullptr here... if (cors == nullptr) { std::shared_ptr b = query->getSharedBuilder(); { @@ -944,19 +905,22 @@ static AqlValue$ buildGeoResult(arangodb::aql::Query* query, try { VPackArrayBuilder guard(b.get()); std::unordered_set forbidden; - bool saveAttr = !attributeName.empty(); - if (saveAttr) { - forbidden.emplace(attributeName); - } - - for (auto& it : distances) { -#warning convert to vpack - ExpandShapedJson(shaper, resolver, cid, it._mptr, *b, - saveAttr, forbidden); - if (saveAttr) { - // The Object is Open and attributeName is not set + if (!attributeName.empty()) { + // We have to copy the entire document + for (auto& it : distances) { + VPackObjectBuilder docGuard(b.get()); b->add(attributeName, VPackValue(it._distance)); - b->close(); + VPackSlice doc(it._mptr->vpack()); + for (auto const& entry : VPackObjectIterator(doc)) { + std::string key = entry.key.copyString(); + if (key != attributeName) { + b->add(key, entry.value); + } + } + } + } else { + for (auto& it : distances) { + InsertMasterPointer(it._mptr, *b); } } } catch (...) { @@ -2384,7 +2348,7 @@ AqlValue$ Functions::Neighbors(arangodb::aql::Query* query, if (n > 4) { auto edgeExamples = ExtractFunctionParameter(trx, parameters, 4); if (!(edgeExamples.isArray() && edgeExamples.length() == 0)) { - opts.addEdgeFilter(edgeExamples, eci->getShaper(), eCid, resolver); + opts.addEdgeFilter(edgeExamples, eCid); } } @@ -2401,10 +2365,10 @@ AqlValue$ Functions::Neighbors(arangodb::aql::Query* query, THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); } - std::unordered_set neighbors; - TRI_RunNeighborsSearch(edgeCollectionInfos, opts, neighbors); + std::unordered_set neighbors; +#warning TRI_RunNeighborsSearch(edgeCollectionInfos, opts, neighbors); - return VertexIdsToAqlValueVPack(query, trx, resolver, neighbors, includeData); + return VertexIdsToAqlValueVPack(query, trx, neighbors, includeData); } //////////////////////////////////////////////////////////////////////////////// @@ -2478,7 +2442,7 @@ AqlValue$ Functions::Near(arangodb::aql::Query* query, trx, latitude.getNumericValue(), longitude.getNumericValue(), limitValue); - return buildGeoResult(query, cors, nullptr, resolver, cid, attributeName); + return buildGeoResult(query, cors, cid, attributeName); } //////////////////////////////////////////////////////////////////////////////// @@ -2540,7 +2504,7 @@ AqlValue$ Functions::Within(arangodb::aql::Query* query, trx, latitude.getNumericValue(), longitude.getNumericValue(), radius.getNumericValue()); - return buildGeoResult(query, cors, nullptr, resolver, cid, attributeName); + return buildGeoResult(query, cors, cid, attributeName); } //////////////////////////////////////////////////////////////////////////////// @@ -2745,103 +2709,6 @@ AqlValue$ Functions::Minus(arangodb::aql::Query* query, return AqlValue$(b.get()); } -static void RegisterCollectionInTransaction( - arangodb::AqlTransaction* trx, std::string const& collectionName, - TRI_voc_cid_t& cid) { - cid = trx->resolver()->getCollectionIdLocal(collectionName); - - if (cid == 0) { - THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, "'%s'", - collectionName.c_str()); - } - trx->addCollectionAtRuntime(cid); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Helper function to get a document by it's identifier -/// The collection has to be locked by the transaction before -//////////////////////////////////////////////////////////////////////////////// - -static void GetDocumentByIdentifier(arangodb::AqlTransaction* trx, - std::string const& collectionName, - std::string const& identifier, - VPackBuilder& result) { - OperationOptions options; - - std::vector parts = - arangodb::basics::StringUtils::split(identifier, "/"); - - if (parts.size() == 1) { - VPackSlice slice; -#warning fill slice from parts[0] - OperationResult opRes = trx->document(collectionName, slice, options); -#warning fill mptr - if (!opRes.successful()) { - return; - } - } else if (parts.size() == 2) { - if (parts[0] != collectionName) { - // Reqesting an _id that cannot be stored in this collection - return; - } - VPackSlice slice; -#warning fill slice from parts[1] - OperationResult opRes = trx->document(collectionName, slice, options); -#warning fill mptr - if (!opRes.successful()) { - return; - } - } else { - return; - } - -#warning convert to vpack - result.add(VPackValue(static_cast(nullptr), VPackValueType::External)); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Helper function to get a document by its _id -/// This function will lazy read-lock the collection. -/// this function will not throw if the document or the collection cannot be -/// found -//////////////////////////////////////////////////////////////////////////////// - -static void GetDocumentByIdentifier(arangodb::AqlTransaction* trx, - std::string const& identifier, - VPackBuilder& result) { - std::vector parts = - arangodb::basics::StringUtils::split(identifier, "/"); - - if (parts.size() != 2) { - return; - } - std::string collectionName = parts[0]; - TRI_voc_cid_t cid = 0; - try { - RegisterCollectionInTransaction(trx, collectionName, cid); - } catch (arangodb::basics::Exception const& ex) { - // don't throw if collection is not found - if (ex.code() == TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) { - return; - } - throw; - } - - OperationOptions options; - - VPackSlice slice; -#warning fill slice from parts[1] - OperationResult opRes = trx->document(collectionName, slice, options); -#warning fill mptr - - if (opRes.code != TRI_ERROR_NO_ERROR) { - return; - } - -#warning convert opRes result to vpack external - result.add(VPackValue(static_cast(nullptr), VPackValueType::External)); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief function Document //////////////////////////////////////////////////////////////////////////////// @@ -2862,7 +2729,7 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query, std::shared_ptr b = query->getSharedBuilder(); if (id.isString()) { std::string identifier = id.copyString(); - GetDocumentByIdentifier(trx, identifier, *b); + GetDocumentByIdentifier(trx, "", identifier, true, *b); if (b->isEmpty()) { // not found b->add(VPackValue(VPackValueType::Null)); @@ -2870,13 +2737,9 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query, } else if (id.isArray()) { VPackArrayBuilder guard(b.get()); for (auto const& next : VPackArrayIterator(id)) { - try { - if (next.isString()) { - std::string identifier = next.copyString(); - GetDocumentByIdentifier(trx, identifier, *b); - } - } catch (arangodb::basics::Exception const&) { - // Ignore all ArangoDB exceptions here + if (next.isString()) { + std::string identifier = next.copyString(); + GetDocumentByIdentifier(trx, "", identifier, true, *b); } } } else { @@ -2891,19 +2754,8 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query, } std::string collectionName = collectionSlice.copyString(); - TRI_voc_cid_t cid; bool notFound = false; - try { - RegisterCollectionInTransaction(trx, collectionName, cid); - } catch (arangodb::basics::Exception const& ex) { - // don't throw if collection is not found - if (ex.code() != TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) { - throw; - } - notFound = true; - } - VPackSlice id = ExtractFunctionParameter(trx, parameters, 1); if (id.isString()) { if (notFound) { @@ -2913,7 +2765,7 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query, } std::shared_ptr b = query->getSharedBuilder(); std::string identifier = id.copyString(); - GetDocumentByIdentifier(trx, collectionName, identifier, *b); + GetDocumentByIdentifier(trx, collectionName, identifier, true, *b); if (b->isEmpty()) { b->add(VPackValue(VPackValueType::Null)); } @@ -2924,13 +2776,9 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query, VPackArrayBuilder guard(b.get()); if (!notFound) { for (auto const& next : VPackArrayIterator(id)) { - try { - if (next.isString()) { - std::string identifier = next.copyString(); - GetDocumentByIdentifier(trx, collectionName, identifier, *b); - } - } catch (arangodb::basics::Exception const&) { - // Ignore all ArangoDB exceptions here + if (next.isString()) { + std::string identifier = next.copyString(); + GetDocumentByIdentifier(trx, collectionName, identifier, true, *b); } } } @@ -3014,8 +2862,6 @@ AqlValue$ Functions::Edges(arangodb::aql::Query* query, return AqlValue$(b.get()); } - auto resolver = trx->resolver(); - std::unique_ptr matcher; TRI_document_collection_t* documentCollection = trx->documentCollection(cid); @@ -3029,7 +2875,7 @@ AqlValue$ Functions::Edges(arangodb::aql::Query* query, if ((exampleSlice.isArray() && exampleSlice.length() != 0)|| exampleSlice.isObject()) { try { matcher.reset( - new arangodb::ExampleMatcher(exampleSlice, resolver, false)); + new arangodb::ExampleMatcher(exampleSlice, false)); } catch (arangodb::basics::Exception const& e) { if (e.code() != TRI_RESULT_ELEMENT_NOT_FOUND) { throw; @@ -4361,7 +4207,6 @@ AqlValue$ Functions::Fulltext(arangodb::aql::Query* query, THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); } - auto shaper = document->getShaper(); size_t const numResults = queryResult->_numDocuments; std::shared_ptr b = query->getSharedBuilder(); @@ -4369,11 +4214,8 @@ AqlValue$ Functions::Fulltext(arangodb::aql::Query* query, VPackArrayBuilder guard(b.get()); for (size_t i = 0; i < numResults; ++i) { - std::unordered_set unused; -#warning convert to vpack - ExpandShapedJson(shaper, resolver, cid, - (TRI_doc_mptr_t const*)queryResult->_documents[i], *b, - false, unused); + InsertMasterPointer((TRI_doc_mptr_t const*)queryResult->_documents[i], + *b); } } catch (...) { TRI_FreeResultFulltextIndex(queryResult); diff --git a/arangod/RestHandler/RestDocumentHandler.cpp b/arangod/RestHandler/RestDocumentHandler.cpp index c96bc9fe32..71627d3efc 100644 --- a/arangod/RestHandler/RestDocumentHandler.cpp +++ b/arangod/RestHandler/RestDocumentHandler.cpp @@ -81,25 +81,29 @@ HttpHandler::status_t RestDocumentHandler::execute() { bool RestDocumentHandler::createDocument() { std::vector const& suffix = _request->suffix(); - if (!suffix.empty()) { + if (suffix.size() > 1) { generateError(HttpResponse::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES, "superfluous suffix, expecting " + DOCUMENT_PATH + "?collection="); return false; } - // extract the cid bool found; - char const* collection = _request->value("collection", found); + std::string collectionName; + if (suffix.size() == 1) { + collectionName = suffix[0]; + found = true; + } else { + collectionName = _request->value("collection", found); + } - if (!found || *collection == '\0') { + if (!found || collectionName.empty()) { generateError(HttpResponse::BAD, TRI_ERROR_ARANGO_COLLECTION_PARAMETER_MISSING, "'collection' is missing, expecting " + DOCUMENT_PATH + - "?collection="); + "/ or query parameter 'collection'"); return false; } - std::string collectionName(collection); bool parseSuccess = true; // copy default options @@ -111,28 +115,23 @@ bool RestDocumentHandler::createDocument() { return false; } - - /* TODO - if (!checkCreateCollection(collection, getCollectionType())) { - return false; - } - */ - // find and load collection given by name or identifier SingleCollectionTransaction trx(StandaloneTransactionContext::Create(_vocbase), - collection, TRI_TRANSACTION_WRITE); - trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); + collectionName, TRI_TRANSACTION_WRITE); + VPackSlice body = parsedBody->slice(); + if (!body.isArray()) { + trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); + } int res = trx.begin(); if (res != TRI_ERROR_NO_ERROR) { - generateTransactionError(collection, res, ""); + generateTransactionError(collectionName, res, ""); return false; } arangodb::OperationOptions opOptions; opOptions.waitForSync = extractWaitForSync(); - VPackSlice body = parsedBody->slice(); arangodb::OperationResult result = trx.insert(collectionName, body, opOptions); // Will commit if no error occured. @@ -165,12 +164,8 @@ bool RestDocumentHandler::readDocument() { switch (len) { case 0: - return readAllDocuments(); - case 1: - generateError(HttpResponse::BAD, TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD, - "expecting GET /_api/document/"); - return false; + return readAllDocuments(); case 2: return readSingleDocument(true); @@ -227,9 +222,9 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) { collection, TRI_TRANSACTION_READ); trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); - // ............................................................................. + // ........................................................................... // inside read transaction - // ............................................................................. + // ........................................................................... int res = trx.begin(); @@ -239,6 +234,7 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) { } OperationOptions options; + options.ignoreRevs = false; OperationResult result = trx.document(collection, search, options); res = trx.finish(result.code); @@ -260,9 +256,7 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) { return false; } - TRI_voc_rid_t const rid = - VelocyPackHelper::getNumericValue( - result.slice(), TRI_VOC_ATTRIBUTE_REV, 0); + TRI_voc_rid_t const rid = TRI_extractRevisionId(result.slice()); if (ifNoneRid != 0 && ifNoneRid == rid) { generateNotModified(rid); } else { @@ -280,7 +274,14 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) { bool RestDocumentHandler::readAllDocuments() { bool found; - std::string const collectionName = _request->value("collection", found); + std::string collectionName; + + std::vector const& suffix = _request->suffix(); + if (suffix.size() == 1) { + collectionName = suffix[0]; + } else { + collectionName = _request->value("collection", found); + } std::string returnType = _request->value("type", found); if (returnType.empty()) { diff --git a/arangod/RestHandler/RestVocbaseBaseHandler.cpp b/arangod/RestHandler/RestVocbaseBaseHandler.cpp index 8256cac48e..e4f449dd5c 100644 --- a/arangod/RestHandler/RestVocbaseBaseHandler.cpp +++ b/arangod/RestHandler/RestVocbaseBaseHandler.cpp @@ -150,9 +150,9 @@ void RestVocbaseBaseHandler::generateSaved( arangodb::OperationResult const& result, std::string const& collectionName, TRI_col_type_e type) { if (result.wasSynchronous) { - createResponse(rest::HttpResponse::ACCEPTED); - } else { createResponse(rest::HttpResponse::CREATED); + } else { + createResponse(rest::HttpResponse::ACCEPTED); } generate20x(result, collectionName, type); } diff --git a/arangod/Utils/CollectionNameResolver.h b/arangod/Utils/CollectionNameResolver.h index 5f4e6081cd..47a2d8a19e 100644 --- a/arangod/Utils/CollectionNameResolver.h +++ b/arangod/Utils/CollectionNameResolver.h @@ -366,6 +366,21 @@ class CollectionNameResolver { buffer.appendText("_unknown"); } + ////////////////////////////////////////////////////////////////////////////// + /// @brief return collection name if given string is either the name or + /// a string with the (numerical) collection id, this returns the cluster + /// wide collection name in the DBserver case + ////////////////////////////////////////////////////////////////////////////// + + std::string getCollectionName(std::string const& nameOrId) const { + if (!nameOrId.empty() && + (nameOrId[0] < '0' || nameOrId[0] > '9')) { + return nameOrId; + } + TRI_voc_cid_t tmp = arangodb::basics::StringUtils::uint64(nameOrId); + return getCollectionName(tmp); + } + private: ////////////////////////////////////////////////////////////////////////////// /// @brief vocbase base pointer diff --git a/arangod/Utils/Transaction.cpp b/arangod/Utils/Transaction.cpp index 2c888e7aba..110b3423e2 100644 --- a/arangod/Utils/Transaction.cpp +++ b/arangod/Utils/Transaction.cpp @@ -198,25 +198,6 @@ std::string Transaction::extractKey(VPackSlice const slice) { return ""; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief extract the _rev attribute from a slice -//////////////////////////////////////////////////////////////////////////////// - -TRI_voc_rid_t Transaction::extractRevisionId(VPackSlice const slice) { - TRI_ASSERT(slice.isObject()); - - VPackSlice r(slice.get(TRI_VOC_ATTRIBUTE_REV)); - if (r.isString()) { - VPackValueLength length; - char const* p = r.getString(length); - return arangodb::basics::StringUtils::uint64(p, length); - } - if (r.isInteger()) { - return r.getNumber(); - } - return 0; -} - ////////////////////////////////////////////////////////////////////////////// /// @brief extract the _id attribute from a slice, and convert it into a /// string @@ -575,7 +556,7 @@ OperationResult Transaction::documentCoordinator(std::string const& collectionNa if (key.empty()) { return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD); } - TRI_voc_rid_t expectedRevision = Transaction::extractRevisionId(value); + TRI_voc_rid_t expectedRevision = TRI_extractRevisionId(value); int res = arangodb::getDocumentOnCoordinator( _vocbase->_name, collectionName, key, expectedRevision, headers, true, @@ -636,7 +617,7 @@ OperationResult Transaction::documentLocal(std::string const& collectionName, TRI_voc_rid_t expectedRevision = 0; if (!options.ignoreRevs) { - expectedRevision = Transaction::extractRevisionId(value); + expectedRevision = TRI_extractRevisionId(value); } TRI_doc_mptr_t mptr; @@ -654,6 +635,8 @@ OperationResult Transaction::documentLocal(std::string const& collectionName, } if (!options.silent) { + //resultBuilder.add(VPackValue(static_cast(mptr.vpack()), VPackValueType::External)); + // This is the future, for now, we have to do this: resultBuilder.add(VPackSlice(mptr.vpack())); } @@ -950,7 +933,7 @@ OperationResult Transaction::updateCoordinator(std::string const& collectionName return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD); } TRI_voc_rid_t const expectedRevision - = options.ignoreRevs ? 0 : Transaction::extractRevisionId(newValue); + = options.ignoreRevs ? 0 : TRI_extractRevisionId(newValue); int res = arangodb::modifyDocumentOnCoordinator( _vocbase->_name, collectionName, key, expectedRevision, @@ -1038,7 +1021,7 @@ OperationResult Transaction::replaceCoordinator(std::string const& collectionNam return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD); } TRI_voc_rid_t const expectedRevision - = options.ignoreRevs ? 0 : Transaction::extractRevisionId(newValue); + = options.ignoreRevs ? 0 : TRI_extractRevisionId(newValue); int res = arangodb::modifyDocumentOnCoordinator( _vocbase->_name, collectionName, key, expectedRevision, @@ -1206,7 +1189,7 @@ OperationResult Transaction::removeCoordinator(std::string const& collectionName if (key.empty()) { return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD); } - TRI_voc_rid_t expectedRevision = Transaction::extractRevisionId(value); + TRI_voc_rid_t expectedRevision = TRI_extractRevisionId(value); int res = arangodb::deleteDocumentOnCoordinator( _vocbase->_name, collectionName, key, expectedRevision, @@ -1309,16 +1292,18 @@ OperationResult Transaction::allKeys(std::string const& collectionName, std::string prefix; + std::string realCollName = resolver()->getCollectionName(collectionName); + if (type == "key") { prefix = ""; } else if (type == "id") { - prefix = collectionName + "/"; + prefix = realCollName + "/"; } else { // default return type: paths to documents if (isEdgeCollection(collectionName)) { - prefix = std::string("/_db/") + _vocbase->_name + "/_api/edge/" + collectionName + "/"; + prefix = std::string("/_db/") + _vocbase->_name + "/_api/edge/" + realCollName + "/"; } else { - prefix = std::string("/_db/") + _vocbase->_name + "/_api/document/" + collectionName + "/"; + prefix = std::string("/_db/") + _vocbase->_name + "/_api/document/" + realCollName + "/"; } } diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index 0863e5d16d..6aeb488648 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -216,12 +216,6 @@ class Transaction { static std::string extractKey(VPackSlice const); - ////////////////////////////////////////////////////////////////////////////// - /// @brief extract the _rev attribute from a slice - ////////////////////////////////////////////////////////////////////////////// - - static TRI_voc_rid_t extractRevisionId(VPackSlice const); - ////////////////////////////////////////////////////////////////////////////// /// @brief extract the _id attribute from a slice, and convert it into a /// string diff --git a/arangod/V8Server/V8Traverser.cpp b/arangod/V8Server/V8Traverser.cpp index 73c374c477..07ce054a61 100644 --- a/arangod/V8Server/V8Traverser.cpp +++ b/arangod/V8Server/V8Traverser.cpp @@ -248,13 +248,12 @@ bool BasicOptions::matchesVertex(VertexId const& v) const { // OperationResult opRes = trx->document(it->second.col, slice, options); OperationResult opRes(TRI_ERROR_INTERNAL); #warning fill vertex - TRI_doc_mptr_t vertex; if (!opRes.successful()) { return false; } - return it->second.matcher->matches(v.cid, &vertex); + return it->second.matcher->matches(opRes.slice()); } //////////////////////////////////////////////////////////////////////////////// @@ -302,13 +301,12 @@ void BasicOptions::addEdgeFilter(Json const& example, VocShaper* shaper, /// @brief Insert a new edge matcher object //////////////////////////////////////////////////////////////////////////////// -void BasicOptions::addEdgeFilter(VPackSlice const& example, VocShaper* shaper, - TRI_voc_cid_t const& cid, - CollectionNameResolver const* resolver) { +void BasicOptions::addEdgeFilter(VPackSlice const& example, + TRI_voc_cid_t const& cid) { useEdgeFilter = true; auto it = _edgeFilter.find(cid); if (it == _edgeFilter.end()) { - _edgeFilter.emplace(cid, new ExampleMatcher(example, resolver, true)); + _edgeFilter.emplace(cid, new ExampleMatcher(example, true)); } } @@ -332,7 +330,7 @@ bool BasicOptions::matchesEdge(EdgeId& e, TRI_doc_mptr_t* edge) const { return false; } - return it->second->matches(e.cid, edge); + return it->second->matches(VPackSlice(edge->vpack())); } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/V8Server/V8Traverser.h b/arangod/V8Server/V8Traverser.h index bd3972f7db..3c3ebde09e 100644 --- a/arangod/V8Server/V8Traverser.h +++ b/arangod/V8Server/V8Traverser.h @@ -121,9 +121,8 @@ struct BasicOptions { TRI_voc_cid_t const& cid, arangodb::CollectionNameResolver const* resolver); - void addEdgeFilter(arangodb::velocypack::Slice const& example, VocShaper* shaper, - TRI_voc_cid_t const& cid, - arangodb::CollectionNameResolver const* resolver); + void addEdgeFilter(arangodb::velocypack::Slice const& example, + TRI_voc_cid_t const& cid); void addVertexFilter(v8::Isolate* isolate, v8::Handle const& example, diff --git a/arangod/V8Server/v8-collection.cpp b/arangod/V8Server/v8-collection.cpp index fcdf8a2af5..36f4c9c34c 100644 --- a/arangod/V8Server/v8-collection.cpp +++ b/arangod/V8Server/v8-collection.cpp @@ -526,12 +526,13 @@ static void DocumentVocbase( LocalCollectionGuard g(const_cast(col)); TRI_ASSERT(col != nullptr); - TRI_ASSERT(!collectionName.empty()); + VPackSlice search = builder.slice(); TRI_ASSERT(search.isObject()); - SingleCollectionTransaction trx(transactionContext, collectionName, TRI_TRANSACTION_READ); + SingleCollectionTransaction trx(transactionContext, collectionName, + TRI_TRANSACTION_READ); trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); int res = trx.begin(); @@ -564,11 +565,121 @@ static void DocumentVocbase( } //////////////////////////////////////////////////////////////////////////////// -/// @brief deletes a document, using a VPack marker +/// @brief deletes (a) document(s), collection method //////////////////////////////////////////////////////////////////////////////// -static void RemoveVocbaseVPack( - bool useCollection, v8::FunctionCallbackInfo const& args) { +static void RemoveVocbaseCol(v8::FunctionCallbackInfo const& args) { + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope scope(isolate); + OperationOptions options; + options.ignoreRevs = false; + + // check the arguments + uint32_t const argLength = args.Length(); + + TRI_GET_GLOBALS(); + + if (argLength < 1 || argLength > 3) { + TRI_V8_THROW_EXCEPTION_USAGE("remove(, )"); + } + + if (argLength > 1) { + if (args[1]->IsObject()) { + v8::Handle optionsObject = args[1].As(); + TRI_GET_GLOBAL_STRING(OverwriteKey); + if (optionsObject->Has(OverwriteKey)) { + options.ignoreRevs = TRI_ObjectToBoolean(optionsObject->Get(OverwriteKey)); + } + TRI_GET_GLOBAL_STRING(WaitForSyncKey); + if (optionsObject->Has(WaitForSyncKey)) { + options.waitForSync = + TRI_ObjectToBoolean(optionsObject->Get(WaitForSyncKey)); + } + } else { // old variant remove(, , ) + options.ignoreRevs = TRI_ObjectToBoolean(args[1]); + if (argLength > 2) { + options.waitForSync = TRI_ObjectToBoolean(args[2]); + } + } + } + + // Find collection and vocbase + std::string collectionName; + TRI_vocbase_col_t const* col + = TRI_UnwrapClass(args.Holder(), WRP_VOCBASE_COL_TYPE); + if (col == nullptr) { + TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract collection"); + } + TRI_vocbase_t* vocbase = col->_vocbase; + collectionName = col->name(); + if (vocbase == nullptr) { + TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); + } + + auto transactionContext = std::make_shared(vocbase, true); + + SingleCollectionTransaction trx(transactionContext, collectionName, TRI_TRANSACTION_WRITE); + if (!args[0]->IsArray()) { + trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); + } + + int res = trx.begin(); + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } + + VPackBuilder searchBuilder; + + auto workOnOneDocument = [&](v8::Local const searchValue) { + std::string collName; + if (!ExtractDocumentHandle(isolate, searchValue, collName, searchBuilder, + true)) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); + } + if (!collName.empty() && collName != collectionName) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_CROSS_COLLECTION_REQUEST); + } + }; + + if (!args[0]->IsArray()) { + VPackObjectBuilder guard(&searchBuilder); + workOnOneDocument(args[0]); + } else { + VPackArrayBuilder guard(&searchBuilder); + auto searchVals = v8::Local::Cast(args[0]); + for (uint32_t i = 0; i < searchVals->Length(); ++i) { + VPackObjectBuilder guard(&searchBuilder); + workOnOneDocument(searchVals->Get(i)); + } + } + + VPackSlice toRemove = searchBuilder.slice(); + + OperationResult result = trx.remove(collectionName, toRemove, options); + + res = trx.finish(result.code); + + if (!result.successful()) { + if (result.code == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND && + options.ignoreRevs && !args[0]->IsArray()) { + TRI_V8_RETURN_FALSE(); + } else { + TRI_V8_THROW_EXCEPTION(result.code); + } + } + + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } + + TRI_V8_RETURN_TRUE(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief deletes a document, database method +//////////////////////////////////////////////////////////////////////////////// + +static void RemoveVocbase(v8::FunctionCallbackInfo const& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); OperationOptions options; @@ -607,34 +718,16 @@ static void RemoveVocbaseVPack( TRI_vocbase_t* vocbase; TRI_vocbase_col_t const* col = nullptr; - if (useCollection) { - // called as db.collection.remove() - col = - TRI_UnwrapClass(args.Holder(), WRP_VOCBASE_COL_TYPE); - - if (col == nullptr) { - TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract collection"); - } - - vocbase = col->_vocbase; - } else { - // called as db._remove() - vocbase = GetContextVocBase(isolate); - } - + vocbase = GetContextVocBase(isolate); if (vocbase == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } - auto transactionContext = std::make_shared(vocbase, true); VPackBuilder builder; std::string collectionName; - LocalCollectionGuard g(useCollection ? nullptr - : const_cast(col)); - { VPackObjectBuilder guard(&builder); int res = ParseDocumentOrDocumentHandle( isolate, vocbase, transactionContext->getResolver(), col, collectionName, builder, @@ -645,10 +738,16 @@ static void RemoveVocbaseVPack( } } + LocalCollectionGuard g(const_cast(col)); + + TRI_ASSERT(col != nullptr); + TRI_ASSERT(!collectionName.empty()); + VPackSlice toRemove = builder.slice(); TRI_ASSERT(toRemove.isObject()); - SingleCollectionTransaction trx(transactionContext, collectionName, TRI_TRANSACTION_WRITE); + SingleCollectionTransaction trx(transactionContext, collectionName, + TRI_TRANSACTION_WRITE); trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); int res = trx.begin(); @@ -662,7 +761,8 @@ static void RemoveVocbaseVPack( res = trx.finish(result.code); if (!result.successful()) { - if (result.code == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND && options.ignoreRevs) { + if (result.code == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND && + options.ignoreRevs) { TRI_V8_RETURN_FALSE(); } else { TRI_V8_THROW_EXCEPTION(result.code); @@ -1329,10 +1429,10 @@ static void JS_PropertiesVocbaseCol( TRI_V8_TRY_CATCH_END } -static void JS_RemoveVocbaseVPack( +static void JS_RemoveVocbaseCol( v8::FunctionCallbackInfo const& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); - return RemoveVocbaseVPack(true, args); + return RemoveVocbaseCol(args); TRI_V8_TRY_CATCH_END } @@ -2615,7 +2715,7 @@ static void JS_CompletionsVocbase( static void JS_RemoveVocbase(v8::FunctionCallbackInfo const& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); - return RemoveVocbaseVPack(false, args); + return RemoveVocbase(args); TRI_V8_TRY_CATCH_END } @@ -2921,7 +3021,7 @@ void TRI_InitV8collection(v8::Handle context, TRI_server_t* server, TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING("properties"), JS_PropertiesVocbaseCol); TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING("remove"), - JS_RemoveVocbaseVPack); + JS_RemoveVocbaseCol); TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING("revision"), JS_RevisionVocbaseCol); TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING("rename"), diff --git a/arangod/VocBase/ExampleMatcher.cpp b/arangod/VocBase/ExampleMatcher.cpp index 031c20bd7e..7640cc80fe 100644 --- a/arangod/VocBase/ExampleMatcher.cpp +++ b/arangod/VocBase/ExampleMatcher.cpp @@ -75,7 +75,7 @@ void ExampleMatcher::fillExampleDefinition( } void ExampleMatcher::fillExampleDefinition( - VPackSlice const& example, CollectionNameResolver const* resolver, + VPackSlice const& example, ExampleDefinition& def) { TRI_ASSERT(def._values.isEmpty()); VPackArrayBuilder guard(&def._values); @@ -166,11 +166,10 @@ ExampleMatcher::ExampleMatcher(TRI_json_t const* example, //////////////////////////////////////////////////////////////////////////////// ExampleMatcher::ExampleMatcher(VPackSlice const& example, - CollectionNameResolver const* resolver, bool allowStrings) { if (example.isObject() || example.isString()) { ExampleDefinition def; - ExampleMatcher::fillExampleDefinition(example, resolver, def); + ExampleMatcher::fillExampleDefinition(example, def); definitions.emplace_back(std::move(def)); } else if (example.isArray()) { for (auto const& e : VPackArrayIterator(example)) { @@ -179,7 +178,7 @@ ExampleMatcher::ExampleMatcher(VPackSlice const& example, // We do not match strings in Array continue; } - ExampleMatcher::fillExampleDefinition(e, resolver, def); + ExampleMatcher::fillExampleDefinition(e, def); definitions.emplace_back(std::move(def)); } if (definitions.empty()) { @@ -190,16 +189,11 @@ ExampleMatcher::ExampleMatcher(VPackSlice const& example, } } - //////////////////////////////////////////////////////////////////////////////// -/// @brief Checks if the given mptr matches the examples in this class +/// @brief Checks if the given velocyPack matches the examples in this class //////////////////////////////////////////////////////////////////////////////// -bool ExampleMatcher::matches(TRI_voc_cid_t, TRI_doc_mptr_t const* mptr) const { - if (mptr == nullptr) { - return false; - } - VPackSlice toMatch(mptr->vpack()); +bool ExampleMatcher::matches(VPackSlice const toMatch) const { for (auto const& def : definitions) { VPackSlice const compareValue = def.slice(); size_t i = 0; @@ -220,12 +214,3 @@ bool ExampleMatcher::matches(TRI_voc_cid_t, TRI_doc_mptr_t const* mptr) const { } return false; } - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Checks if the given velocyPack matches the examples in this class -//////////////////////////////////////////////////////////////////////////////// - -bool ExampleMatcher::matches(VPackSlice const slice) const { -#warning IMPLEMENT THIS - THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); -} diff --git a/arangod/VocBase/ExampleMatcher.h b/arangod/VocBase/ExampleMatcher.h index 64c33fb715..e65a7ab6ac 100644 --- a/arangod/VocBase/ExampleMatcher.h +++ b/arangod/VocBase/ExampleMatcher.h @@ -29,8 +29,6 @@ #include -struct TRI_doc_mptr_t; - namespace arangodb { namespace velocypack { @@ -50,7 +48,6 @@ class ExampleMatcher { std::vector definitions; void fillExampleDefinition(arangodb::velocypack::Slice const& example, - arangodb::CollectionNameResolver const* resolver, ExampleDefinition& def); void fillExampleDefinition(v8::Isolate* isolate, @@ -69,13 +66,10 @@ class ExampleMatcher { arangodb::CollectionNameResolver const* resolver); ExampleMatcher(arangodb::velocypack::Slice const& example, - arangodb::CollectionNameResolver const* resolver, bool allowStrings); ~ExampleMatcher() { } - bool matches(TRI_voc_cid_t, TRI_doc_mptr_t const* mptr) const; - bool matches(arangodb::velocypack::Slice const) const; }; } diff --git a/arangod/VocBase/MasterPointer.cpp b/arangod/VocBase/MasterPointer.cpp index 7e3313a896..f878e745eb 100644 --- a/arangod/VocBase/MasterPointer.cpp +++ b/arangod/VocBase/MasterPointer.cpp @@ -23,6 +23,7 @@ #include "MasterPointer.h" #include "Basics/VelocyPackHelper.h" +#include "VocBase/vocbase.h" #include #include @@ -31,13 +32,6 @@ using namespace arangodb; TRI_voc_rid_t TRI_doc_mptr_t::revisionId() const { VPackSlice const slice(vpack()); - VPackSlice const revisionSlice = slice.get(TRI_VOC_ATTRIBUTE_REV); - if (revisionSlice.isString()) { - return arangodb::basics::VelocyPackHelper::stringUInt64(revisionSlice); - } - else if (revisionSlice.isNumber()) { - return revisionSlice.getNumber(); - } - return 0; + return TRI_extractRevisionId(slice); } diff --git a/arangod/VocBase/transaction.cpp b/arangod/VocBase/transaction.cpp index a413b8ca3e..c19164df10 100644 --- a/arangod/VocBase/transaction.cpp +++ b/arangod/VocBase/transaction.cpp @@ -1046,8 +1046,6 @@ int TRI_AddOperationTransaction(TRI_transaction_t* trx, trx->_waitForSync = true; } - // default is false - waitForSync = false; if (isSingleOperationTransaction) { waitForSync |= document->_info.waitForSync(); } diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index 03a03f09f7..089d1d97a9 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -2317,3 +2317,22 @@ void TRI_FillVPackSub(TRI_vpack_sub_t* sub, } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief extract the _rev attribute from a slice +//////////////////////////////////////////////////////////////////////////////// + +TRI_voc_rid_t TRI_extractRevisionId(VPackSlice const slice) { + TRI_ASSERT(slice.isObject()); + + VPackSlice r(slice.get(TRI_VOC_ATTRIBUTE_REV)); + if (r.isString()) { + VPackValueLength length; + char const* p = r.getString(length); + return arangodb::basics::StringUtils::uint64(p, length); + } + if (r.isInteger()) { + return r.getNumber(); + } + return 0; +} + diff --git a/arangod/VocBase/vocbase.h b/arangod/VocBase/vocbase.h index 447faa8019..3bc1fdf426 100644 --- a/arangod/VocBase/vocbase.h +++ b/arangod/VocBase/vocbase.h @@ -27,6 +27,7 @@ #include "Basics/Common.h" #include "Basics/DeadlockDetector.h" #include "Basics/ReadWriteLock.h" +#include "Basics/StringUtils.h" #include "Basics/threads.h" #include "Basics/vector.h" #include "Basics/voc-errors.h" @@ -627,4 +628,10 @@ bool TRI_GetThrowCollectionNotLoadedVocBase(TRI_vocbase_t*); void TRI_SetThrowCollectionNotLoadedVocBase(TRI_vocbase_t*, bool); +//////////////////////////////////////////////////////////////////////////////// +/// @brief extract the _rev attribute from a slice +//////////////////////////////////////////////////////////////////////////////// + +TRI_voc_rid_t TRI_extractRevisionId(VPackSlice const slice); + #endif