1
0
Fork 0

Merge branch 'spdvpk' of https://github.com/arangodb/arangodb into spdvpk

This commit is contained in:
Jan Steemann 2016-03-09 17:56:57 +01:00
commit 7e01c3208a
20 changed files with 453 additions and 639 deletions

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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)

View File

@ -66,6 +66,17 @@ using VertexId = arangodb::traverser::VertexId;
thread_local std::unordered_map<std::string, RegexMatcher*>* 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<void const*>(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<std::string> const& forbidden) {
b.add(VPackValue(VPackValueType::Object));
TRI_df_marker_t const* marker =
static_cast<TRI_df_marker_t const*>(mptr->getDataPtr());
TRI_shaped_json_t shaped;
TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, marker);
std::shared_ptr<VPackBuilder> 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<void const*>(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<TRI_doc_mptr_t>& 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<std::string> 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<void const*>(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<VertexId> to AQL VelocyPack values
////////////////////////////////////////////////////////////////////////////////
static AqlValue$ VertexIdsToAqlValueVPack(
arangodb::aql::Query* query, arangodb::AqlTransaction* trx,
CollectionNameResolver const* resolver, std::unordered_set<VertexId>& ids,
bool includeData = false) {
static AqlValue$ VertexIdsToAqlValueVPack(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
std::unordered_set<std::string>& ids,
bool includeData = false) {
std::shared_ptr<VPackBuilder> 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<VPackBuilder> b = query->getSharedBuilder();
{
@ -944,19 +905,22 @@ static AqlValue$ buildGeoResult(arangodb::aql::Query* query,
try {
VPackArrayBuilder guard(b.get());
std::unordered_set<std::string> 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<VertexId> neighbors;
TRI_RunNeighborsSearch(edgeCollectionInfos, opts, neighbors);
std::unordered_set<std::string> 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<double>(),
longitude.getNumericValue<double>(), 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<double>(),
longitude.getNumericValue<double>(), radius.getNumericValue<double>());
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<std::string> 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<void const*>(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<std::string> 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<void const*>(nullptr), VPackValueType::External));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief function Document
////////////////////////////////////////////////////////////////////////////////
@ -2862,7 +2729,7 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query,
std::shared_ptr<VPackBuilder> 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<VPackBuilder> 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<arangodb::ExampleMatcher> 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<VPackBuilder> 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<std::string> 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);

View File

@ -81,25 +81,29 @@ HttpHandler::status_t RestDocumentHandler::execute() {
bool RestDocumentHandler::createDocument() {
std::vector<std::string> 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=<identifier>");
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=<identifier>");
"/<collectionname> 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/<document-handle>");
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<TRI_voc_rid_t>(
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<std::string> 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()) {

View File

@ -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);
}

View File

@ -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

View File

@ -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<TRI_voc_rid_t>();
}
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<void const*>(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 + "/";
}
}

View File

@ -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

View File

@ -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()));
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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<v8::Value> const& example,

View File

@ -526,12 +526,13 @@ static void DocumentVocbase(
LocalCollectionGuard g(const_cast<TRI_vocbase_col_t*>(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<v8::Value> const& args) {
static void RemoveVocbaseCol(v8::FunctionCallbackInfo<v8::Value> 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(<document>, <options>)");
}
if (argLength > 1) {
if (args[1]->IsObject()) {
v8::Handle<v8::Object> optionsObject = args[1].As<v8::Object>();
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(<document>, <overwrite>, <waitForSync>)
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<TRI_vocbase_col_t>(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<V8TransactionContext>(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<v8::Value> 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<v8::Array>::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<v8::Value> 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<TRI_vocbase_col_t>(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<V8TransactionContext>(vocbase, true);
VPackBuilder builder;
std::string collectionName;
LocalCollectionGuard g(useCollection ? nullptr
: const_cast<TRI_vocbase_col_t*>(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<TRI_vocbase_col_t*>(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<v8::Value> 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<v8::Value> 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<v8::Context> 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"),

View File

@ -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);
}

View File

@ -29,8 +29,6 @@
#include <v8.h>
struct TRI_doc_mptr_t;
namespace arangodb {
namespace velocypack {
@ -50,7 +48,6 @@ class ExampleMatcher {
std::vector<ExampleDefinition> 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;
};
}

View File

@ -23,6 +23,7 @@
#include "MasterPointer.h"
#include "Basics/VelocyPackHelper.h"
#include "VocBase/vocbase.h"
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
@ -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<TRI_voc_rid_t>();
}
return 0;
return TRI_extractRevisionId(slice);
}

View File

@ -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();
}

View File

@ -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<TRI_voc_rid_t>();
}
return 0;
}

View File

@ -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