mirror of https://gitee.com/bigwinds/arangodb
677 lines
21 KiB
C++
677 lines
21 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Tobias Gödderz
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Graph.h"
|
|
|
|
#include <velocypack/Buffer.h>
|
|
#include <velocypack/Collection.h>
|
|
#include <velocypack/Iterator.h>
|
|
#include <velocypack/velocypack-aliases.h>
|
|
#include <array>
|
|
#include <boost/variant.hpp>
|
|
#include <utility>
|
|
|
|
#include "Aql/AstNode.h"
|
|
#include "Aql/Graphs.h"
|
|
#include "Aql/Query.h"
|
|
#include "Basics/ReadLocker.h"
|
|
#include "Basics/StaticStrings.h"
|
|
#include "Basics/VelocyPackHelper.h"
|
|
#include "Basics/WriteLocker.h"
|
|
#include "Cluster/ServerState.h"
|
|
#include "Transaction/Methods.h"
|
|
#include "Transaction/StandaloneContext.h"
|
|
#include "Utils/OperationOptions.h"
|
|
#include "Utils/SingleCollectionTransaction.h"
|
|
#include "VocBase/LogicalCollection.h"
|
|
#include "VocBase/Methods/Collections.h"
|
|
|
|
using namespace arangodb;
|
|
using namespace arangodb::graph;
|
|
using VelocyPackHelper = basics::VelocyPackHelper;
|
|
|
|
#ifndef USE_ENTERPRISE
|
|
// Factory methods
|
|
std::unique_ptr<Graph> Graph::fromPersistence(VPackSlice document, TRI_vocbase_t& vocbase) {
|
|
if (document.isExternal()) {
|
|
document = document.resolveExternal();
|
|
}
|
|
std::unique_ptr<Graph> result{new Graph{document}};
|
|
return result;
|
|
}
|
|
|
|
std::unique_ptr<Graph> Graph::fromUserInput(std::string&& name, VPackSlice document,
|
|
VPackSlice options) {
|
|
if (document.isExternal()) {
|
|
document = document.resolveExternal();
|
|
}
|
|
std::unique_ptr<Graph> result{new Graph{std::move(name), document, options}};
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
std::unique_ptr<Graph> Graph::fromUserInput(std::string const& name,
|
|
VPackSlice document, VPackSlice options) {
|
|
return Graph::fromUserInput(std::string{name}, document, options);
|
|
}
|
|
|
|
// From persistence
|
|
Graph::Graph(velocypack::Slice const& slice)
|
|
: _graphName(
|
|
VelocyPackHelper::getStringValue(slice, StaticStrings::KeyString, "")),
|
|
_vertexColls(),
|
|
_edgeColls(),
|
|
_numberOfShards(basics::VelocyPackHelper::readNumericValue<uint64_t>(slice, StaticStrings::NumberOfShards,
|
|
1)),
|
|
_replicationFactor(basics::VelocyPackHelper::readNumericValue<uint64_t>(
|
|
slice, StaticStrings::ReplicationFactor, 1)),
|
|
_rev(basics::VelocyPackHelper::getStringValue(slice, StaticStrings::RevString,
|
|
"")) {
|
|
// If this happens we have a document without an _key Attribute.
|
|
TRI_ASSERT(!_graphName.empty());
|
|
if (_graphName.empty()) {
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
|
"Persisted graph is invalid. It does not "
|
|
"have a _key set. Please contact support.");
|
|
}
|
|
|
|
// If this happens we have a document without an _rev Attribute.
|
|
TRI_ASSERT(!_rev.empty());
|
|
if (_rev.empty()) {
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
|
"Persisted graph is invalid. It does not "
|
|
"have a _rev set. Please contact support.");
|
|
}
|
|
|
|
if (slice.hasKey(StaticStrings::GraphEdgeDefinitions)) {
|
|
parseEdgeDefinitions(slice.get(StaticStrings::GraphEdgeDefinitions));
|
|
}
|
|
if (slice.hasKey(StaticStrings::GraphOrphans)) {
|
|
insertOrphanCollections(slice.get(StaticStrings::GraphOrphans));
|
|
}
|
|
}
|
|
|
|
// From user input
|
|
Graph::Graph(std::string&& graphName, VPackSlice const& info, VPackSlice const& options)
|
|
: _graphName(graphName),
|
|
_vertexColls(),
|
|
_edgeColls(),
|
|
_numberOfShards(1),
|
|
_replicationFactor(1),
|
|
_rev("") {
|
|
if (_graphName.empty()) {
|
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
|
}
|
|
TRI_ASSERT(_rev.empty());
|
|
|
|
if (info.hasKey(StaticStrings::GraphEdgeDefinitions)) {
|
|
parseEdgeDefinitions(info.get(StaticStrings::GraphEdgeDefinitions));
|
|
}
|
|
if (info.hasKey(StaticStrings::GraphOrphans)) {
|
|
insertOrphanCollections(info.get(StaticStrings::GraphOrphans));
|
|
}
|
|
if (options.isObject()) {
|
|
_numberOfShards =
|
|
VelocyPackHelper::readNumericValue<uint64_t>(options, StaticStrings::NumberOfShards, 1);
|
|
_replicationFactor =
|
|
VelocyPackHelper::readNumericValue<uint64_t>(options, StaticStrings::ReplicationFactor, 1);
|
|
}
|
|
}
|
|
|
|
void Graph::parseEdgeDefinitions(VPackSlice edgeDefs) {
|
|
TRI_ASSERT(edgeDefs.isArray());
|
|
if (!edgeDefs.isArray()) {
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(
|
|
TRI_ERROR_GRAPH_INVALID_GRAPH,
|
|
"'edgeDefinitions' are not an array in the graph definition");
|
|
}
|
|
|
|
for (auto const& def : VPackArrayIterator(edgeDefs)) {
|
|
auto edgeDefRes = addEdgeDefinition(def);
|
|
if (edgeDefRes.fail()) {
|
|
THROW_ARANGO_EXCEPTION(std::move(edgeDefRes).result());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Graph::insertOrphanCollections(VPackSlice const arr) {
|
|
TRI_ASSERT(arr.isArray());
|
|
for (auto const& c : VPackArrayIterator(arr)) {
|
|
TRI_ASSERT(c.isString());
|
|
validateOrphanCollection(c);
|
|
addOrphanCollection(c.copyString());
|
|
}
|
|
}
|
|
|
|
std::set<std::string> const& Graph::vertexCollections() const {
|
|
return _vertexColls;
|
|
}
|
|
|
|
std::set<std::string> const& Graph::orphanCollections() const {
|
|
return _orphanColls;
|
|
}
|
|
|
|
std::set<std::string> const& Graph::edgeCollections() const {
|
|
return _edgeColls;
|
|
}
|
|
|
|
std::map<std::string, EdgeDefinition> const& Graph::edgeDefinitions() const {
|
|
return _edgeDefs;
|
|
}
|
|
|
|
std::map<std::string, EdgeDefinition>& Graph::edgeDefinitions() {
|
|
return _edgeDefs;
|
|
}
|
|
|
|
uint64_t Graph::numberOfShards() const { return _numberOfShards; }
|
|
|
|
uint64_t Graph::replicationFactor() const { return _replicationFactor; }
|
|
|
|
std::string const Graph::id() const {
|
|
return std::string(StaticStrings::GraphCollection + "/" + _graphName);
|
|
}
|
|
|
|
std::string const& Graph::rev() const { return _rev; }
|
|
|
|
void Graph::addVertexCollection(std::string const& name) {
|
|
// Promote Orphans to vertices
|
|
_orphanColls.erase(name);
|
|
_vertexColls.emplace(name);
|
|
}
|
|
|
|
void Graph::rebuildOrphans(EdgeDefinition const& oldEdgeDefinition) {
|
|
std::set<std::string> potentialNewOrphans;
|
|
|
|
// build the potential new orphans
|
|
for (auto const& from : oldEdgeDefinition.getFrom()) {
|
|
potentialNewOrphans.emplace(from);
|
|
}
|
|
for (auto const& to : oldEdgeDefinition.getTo()) {
|
|
potentialNewOrphans.emplace(to);
|
|
}
|
|
|
|
// check if potential new orphans are still available in other
|
|
// edgeDefinitions from's or to's or not.
|
|
for (auto potOrphan : potentialNewOrphans) {
|
|
bool found = false;
|
|
for (auto const& edgeDefinition : edgeDefinitions()) {
|
|
if (edgeDefinition.second.isVertexCollectionUsed(potOrphan)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
_vertexColls.erase(potOrphan);
|
|
addOrphanCollection(std::move(potOrphan));
|
|
}
|
|
}
|
|
}
|
|
|
|
Result Graph::removeOrphanCollection(std::string&& name) {
|
|
TRI_ASSERT(_vertexColls.find(name) != _vertexColls.end());
|
|
if (_orphanColls.find(name) != _orphanColls.end()) {
|
|
_orphanColls.erase(name);
|
|
_vertexColls.erase(name);
|
|
return TRI_ERROR_NO_ERROR;
|
|
} else {
|
|
return TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION;
|
|
}
|
|
}
|
|
|
|
Result Graph::addOrphanCollection(std::string&& name) {
|
|
if (!_vertexColls.insert(name).second) {
|
|
return TRI_ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF;
|
|
}
|
|
TRI_ASSERT(_orphanColls.find(name) == _orphanColls.end());
|
|
_orphanColls.insert(std::move(name));
|
|
return TRI_ERROR_NO_ERROR;
|
|
}
|
|
|
|
void Graph::setNumberOfShards(uint64_t numberOfShards) {
|
|
_numberOfShards = numberOfShards;
|
|
}
|
|
|
|
void Graph::setReplicationFactor(uint64_t replicationFactor) {
|
|
_replicationFactor = replicationFactor;
|
|
}
|
|
|
|
void Graph::setRev(std::string&& rev) { _rev = std::move(rev); }
|
|
|
|
void Graph::toVelocyPack(VPackBuilder& builder) const {
|
|
VPackObjectBuilder guard(&builder);
|
|
|
|
if (!_vertexColls.empty()) {
|
|
builder.add(VPackValue("vertexCollectionNames"));
|
|
VPackArrayBuilder guard2(&builder);
|
|
for (auto const& cn : _vertexColls) {
|
|
builder.add(VPackValue(cn));
|
|
}
|
|
}
|
|
|
|
if (!_edgeColls.empty()) {
|
|
builder.add(VPackValue("edgeCollectionNames"));
|
|
VPackArrayBuilder guard2(&builder);
|
|
for (auto const& cn : _edgeColls) {
|
|
builder.add(VPackValue(cn));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Graph::toPersistence(VPackBuilder& builder) const {
|
|
TRI_ASSERT(builder.isOpenObject());
|
|
|
|
// The name
|
|
builder.add(StaticStrings::KeyString, VPackValue(_graphName));
|
|
|
|
// Cluster Information
|
|
builder.add(StaticStrings::NumberOfShards, VPackValue(_numberOfShards));
|
|
builder.add(StaticStrings::ReplicationFactor, VPackValue(_replicationFactor));
|
|
builder.add(StaticStrings::GraphIsSmart, VPackValue(isSmart()));
|
|
|
|
// EdgeDefinitions
|
|
builder.add(VPackValue(StaticStrings::GraphEdgeDefinitions));
|
|
builder.openArray();
|
|
for (auto const& it : edgeDefinitions()) {
|
|
it.second.addToBuilder(builder);
|
|
}
|
|
builder.close(); // EdgeDefinitions
|
|
|
|
// Orphan Collections
|
|
builder.add(VPackValue(StaticStrings::GraphOrphans));
|
|
builder.openArray();
|
|
for (auto const& on : _orphanColls) {
|
|
builder.add(VPackValue(on));
|
|
}
|
|
builder.close(); // Orphans
|
|
}
|
|
|
|
void Graph::enhanceEngineInfo(VPackBuilder&) const {}
|
|
|
|
// validates the type:
|
|
// edgeDefinition : { collection : string, from : [string], to : [string] }
|
|
Result EdgeDefinition::validateEdgeDefinition(VPackSlice const& edgeDefinition) {
|
|
if (!edgeDefinition.isObject()) {
|
|
return Result(TRI_ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION);
|
|
}
|
|
|
|
for (auto const& key : std::array<std::string, 3>{
|
|
{"collection", StaticStrings::GraphFrom, StaticStrings::GraphTo}}) {
|
|
if (!edgeDefinition.hasKey(key)) {
|
|
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
|
"Attribute '" + key + "' missing in edge definition!");
|
|
}
|
|
}
|
|
|
|
if (!edgeDefinition.get("collection").isString()) {
|
|
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
|
"edge definition is not a string!");
|
|
}
|
|
|
|
for (auto const& key :
|
|
std::array<std::string, 2>{{StaticStrings::GraphFrom, StaticStrings::GraphTo}}) {
|
|
if (!edgeDefinition.get(key).isArray()) {
|
|
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
|
"Edge definition '" + key + "' is not an array!");
|
|
}
|
|
|
|
for (auto const& it : VPackArrayIterator(edgeDefinition.get(key))) {
|
|
if (!it.isString()) {
|
|
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
|
std::string("Edge definition '") + key +
|
|
"' does not only contain strings!");
|
|
}
|
|
}
|
|
}
|
|
|
|
return Result();
|
|
}
|
|
|
|
void EdgeDefinition::toVelocyPack(VPackBuilder& builder) const {
|
|
TRI_ASSERT(builder.isOpenObject());
|
|
|
|
builder.add("collection", VPackValue(getName()));
|
|
builder.add("from", VPackValue(VPackValueType::Array));
|
|
for (auto const& from : getFrom()) {
|
|
builder.add(VPackValue(from));
|
|
}
|
|
builder.close(); // array
|
|
builder.add("to", VPackValue(VPackValueType::Array));
|
|
for (auto const& to : getTo()) {
|
|
builder.add(VPackValue(to));
|
|
}
|
|
builder.close(); // array
|
|
}
|
|
|
|
ResultT<EdgeDefinition> EdgeDefinition::createFromVelocypack(VPackSlice edgeDefinition) {
|
|
Result res = EdgeDefinition::validateEdgeDefinition(edgeDefinition);
|
|
if (res.fail()) {
|
|
return res;
|
|
}
|
|
std::string collection = edgeDefinition.get("collection").copyString();
|
|
VPackSlice from = edgeDefinition.get(StaticStrings::GraphFrom);
|
|
VPackSlice to = edgeDefinition.get(StaticStrings::GraphTo);
|
|
|
|
std::set<std::string> fromSet;
|
|
std::set<std::string> toSet;
|
|
|
|
// duplicates in from and to shouldn't occur, but are safely ignored here
|
|
for (auto const& it : VPackArrayIterator(from)) {
|
|
fromSet.emplace(it.copyString());
|
|
}
|
|
for (auto const& it : VPackArrayIterator(to)) {
|
|
toSet.emplace(it.copyString());
|
|
}
|
|
|
|
// We do not allow creating an edge definition with either an empty from
|
|
// or an empty to set
|
|
if (fromSet.size() == 0 || toSet.size() == 0) {
|
|
return Result(TRI_ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION);
|
|
}
|
|
|
|
return EdgeDefinition{collection, std::move(fromSet), std::move(toSet)};
|
|
}
|
|
|
|
bool EdgeDefinition::operator==(EdgeDefinition const& other) const {
|
|
return getName() == other.getName() && getFrom() == other.getFrom() &&
|
|
getTo() == other.getTo();
|
|
}
|
|
|
|
bool EdgeDefinition::operator!=(EdgeDefinition const& other) const {
|
|
return getName() != other.getName() || getFrom() != other.getFrom() ||
|
|
getTo() != other.getTo();
|
|
}
|
|
|
|
bool EdgeDefinition::renameCollection(std::string const& oldName, std::string const& newName) {
|
|
bool renamed = false;
|
|
|
|
// from
|
|
if (isFromVertexCollectionUsed(oldName)) {
|
|
_from.erase(oldName);
|
|
_from.insert(newName);
|
|
renamed = true;
|
|
}
|
|
|
|
// to
|
|
if (isToVertexCollectionUsed(oldName)) {
|
|
_to.erase(oldName);
|
|
_to.insert(newName);
|
|
renamed = true;
|
|
}
|
|
|
|
// edge collection
|
|
if (getName() == oldName) {
|
|
setName(newName);
|
|
renamed = true;
|
|
}
|
|
|
|
return renamed;
|
|
}
|
|
|
|
bool EdgeDefinition::isFromVertexCollectionUsed(std::string const& collectionName) const {
|
|
if (getFrom().find(collectionName) != getFrom().end()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool EdgeDefinition::isToVertexCollectionUsed(std::string const& collectionName) const {
|
|
if (getTo().find(collectionName) != getTo().end()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool EdgeDefinition::isVertexCollectionUsed(std::string const& collectionName) const {
|
|
if (getFrom().find(collectionName) != getFrom().end() ||
|
|
getTo().find(collectionName) != getTo().end()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void EdgeDefinition::addToBuilder(VPackBuilder& builder) const {
|
|
builder.add(VPackValue(VPackValueType::Object));
|
|
builder.add("collection", VPackValue(getName()));
|
|
|
|
builder.add("from", VPackValue(VPackValueType::Array));
|
|
for (auto const& from : getFrom()) {
|
|
builder.add(VPackValue(from));
|
|
}
|
|
builder.close(); // from
|
|
|
|
// to
|
|
builder.add("to", VPackValue(VPackValueType::Array));
|
|
for (auto const& to : getTo()) {
|
|
builder.add(VPackValue(to));
|
|
}
|
|
builder.close(); // to
|
|
|
|
builder.close(); // obj
|
|
}
|
|
|
|
bool EdgeDefinition::hasFrom(std::string const& vertexCollection) const {
|
|
return getFrom().find(vertexCollection) != getFrom().end();
|
|
}
|
|
|
|
bool EdgeDefinition::hasTo(std::string const& vertexCollection) const {
|
|
return getTo().find(vertexCollection) != getTo().end();
|
|
}
|
|
|
|
// validates the type:
|
|
// orphanDefinition : string <collectionName>
|
|
Result Graph::validateOrphanCollection(VPackSlice const& orphanCollection) {
|
|
if (!orphanCollection.isString()) {
|
|
return Result(TRI_ERROR_GRAPH_CREATE_MALFORMED_ORPHAN_LIST,
|
|
"orphan collection is not a string!");
|
|
}
|
|
return Result();
|
|
}
|
|
|
|
bool Graph::removeEdgeDefinition(std::string const& edgeDefinitionName) {
|
|
auto maybeOldEdgeDef = getEdgeDefinition(edgeDefinitionName);
|
|
if (!maybeOldEdgeDef) {
|
|
// Graph doesn't contain this edge definition, no need to do anything.
|
|
return false;
|
|
}
|
|
EdgeDefinition const oldEdgeDef = maybeOldEdgeDef.get();
|
|
|
|
_edgeColls.erase(edgeDefinitionName);
|
|
_edgeDefs.erase(edgeDefinitionName);
|
|
rebuildOrphans(oldEdgeDef);
|
|
return true;
|
|
}
|
|
|
|
Result Graph::replaceEdgeDefinition(EdgeDefinition const& edgeDefinition) {
|
|
if (removeEdgeDefinition(edgeDefinition.getName())) {
|
|
return addEdgeDefinition(edgeDefinition).result();
|
|
}
|
|
// Graph doesn't contain this edge definition, no need to do anything.
|
|
return TRI_ERROR_GRAPH_EDGE_COL_DOES_NOT_EXIST;
|
|
}
|
|
|
|
ResultT<EdgeDefinition const*> Graph::addEdgeDefinition(EdgeDefinition const& edgeDefinition) {
|
|
std::string const& collection = edgeDefinition.getName();
|
|
if (hasEdgeCollection(collection)) {
|
|
return {Result(TRI_ERROR_GRAPH_COLLECTION_MULTI_USE,
|
|
collection + " " +
|
|
std::string{TRI_errno_string(TRI_ERROR_GRAPH_COLLECTION_MULTI_USE)})};
|
|
}
|
|
|
|
_edgeColls.emplace(collection);
|
|
_edgeDefs.emplace(collection, edgeDefinition);
|
|
TRI_ASSERT(hasEdgeCollection(collection));
|
|
for (auto const& it : edgeDefinition.getFrom()) {
|
|
addVertexCollection(it);
|
|
}
|
|
for (auto const& it : edgeDefinition.getTo()) {
|
|
addVertexCollection(it);
|
|
}
|
|
|
|
return &_edgeDefs.find(collection)->second;
|
|
}
|
|
|
|
ResultT<EdgeDefinition const*> Graph::addEdgeDefinition(VPackSlice const& edgeDefinitionSlice) {
|
|
auto res = EdgeDefinition::createFromVelocypack(edgeDefinitionSlice);
|
|
|
|
if (res.fail()) {
|
|
return std::move(res).result();
|
|
}
|
|
TRI_ASSERT(res.ok());
|
|
|
|
EdgeDefinition const& edgeDefinition = res.get();
|
|
|
|
return addEdgeDefinition(edgeDefinition);
|
|
}
|
|
|
|
std::ostream& Graph::operator<<(std::ostream& ostream) {
|
|
ostream << "Graph \"" << name() << "\" {\n";
|
|
for (auto const& it : _edgeDefs) {
|
|
EdgeDefinition const& def = it.second;
|
|
ostream << " collection \"" << def.getName() << "\" {\n";
|
|
ostream << " from [";
|
|
bool first = true;
|
|
for (auto const& from : def.getFrom()) {
|
|
if (!first) {
|
|
ostream << ", ";
|
|
}
|
|
first = false;
|
|
ostream << from;
|
|
}
|
|
ostream << " to [";
|
|
first = true;
|
|
for (auto const& to : def.getTo()) {
|
|
if (!first) {
|
|
ostream << ", ";
|
|
}
|
|
first = false;
|
|
ostream << to;
|
|
}
|
|
ostream << " }\n";
|
|
}
|
|
ostream << "}";
|
|
|
|
return ostream;
|
|
}
|
|
|
|
bool Graph::hasEdgeCollection(std::string const& collectionName) const {
|
|
TRI_ASSERT((edgeDefinitions().find(collectionName) != edgeDefinitions().end()) ==
|
|
(edgeCollections().find(collectionName) != edgeCollections().end()));
|
|
return edgeCollections().find(collectionName) != edgeCollections().end();
|
|
}
|
|
|
|
bool Graph::hasVertexCollection(std::string const& collectionName) const {
|
|
return vertexCollections().find(collectionName) != vertexCollections().end();
|
|
}
|
|
|
|
bool Graph::hasOrphanCollection(std::string const& collectionName) const {
|
|
return orphanCollections().find(collectionName) != orphanCollections().end();
|
|
}
|
|
|
|
bool Graph::renameCollections(std::string const& oldName, std::string const& newName) {
|
|
// rename not allowed in a smart collection
|
|
if (isSmart()) {
|
|
return false;
|
|
}
|
|
|
|
bool renamed = false;
|
|
|
|
// rename collections found in edgeDefinitions
|
|
for (auto& it : edgeDefinitions()) {
|
|
if (!renamed) {
|
|
renamed = it.second.renameCollection(oldName, newName);
|
|
} else {
|
|
it.second.renameCollection(oldName, newName);
|
|
}
|
|
}
|
|
|
|
// orphans
|
|
if (hasOrphanCollection(oldName)) {
|
|
_orphanColls.erase(oldName);
|
|
_orphanColls.insert(newName);
|
|
renamed = true;
|
|
}
|
|
|
|
return renamed;
|
|
}
|
|
|
|
void Graph::graphForClient(VPackBuilder& builder) const {
|
|
TRI_ASSERT(builder.isOpenObject());
|
|
builder.add(VPackValue("graph"));
|
|
builder.openObject();
|
|
|
|
toPersistence(builder);
|
|
TRI_ASSERT(builder.isOpenObject());
|
|
builder.add(StaticStrings::RevString, VPackValue(rev()));
|
|
builder.add(StaticStrings::IdString, VPackValue(id()));
|
|
builder.add(StaticStrings::GraphName, VPackValue(_graphName));
|
|
builder.close(); // graph object
|
|
}
|
|
|
|
Result Graph::validateCollection(LogicalCollection& col) const {
|
|
return {TRI_ERROR_NO_ERROR};
|
|
}
|
|
|
|
void Graph::edgesToVpack(VPackBuilder& builder) const {
|
|
builder.add(VPackValue(VPackValueType::Object));
|
|
builder.add("collections", VPackValue(VPackValueType::Array));
|
|
|
|
for (auto const& edgeCollection : edgeCollections()) {
|
|
builder.add(VPackValue(edgeCollection));
|
|
}
|
|
builder.close();
|
|
|
|
builder.close();
|
|
}
|
|
|
|
void Graph::verticesToVpack(VPackBuilder& builder) const {
|
|
builder.add(VPackValue(VPackValueType::Object));
|
|
builder.add("collections", VPackValue(VPackValueType::Array));
|
|
|
|
for (auto const& vertexCollection : vertexCollections()) {
|
|
builder.add(VPackValue(vertexCollection));
|
|
}
|
|
builder.close();
|
|
|
|
builder.close();
|
|
}
|
|
|
|
bool Graph::isSmart() const { return false; }
|
|
|
|
void Graph::createCollectionOptions(VPackBuilder& builder, bool waitForSync) const {
|
|
TRI_ASSERT(builder.isOpenObject());
|
|
|
|
builder.add(StaticStrings::WaitForSyncString, VPackValue(waitForSync));
|
|
builder.add(StaticStrings::NumberOfShards, VPackValue(numberOfShards()));
|
|
builder.add(StaticStrings::ReplicationFactor, VPackValue(replicationFactor()));
|
|
}
|
|
|
|
boost::optional<const EdgeDefinition&> Graph::getEdgeDefinition(std::string const& collectionName) const {
|
|
auto it = edgeDefinitions().find(collectionName);
|
|
if (it == edgeDefinitions().end()) {
|
|
TRI_ASSERT(!hasEdgeCollection(collectionName));
|
|
return boost::none;
|
|
}
|
|
|
|
TRI_ASSERT(hasEdgeCollection(collectionName));
|
|
return {it->second};
|
|
}
|