mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'engine-api' of https://github.com/arangodb/arangodb into engine-api
This commit is contained in:
commit
ee99288f88
|
@ -1,6 +1,12 @@
|
|||
devel
|
||||
-----
|
||||
|
||||
* Removed undocumented internal HTTP APIs:
|
||||
* POST _api/edges
|
||||
* PUT _api/edges
|
||||
|
||||
The documented GET _api/edges remains unmodified.
|
||||
|
||||
* moved V8 code into a git submodule
|
||||
this requires running the command
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "Graphs.h"
|
||||
#include "Aql/AstNode.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
|
||||
#include <velocypack/Iterator.h>
|
||||
|
@ -39,10 +40,16 @@ EdgeConditionBuilder::EdgeConditionBuilder(AstNode* modCondition)
|
|||
_toCondition(nullptr),
|
||||
_modCondition(modCondition),
|
||||
_containsCondition(false) {
|
||||
TRI_ASSERT(_modCondition->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||
#ifdef TRI_ENABLE_MAINTAINER_MODE
|
||||
if (_modCondition != nullptr) {
|
||||
TRI_ASSERT(_modCondition->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EdgeConditionBuilder::addConditionPart(AstNode const* part) {
|
||||
TRI_ASSERT(_modCondition != nullptr);
|
||||
TRI_ASSERT(_modCondition->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||
TRI_ASSERT(!_containsCondition);
|
||||
// The ordering is only maintained before we request a specific
|
||||
// condition
|
||||
|
@ -71,7 +78,7 @@ void EdgeConditionBuilder::swapSides(AstNode* cond) {
|
|||
TRI_ASSERT(_modCondition->numMembers() > 0);
|
||||
}
|
||||
|
||||
AstNode const* EdgeConditionBuilder::getOutboundCondition() {
|
||||
AstNode* EdgeConditionBuilder::getOutboundCondition() {
|
||||
if (_fromCondition == nullptr) {
|
||||
buildFromCondition();
|
||||
}
|
||||
|
@ -80,7 +87,7 @@ AstNode const* EdgeConditionBuilder::getOutboundCondition() {
|
|||
return _modCondition;
|
||||
}
|
||||
|
||||
AstNode const* EdgeConditionBuilder::getInboundCondition() {
|
||||
AstNode* EdgeConditionBuilder::getInboundCondition() {
|
||||
if (_toCondition == nullptr) {
|
||||
buildToCondition();
|
||||
}
|
||||
|
@ -89,6 +96,72 @@ AstNode const* EdgeConditionBuilder::getInboundCondition() {
|
|||
return _modCondition;
|
||||
}
|
||||
|
||||
EdgeConditionBuilderContainer::EdgeConditionBuilderContainer() :
|
||||
EdgeConditionBuilder(nullptr) {
|
||||
auto node = std::make_unique<AstNode>(NODE_TYPE_OPERATOR_NARY_AND);
|
||||
_modCondition = node.get();
|
||||
_astNodes.emplace_back(node.get());
|
||||
node.release();
|
||||
|
||||
auto comp = std::make_unique<AstNode>(NODE_TYPE_VALUE);
|
||||
comp->setValueType(VALUE_TYPE_STRING);
|
||||
comp->setStringValue("", 0);
|
||||
_astNodes.emplace_back(comp.get());
|
||||
_compareNode = comp.release();
|
||||
|
||||
_var = _varGen.createTemporaryVariable();
|
||||
|
||||
auto varNode = std::make_unique<AstNode>(NODE_TYPE_REFERENCE);
|
||||
varNode->setData(_var);
|
||||
_astNodes.emplace_back(varNode.get());
|
||||
_varNode = varNode.release();
|
||||
}
|
||||
|
||||
EdgeConditionBuilderContainer::~EdgeConditionBuilderContainer() {
|
||||
// we have to clean up the AstNodes
|
||||
for (auto it : _astNodes) {
|
||||
delete it;
|
||||
}
|
||||
_astNodes.clear();
|
||||
}
|
||||
|
||||
AstNode* EdgeConditionBuilderContainer::createEqCheck(AstNode const* access) {
|
||||
auto node = std::make_unique<AstNode>(NODE_TYPE_OPERATOR_BINARY_EQ);
|
||||
node->reserve(2);
|
||||
node->addMember(access);
|
||||
node->addMember(_compareNode);
|
||||
_astNodes.emplace_back(node.get());
|
||||
return node.release();
|
||||
}
|
||||
|
||||
AstNode* EdgeConditionBuilderContainer::createAttributeAccess(std::string const& attr) {
|
||||
auto node = std::make_unique<AstNode>(NODE_TYPE_ATTRIBUTE_ACCESS);
|
||||
node->addMember(_varNode);
|
||||
node->setStringValue(attr.c_str(), attr.length());
|
||||
_astNodes.emplace_back(node.get());
|
||||
return node.release();
|
||||
}
|
||||
|
||||
void EdgeConditionBuilderContainer::buildFromCondition() {
|
||||
TRI_ASSERT(_fromCondition == nullptr);
|
||||
auto access = createAttributeAccess(StaticStrings::FromString);
|
||||
_fromCondition = createEqCheck(access);
|
||||
}
|
||||
|
||||
void EdgeConditionBuilderContainer::buildToCondition() {
|
||||
TRI_ASSERT(_toCondition == nullptr);
|
||||
auto access = createAttributeAccess(StaticStrings::ToString);
|
||||
_toCondition = createEqCheck(access);
|
||||
}
|
||||
|
||||
Variable const* EdgeConditionBuilderContainer::getVariable() const {
|
||||
return _var;
|
||||
}
|
||||
|
||||
void EdgeConditionBuilderContainer::setVertexId(std::string const& id) {
|
||||
_compareNode->setStringValue(id.c_str(), id.length());
|
||||
}
|
||||
|
||||
void Graph::insertVertexCollections(VPackSlice& arr) {
|
||||
TRI_ASSERT(arr.isArray());
|
||||
for (auto const& c : VPackArrayIterator(arr)) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define ARANGOD_AQL_GRAPHS_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/VariableGenerator.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
|
@ -82,16 +83,64 @@ class EdgeConditionBuilder {
|
|||
void addConditionPart(AstNode const*);
|
||||
|
||||
// Get the complete condition for outbound edges
|
||||
AstNode const* getOutboundCondition();
|
||||
AstNode* getOutboundCondition();
|
||||
|
||||
// Get the complete condition for inbound edges
|
||||
AstNode const* getInboundCondition();
|
||||
AstNode* getInboundCondition();
|
||||
|
||||
private:
|
||||
// Internal helper to swap _from and _to parts
|
||||
void swapSides(AstNode* condition);
|
||||
};
|
||||
|
||||
// Wrapper around EdgeConditionBuilder that takes responsibility for all
|
||||
// AstNodes created with it. Can be used outside of an AQL query.
|
||||
class EdgeConditionBuilderContainer final : public EdgeConditionBuilder {
|
||||
public:
|
||||
EdgeConditionBuilderContainer();
|
||||
|
||||
~EdgeConditionBuilderContainer();
|
||||
|
||||
// Get a pointer to the used variable
|
||||
Variable const* getVariable() const;
|
||||
|
||||
// Set the id of the searched vertex
|
||||
// NOTE: This class does not take responsiblity for the string.
|
||||
// So caller needs to make sure it does not run out of scope
|
||||
// as long as these conditions are used.
|
||||
void setVertexId(std::string const&);
|
||||
|
||||
protected:
|
||||
// Create the _fromCondition for the first time.
|
||||
void buildFromCondition() override;
|
||||
|
||||
// Create the _toCondition for the first time.
|
||||
void buildToCondition() override;
|
||||
|
||||
private:
|
||||
// Create the equality node using the given access
|
||||
AstNode* createEqCheck(AstNode const* access);
|
||||
|
||||
// Create a node with access of attr on the variable
|
||||
AstNode* createAttributeAccess(std::string const& attr);
|
||||
|
||||
private:
|
||||
// List of AstNodes this container is responsible for
|
||||
std::vector<AstNode*> _astNodes;
|
||||
|
||||
// The variable node that is used to hold the edge
|
||||
AstNode* _varNode;
|
||||
|
||||
// The value the edge is compared to
|
||||
AstNode* _compareNode;
|
||||
|
||||
// Reference to the exchangeable variable node
|
||||
Variable* _var;
|
||||
|
||||
// Reference to the VariableGenerator
|
||||
VariableGenerator _varGen;
|
||||
};
|
||||
|
||||
class Graph {
|
||||
public:
|
||||
explicit Graph(arangodb::velocypack::Slice const&);
|
||||
|
|
|
@ -22,14 +22,15 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RestEdgesHandler.h"
|
||||
#include "Aql/AstNode.h"
|
||||
#include "Aql/Graphs.h"
|
||||
#include "Aql/Variable.h"
|
||||
#include "Basics/ScopeGuard.h"
|
||||
#include "Cluster/ClusterMethods.h"
|
||||
#include "MMFiles/MMFilesEdgeIndex.h"
|
||||
#include "Utils/CollectionNameResolver.h"
|
||||
#include "Utils/OperationCursor.h"
|
||||
#include "Utils/SingleCollectionTransaction.h"
|
||||
#include "Utils/StandaloneTransactionContext.h"
|
||||
#include "VocBase/Traverser.h"
|
||||
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
@ -47,18 +48,9 @@ RestStatus RestEdgesHandler::execute() {
|
|||
|
||||
// execute one of the CRUD methods
|
||||
switch (type) {
|
||||
case rest::RequestType::GET: {
|
||||
case rest::RequestType::GET:
|
||||
readEdges();
|
||||
break;
|
||||
}
|
||||
case rest::RequestType::PUT:
|
||||
// Now unsupported. Just temporary to check
|
||||
TRI_ASSERT(false);
|
||||
readEdges();
|
||||
break;
|
||||
case rest::RequestType::POST:
|
||||
readEdgesForMultipleVertices();
|
||||
break;
|
||||
default:
|
||||
generateNotImplemented("ILLEGAL " + EDGES_PATH);
|
||||
break;
|
||||
|
@ -68,43 +60,38 @@ RestStatus RestEdgesHandler::execute() {
|
|||
return RestStatus::DONE;
|
||||
}
|
||||
|
||||
bool RestEdgesHandler::getEdgesForVertexList(
|
||||
VPackSlice const ids,
|
||||
TRI_edge_direction_e direction, SingleCollectionTransaction& trx,
|
||||
VPackBuilder& result, size_t& scannedIndex, size_t& filtered) {
|
||||
TRI_ASSERT(result.isOpenArray());
|
||||
TRI_ASSERT(ids.isArray());
|
||||
trx.orderDitch(trx.cid()); // will throw when it fails
|
||||
void RestEdgesHandler::readCursor(aql::AstNode* condition,
|
||||
aql::Variable const* var,
|
||||
std::string const& collectionName,
|
||||
SingleCollectionTransaction& trx,
|
||||
VPackBuilder& result,
|
||||
std::function<void(DocumentIdentifierToken const&)> cb) {
|
||||
|
||||
std::string const collectionName =
|
||||
trx.resolver()->getCollectionName(trx.cid());
|
||||
Transaction::IndexHandle indexId = trx.edgeIndexHandle(collectionName);
|
||||
Transaction::IndexHandle indexId;
|
||||
bool foundIdx = trx.getBestIndexHandleForFilterCondition(
|
||||
collectionName, condition, var, 1000, indexId);
|
||||
if (!foundIdx) {
|
||||
// Right now we enforce an edge index that can exactly! work on this condition.
|
||||
// So it is impossible to not find an index.
|
||||
TRI_ASSERT(false);
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_ARANGO_NO_INDEX,
|
||||
"Unable to find an edge-index to identify matching edges.");
|
||||
}
|
||||
|
||||
VPackBuilder searchValueBuilder;
|
||||
MMFilesEdgeIndex::buildSearchValueFromArray(direction, ids, searchValueBuilder);
|
||||
VPackSlice search = searchValueBuilder.slice();
|
||||
ManagedDocumentResult mmdr;
|
||||
std::unique_ptr<OperationCursor> cursor(trx.indexScanForCondition(
|
||||
indexId, condition, var, &mmdr, UINT64_MAX, 1000, false));
|
||||
|
||||
std::unique_ptr<OperationCursor> cursor =
|
||||
trx.indexScan(collectionName, arangodb::Transaction::CursorType::INDEX,
|
||||
indexId, search, nullptr, 0, UINT64_MAX, 1000, false);
|
||||
if (cursor->failed()) {
|
||||
THROW_ARANGO_EXCEPTION(cursor->code);
|
||||
}
|
||||
|
||||
ManagedDocumentResult mmdr;
|
||||
auto collection = trx.documentCollection();
|
||||
auto cb = [&](DocumentIdentifierToken const& token) {
|
||||
if (collection->readDocument(&trx, mmdr, token)) {
|
||||
result.add(VPackSlice(mmdr.vpack()));
|
||||
}
|
||||
scannedIndex++;
|
||||
};
|
||||
while (cursor->getMore(cb, 1000)) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RestEdgesHandler::getEdgesForVertex(
|
||||
std::string const& id, std::string const& collectionName,
|
||||
TRI_edge_direction_e direction, SingleCollectionTransaction& trx,
|
||||
|
@ -112,30 +99,68 @@ bool RestEdgesHandler::getEdgesForVertex(
|
|||
TRI_ASSERT(result.isOpenArray());
|
||||
trx.orderDitch(trx.cid()); // will throw when it fails
|
||||
|
||||
Transaction::IndexHandle indexId = trx.edgeIndexHandle(collectionName);
|
||||
|
||||
VPackBuilder searchValueBuilder;
|
||||
MMFilesEdgeIndex::buildSearchValue(direction, id, searchValueBuilder);
|
||||
VPackSlice search = searchValueBuilder.slice();
|
||||
|
||||
std::unique_ptr<OperationCursor> cursor =
|
||||
trx.indexScan(collectionName, arangodb::Transaction::CursorType::INDEX,
|
||||
indexId, search, nullptr, 0, UINT64_MAX, 1000, false);
|
||||
if (cursor->failed()) {
|
||||
THROW_ARANGO_EXCEPTION(cursor->code);
|
||||
}
|
||||
|
||||
ManagedDocumentResult mmdr;
|
||||
auto collection = trx.documentCollection();
|
||||
auto cb = [&] (DocumentIdentifierToken const& token) {
|
||||
if (collection->readDocument(&trx, mmdr, token)) {
|
||||
result.add(VPackSlice(mmdr.vpack()));
|
||||
}
|
||||
scannedIndex++;
|
||||
};
|
||||
while (cursor->getMore(cb, 1000)) {
|
||||
}
|
||||
|
||||
// Create a conditionBuilder that manages the AstNodes for querying
|
||||
aql::EdgeConditionBuilderContainer condBuilder;
|
||||
condBuilder.setVertexId(id);
|
||||
|
||||
aql::Variable const* var = condBuilder.getVariable();
|
||||
|
||||
switch (direction) {
|
||||
case TRI_EDGE_IN:
|
||||
{
|
||||
auto cb = [&] (DocumentIdentifierToken const& token) {
|
||||
if (collection->readDocument(&trx, mmdr, token)) {
|
||||
result.add(VPackSlice(mmdr.vpack()));
|
||||
}
|
||||
scannedIndex++;
|
||||
};
|
||||
readCursor(condBuilder.getInboundCondition(), var, collectionName, trx,
|
||||
result, cb);
|
||||
break;
|
||||
}
|
||||
case TRI_EDGE_OUT:
|
||||
{
|
||||
auto cb = [&] (DocumentIdentifierToken const& token) {
|
||||
if (collection->readDocument(&trx, mmdr, token)) {
|
||||
result.add(VPackSlice(mmdr.vpack()));
|
||||
}
|
||||
scannedIndex++;
|
||||
};
|
||||
readCursor(condBuilder.getOutboundCondition(), var, collectionName, trx,
|
||||
result, cb);
|
||||
break;
|
||||
}
|
||||
case TRI_EDGE_ANY:
|
||||
// We have to call both directions AND we have to unify reverse direction
|
||||
{
|
||||
std::unordered_set<DocumentIdentifierToken> found;
|
||||
auto inboundCB = [&] (DocumentIdentifierToken const& token) {
|
||||
if (collection->readDocument(&trx, mmdr, token)) {
|
||||
result.add(VPackSlice(mmdr.vpack()));
|
||||
// Mark edges we find
|
||||
found.emplace(token);
|
||||
}
|
||||
scannedIndex++;
|
||||
};
|
||||
auto outboundCB = [&] (DocumentIdentifierToken const& token) {
|
||||
if (found.find(token) == found.end()) {
|
||||
// Only add those tokens we have not found yet
|
||||
if (collection->readDocument(&trx, mmdr, token)) {
|
||||
result.add(VPackSlice(mmdr.vpack()));
|
||||
}
|
||||
scannedIndex++;
|
||||
}
|
||||
};
|
||||
readCursor(condBuilder.getInboundCondition(), var, collectionName, trx,
|
||||
result, inboundCB);
|
||||
readCursor(condBuilder.getOutboundCondition(), var, collectionName, trx,
|
||||
result, outboundCB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -280,160 +305,3 @@ bool RestEdgesHandler::readEdges() {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Internal function to receive all edges for a list of vertices
|
||||
// Not publicly documented on purpose.
|
||||
// NOTE: It ONLY except _id strings. Nothing else
|
||||
bool RestEdgesHandler::readEdgesForMultipleVertices() {
|
||||
std::vector<std::string> const& suffixes = _request->decodedSuffixes();
|
||||
|
||||
if (suffixes.size() != 1) {
|
||||
generateError(rest::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expected POST " + EDGES_PATH +
|
||||
"/<collection-identifier>?direction=<direction>");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parseSuccess = true;
|
||||
std::shared_ptr<VPackBuilder> parsedBody =
|
||||
parseVelocyPackBody(&VPackOptions::Defaults, parseSuccess);
|
||||
|
||||
if (!parseSuccess) {
|
||||
generateError(rest::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"expected POST " + EDGES_PATH +
|
||||
"/<collection-identifier>?direction=<direction>");
|
||||
// A body is required
|
||||
return false;
|
||||
}
|
||||
VPackSlice body = parsedBody->slice();
|
||||
|
||||
if (!body.isArray()) {
|
||||
generateError(rest::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"Expected an array of vertex _id's in body parameter");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string collectionName = suffixes[0];
|
||||
CollectionNameResolver resolver(_vocbase);
|
||||
TRI_col_type_e colType = resolver.getCollectionTypeCluster(collectionName);
|
||||
|
||||
if (colType == TRI_COL_TYPE_UNKNOWN) {
|
||||
generateError(rest::ResponseCode::NOT_FOUND,
|
||||
TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
return false;
|
||||
} else if (colType != TRI_COL_TYPE_EDGE) {
|
||||
generateError(rest::ResponseCode::BAD,
|
||||
TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found;
|
||||
std::string dirString = _request->value("direction", found);
|
||||
|
||||
if (!found || dirString.empty()) {
|
||||
dirString = "any";
|
||||
}
|
||||
|
||||
TRI_edge_direction_e direction;
|
||||
|
||||
if (dirString == "any") {
|
||||
direction = TRI_EDGE_ANY;
|
||||
} else if (dirString == "out" || dirString == "outbound") {
|
||||
direction = TRI_EDGE_OUT;
|
||||
} else if (dirString == "in" || dirString == "inbound") {
|
||||
direction = TRI_EDGE_IN;
|
||||
} else {
|
||||
generateError(rest::ResponseCode::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"<direction> must by any, in, or out, not: " + dirString);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
rest::ResponseCode responseCode;
|
||||
VPackBuilder resultDocument;
|
||||
resultDocument.openObject();
|
||||
|
||||
for (auto const& it : VPackArrayIterator(body)) {
|
||||
if (it.isString()) {
|
||||
std::string vertexString(it.copyString());
|
||||
|
||||
int res = getFilteredEdgesOnCoordinator(
|
||||
_vocbase->name(), collectionName, vertexString, direction,
|
||||
responseCode, resultDocument);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
generateError(responseCode, res);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
resultDocument.add("error", VPackValue(false));
|
||||
resultDocument.add("code", VPackValue(200));
|
||||
resultDocument.close();
|
||||
|
||||
generateResult(rest::ResponseCode::OK, resultDocument.slice());
|
||||
return true;
|
||||
}
|
||||
|
||||
// find and load collection given by name or identifier
|
||||
SingleCollectionTransaction trx(
|
||||
StandaloneTransactionContext::Create(_vocbase), collectionName,
|
||||
AccessMode::Type::READ);
|
||||
|
||||
// .............................................................................
|
||||
// inside read transaction
|
||||
// .............................................................................
|
||||
|
||||
int res = trx.begin();
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
generateTransactionError(collectionName, res, "");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are a DBserver, we want to use the cluster-wide collection
|
||||
// name for error reporting:
|
||||
if (ServerState::instance()->isDBServer()) {
|
||||
collectionName = trx.resolver()->getCollectionName(trx.cid());
|
||||
}
|
||||
|
||||
size_t filtered = 0;
|
||||
size_t scannedIndex = 0;
|
||||
|
||||
VPackBuilder resultBuilder;
|
||||
resultBuilder.openObject();
|
||||
// build edges
|
||||
resultBuilder.add(VPackValue("edges")); // only key
|
||||
resultBuilder.openArray();
|
||||
|
||||
bool ok = getEdgesForVertexList(body, direction, trx, resultBuilder,
|
||||
scannedIndex, filtered);
|
||||
|
||||
if (!ok) {
|
||||
// Ignore the error
|
||||
}
|
||||
|
||||
resultBuilder.close();
|
||||
|
||||
res = trx.finish(res);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
generateTransactionError(collectionName, res, "");
|
||||
return false;
|
||||
}
|
||||
|
||||
resultBuilder.add("error", VPackValue(false));
|
||||
resultBuilder.add("code", VPackValue(200));
|
||||
resultBuilder.add("stats", VPackValue(VPackValueType::Object));
|
||||
resultBuilder.add("scannedIndex", VPackValue(scannedIndex));
|
||||
resultBuilder.add("filtered", VPackValue(filtered));
|
||||
resultBuilder.close(); // inner object
|
||||
resultBuilder.close();
|
||||
|
||||
// and generate a response
|
||||
generateResult(rest::ResponseCode::OK, resultBuilder.slice(),
|
||||
trx.transactionContext());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,14 @@
|
|||
#include <velocypack/Builder.h>
|
||||
|
||||
namespace arangodb {
|
||||
struct DocumentIdentifierToken;
|
||||
class SingleCollectionTransaction;
|
||||
|
||||
namespace aql {
|
||||
struct AstNode;
|
||||
struct Variable;
|
||||
}
|
||||
|
||||
class RestEdgesHandler : public RestVocbaseBaseHandler {
|
||||
public:
|
||||
explicit RestEdgesHandler(GeneralRequest*, GeneralResponse*);
|
||||
|
@ -48,10 +54,14 @@ class RestEdgesHandler : public RestVocbaseBaseHandler {
|
|||
bool readEdges();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads all edges in given direction for a given list of vertices
|
||||
/// @brief find the index and read it completely with the given callback
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool readEdgesForMultipleVertices();
|
||||
void readCursor(aql::AstNode* condition, aql::Variable const* var,
|
||||
std::string const& collectionName,
|
||||
SingleCollectionTransaction& trx,
|
||||
arangodb::velocypack::Builder& result,
|
||||
std::function<void(DocumentIdentifierToken const&)> cb);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get all edges for a given vertex. Independent from the request
|
||||
|
@ -61,15 +71,6 @@ class RestEdgesHandler : public RestVocbaseBaseHandler {
|
|||
std::string const& id, std::string const& collectionName,
|
||||
TRI_edge_direction_e direction, SingleCollectionTransaction& trx,
|
||||
arangodb::velocypack::Builder&, size_t& scannedIndex, size_t& filtered);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get all edges for a list of vertices. Independent from the request
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool getEdgesForVertexList(
|
||||
arangodb::velocypack::Slice const ids,
|
||||
TRI_edge_direction_e direction, SingleCollectionTransaction& trx,
|
||||
arangodb::velocypack::Builder&, size_t& scannedIndex, size_t& filtered);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue