mirror of https://gitee.com/bigwinds/arangodb
issue 496.1: switch scope of responsibility between a TRI_vocbase_t and a LogicalView in respect to view creation/deletion (#7101)
* issue 496.1: switch scope of responsibility between a TRI_vocbase_t and a LogicalView in respect to view creation/deletion * backport: address test failures * backport: ensure arangosearch links get exported in the dump * backport: ensure view is created during restore on the coordinator * Updates for ArangoSearch DDL tests, IResearchView unregistration and known issues * Add fix for internal issue 483
This commit is contained in:
parent
84de3f6052
commit
8f44afb6cf
|
@ -43,5 +43,4 @@ ArangoSearch
|
|||
* ArangoSearch ignores `_id` attribute even if `includeAllFields` is set to `true` (internal #445)
|
||||
* Using score functions (BM25/TFIDF) in ArangoDB expression is not supported (internal #316)
|
||||
* Using a loop variable in expressions within a corresponding SEARCH condition is not supported (internal #318)
|
||||
* ArangoSearch doesn't support joins with satellite collections (internal #440)
|
||||
* RocksDB recovery fails sometimes after renaming a view (internal #469)
|
||||
|
|
|
@ -580,32 +580,28 @@ void ClusterInfo::loadPlan() {
|
|||
viewPairSlice.key.copyString();
|
||||
|
||||
try {
|
||||
auto preCommit = [this, viewId, databaseName](std::shared_ptr<LogicalView> const& view)->bool {
|
||||
auto& views = _newPlannedViews[databaseName];
|
||||
// register with name as well as with id:
|
||||
views.reserve(views.size() + 2);
|
||||
views[viewId] = view;
|
||||
views[view->name()] = view;
|
||||
views[view->guid()] = view;
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto newView = LogicalView::create(
|
||||
*vocbase,
|
||||
viewPairSlice.value,
|
||||
false, // false == coming from Agency
|
||||
newPlanVersion,
|
||||
preCommit
|
||||
LogicalView::ptr view;
|
||||
auto res = LogicalView::instantiate(
|
||||
view, *vocbase, viewPairSlice.value, newPlanVersion
|
||||
);
|
||||
|
||||
if (!newView) {
|
||||
if (!res.ok() || !view) {
|
||||
LOG_TOPIC(ERR, Logger::AGENCY)
|
||||
<< "Failed to create view '" << viewId
|
||||
<< "'. The view will be ignored for now and the invalid information "
|
||||
"will be repaired. VelocyPack: "
|
||||
<< viewSlice.toJson();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& views = _newPlannedViews[databaseName];
|
||||
|
||||
// register with guid/id/name
|
||||
views.reserve(views.size() + 3);
|
||||
views[viewId] = view;
|
||||
views[view->name()] = view;
|
||||
views[view->guid()] = view;
|
||||
} catch (std::exception const& ex) {
|
||||
// The Plan contains invalid view information.
|
||||
// This should not happen in healthy situations.
|
||||
|
@ -619,7 +615,6 @@ void ClusterInfo::loadPlan() {
|
|||
<< viewSlice.toJson();
|
||||
|
||||
TRI_ASSERT(false);
|
||||
continue;
|
||||
} catch (...) {
|
||||
// The Plan contains invalid view information.
|
||||
// This should not happen in healthy situations.
|
||||
|
@ -633,7 +628,6 @@ void ClusterInfo::loadPlan() {
|
|||
<< viewSlice.toJson();
|
||||
|
||||
TRI_ASSERT(false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -345,11 +345,11 @@ void registerViewFactory() {
|
|||
|
||||
// DB server in custer or single-server
|
||||
if (arangodb::ServerState::instance()->isCoordinator()) {
|
||||
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchViewCoordinator::make);
|
||||
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchViewCoordinator::factory());
|
||||
} else if (arangodb::ServerState::instance()->isDBServer()) {
|
||||
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchViewDBServer::make);
|
||||
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchViewDBServer::factory());
|
||||
} else if (arangodb::ServerState::instance()->isSingleServer()) {
|
||||
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchView::make);
|
||||
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchView::factory());
|
||||
} else {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_FAILED,
|
||||
|
|
|
@ -147,13 +147,13 @@ int IResearchLink::drop() {
|
|||
_dropCollectionInDestructor = false; // will do drop now
|
||||
_defaultGuid = _view->guid(); // remember view ID just in case (e.g. call to toVelocyPack(...) after unload())
|
||||
|
||||
TRI_voc_cid_t vid = _view->id();
|
||||
auto view = _view;
|
||||
_view = nullptr; // mark as unassociated
|
||||
_viewLock.unlock(); // release read-lock on the IResearch View
|
||||
|
||||
// FIXME TODO this workaround should be in ClusterInfo when moving 'Plan' to 'Current', i.e. IResearchViewDBServer::drop
|
||||
if (arangodb::ServerState::instance()->isDBServer()) {
|
||||
return _collection.vocbase().dropView(vid, true).errorNumber(); // cluster-view in ClusterInfo should already not have cid-view
|
||||
return view->drop().errorNumber(); // cluster-view in ClusterInfo should already not have cid-view
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -552,4 +552,4 @@ NS_END // arangodb
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -502,6 +502,68 @@ namespace iresearch {
|
|||
return LINK_TYPE;
|
||||
}
|
||||
|
||||
/*static*/ arangodb::Result IResearchLinkHelper::validateLinks(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& links
|
||||
) {
|
||||
if (!links.isObject()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("while validating arangosearch link definition, error: definition is not an object")
|
||||
);
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
arangodb::CollectionNameResolver resolver(vocbase);
|
||||
|
||||
for (arangodb::velocypack::ObjectIterator itr(links);
|
||||
itr.valid();
|
||||
++itr, ++offset
|
||||
) {
|
||||
auto collectionName = itr.key();
|
||||
auto linkDefinition = itr.value();
|
||||
|
||||
if (!collectionName.isString()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("while validating arangosearch link definition, error: collection at offset ") + std::to_string(offset) + " is not a string"
|
||||
);
|
||||
}
|
||||
|
||||
auto collection = resolver.getCollection(collectionName.copyString());
|
||||
|
||||
if (!collection) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("while validating arangosearch link definition, error: collection '") + collectionName.copyString() + "' not a string"
|
||||
);
|
||||
}
|
||||
|
||||
// check link auth as per https://github.com/arangodb/backlog/issues/459
|
||||
if (arangodb::ExecContext::CURRENT
|
||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase.name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
std::string("while validating arangosearch link definition, error: collection '") + collectionName.copyString() + "' not authorised for read access"
|
||||
);
|
||||
}
|
||||
|
||||
IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
|
||||
if (!linkDefinition.isNull() && !meta.init(linkDefinition, errorField)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
errorField.empty()
|
||||
? (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "': " + linkDefinition.toString())
|
||||
: (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "' error in attribute: " + errorField)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
/*static*/ arangodb::Result IResearchLinkHelper::updateLinks(
|
||||
std::unordered_set<TRI_voc_cid_t>& modified,
|
||||
TRI_vocbase_t& vocbase,
|
||||
|
@ -577,4 +639,4 @@ namespace iresearch {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -65,6 +65,18 @@ struct IResearchLinkHelper {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::string const& type() noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate the link specifications for:
|
||||
/// * valid link meta
|
||||
/// * collection existence
|
||||
/// * collection permissions
|
||||
/// * valid link meta
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::Result validateLinks(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& links
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief updates the collections in 'vocbase' to match the specified
|
||||
/// IResearchLink definitions
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "RestServer/DatabaseFeature.h"
|
||||
#include "RestServer/DatabasePathFeature.h"
|
||||
#include "RestServer/FlushFeature.h"
|
||||
#include "RestServer/ViewTypesFeature.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/ExecContext.h"
|
||||
|
@ -538,6 +539,115 @@ IResearchView::PersistedStore::PersistedStore(irs::utf8_path&& path)
|
|||
: _path(std::move(path)) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief IResearchView-specific implementation of a ViewFactory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct IResearchView::ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
auto* engine = arangodb::EngineSelectorFeature::ENGINE;
|
||||
auto& properties = definition.isObject() ? definition : emptyObjectSlice(); // if no 'info' then assume defaults
|
||||
auto links = properties.hasKey(StaticStrings::LinksField)
|
||||
? properties.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice();
|
||||
auto res = engine && engine->inRecovery()
|
||||
? arangodb::Result() // do not validate if in recovery
|
||||
: IResearchLinkHelper::validateLinks(vocbase, links);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
TRI_set_errno(TRI_ERROR_NO_ERROR); // reset before calling createView(...)
|
||||
auto impl = vocbase.createView(definition);
|
||||
|
||||
if (!impl) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_NO_ERROR == TRI_errno() ? TRI_ERROR_INTERNAL : TRI_errno(),
|
||||
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
// create links on a best-effor basis
|
||||
// link creation failure does not cause view creation failure
|
||||
try {
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
|
||||
res = IResearchLinkHelper::updateLinks(
|
||||
collections, vocbase, *impl, links
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to create links while creating arangosearch view '" << view->name() << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.code() << " " << e.what();
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.what();
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "'";
|
||||
}
|
||||
|
||||
view = impl;
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
auto* feature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::DatabasePathFeature
|
||||
>("DatabasePath");
|
||||
|
||||
if (!feature) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to find feature 'DatabasePath' while constructing arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
std::string error;
|
||||
auto meta = std::make_shared<AsyncMeta>();
|
||||
auto impl = std::shared_ptr<IResearchView>(
|
||||
new IResearchView(vocbase, definition, *feature, planVersion)
|
||||
);
|
||||
|
||||
if (!meta->init(definition, error)
|
||||
|| !impl->_metaState.init(definition, error)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
error.empty()
|
||||
? (std::string("failed to initialize arangosearch View '") + impl->name() + "' from definition: " + definition.toString())
|
||||
: (std::string("failed to initialize arangosearch View '") + impl->name() + "' from definition, error in attribute '" + error + "': " + definition.toString())
|
||||
);
|
||||
}
|
||||
|
||||
auto res = impl->updateProperties(meta); // update separately since per-instance async jobs already started
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
view = impl;
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief container storing the view 'read' state for a given TransactionState
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -870,13 +980,6 @@ IResearchView::~IResearchView() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// noexcept below
|
||||
if (deleted()) {
|
||||
StorageEngine* engine = EngineSelectorFeature::ENGINE;
|
||||
TRI_ASSERT(engine);
|
||||
engine->destroyView(vocbase(), *this);
|
||||
}
|
||||
}
|
||||
|
||||
arangodb::Result IResearchView::appendVelocyPackDetailed(
|
||||
|
@ -1065,6 +1168,8 @@ arangodb::Result IResearchView::drop(
|
|||
// if an errors occurs below than a drop retry would most likely happen
|
||||
// ...........................................................................
|
||||
|
||||
_flushCallback.reset(); // unregister flush callback from flush thread
|
||||
|
||||
try {
|
||||
if (_storePersisted) {
|
||||
_storePersisted._writer->documents().remove(shared_filter);
|
||||
|
@ -1274,6 +1379,12 @@ bool IResearchView::emplace(TRI_voc_cid_t cid) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/*static*/ arangodb::ViewFactory const& IResearchView::factory() {
|
||||
static const ViewFactory factory;
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
arangodb::Result IResearchView::commit() {
|
||||
ReadMutex mutex(_mutex); // '_storePersisted' can be asynchronously updated
|
||||
SCOPED_LOCK(mutex);
|
||||
|
@ -1513,122 +1624,6 @@ int IResearchView::insert(
|
|||
return insertImpl(*ctx);
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<LogicalView> IResearchView::make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
LogicalView::PreCommitCallback const& preCommit /*= {}*/
|
||||
) {
|
||||
auto* feature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::DatabasePathFeature
|
||||
>("DatabasePath");
|
||||
|
||||
if (!feature) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure to find feature 'DatabasePath' while constructing arangosearch View in database '" << vocbase.id() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto view = std::shared_ptr<IResearchView>(
|
||||
new IResearchView(vocbase, info, *feature, planVersion)
|
||||
);
|
||||
auto& impl = reinterpret_cast<IResearchView&>(*view);
|
||||
auto meta = std::make_shared<AsyncMeta>();
|
||||
auto& properties = info.isObject() ? info : emptyObjectSlice(); // if no 'info' then assume defaults
|
||||
std::string error;
|
||||
|
||||
if (!meta->init(properties, error)
|
||||
|| !impl.updateProperties(meta).ok() // update separately since per-instance async jobs already started
|
||||
|| !impl._metaState.init(properties, error)) {
|
||||
TRI_set_errno(TRI_ERROR_BAD_PARAMETER);
|
||||
|
||||
if (error.empty()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to initialize arangosearch view '" << impl.name() << "' from definition";
|
||||
} else {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to initialize arangosearch view '" << impl.name() << "' from definition, error in attribute: " << error;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto links = properties.hasKey(StaticStrings::LinksField)
|
||||
? properties.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice();
|
||||
|
||||
// check link auth as per https://github.com/arangodb/backlog/issues/459
|
||||
if (arangodb::ExecContext::CURRENT) {
|
||||
// check new links
|
||||
for (arangodb::velocypack::ObjectIterator itr(links); itr.valid(); ++itr) {
|
||||
if (!itr.key().isString()) {
|
||||
continue; // not a resolvable collection (invalid jSON)
|
||||
}
|
||||
|
||||
auto collection = vocbase.lookupCollection(itr.key().copyString());
|
||||
|
||||
if (collection
|
||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase.name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||
TRI_set_errno(TRI_ERROR_FORBIDDEN);
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "insufficient rights to create view with link to collection' " << collection->name() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (preCommit && !preCommit(view)) {
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failure during pre-commit while constructing arangosearch View in database '" << vocbase.id() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!isNew) {
|
||||
return view; // nothing more to do
|
||||
}
|
||||
|
||||
auto const res = create(static_cast<arangodb::LogicalViewStorageEngine&>(*view));
|
||||
|
||||
if (!res.ok()) {
|
||||
TRI_set_errno(res.errorNumber());
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failure during commit of created view while constructing arangosearch View in database '" << vocbase.id() << "', error: " << res.errorMessage();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// create links on a best-effor basis
|
||||
// link creation failure does not cause view creation failure
|
||||
try {
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
auto res =
|
||||
IResearchLinkHelper::updateLinks(collections, vocbase, *view, links);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to create links while creating arangosearch view '" << view->name() << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.code() << " " << e.what();
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.what();
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "'";
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
size_t IResearchView::memory() const {
|
||||
ReadMutex mutex(_mutex); // view members can be asynchronously updated
|
||||
SCOPED_LOCK(mutex);
|
||||
|
@ -1921,33 +1916,20 @@ arangodb::Result IResearchView::updateProperties(
|
|||
arangodb::velocypack::Slice const& slice,
|
||||
bool partialUpdate
|
||||
) {
|
||||
std::string error;
|
||||
IResearchViewMeta meta;
|
||||
WriteMutex mutex(_mutex); // '_metaState' can be asynchronously read
|
||||
arangodb::Result res;
|
||||
SCOPED_LOCK_NAMED(mutex, mtx);
|
||||
try {
|
||||
auto links = slice.hasKey(StaticStrings::LinksField)
|
||||
? slice.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice();
|
||||
auto res = _inRecovery
|
||||
? arangodb::Result() // do not validate if in recovery
|
||||
: IResearchLinkHelper::validateLinks(vocbase(), links);
|
||||
|
||||
{
|
||||
auto viewMeta = std::atomic_load(&_meta);
|
||||
SCOPED_LOCK(viewMeta->write());
|
||||
IResearchViewMeta* metaPtr = viewMeta.get();
|
||||
auto& initialMeta = partialUpdate ? *metaPtr : IResearchViewMeta::DEFAULT();
|
||||
|
||||
if (!meta.init(slice, error, initialMeta)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
error.empty()
|
||||
? (std::string("failed to update arangosearch view '") + name() + "' from definition")
|
||||
: (std::string("failed to update arangosearch view '") + name() + "' from definition, error in attribute: " + error)
|
||||
);
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// reset non-updatable values to match current meta
|
||||
meta._locale = viewMeta->_locale;
|
||||
|
||||
if (arangodb::ServerState::instance()->isDBServer()) {
|
||||
viewMeta = std::make_shared<AsyncMeta>(); // create an instance not shared with cluster-view
|
||||
}
|
||||
WriteMutex mutex(_mutex); // '_metaState' can be asynchronously read
|
||||
SCOPED_LOCK_NAMED(mutex, mtx);
|
||||
|
||||
// check link auth as per https://github.com/arangodb/backlog/issues/459
|
||||
if (arangodb::ExecContext::CURRENT) {
|
||||
|
@ -1957,70 +1939,105 @@ arangodb::Result IResearchView::updateProperties(
|
|||
|
||||
if (collection
|
||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase().name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||
return arangodb::Result(TRI_ERROR_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
auto links = slice.hasKey(StaticStrings::LinksField)
|
||||
? slice.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice();
|
||||
|
||||
// check new links
|
||||
for (arangodb::velocypack::ObjectIterator itr(links); itr.valid(); ++itr) {
|
||||
if (!itr.key().isString()) {
|
||||
continue; // not a resolvable collection (invalid jSON)
|
||||
}
|
||||
|
||||
auto collection = vocbase().lookupCollection(itr.key().copyString());
|
||||
|
||||
if (collection
|
||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase().name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||
return arangodb::Result(TRI_ERROR_FORBIDDEN);
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
std::string("while updating arangosearch definition, error: collection '") + collection->name() + "' not authorised for read access"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static_cast<IResearchViewMeta&>(*viewMeta) = std::move(meta);
|
||||
updateProperties(viewMeta); // trigger reload of settings for async jobs
|
||||
}
|
||||
std::string error;
|
||||
IResearchViewMeta meta;
|
||||
|
||||
mutex.unlock(true); // downgrade to a read-lock
|
||||
{
|
||||
auto viewMeta = std::atomic_load(&_meta);
|
||||
SCOPED_LOCK(viewMeta->write());
|
||||
IResearchViewMeta* metaPtr = viewMeta.get();
|
||||
auto& initialMeta = partialUpdate ? *metaPtr : IResearchViewMeta::DEFAULT();
|
||||
|
||||
if (!slice.hasKey(StaticStrings::LinksField)
|
||||
&& (partialUpdate || _inRecovery.load())) { // ignore missing links coming from WAL (inRecovery)
|
||||
return res;
|
||||
}
|
||||
if (!meta.init(slice, error, initialMeta)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
error.empty()
|
||||
? (std::string("failed to update arangosearch view '") + name() + "' from definition: " + slice.toString())
|
||||
: (std::string("failed to update arangosearch view '") + name() + "' from definition, error in attribute '" + error + "': " + slice.toString())
|
||||
);
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// update links if requested (on a best-effort basis)
|
||||
// indexing of collections is done in different threads so no locks can be held and rollback is not possible
|
||||
// as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections)
|
||||
// ...........................................................................
|
||||
// reset non-updatable values to match current meta
|
||||
meta._locale = viewMeta->_locale;
|
||||
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
auto links = slice.hasKey(StaticStrings::LinksField)
|
||||
? slice.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice(); // used for !partialUpdate
|
||||
if (arangodb::ServerState::instance()->isDBServer()) {
|
||||
viewMeta = std::make_shared<AsyncMeta>(); // create an instance not shared with cluster-view
|
||||
}
|
||||
|
||||
static_cast<IResearchViewMeta&>(*viewMeta) = std::move(meta);
|
||||
updateProperties(viewMeta); // trigger reload of settings for async jobs
|
||||
}
|
||||
|
||||
mutex.unlock(true); // downgrade to a read-lock
|
||||
|
||||
if (links.isEmptyObject() && (partialUpdate || _inRecovery.load())) { // ignore missing links coming from WAL (inRecovery)
|
||||
return res;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// update links if requested (on a best-effort basis)
|
||||
// indexing of collections is done in different threads so no locks can be held and rollback is not possible
|
||||
// as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections)
|
||||
// ...........................................................................
|
||||
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
|
||||
if (partialUpdate) {
|
||||
mtx.unlock(); // release lock
|
||||
|
||||
SCOPED_LOCK(_updateLinksLock);
|
||||
|
||||
return IResearchLinkHelper::updateLinks(
|
||||
collections, vocbase(), *this, links
|
||||
);
|
||||
}
|
||||
|
||||
auto stale = _metaState._collections;
|
||||
|
||||
if (partialUpdate) {
|
||||
mtx.unlock(); // release lock
|
||||
|
||||
SCOPED_LOCK(_updateLinksLock);
|
||||
|
||||
return IResearchLinkHelper::updateLinks(
|
||||
collections, vocbase(), *this, links
|
||||
collections, vocbase(), *this, links, stale
|
||||
); } catch (arangodb::basics::Exception& e) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "caught exception while updating properties for arangosearch view '" << name() << "': " << e.code() << " " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
e.code(),
|
||||
std::string("error updating properties for arangosearch view '") + name() + "'"
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "caught exception while updating properties for arangosearch view '" << name() << "': " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating properties for arangosearch view '") + name() + "'"
|
||||
);
|
||||
} catch (...) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "caught exception while updating properties for arangosearch view '" << name() << "'";
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating properties for arangosearch view '") + name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto stale = _metaState._collections;
|
||||
|
||||
mtx.unlock(); // release lock
|
||||
|
||||
SCOPED_LOCK(_updateLinksLock);
|
||||
|
||||
return IResearchLinkHelper::updateLinks(
|
||||
collections, vocbase(), *this, links, stale
|
||||
);
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
arangodb::Result IResearchView::updateProperties(
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace arangodb {
|
|||
|
||||
class DatabasePathFeature; // forward declaration
|
||||
class TransactionState; // forward declaration
|
||||
struct ViewFactory; // forward declaration
|
||||
class ViewIterator; // forward declaration
|
||||
|
||||
namespace aql {
|
||||
|
@ -199,6 +200,11 @@ class IResearchView final
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool emplace(TRI_voc_cid_t cid);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the factory for this type of view
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::ViewFactory const& factory();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief insert a document into this IResearch View and the underlying
|
||||
/// IResearch stores
|
||||
|
@ -227,18 +233,6 @@ class IResearchView final
|
|||
IResearchLinkMeta const& meta
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief view factory
|
||||
/// @returns initialized view object
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static std::shared_ptr<LogicalView> make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
LogicalView::PreCommitCallback const& preCommit = {}
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief amount of memory in bytes occupied by this iResearch Link
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -334,6 +328,7 @@ class IResearchView final
|
|||
PersistedStore(irs::utf8_path&& path);
|
||||
};
|
||||
|
||||
struct ViewFactory; // forward declaration
|
||||
class ViewStateHelper; // forward declaration
|
||||
struct ViewStateRead; // forward declaration
|
||||
struct ViewStateWrite; // forward declaration
|
||||
|
|
|
@ -334,6 +334,8 @@ IResearchViewBlockBase::getSome(size_t atMost) {
|
|||
std::pair<ExecutionState, size_t> IResearchViewBlockBase::skipSome(size_t atMost) {
|
||||
traceSkipSomeBegin(atMost);
|
||||
if (_done) {
|
||||
// aggregate stats
|
||||
_engine->_stats.scannedIndex += static_cast<int64_t>(_inflight);
|
||||
size_t skipped = _inflight;
|
||||
_inflight = 0;
|
||||
traceSkipSomeEnd(skipped, ExecutionState::DONE);
|
||||
|
@ -351,6 +353,8 @@ std::pair<ExecutionState, size_t> IResearchViewBlockBase::skipSome(size_t atMost
|
|||
_upstreamState = upstreamRes.first;
|
||||
if (!upstreamRes.second) {
|
||||
_done = true;
|
||||
// aggregate stats
|
||||
_engine->_stats.scannedIndex += static_cast<int64_t>(_inflight);
|
||||
size_t skipped = _inflight;
|
||||
_inflight = 0;
|
||||
traceSkipSomeEnd(skipped, ExecutionState::DONE);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "Cluster/ServerState.h"
|
||||
#include "IResearch/IResearchFeature.h"
|
||||
#include "IResearch/VelocyPackHelper.h"
|
||||
#include "RestServer/ViewTypesFeature.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/CollectionNameResolver.h"
|
||||
|
@ -51,6 +52,134 @@ typedef irs::async_utils::read_write_mutex::write_mutex WriteMutex;
|
|||
namespace arangodb {
|
||||
namespace iresearch {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief IResearchView-specific implementation of a ViewFactory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct IResearchViewCoordinator::ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to find 'ClusterInfo' instance while creating arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto& properties = definition.isObject() ? definition : emptyObjectSlice(); // if no 'info' then assume defaults
|
||||
auto links = properties.hasKey(StaticStrings::LinksField)
|
||||
? properties.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice();
|
||||
auto res = IResearchLinkHelper::validateLinks(vocbase, links);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
arangodb::LogicalView::ptr impl;
|
||||
|
||||
res = instantiate(impl, vocbase, definition, 0);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!impl) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
res = impl->toVelocyPack(builder, true, true); // include links so that Agency will always have a full definition
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
builder.close();
|
||||
|
||||
std::string error;
|
||||
auto resNum = ci->createViewCoordinator(
|
||||
vocbase.name(), std::to_string(impl->id()), builder.slice(), error
|
||||
);
|
||||
|
||||
if (TRI_ERROR_NO_ERROR != resNum) {
|
||||
return arangodb::Result(
|
||||
resNum,
|
||||
std::string("failure during ClusterInfo persistance of created view while creating arangosearch View in database '") + vocbase.name() + "', error: " + error
|
||||
);
|
||||
}
|
||||
|
||||
// create links on a best-effor basis
|
||||
// link creation failure does not cause view creation failure
|
||||
try {
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
|
||||
res = IResearchLinkHelper::updateLinks(
|
||||
collections, vocbase, *impl, links
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to create links while creating arangosearch view '" << view->name() << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.code() << " " << e.what();
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.what();
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "'";
|
||||
}
|
||||
|
||||
view = ci->getView(vocbase.name(), std::to_string(impl->id())); // refresh view from Agency
|
||||
|
||||
if (view) {
|
||||
view->open(); // open view to match the behaviour in StorageEngine::openExistingDatabase(...) and original behaviour of TRI_vocbase_t::createView(...)
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
std::string error;
|
||||
auto impl = std::shared_ptr<IResearchViewCoordinator>(
|
||||
new IResearchViewCoordinator(vocbase, definition, planVersion)
|
||||
);
|
||||
|
||||
if (!impl->_meta.init(definition, error)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
error.empty()
|
||||
? (std::string("failed to initialize arangosearch View '") + impl->name() + "' from definition: " + definition.toString())
|
||||
: (std::string("failed to initialize arangosearch View '") + impl->name() + "' from definition, error in attribute '" + error + "': " + definition.toString())
|
||||
);
|
||||
}
|
||||
|
||||
view = impl;
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
arangodb::Result IResearchViewCoordinator::appendVelocyPackDetailed(
|
||||
arangodb::velocypack::Builder& builder,
|
||||
bool forPersistence
|
||||
|
@ -169,136 +298,10 @@ bool IResearchViewCoordinator::emplace(
|
|||
).second;
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<LogicalView> IResearchViewCoordinator::make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice const& info,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
LogicalView::PreCommitCallback const& preCommit
|
||||
) {
|
||||
auto& properties = info.isObject() ? info : emptyObjectSlice(); // if no 'info' then assume defaults
|
||||
std::string error;
|
||||
/*static*/ arangodb::ViewFactory const& IResearchViewCoordinator::factory() {
|
||||
static const ViewFactory factory;
|
||||
|
||||
auto view = std::shared_ptr<IResearchViewCoordinator>(
|
||||
new IResearchViewCoordinator(vocbase, info, planVersion)
|
||||
);
|
||||
|
||||
if (!view->_meta.init(properties, error)) {
|
||||
TRI_set_errno(TRI_ERROR_BAD_PARAMETER);
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "failed to initialize arangosearch view from definition, error: " << error;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto links = properties.hasKey(StaticStrings::LinksField)
|
||||
? properties.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice();
|
||||
|
||||
if (links.length()) {
|
||||
auto* engine = arangodb::ClusterInfo::instance();
|
||||
|
||||
if (!engine) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// check link auth as per https://github.com/arangodb/backlog/issues/459
|
||||
if (arangodb::ExecContext::CURRENT) {
|
||||
// check new links
|
||||
if (info.hasKey(StaticStrings::LinksField)) {
|
||||
for (arangodb::velocypack::ObjectIterator itr(info.get(StaticStrings::LinksField)); itr.valid(); ++itr) {
|
||||
if (!itr.key().isString()) {
|
||||
continue; // not a resolvable collection (invalid jSON)
|
||||
}
|
||||
|
||||
auto collection =
|
||||
engine->getCollection(vocbase.name(), itr.key().copyString());
|
||||
|
||||
if (collection
|
||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase.name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||
TRI_set_errno(TRI_ERROR_FORBIDDEN);
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "insufficient rights to create view with link to collection' " << collection->name() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (preCommit && !preCommit(view)) {
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failure during pre-commit while constructing arangosearch view in database '" << vocbase.id() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!isNew) {
|
||||
return view; // nothing more to do
|
||||
}
|
||||
arangodb::velocypack::Builder builder;
|
||||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failure to find ClusterInfo instance while constructing arangosearch view in database '" << vocbase.id() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
builder.openObject();
|
||||
|
||||
auto res = view->toVelocyPack(builder, true, true); // include links so that Agency will always have a full definition
|
||||
|
||||
if (!res.ok()) {
|
||||
TRI_set_errno(res.errorNumber());
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failure to generate definitionf created view while constructing arangosearch view in database '" << vocbase.id() << "', error: " << res.errorMessage();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
builder.close();
|
||||
|
||||
auto resNum = ci->createViewCoordinator(
|
||||
vocbase.name(), std::to_string(view->id()), builder.slice(), error
|
||||
);
|
||||
|
||||
if (TRI_ERROR_NO_ERROR != resNum) {
|
||||
TRI_set_errno(resNum);
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failure during commit of created view while constructing arangosearch view in database '" << vocbase.id() << "', error: " << error;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// create links on a best-effor basis
|
||||
// link creation failure does not cause view creation failure
|
||||
try {
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
auto res =
|
||||
IResearchLinkHelper::updateLinks(collections, vocbase, *view, links);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to create links while creating arangosearch view '" << view->name() << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.code() << " " << e.what();
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "': " << e.what();
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating arangosearch view '" << view->name() << "'";
|
||||
}
|
||||
|
||||
return view;
|
||||
return factory;
|
||||
}
|
||||
|
||||
IResearchViewCoordinator::IResearchViewCoordinator(
|
||||
|
@ -339,20 +342,15 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
}
|
||||
|
||||
try {
|
||||
IResearchViewMeta meta;
|
||||
std::string error;
|
||||
auto links = slice.hasKey(StaticStrings::LinksField)
|
||||
? slice.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice();
|
||||
auto res = IResearchLinkHelper::validateLinks(vocbase(), links);
|
||||
|
||||
auto const& defaults = partialUpdate
|
||||
? _meta
|
||||
: IResearchViewMeta::DEFAULT();
|
||||
|
||||
if (!meta.init(slice, error, defaults)) {
|
||||
return { TRI_ERROR_BAD_PARAMETER, error };
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// reset non-updatable values to match current meta
|
||||
meta._locale = _meta._locale;
|
||||
|
||||
// check link auth as per https://github.com/arangodb/backlog/issues/459
|
||||
if (arangodb::ExecContext::CURRENT) {
|
||||
// check existing links
|
||||
|
@ -362,31 +360,35 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
|
||||
if (collection
|
||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase().name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||
return arangodb::Result(TRI_ERROR_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
// check new links
|
||||
if (slice.hasKey(StaticStrings::LinksField)) {
|
||||
for (arangodb::velocypack::ObjectIterator itr(slice.get(StaticStrings::LinksField)); itr.valid(); ++itr) {
|
||||
if (!itr.key().isString()) {
|
||||
continue; // not a resolvable collection (invalid jSON)
|
||||
}
|
||||
|
||||
auto collection =
|
||||
engine->getCollection(vocbase().name(), itr.key().copyString());
|
||||
|
||||
if (collection
|
||||
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase().name(), collection->name(), arangodb::auth::Level::RO)) {
|
||||
return arangodb::Result(TRI_ERROR_FORBIDDEN);
|
||||
}
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
std::string("while updating arangosearch definition, error: collection '") + collection->name() + "' not authorised for read access"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string error;
|
||||
IResearchViewMeta meta;
|
||||
|
||||
auto const& defaults = partialUpdate
|
||||
? _meta
|
||||
: IResearchViewMeta::DEFAULT();
|
||||
|
||||
if (!meta.init(slice, error, defaults)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
error.empty()
|
||||
? (std::string("failed to update arangosearch view '") + name() + "' from definition: " + slice.toString())
|
||||
: (std::string("failed to update arangosearch view '") + name() + "' from definition, error in attribute '" + error + "': " + slice.toString())
|
||||
);
|
||||
}
|
||||
|
||||
// reset non-updatable values to match current meta
|
||||
meta._locale = _meta._locale;
|
||||
|
||||
// only trigger persisting of properties if they have changed
|
||||
if (_meta != meta) {
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
|
@ -408,7 +410,7 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
}
|
||||
}
|
||||
|
||||
if (!slice.hasKey(StaticStrings::LinksField) && partialUpdate) {
|
||||
if (links.isEmptyObject() && partialUpdate) {
|
||||
return arangodb::Result(); // nothing more to do
|
||||
}
|
||||
|
||||
|
@ -436,9 +438,6 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
}
|
||||
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
auto links = slice.hasKey(StaticStrings::LinksField)
|
||||
? slice.get(StaticStrings::LinksField)
|
||||
: arangodb::velocypack::Slice::emptyObjectSlice(); // used for !partialUpdate
|
||||
|
||||
if (partialUpdate) {
|
||||
return IResearchLinkHelper::updateLinks(
|
||||
|
@ -478,10 +477,10 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
);
|
||||
}
|
||||
|
||||
return {};
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
Result IResearchViewCoordinator::drop() {
|
||||
Result IResearchViewCoordinator::dropImpl() {
|
||||
auto* engine = arangodb::ClusterInfo::instance();
|
||||
|
||||
if (!engine) {
|
||||
|
@ -527,21 +526,6 @@ Result IResearchViewCoordinator::drop() {
|
|||
}
|
||||
}
|
||||
|
||||
// drop view then
|
||||
std::string errorMsg;
|
||||
|
||||
int const res = ClusterInfo::instance()->dropViewCoordinator(
|
||||
vocbase().name(), std::to_string(id()), errorMsg
|
||||
);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG_TOPIC(ERR, arangodb::Logger::CLUSTER)
|
||||
<< "Could not drop view in agency, error: " << errorMsg
|
||||
<< ", errorCode: " << res;
|
||||
|
||||
return { res, errorMsg };
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -550,4 +534,4 @@ Result IResearchViewCoordinator::drop() {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -30,6 +30,12 @@
|
|||
#include <velocypack/Builder.h>
|
||||
#include <velocypack/Slice.h>
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
struct ViewFactory; // forward declaration
|
||||
|
||||
} // arangodb
|
||||
|
||||
namespace arangodb {
|
||||
namespace iresearch {
|
||||
|
||||
|
@ -41,6 +47,8 @@ namespace iresearch {
|
|||
class IResearchViewCoordinator final : public arangodb::LogicalViewClusterInfo {
|
||||
public:
|
||||
|
||||
using LogicalView::drop;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove all documents matching collection 'cid' from this IResearch
|
||||
/// View
|
||||
|
@ -63,17 +71,10 @@ class IResearchViewCoordinator final : public arangodb::LogicalViewClusterInfo {
|
|||
arangodb::velocypack::Slice const& value
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief view factory
|
||||
/// @returns initialized view object
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static std::shared_ptr<LogicalView> make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice const& info,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
LogicalView::PreCommitCallback const& preCommit
|
||||
);
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the factory for this type of view
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::ViewFactory const& factory();
|
||||
|
||||
bool visitCollections(CollectionVisitor const& visitor) const override;
|
||||
|
||||
|
@ -81,8 +82,6 @@ class IResearchViewCoordinator final : public arangodb::LogicalViewClusterInfo {
|
|||
// NOOP
|
||||
}
|
||||
|
||||
Result drop() override;
|
||||
|
||||
virtual Result rename(
|
||||
std::string&& /*newName*/,
|
||||
bool /*doSync*/
|
||||
|
@ -103,7 +102,11 @@ class IResearchViewCoordinator final : public arangodb::LogicalViewClusterInfo {
|
|||
bool forPersistence
|
||||
) const override;
|
||||
|
||||
virtual arangodb::Result dropImpl() override;
|
||||
|
||||
private:
|
||||
struct ViewFactory; // forward declaration
|
||||
|
||||
IResearchViewCoordinator(
|
||||
TRI_vocbase_t& vocbase, velocypack::Slice info, uint64_t planVersion
|
||||
);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Logger/LogMacros.h"
|
||||
#include "RestServer/DatabasePathFeature.h"
|
||||
#include "RestServer/ViewTypesFeature.h"
|
||||
#include "StorageEngine/TransactionState.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
|
@ -176,6 +177,240 @@ std::string generateName(TRI_voc_cid_t viewId, TRI_voc_cid_t collectionId) {
|
|||
namespace arangodb {
|
||||
namespace iresearch {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief IResearchView-specific implementation of a ViewFactory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct IResearchViewDBServer::ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to find 'ClusterInfo' instance while creating arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
arangodb::LogicalView::ptr impl;
|
||||
auto res = instantiate(impl, vocbase, definition, 0);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!impl) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
res = impl->toVelocyPack(builder, true, true); // include links so that Agency will always have a full definition
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
builder.close();
|
||||
|
||||
std::string error;
|
||||
auto resNum = ci->createViewCoordinator(
|
||||
vocbase.name(), std::to_string(impl->id()), builder.slice(), error
|
||||
);
|
||||
|
||||
if (TRI_ERROR_NO_ERROR != resNum) {
|
||||
return arangodb::Result(
|
||||
resNum,
|
||||
std::string("failure during ClusterInfo persistance of created view while creating arangosearch View in database '") + vocbase.name() + "', error: " + error
|
||||
);
|
||||
}
|
||||
|
||||
// NOTE: link creation is ignored since on the db-server links are created
|
||||
// by their LogicalCollections themselves
|
||||
|
||||
view = ci->getView(vocbase.name(), std::to_string(impl->id())); // refresh view from Agency
|
||||
|
||||
if (view) {
|
||||
view->open(); // open view to match the behaviour in StorageEngine::openExistingDatabase(...) and original behaviour of TRI_vocbase_t::createView(...)
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
irs::string_ref name;
|
||||
bool seen;
|
||||
|
||||
if (!getString(name, definition, arangodb::StaticStrings::DataSourceName, seen, irs::string_ref::EMPTY)
|
||||
|| !seen) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("definition supplied without a 'name' while instantiating arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
// not a per-cid view instance (get here from ClusterInfo)
|
||||
if (!irs::starts_with(name, VIEW_NAME_PREFIX)) {
|
||||
auto* feature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::DatabasePathFeature
|
||||
>("DatabasePath");
|
||||
|
||||
if (!feature) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to find feature 'DatabasePath' while constructing arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to find 'ClusterInfo' instance while constructing arangosearch View in database '") + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto wiew = std::shared_ptr<IResearchViewDBServer>(
|
||||
new IResearchViewDBServer(vocbase, definition, *feature, planVersion)
|
||||
);
|
||||
|
||||
std::string error;
|
||||
IResearchViewMeta meta;
|
||||
|
||||
if (!meta.init(definition, error)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
error.empty()
|
||||
? (std::string("failed to initialize arangosearch View '") + wiew->name() + "' from definition: " + definition.toString())
|
||||
: (std::string("failed to initialize arangosearch View '") + wiew->name() + "' from definition, error in attribute '" + error + "': " + definition.toString())
|
||||
);
|
||||
}
|
||||
|
||||
// search for the previous view instance and check if it's meta is the same
|
||||
{
|
||||
auto oldLogicalWiew =
|
||||
ci->getViewCurrent(vocbase.name(), std::to_string(wiew->id()));
|
||||
auto* oldWiew = arangodb::LogicalView::cast<IResearchViewDBServer>(
|
||||
oldLogicalWiew.get()
|
||||
);
|
||||
|
||||
if (oldWiew && *(oldWiew->_meta) == meta) {
|
||||
wiew->_meta = oldWiew->_meta;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(wiew->_meta)) {
|
||||
wiew->_meta = std::make_shared<AsyncMeta>();
|
||||
static_cast<IResearchViewMeta&>(*(wiew->_meta)) = std::move(meta);
|
||||
}
|
||||
|
||||
view = wiew;
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
// .........................................................................
|
||||
// a per-cid view instance
|
||||
// get here only from StorageEngine startup or WAL recovery
|
||||
// .........................................................................
|
||||
|
||||
view = vocbase.lookupView(name);
|
||||
|
||||
if (view) {
|
||||
return arangodb::Result(); // resuse view from vocbase
|
||||
}
|
||||
|
||||
auto* ci = ClusterInfo::instance();
|
||||
std::shared_ptr<AsyncMeta> meta;
|
||||
|
||||
// reference meta from cluster-wide view if available to
|
||||
// avoid memory and thread allocation
|
||||
// if not availble then the meta will be reassigned when
|
||||
// the per-cid instance is associated with the cluster-wide view
|
||||
if (ci) {
|
||||
auto planId = arangodb::basics::VelocyPackHelper::stringUInt64(
|
||||
definition.get(arangodb::StaticStrings::DataSourcePlanId)
|
||||
); // planId set in ensure(...)
|
||||
auto wiewId = std::to_string(planId);
|
||||
auto logicalWiew = ci->getView(vocbase.name(), wiewId); // here if creating per-cid view during loadPlan()
|
||||
auto* wiew = arangodb::LogicalView::cast<IResearchViewDBServer>(
|
||||
logicalWiew.get()
|
||||
);
|
||||
|
||||
// if not found in 'Plan' then search in 'Current'
|
||||
if (!wiew) {
|
||||
logicalWiew = ci->getViewCurrent(vocbase.name(), wiewId); // here if creating per-cid view outisde of loadPlan()
|
||||
wiew = arangodb::LogicalView::cast<IResearchViewDBServer>(
|
||||
logicalWiew.get()
|
||||
);
|
||||
}
|
||||
|
||||
if (wiew) {
|
||||
meta = wiew->_meta;
|
||||
}
|
||||
}
|
||||
|
||||
// no view for shard
|
||||
arangodb::LogicalView::ptr impl;
|
||||
auto res = IResearchView::factory().instantiate(
|
||||
impl, vocbase, definition, planVersion
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!impl) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure during instantiation while creating an arangosearch View '") + std::string(name) + "' in database '" + vocbase.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
if (meta) {
|
||||
res = arangodb::LogicalView::cast<IResearchView>(*impl).updateProperties(meta);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// a wrapper to remove the view from vocbase if it no longer has any links
|
||||
// hold a reference to the original view in the deleter so that the view is
|
||||
// still valid for the duration of the pointer wrapper
|
||||
view = std::shared_ptr<arangodb::LogicalView>(
|
||||
impl.get(),
|
||||
[impl](arangodb::LogicalView*)->void {
|
||||
static const auto visitor = [](TRI_voc_cid_t)->bool { return false; };
|
||||
auto& vocbase = impl->vocbase();
|
||||
|
||||
// same view in vocbase and with no collections
|
||||
if (impl.get() == vocbase.lookupView(impl->id()).get() // avoid double dropView(...)
|
||||
&& impl->visitCollections(visitor)
|
||||
&& !impl->drop().ok()) { // per-cid collections always system
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure to drop stale arangosearch View '" << impl->name() << "' while from database '" << vocbase.name() << "'";
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
IResearchViewDBServer::IResearchViewDBServer(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
|
@ -214,12 +449,12 @@ arangodb::Result IResearchViewDBServer::appendVelocyPackDetailed(
|
|||
}
|
||||
|
||||
|
||||
arangodb::Result IResearchViewDBServer::drop() {
|
||||
arangodb::Result IResearchViewDBServer::dropImpl() {
|
||||
WriteMutex mutex(_mutex);
|
||||
SCOPED_LOCK(mutex); // 'collections_' can be asynchronously read
|
||||
|
||||
for (auto itr = _collections.begin(); itr != _collections.end();) {
|
||||
auto res = vocbase().dropView(itr->second->id(), true); // per-cid collections always system
|
||||
auto res = itr->second->drop();
|
||||
|
||||
if (!res.ok()) {
|
||||
return res; // fail on first failure
|
||||
|
@ -241,7 +476,7 @@ arangodb::Result IResearchViewDBServer::drop(TRI_voc_cid_t cid) noexcept {
|
|||
return arangodb::Result(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||
}
|
||||
|
||||
auto res = vocbase().dropView(itr->second->id(), true); // per-cid collections always system
|
||||
auto res = itr->second->drop();
|
||||
|
||||
if (res.ok()) {
|
||||
_collections.erase(itr);
|
||||
|
@ -373,161 +608,10 @@ std::shared_ptr<arangodb::LogicalView> IResearchViewDBServer::ensure(
|
|||
);
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<LogicalView> IResearchViewDBServer::make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
LogicalView::PreCommitCallback const& preCommit /*= {}*/
|
||||
) {
|
||||
if (!info.isObject()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "non-object definition supplied while instantiating arangosearch view in database '" << vocbase.name() << "'";
|
||||
/*static*/ arangodb::ViewFactory const& IResearchViewDBServer::factory() {
|
||||
static const ViewFactory factory;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
irs::string_ref name;
|
||||
bool seen;
|
||||
|
||||
if (!getString(name, info, arangodb::StaticStrings::DataSourceName, seen, std::string())
|
||||
|| !seen) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "definition supplied without a 'name' while instantiating arangosearch view in database '" << vocbase.name() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// not a per-cid view instance (get here from ClusterInfo)
|
||||
if (!irs::starts_with(name, VIEW_NAME_PREFIX)) {
|
||||
auto* feature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::DatabasePathFeature
|
||||
>("DatabasePath");
|
||||
|
||||
if (!feature) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure to find feature 'DatabasePath' while constructing arangosearch view in database '" << vocbase.id() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure to find ClusterInfo instance while constructing arangosearch view in database '" << vocbase.id() << "'";
|
||||
TRI_set_errno(TRI_ERROR_INTERNAL);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto wiew = std::shared_ptr<IResearchViewDBServer>(
|
||||
new IResearchViewDBServer(vocbase, info, *feature, planVersion)
|
||||
);
|
||||
|
||||
auto& properties = info.isObject() ? info : emptyObjectSlice(); // if no 'info' then assume defaults
|
||||
std::string error;
|
||||
IResearchViewMeta meta;
|
||||
|
||||
if (!meta.init(properties, error)) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to initialize arangosearch view from definition, error: " << error;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// search for the previous view instance and check if it's meta is the same
|
||||
{
|
||||
auto oldLogicalWiew =
|
||||
ci->getViewCurrent(vocbase.name(), std::to_string(wiew->id()));
|
||||
auto* oldWiew =
|
||||
LogicalView::cast<IResearchViewDBServer>(oldLogicalWiew.get());
|
||||
|
||||
if (oldWiew && *(oldWiew->_meta) == meta) {
|
||||
wiew->_meta = oldWiew->_meta;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(wiew->_meta)) {
|
||||
wiew->_meta = std::make_shared<AsyncMeta>();
|
||||
static_cast<IResearchViewMeta&>(*(wiew->_meta)) = std::move(meta);
|
||||
}
|
||||
|
||||
if (preCommit && !preCommit(wiew)) {
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "failure during pre-commit while constructing arangosearch view in database '" << vocbase.id() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return wiew;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// a per-cid view instance (get here only from StorageEngine startup or WAL recovery)
|
||||
// ...........................................................................
|
||||
|
||||
auto view = vocbase.lookupView(name);
|
||||
|
||||
if (view) {
|
||||
return view;
|
||||
}
|
||||
|
||||
auto* ci = ClusterInfo::instance();
|
||||
std::shared_ptr<AsyncMeta> meta;
|
||||
|
||||
// reference meta from cluster-wide view if available to
|
||||
// avoid memory and thread allocation
|
||||
// if not availble then the meta will be reassigned when
|
||||
// the per-cid instance is associated with the cluster-wide view
|
||||
if (ci) {
|
||||
auto planId = arangodb::basics::VelocyPackHelper::stringUInt64(
|
||||
info.get(arangodb::StaticStrings::DataSourcePlanId)
|
||||
); // planId set in ensure(...)
|
||||
auto wiewId = std::to_string(planId);
|
||||
auto logicalWiew = ci->getView(vocbase.name(), wiewId); // here if creating per-cid view during loadPlan()
|
||||
auto* wiew = LogicalView::cast<IResearchViewDBServer>(logicalWiew.get());
|
||||
|
||||
// if not found in 'Plan' then search in 'Current'
|
||||
if (!wiew) {
|
||||
logicalWiew = ci->getViewCurrent(vocbase.name(), wiewId); // here if creating per-cid view outisde of loadPlan()
|
||||
wiew = LogicalView::cast<IResearchViewDBServer>(logicalWiew.get());
|
||||
}
|
||||
|
||||
if (wiew) {
|
||||
meta = wiew->_meta;
|
||||
}
|
||||
}
|
||||
|
||||
// no view for shard
|
||||
view = IResearchView::make(vocbase, info, isNew, planVersion, preCommit);
|
||||
|
||||
if (!view
|
||||
|| (meta && !LogicalView::cast<IResearchView>(*view).updateProperties(meta).ok())) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure while creating an arangosearch view '" << name << "' in database '" << vocbase.name() << "'";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// a wrapper to remove the view from vocbase if it no longer has any links
|
||||
// hold a reference to the original view in the deleter so that the view is
|
||||
// still valid for the duration of the pointer wrapper
|
||||
return std::shared_ptr<arangodb::LogicalView>(
|
||||
view.get(),
|
||||
[view](arangodb::LogicalView*)->void {
|
||||
static const auto visitor = [](TRI_voc_cid_t)->bool { return false; };
|
||||
auto& vocbase = view->vocbase();
|
||||
|
||||
// same view in vocbase and with no collections
|
||||
if (view.get() == vocbase.lookupView(view->id()).get() // avoid double dropView(...)
|
||||
&& view->visitCollections(visitor)
|
||||
&& !vocbase.dropView(view->id(), true).ok()) { // per-cid collections always system
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure to drop stale arangosearch view '" << view->name() << "' while from database '" << vocbase.name() << "'";
|
||||
}
|
||||
}
|
||||
);
|
||||
return factory;
|
||||
}
|
||||
|
||||
void IResearchViewDBServer::open() {
|
||||
|
@ -784,4 +868,4 @@ bool IResearchViewDBServer::visitCollections(
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -35,6 +35,7 @@ namespace arangodb {
|
|||
|
||||
class DatabasePathFeature;
|
||||
class TransactionState;
|
||||
struct ViewFactory; // forward declaration
|
||||
class CollectionNameResolver;
|
||||
|
||||
namespace transaction {
|
||||
|
@ -55,8 +56,7 @@ class IResearchViewDBServer final: public arangodb::LogicalViewClusterInfo {
|
|||
public:
|
||||
virtual ~IResearchViewDBServer();
|
||||
|
||||
/// @return success
|
||||
virtual arangodb::Result drop() override;
|
||||
using LogicalView::drop;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief drop the view association for the specified 'cid'
|
||||
|
@ -76,17 +76,10 @@ class IResearchViewDBServer final: public arangodb::LogicalViewClusterInfo {
|
|||
bool create = true
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief view factory
|
||||
/// @returns initialized view object
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static std::shared_ptr<LogicalView> make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
LogicalView::PreCommitCallback const& preCommit = {}
|
||||
);
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the factory for this type of view
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::ViewFactory const& factory();
|
||||
|
||||
virtual void open() override;
|
||||
virtual arangodb::Result rename(std::string&& newName, bool doSync) override;
|
||||
|
@ -118,7 +111,11 @@ class IResearchViewDBServer final: public arangodb::LogicalViewClusterInfo {
|
|||
bool forPersistence
|
||||
) const override;
|
||||
|
||||
virtual arangodb::Result dropImpl() override;
|
||||
|
||||
private:
|
||||
struct ViewFactory; // forward declaration
|
||||
|
||||
std::map<TRI_voc_cid_t, std::shared_ptr<arangodb::LogicalView>> _collections;
|
||||
std::shared_ptr<AsyncMeta> _meta; // the shared view configuration (never null!!!)
|
||||
mutable irs::async_utils::read_write_mutex _mutex; // for use with members
|
||||
|
@ -134,4 +131,4 @@ class IResearchViewDBServer final: public arangodb::LogicalViewClusterInfo {
|
|||
} // iresearch
|
||||
} // arangodb
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -2090,9 +2090,10 @@ std::unique_ptr<TRI_vocbase_t> MMFilesEngine::openExistingDatabase(
|
|||
);
|
||||
}
|
||||
|
||||
auto const view = LogicalView::create(*vocbase, it, false);
|
||||
LogicalView::ptr view;
|
||||
auto res = LogicalView::instantiate(view, *vocbase, it);
|
||||
|
||||
if (!view) {
|
||||
if (!res.ok() || !view) {
|
||||
auto const message = "failed to instantiate view '" + name + "'";
|
||||
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message.c_str());
|
||||
|
@ -3641,3 +3642,7 @@ void MMFilesEngine::enableCompaction() {
|
|||
bool MMFilesEngine::isCompactionDisabled() const {
|
||||
return _compactionDisabled.load() > 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
|
@ -1125,7 +1125,7 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
|
|||
vocbase->lookupView(viewId);
|
||||
|
||||
if (view != nullptr) {
|
||||
vocbase->dropView(view->id(), true); // drop an existing view
|
||||
view->drop(); // drop an existing view
|
||||
}
|
||||
|
||||
// check if there is another view with the same name as the one that
|
||||
|
@ -1138,7 +1138,7 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
|
|||
view = vocbase->lookupView(name);
|
||||
|
||||
if (view != nullptr) {
|
||||
vocbase->dropView(view->id(), true);
|
||||
view->drop();
|
||||
}
|
||||
} else {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::ENGINES)
|
||||
|
@ -1162,7 +1162,8 @@ bool MMFilesWalRecoverState::ReplayMarker(MMFilesMarker const* marker,
|
|||
TRI_DEFER(state->databaseFeature->forceSyncProperties(oldSync));
|
||||
}
|
||||
|
||||
view = vocbase->createView(payloadSlice);
|
||||
auto res = arangodb::LogicalView::create(view,*vocbase, payloadSlice);
|
||||
TRI_ASSERT(res.ok());
|
||||
TRI_ASSERT(view != nullptr);
|
||||
TRI_ASSERT(view->id() == viewId); // otherwise this a corrupt marker
|
||||
} catch (basics::Exception const& ex) {
|
||||
|
|
|
@ -1740,6 +1740,57 @@ void RestReplicationHandler::handleCommandRestoreView() {
|
|||
|
||||
LOG_TOPIC(TRACE, Logger::REPLICATION) << "restoring view: "
|
||||
<< nameSlice.copyString();
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
try {
|
||||
auto* ci = ClusterInfo::instance();
|
||||
auto view = ci->getView(_vocbase.name(), nameSlice.toString());
|
||||
|
||||
if (view) {
|
||||
if (overwrite) {
|
||||
auto res = view->drop();
|
||||
|
||||
if (!res.ok()) {
|
||||
generateError(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
generateError(TRI_ERROR_ARANGO_DUPLICATE_NAME);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto res = LogicalView::create(view, _vocbase, slice); // must create() since view was drop()ed
|
||||
|
||||
if (!res.ok()) {
|
||||
generateError(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
generateError(Result(TRI_ERROR_INTERNAL, "problem creating view"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
velocypack::Builder result;
|
||||
|
||||
result.openObject();
|
||||
result.add("result", velocypack::Slice::trueSlice());
|
||||
result.close();
|
||||
generateResult(rest::ResponseCode::OK, result.slice());
|
||||
} catch (basics::Exception const& ex) {
|
||||
generateError(Result(ex.code(), ex.message()));
|
||||
} catch (...) {
|
||||
generateError(Result(TRI_ERROR_INTERNAL, "problem creating view"));
|
||||
}
|
||||
|
||||
return; // done
|
||||
}
|
||||
|
||||
auto view = _vocbase.lookupView(nameSlice.copyString());
|
||||
|
||||
if (view) {
|
||||
|
@ -1760,6 +1811,7 @@ void RestReplicationHandler::handleCommandRestoreView() {
|
|||
|
||||
try {
|
||||
view = _vocbase.createView(slice);
|
||||
|
||||
if (view == nullptr) {
|
||||
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
|
||||
"problem creating view");
|
||||
|
|
|
@ -200,32 +200,38 @@ void RestViewHandler::createView() {
|
|||
}
|
||||
|
||||
try {
|
||||
auto view = _vocbase.createView(body);
|
||||
LogicalView::ptr view;
|
||||
auto res = LogicalView::create(view, _vocbase, body);
|
||||
|
||||
if (view != nullptr) {
|
||||
VPackBuilder props;
|
||||
if (!res.ok()) {
|
||||
generateError(res);
|
||||
|
||||
props.openObject();
|
||||
|
||||
auto res = view->toVelocyPack(props, true, false);
|
||||
|
||||
if (!res.ok()) {
|
||||
generateError(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
props.close();
|
||||
generateResult(rest::ResponseCode::CREATED, props.slice());
|
||||
} else {
|
||||
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
|
||||
"problem creating view");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
generateError(arangodb::Result(TRI_ERROR_INTERNAL, "problem creating view"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
res = view->toVelocyPack(builder, true, false);
|
||||
|
||||
if (!res.ok()) {
|
||||
generateError(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.close();
|
||||
generateResult(rest::ResponseCode::CREATED, builder.slice());
|
||||
} catch (basics::Exception const& ex) {
|
||||
generateError(GeneralResponse::responseCode(ex.code()), ex.code(), ex.message());
|
||||
generateError(arangodb::Result(ex.code(), ex.message()));
|
||||
} catch (...) {
|
||||
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
|
||||
"problem creating view");
|
||||
generateError(arangodb::Result(TRI_errno(), "problem creating view"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,13 +423,22 @@ void RestViewHandler::deleteView() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto res = _vocbase.dropView(view->id(), allowDropSystem);
|
||||
// prevent dropping of system views
|
||||
if (!allowDropSystem && view->system()) {
|
||||
generateError(Result(TRI_ERROR_FORBIDDEN, "insufficient rights to drop system view"));
|
||||
|
||||
if (res.ok()) {
|
||||
generateOk(rest::ResponseCode::OK, VPackSlice::trueSlice());
|
||||
} else {
|
||||
generateError(res);
|
||||
return;
|
||||
}
|
||||
|
||||
auto res = view->drop();
|
||||
|
||||
if (!res.ok()) {
|
||||
generateError(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
generateOk(rest::ResponseCode::OK, VPackSlice::trueSlice());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -29,8 +29,33 @@
|
|||
|
||||
namespace {
|
||||
|
||||
struct InvalidViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr&,
|
||||
TRI_vocbase_t&,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("failure to create view without a factory for definition: ") + definition.toString()
|
||||
);
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr&,
|
||||
TRI_vocbase_t&,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t
|
||||
) const override {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("failure to instantiate view without a factory for definition: ") + definition.toString()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
std::string const FEATURE_NAME("ViewTypes");
|
||||
arangodb::ViewTypesFeature::ViewFactory const INVALID{};
|
||||
InvalidViewFactory const INVALID;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -47,13 +72,6 @@ arangodb::Result ViewTypesFeature::emplace(
|
|||
LogicalDataSource::Type const& type,
|
||||
ViewFactory const& factory
|
||||
) {
|
||||
if (!factory) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("view factory undefined during view factory registration for view type '") + type.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto* feature =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature("Bootstrap");
|
||||
auto* bootstrapFeature = dynamic_cast<BootstrapFeature*>(feature);
|
||||
|
@ -66,7 +84,7 @@ arangodb::Result ViewTypesFeature::emplace(
|
|||
);
|
||||
}
|
||||
|
||||
if (!_factories.emplace(&type, factory).second) {
|
||||
if (!_factories.emplace(&type, &factory).second) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DUPLICATE_IDENTIFIER,
|
||||
std::string("view factory previously registered during view factory registration for view type '") + type.name() + "'"
|
||||
|
@ -76,12 +94,13 @@ arangodb::Result ViewTypesFeature::emplace(
|
|||
return arangodb::Result();
|
||||
}
|
||||
|
||||
ViewTypesFeature::ViewFactory const& ViewTypesFeature::factory(
|
||||
ViewFactory const& ViewTypesFeature::factory(
|
||||
LogicalDataSource::Type const& type
|
||||
) const noexcept {
|
||||
auto itr = _factories.find(&type);
|
||||
TRI_ASSERT(itr == _factories.end() || false == !(itr->second)); // ViewTypesFeature::emplace(...) inserts non-nullptr
|
||||
|
||||
return itr == _factories.end() ? INVALID : itr->second;
|
||||
return itr == _factories.end() ? INVALID : *(itr->second);
|
||||
}
|
||||
|
||||
/*static*/ std::string const& ViewTypesFeature::name() {
|
||||
|
|
|
@ -28,27 +28,36 @@
|
|||
|
||||
namespace arangodb {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief LogicalView factory for both end-user and internal instantiation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct ViewFactory {
|
||||
virtual ~ViewFactory() = default; // define to silence warning
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief LogicalView factory for end-user validation instantiation and
|
||||
/// persistence
|
||||
/// @return if success then 'view' is set, else 'view' state is undefined
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
virtual Result create(
|
||||
LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice const& definition
|
||||
) const = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief LogicalView factory for internal instantiation only
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
virtual Result instantiate(
|
||||
LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice const& definition,
|
||||
uint64_t planVersion // cluster plan version ('0' by default for non-cluster)
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
class ViewTypesFeature final: public application_features::ApplicationFeature {
|
||||
public:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief typedef for a LogicalView factory function
|
||||
/// This typedef is used when registering the factory function for any view
|
||||
/// type. the creator function is called when a view is first created or
|
||||
/// re-opened after a server restart. the VelocyPack Slice will contain all
|
||||
/// information about the view's general and implementation-specific properties.
|
||||
/// @param preCommit called before completing view creation (IFF returns true)
|
||||
/// e.g. before persisting definition to filesystem
|
||||
/// IFF preCommit == false then skip invocation
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
typedef std::function<std::shared_ptr<LogicalView>(
|
||||
TRI_vocbase_t& vocbase, // database
|
||||
velocypack::Slice const& definition, // view definition
|
||||
bool isNew, // new view mark
|
||||
uint64_t planVersion, // cluster plan version ('0' by default for non-cluster)
|
||||
LogicalView::PreCommitCallback const& preCommit
|
||||
)> ViewFactory;
|
||||
|
||||
explicit ViewTypesFeature(application_features::ApplicationServer& server);
|
||||
|
||||
/// @return 'factory' for 'type' was added successfully
|
||||
|
@ -67,7 +76,7 @@ class ViewTypesFeature final: public application_features::ApplicationFeature {
|
|||
void unprepare() override final;
|
||||
|
||||
private:
|
||||
std::unordered_map<LogicalDataSource::Type const*, ViewFactory> _factories;
|
||||
std::unordered_map<LogicalDataSource::Type const*, ViewFactory const*> _factories;
|
||||
};
|
||||
|
||||
} // arangodb
|
||||
|
|
|
@ -1900,9 +1900,10 @@ std::unique_ptr<TRI_vocbase_t> RocksDBEngine::openExistingDatabase(
|
|||
|
||||
TRI_ASSERT(!it.get("id").isNone());
|
||||
|
||||
auto const view = LogicalView::create(*vocbase, it, false);
|
||||
LogicalView::ptr view;
|
||||
auto res = LogicalView::instantiate(view, *vocbase, it);
|
||||
|
||||
if (!view) {
|
||||
if (!res.ok() || !view) {
|
||||
auto const message = "failed to instantiate view '" + name + "'";
|
||||
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message);
|
||||
|
@ -2293,4 +2294,4 @@ bool RocksDBEngine::canUseRangeDeleteInWal() const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -199,11 +199,19 @@ static void JS_CreateViewVocbase(
|
|||
);
|
||||
|
||||
try {
|
||||
auto view = vocbase.createView(builder.slice());
|
||||
LogicalView::ptr view;
|
||||
auto res = LogicalView::create(view, vocbase, builder.slice());
|
||||
|
||||
TRI_ASSERT(view != nullptr);
|
||||
if (!res.ok()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(res.errorNumber(), res.errorMessage());
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "problem creating view");
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> result = WrapView(isolate, view);
|
||||
|
||||
if (result.IsEmpty()) {
|
||||
TRI_V8_THROW_EXCEPTION_MEMORY();
|
||||
}
|
||||
|
@ -268,7 +276,12 @@ static void JS_DropViewVocbase(
|
|||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FORBIDDEN, "insufficient rights to drop view");
|
||||
}
|
||||
|
||||
auto res = vocbase.dropView(view->id(), allowDropSystem);
|
||||
// prevent dropping of system views
|
||||
if (!allowDropSystem && view->system()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FORBIDDEN, "insufficient rights to drop system view");
|
||||
}
|
||||
|
||||
auto res = view->drop();
|
||||
|
||||
if (!res.ok()) {
|
||||
TRI_V8_THROW_EXCEPTION(res);
|
||||
|
@ -319,7 +332,12 @@ static void JS_DropViewVocbaseObj(
|
|||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FORBIDDEN, "insufficient rights to drop view");
|
||||
}
|
||||
|
||||
auto res = view->vocbase().dropView(view->id(), allowDropSystem);
|
||||
// prevent dropping of system views
|
||||
if (!allowDropSystem && view->system()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FORBIDDEN, "insufficient rights to drop system view");
|
||||
}
|
||||
|
||||
auto res = view->drop();
|
||||
|
||||
if (!res.ok()) {
|
||||
TRI_V8_THROW_EXCEPTION(res);
|
||||
|
|
|
@ -147,7 +147,7 @@ namespace arangodb {
|
|||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto itr = types.emplace(name, Type());
|
||||
|
||||
if (itr.second) {
|
||||
if (itr.second && name.data()) {
|
||||
const_cast<std::string&>(itr.first->second._name) = name.toString(); // update '_name'
|
||||
const_cast<arangodb::velocypack::StringRef&>(itr.first->first) =
|
||||
itr.first->second.name(); // point key at value stored in '_name'
|
||||
|
|
|
@ -90,53 +90,51 @@ LogicalView::LogicalView(
|
|||
return category;
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<LogicalView> LogicalView::create(
|
||||
/*static*/ Result LogicalView::create(
|
||||
LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice definition,
|
||||
bool isNew,
|
||||
uint64_t planVersion /*= 0*/,
|
||||
PreCommitCallback const& preCommit /*= PreCommitCallback()*/
|
||||
velocypack::Slice definition
|
||||
) {
|
||||
auto const* viewTypes =
|
||||
auto* viewTypes =
|
||||
application_features::ApplicationServer::lookupFeature<ViewTypesFeature>();
|
||||
|
||||
if (!viewTypes) {
|
||||
LOG_TOPIC(ERR, Logger::VIEWS)
|
||||
<< "Failure to get 'ViewTypes' feature while creating LogicalView";
|
||||
|
||||
return nullptr;
|
||||
return Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"Failure to get 'ViewTypes' feature while creating LogicalView"
|
||||
);
|
||||
}
|
||||
|
||||
auto const viewType = basics::VelocyPackHelper::getStringRef(
|
||||
definition, StaticStrings::DataSourceType, ""
|
||||
auto type = basics::VelocyPackHelper::getStringRef(
|
||||
definition, StaticStrings::DataSourceType, velocypack::StringRef(nullptr, 0)
|
||||
);
|
||||
auto const& dataSourceType =
|
||||
arangodb::LogicalDataSource::Type::emplace(viewType);
|
||||
auto const& viewFactory = viewTypes->factory(dataSourceType);
|
||||
auto& factory = viewTypes->factory(LogicalDataSource::Type::emplace(type));
|
||||
|
||||
if (!viewFactory) {
|
||||
TRI_set_errno(TRI_ERROR_BAD_PARAMETER);
|
||||
LOG_TOPIC(ERR, Logger::VIEWS)
|
||||
<< "Found view type for which there is no factory, type: "
|
||||
<< viewType.toString();
|
||||
return factory.create(view, vocbase, definition);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
/*static*/ Result LogicalView::instantiate(
|
||||
LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice definition,
|
||||
uint64_t planVersion /*= 0*/
|
||||
) {
|
||||
auto* viewTypes =
|
||||
application_features::ApplicationServer::lookupFeature<ViewTypesFeature>();
|
||||
|
||||
if (!viewTypes) {
|
||||
return Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"Failure to get 'ViewTypes' feature while creating LogicalView"
|
||||
);
|
||||
}
|
||||
|
||||
auto view = viewFactory(vocbase, definition, isNew, planVersion, preCommit);
|
||||
auto type = basics::VelocyPackHelper::getStringRef(
|
||||
definition, StaticStrings::DataSourceType, velocypack::StringRef(nullptr, 0)
|
||||
);
|
||||
auto& factory = viewTypes->factory(LogicalDataSource::Type::emplace(type));
|
||||
|
||||
if (!view) {
|
||||
LOG_TOPIC(ERR, Logger::VIEWS)
|
||||
<< "Failure to instantiate view of type: " << viewType.toString();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG_TOPIC(DEBUG, Logger::VIEWS)
|
||||
<< "created '" << viewType.toString() << "' view '" << view->name() << "' ("
|
||||
<< view->guid() << ")";
|
||||
|
||||
return view;
|
||||
return factory.instantiate(view, vocbase, definition, planVersion);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -188,6 +186,53 @@ arangodb::Result LogicalViewClusterInfo::appendVelocyPack(
|
|||
return arangodb::Result();
|
||||
}
|
||||
|
||||
arangodb::Result LogicalViewClusterInfo::drop() {
|
||||
if (deleted()) {
|
||||
return Result(); // view already dropped
|
||||
}
|
||||
|
||||
auto* engine = arangodb::ClusterInfo::instance();
|
||||
|
||||
if (!engine) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to get storage engine while dropping View '") + name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
deleted(true); // mark as deleted to avoid double-delete (including recursive calls)
|
||||
|
||||
auto res = dropImpl();
|
||||
|
||||
if (!res.ok()) {
|
||||
deleted(false); // not fully deleted
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
auto resNum = engine->dropViewCoordinator(
|
||||
vocbase().name(), std::to_string(id()), error
|
||||
);
|
||||
|
||||
if (TRI_ERROR_NO_ERROR != resNum) {
|
||||
deleted(false); // not fully deleted
|
||||
|
||||
return arangodb::Result(
|
||||
resNum,
|
||||
std::string("failure during ClusterInfo removal of View in database '") + vocbase().name() + "', error: " + error
|
||||
);
|
||||
}
|
||||
} catch (...) {
|
||||
deleted(false); // not fully deleted
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- LogicalViewStorageEngine
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -207,7 +252,7 @@ LogicalViewStorageEngine::~LogicalViewStorageEngine() {
|
|||
if (deleted()) {
|
||||
StorageEngine* engine = EngineSelectorFeature::ENGINE;
|
||||
TRI_ASSERT(engine);
|
||||
|
||||
// FIXME TODO is this required?
|
||||
engine->destroyView(vocbase(), *this);
|
||||
}
|
||||
}
|
||||
|
@ -260,51 +305,36 @@ arangodb::Result LogicalViewStorageEngine::appendVelocyPack(
|
|||
return arangodb::Result();
|
||||
}
|
||||
|
||||
/*static*/ arangodb::Result LogicalViewStorageEngine::create(
|
||||
LogicalViewStorageEngine const& view
|
||||
) {
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
StorageEngine* engine = EngineSelectorFeature::ENGINE;
|
||||
|
||||
if (!engine) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to get storage engine during storage engine persistance of view '") + view.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return engine->createView(view.vocbase(), view.id(), view);
|
||||
} catch (std::exception const& e) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception during storage engine persistance of view '") + view.name() + "': " + e.what()
|
||||
);
|
||||
} catch (...) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception during storage engine persistance of view '") + view.name() + "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
arangodb::Result LogicalViewStorageEngine::drop() {
|
||||
if (deleted()) {
|
||||
return Result(); // view already dropped
|
||||
}
|
||||
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
StorageEngine* engine = EngineSelectorFeature::ENGINE;
|
||||
TRI_ASSERT(engine);
|
||||
auto res = dropImpl();
|
||||
try {
|
||||
deleted(true); // mark as deleted to avoid double-delete (including recursive calls)
|
||||
|
||||
// skip on error or if already called by dropImpl()
|
||||
if (res.ok() && !deleted()) {
|
||||
deleted(true);
|
||||
engine->dropView(vocbase(), *this);
|
||||
auto res = dropImpl();
|
||||
|
||||
if (!res.ok()) {
|
||||
deleted(false); // not fully deleted
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
res = vocbase().dropView(id(), true); // true since caller should have checked for 'system'
|
||||
|
||||
if (!res.ok()) {
|
||||
deleted(false); // not fully deleted
|
||||
|
||||
return res;
|
||||
}
|
||||
} catch (...) {
|
||||
deleted(false); // not fully deleted
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return res;
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
Result LogicalViewStorageEngine::rename(std::string&& newName, bool doSync) {
|
||||
|
|
|
@ -47,18 +47,9 @@ class Builder;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
class LogicalView : public LogicalDataSource {
|
||||
public:
|
||||
typedef std::shared_ptr<LogicalView> ptr;
|
||||
typedef std::function<bool(TRI_voc_cid_t)> CollectionVisitor;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief typedef for a LogicalView pre-commit callback
|
||||
/// called before completing view creation
|
||||
/// e.g. before persisting definition to filesystem
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
typedef std::function<bool(
|
||||
std::shared_ptr<LogicalView>const& view // a pointer to the created view
|
||||
)> PreCommitCallback;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief casts a specified 'LogicalView' to a provided Target type
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -123,16 +114,30 @@ class LogicalView : public LogicalDataSource {
|
|||
static Category const& category() noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates view according to a definition
|
||||
/// @param preCommit called before completing view creation (IFF returns true)
|
||||
/// e.g. before persisting definition to filesystem
|
||||
/// @brief creates a new view according to a definition
|
||||
/// @param view out-param for created view on success
|
||||
/// on success non-null, on failure undefined
|
||||
/// @param vocbase database where the view resides
|
||||
/// @param definition the view definition
|
||||
/// @return success and sets 'view' or failure
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static std::shared_ptr<LogicalView> create(
|
||||
static Result create(
|
||||
LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice definition
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief instantiates an existing view according to a definition
|
||||
/// @param vocbase database where the view resides
|
||||
/// @param definition the view definition
|
||||
/// @return view instance or nullptr on error
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static Result instantiate(
|
||||
LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice definition,
|
||||
bool isNew,
|
||||
uint64_t planVersion = 0,
|
||||
PreCommitCallback const& preCommit = PreCommitCallback() // called before
|
||||
uint64_t planVersion = 0 // '0' by default for non-cluster
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -187,6 +192,13 @@ class LogicalView : public LogicalDataSource {
|
|||
/// @brief a LogicalView base class for ClusterInfo view implementations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class LogicalViewClusterInfo: public LogicalView {
|
||||
public:
|
||||
virtual Result drop() override final;
|
||||
|
||||
/*FIXME TODO add to trigger rename via vocbase or cluster-info
|
||||
virtual Result rename(std::string&& newName, bool doSync) override final;
|
||||
*/
|
||||
|
||||
protected:
|
||||
LogicalViewClusterInfo(
|
||||
TRI_vocbase_t& vocbase,
|
||||
|
@ -207,6 +219,12 @@ class LogicalViewClusterInfo: public LogicalView {
|
|||
velocypack::Builder& builder,
|
||||
bool forPersistence
|
||||
) const = 0;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief drop implementation-specific parts of an existing view
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
virtual arangodb::Result dropImpl() = 0;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -216,12 +234,10 @@ class LogicalViewStorageEngine: public LogicalView {
|
|||
public:
|
||||
~LogicalViewStorageEngine() override;
|
||||
|
||||
arangodb::Result drop() override final;
|
||||
virtual Result drop() override final;
|
||||
|
||||
Result rename(
|
||||
std::string&& newName,
|
||||
bool doSync
|
||||
) override final;
|
||||
// FIXME TODO rename via vocbase or cluster-info
|
||||
virtual Result rename(std::string&& newName, bool doSync) override final;
|
||||
|
||||
arangodb::Result updateProperties(
|
||||
velocypack::Slice const& properties,
|
||||
|
@ -250,12 +266,6 @@ class LogicalViewStorageEngine: public LogicalView {
|
|||
bool forPersistence
|
||||
) const = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief called by view factories during view creation to persist the view
|
||||
/// to the storage engine
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::Result create(LogicalViewStorageEngine const& view);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief drop implementation-specific parts of an existing view
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -272,4 +282,4 @@ class LogicalViewStorageEngine: public LogicalView {
|
|||
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1016,10 +1016,8 @@ void TRI_vocbase_t::inventory(
|
|||
collection->getIndexesVPack(result, Index::makeFlags(), [](arangodb::Index const* idx) {
|
||||
// we have to exclude the primary and the edge index here, because otherwise
|
||||
// at least the MMFiles engine will try to create it
|
||||
// AND exclude arangosearch indexes
|
||||
return (idx->type() != arangodb::Index::TRI_IDX_TYPE_PRIMARY_INDEX &&
|
||||
idx->type() != arangodb::Index::TRI_IDX_TYPE_EDGE_INDEX &&
|
||||
idx->type() != arangodb::Index::TRI_IDX_TYPE_IRESEARCH_LINK);
|
||||
idx->type() != arangodb::Index::TRI_IDX_TYPE_EDGE_INDEX);
|
||||
});
|
||||
result.add("parameters", VPackValue(VPackValueType::Object));
|
||||
collection->toVelocyPackIgnore(result, { "objectId", "path", "statusString", "indexes" }, true, false);
|
||||
|
@ -1647,92 +1645,65 @@ void TRI_vocbase_t::releaseCollection(arangodb::LogicalCollection* collection) {
|
|||
std::shared_ptr<arangodb::LogicalView> TRI_vocbase_t::createView(
|
||||
arangodb::velocypack::Slice parameters
|
||||
) {
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
auto* engine = EngineSelectorFeature::ENGINE;
|
||||
|
||||
if (!engine) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"failure to get storage engine during creation of view"
|
||||
);
|
||||
}
|
||||
|
||||
// check that the name does not contain any strange characters
|
||||
if (!IsAllowedName(parameters)) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_ILLEGAL_NAME);
|
||||
}
|
||||
|
||||
std::shared_ptr<arangodb::LogicalView> view;
|
||||
arangodb::LogicalView::ptr view;
|
||||
auto res = LogicalView::instantiate(view, *this, parameters);
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failed to find ClusterInfo while creating view")
|
||||
);
|
||||
}
|
||||
|
||||
TRI_set_errno(TRI_ERROR_NO_ERROR); // clear error state so can get valid error below
|
||||
view = LogicalView::create(*this, parameters, true);
|
||||
|
||||
if (!view) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_NO_ERROR == TRI_errno() ? TRI_ERROR_INTERNAL : TRI_errno(),
|
||||
std::string("failed to instantiate view in agency'")
|
||||
);
|
||||
}
|
||||
|
||||
view = ci->getView(name(), std::to_string(view->id())); // refresh view from Agency
|
||||
} else {
|
||||
std::shared_ptr<arangodb::LogicalView> registeredView;
|
||||
auto callback = [this, ®isteredView](
|
||||
std::shared_ptr<arangodb::LogicalView> const& view
|
||||
)->bool {
|
||||
TRI_ASSERT(false == !view);
|
||||
RECURSIVE_WRITE_LOCKER(_dataSourceLock, _dataSourceLockWriteOwner);
|
||||
auto itr = _dataSourceByName.find(view->name());
|
||||
|
||||
if (itr != _dataSourceByName.end()) {
|
||||
events::CreateView(view->name(), TRI_ERROR_ARANGO_DUPLICATE_NAME);
|
||||
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DUPLICATE_NAME);
|
||||
}
|
||||
|
||||
registerView(basics::ConditionalLocking::DoNotLock, view);
|
||||
registeredView = view;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
READ_LOCKER(readLocker, _inventoryLock);
|
||||
|
||||
// Try to create a new view. This is not registered yet
|
||||
TRI_set_errno(TRI_ERROR_NO_ERROR); // clear error state so can get valid error below
|
||||
view = LogicalView::create(*this, parameters, true, 0, callback);
|
||||
|
||||
if (!view) {
|
||||
auto errorNumber = TRI_ERROR_NO_ERROR == TRI_errno()
|
||||
? TRI_ERROR_INTERNAL : TRI_errno();
|
||||
|
||||
if (registeredView) {
|
||||
unregisterView(*registeredView);
|
||||
}
|
||||
|
||||
auto name = arangodb::basics::VelocyPackHelper::getStringValue(
|
||||
parameters, StaticStrings::DataSourceName, ""
|
||||
);
|
||||
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
errorNumber,
|
||||
std::string("failed to instantiate view '") + name + "'"
|
||||
);
|
||||
}
|
||||
|
||||
events::CreateView(view->name(), TRI_ERROR_NO_ERROR);
|
||||
|
||||
if (DatabaseFeature::DATABASE != nullptr &&
|
||||
DatabaseFeature::DATABASE->versionTracker() != nullptr) {
|
||||
DatabaseFeature::DATABASE->versionTracker()->track("create view");
|
||||
}
|
||||
if (!res.ok() || !view) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failed to instantiate view from definition: ") + parameters.toString()
|
||||
);
|
||||
}
|
||||
|
||||
// And lets open it.
|
||||
if (view) {
|
||||
view->open();
|
||||
READ_LOCKER(readLocker, _inventoryLock);
|
||||
RECURSIVE_WRITE_LOCKER(_dataSourceLock, _dataSourceLockWriteOwner);
|
||||
auto itr = _dataSourceByName.find(view->name());
|
||||
|
||||
if (itr != _dataSourceByName.end()) {
|
||||
events::CreateView(view->name(), TRI_ERROR_ARANGO_DUPLICATE_NAME);
|
||||
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DUPLICATE_NAME);
|
||||
}
|
||||
|
||||
registerView(basics::ConditionalLocking::DoNotLock, view);
|
||||
|
||||
try {
|
||||
auto res = engine->createView(view->vocbase(), view->id(), *view);
|
||||
|
||||
if (!res.ok()) {
|
||||
unregisterView(*view);
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(res.errorNumber(), res.errorMessage());
|
||||
}
|
||||
} catch (...) {
|
||||
unregisterView(*view);
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
events::CreateView(view->name(), TRI_ERROR_NO_ERROR);
|
||||
|
||||
if (DatabaseFeature::DATABASE != nullptr &&
|
||||
DatabaseFeature::DATABASE->versionTracker() != nullptr) {
|
||||
DatabaseFeature::DATABASE->versionTracker()->track("create view");
|
||||
}
|
||||
|
||||
view->open(); // And lets open it.
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -1741,29 +1712,24 @@ arangodb::Result TRI_vocbase_t::dropView(
|
|||
TRI_voc_cid_t cid,
|
||||
bool allowDropSystem
|
||||
) {
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
auto const view = lookupView(cid);
|
||||
|
||||
if (!view) {
|
||||
return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!allowDropSystem && view->system()) {
|
||||
StorageEngine* engine = EngineSelectorFeature::ENGINE;
|
||||
StorageEngine* engine = EngineSelectorFeature::ENGINE;
|
||||
|
||||
if (!engine) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failed to find StorageEngine while dropping view '") + view->name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
if (!engine->inRecovery()) {
|
||||
return TRI_ERROR_FORBIDDEN; // prevent dropping of system views
|
||||
}
|
||||
if (!engine) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failed to find StorageEngine while dropping view '") + view->name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
return view->drop(); // will internally drop view from ClusterInfo
|
||||
if (!allowDropSystem && view->system() && !engine->inRecovery()) {
|
||||
return TRI_ERROR_FORBIDDEN; // prevent dropping of system views
|
||||
}
|
||||
|
||||
READ_LOCKER(readLocker, _inventoryLock);
|
||||
|
@ -1807,7 +1773,7 @@ arangodb::Result TRI_vocbase_t::dropView(
|
|||
arangodb::aql::PlanCache::instance()->invalidate(this);
|
||||
arangodb::aql::QueryCache::instance()->invalidate(this);
|
||||
|
||||
auto res = view->drop();
|
||||
auto res = engine->dropView(*this, *view);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
|
|
|
@ -315,7 +315,8 @@ SECTION("test_create_drop") {
|
|||
{
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"id\" : \"42\", \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto logicalView = vocbase->createView(viewJson->slice());
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::create(logicalView, *vocbase, viewJson->slice()).ok()));
|
||||
REQUIRE(logicalView);
|
||||
auto const viewId = std::to_string(logicalView->planId());
|
||||
CHECK("42" == viewId);
|
||||
|
@ -390,7 +391,7 @@ SECTION("test_create_drop") {
|
|||
CHECK(!arangodb::iresearch::IResearchLinkCoordinator::find(*updatedCollection, *logicalView));
|
||||
|
||||
// drop view
|
||||
CHECK(vocbase->dropView(logicalView->planId(), false).ok());
|
||||
CHECK(logicalView->drop().ok());
|
||||
CHECK(nullptr == ci->getView(vocbase->name(), viewId));
|
||||
|
||||
// old index remains valid
|
||||
|
@ -421,7 +422,8 @@ SECTION("test_create_drop") {
|
|||
{
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"id\":\"42\", \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto logicalView = vocbase->createView(viewJson->slice());
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::create(logicalView, *vocbase, viewJson->slice()).ok()));
|
||||
REQUIRE(logicalView);
|
||||
auto const viewId = std::to_string(logicalView->planId());
|
||||
CHECK("42" == viewId);
|
||||
|
@ -513,4 +515,4 @@ SECTION("test_create_drop") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -39,6 +39,7 @@
|
|||
#include "Aql/Function.h"
|
||||
#include "Aql/SortCondition.h"
|
||||
#include "Basics/ArangoGlobalContext.h"
|
||||
#include "Basics/error.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Utils/ExecContext.h"
|
||||
|
||||
|
@ -266,8 +267,9 @@ SECTION("test_defaults") {
|
|||
|
||||
// view definition with LogicalView (for persistence)
|
||||
{
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
arangodb::LogicalView::ptr view;
|
||||
CHECK((arangodb::iresearch::IResearchView::factory().create(view, vocbase, json->slice()).ok()));
|
||||
CHECK((false == !view));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
|
@ -297,7 +299,8 @@ SECTION("test_defaults") {
|
|||
// view definition with LogicalView
|
||||
{
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr view;
|
||||
CHECK((arangodb::iresearch::IResearchView::factory().create(view, vocbase, json->slice()).ok()));
|
||||
CHECK((false == !view));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
|
@ -322,96 +325,42 @@ SECTION("test_defaults") {
|
|||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
}
|
||||
|
||||
// new view definition with links
|
||||
// new view definition with links to missing collections
|
||||
{
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": 101, \"links\": { \"testCollection\": {} } }");
|
||||
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
arangodb::LogicalView::ptr view;
|
||||
auto res = arangodb::iresearch::IResearchView::factory().create(view, vocbase, viewCreateJson->slice());
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == res.errorNumber()));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
}
|
||||
|
||||
// new view definition with links with invalid definition
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": 101, \"links\": { \"testCollection\": {} } }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": 101, \"links\": { \"testCollection\": 42 } }");
|
||||
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
CHECK((nullptr != logicalCollection));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
auto logicalView = vocbase.createView(viewJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
std::set<TRI_voc_cid_t> cids;
|
||||
logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; });
|
||||
CHECK((1 == cids.size()));
|
||||
CHECK((false == logicalCollection->getIndexes().empty()));
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length()));
|
||||
CHECK((true == tmpSlice.hasKey("testCollection")));
|
||||
arangodb::LogicalView::ptr view;
|
||||
auto res = arangodb::iresearch::IResearchView::factory().create(view, vocbase, viewCreateJson->slice());
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == res.errorNumber()));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
}
|
||||
|
||||
// view definition with links
|
||||
// new view definition with links (collection not authorized)
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
auto viewUpdateJson = arangodb::velocypack::Parser::fromJson("{ \"links\": { \"testCollection\": {} } }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"links\": { \"testCollection\": {} } }");
|
||||
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto logicalView = vocbase.createView(viewCreateJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
CHECK((logicalView->updateProperties(viewUpdateJson->slice(), true, false).ok()));
|
||||
|
||||
CHECK((false == logicalCollection->getIndexes().empty()));
|
||||
CHECK((false == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK(slice.get("name").copyString() == "testView");
|
||||
CHECK(slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name());
|
||||
CHECK((false == slice.hasKey("deleted")));
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length()));
|
||||
CHECK((true == tmpSlice.hasKey("testCollection")));
|
||||
}
|
||||
|
||||
// view definition with links (collection not authorized)
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
auto viewUpdateJson = arangodb::velocypack::Parser::fromJson("{ \"links\": { \"testCollection\": {} } }");
|
||||
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto logicalView = vocbase.createView(viewCreateJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
CHECK((logicalView->updateProperties(viewUpdateJson->slice(), true, false).ok()));
|
||||
|
||||
CHECK((false == logicalCollection->getIndexes().empty()));
|
||||
CHECK((false == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
struct ExecContext: public arangodb::ExecContext {
|
||||
ExecContext(): arangodb::ExecContext(arangodb::ExecContext::Type::Default, "", "",
|
||||
|
@ -426,10 +375,51 @@ SECTION("test_defaults") {
|
|||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
auto resetUserManager = irs::make_finally([userManager]()->void{ userManager->removeAllUsers(); });
|
||||
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
arangodb::LogicalView::ptr view;
|
||||
auto res = arangodb::iresearch::IResearchView::factory().create(view, vocbase, viewCreateJson->slice());
|
||||
CHECK((TRI_ERROR_FORBIDDEN == res.errorNumber()));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
}
|
||||
|
||||
// new view definition with links
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": 101, \"links\": { \"testCollection\": {} } }");
|
||||
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
CHECK((nullptr != logicalCollection));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
CHECK((arangodb::iresearch::IResearchView::factory().create(logicalView, vocbase, viewCreateJson->slice()).ok()));
|
||||
REQUIRE((false == !logicalView));
|
||||
std::set<TRI_voc_cid_t> cids;
|
||||
logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; });
|
||||
CHECK((1 == cids.size()));
|
||||
CHECK((false == logicalCollection->getIndexes().empty()));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((TRI_ERROR_FORBIDDEN == logicalView->toVelocyPack(builder, true, false).errorNumber()));
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((false == slice.hasKey("deleted")));
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length()));
|
||||
CHECK((true == tmpSlice.hasKey("testCollection")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +519,7 @@ SECTION("test_drop") {
|
|||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
CHECK((false == !vocbase.lookupView("testView")));
|
||||
CHECK((true == TRI_IsDirectory(dataPath.c_str())));
|
||||
CHECK((true == vocbase.dropView(view->id(), false).ok()));
|
||||
CHECK((true == view->drop().ok()));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
CHECK((false == TRI_IsDirectory(dataPath.c_str())));
|
||||
|
@ -586,7 +576,7 @@ SECTION("test_drop_with_link") {
|
|||
user.grantCollection(vocbase.name(), "testCollection", arangodb::auth::Level::NONE); // for missing collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
CHECK((TRI_ERROR_FORBIDDEN == vocbase.dropView(view->id(), false).errorNumber()));
|
||||
CHECK((TRI_ERROR_FORBIDDEN == view->drop().errorNumber()));
|
||||
CHECK((false == logicalCollection->getIndexes().empty()));
|
||||
CHECK((false == !vocbase.lookupView("testView")));
|
||||
CHECK((true == TRI_IsDirectory(dataPath.c_str())));
|
||||
|
@ -599,7 +589,7 @@ SECTION("test_drop_with_link") {
|
|||
user.grantCollection(vocbase.name(), "testCollection", arangodb::auth::Level::RO); // for missing collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
CHECK((true == vocbase.dropView(view->id(), false).ok()));
|
||||
CHECK((true == view->drop().ok()));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
CHECK((false == TRI_IsDirectory(dataPath.c_str())));
|
||||
|
@ -1457,7 +1447,8 @@ SECTION("test_insert") {
|
|||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto viewImpl = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr viewImpl;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(viewImpl, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !viewImpl));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchView*>(viewImpl.get());
|
||||
CHECK((nullptr != view));
|
||||
|
@ -1501,7 +1492,8 @@ SECTION("test_insert") {
|
|||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto viewImpl = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr viewImpl;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(viewImpl, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !viewImpl));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchView*>(viewImpl.get());
|
||||
CHECK((nullptr != view));
|
||||
|
@ -1545,7 +1537,8 @@ SECTION("test_insert") {
|
|||
{
|
||||
StorageEngineMock::inRecoveryResult = false;
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto viewImpl = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr viewImpl;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(viewImpl, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !viewImpl));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchView*>(viewImpl.get());
|
||||
CHECK((nullptr != view));
|
||||
|
@ -1629,7 +1622,8 @@ SECTION("test_insert") {
|
|||
{
|
||||
StorageEngineMock::inRecoveryResult = false;
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto viewImpl = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr viewImpl;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(viewImpl, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !viewImpl));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchView*>(viewImpl.get());
|
||||
CHECK((nullptr != view));
|
||||
|
@ -1672,7 +1666,8 @@ SECTION("test_insert") {
|
|||
{
|
||||
StorageEngineMock::inRecoveryResult = false;
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto viewImpl = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr viewImpl;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(viewImpl, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !viewImpl));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchView*>(viewImpl.get());
|
||||
CHECK((nullptr != view));
|
||||
|
@ -1713,7 +1708,8 @@ SECTION("test_insert") {
|
|||
{
|
||||
StorageEngineMock::inRecoveryResult = false;
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto viewImpl = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr viewImpl;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(viewImpl, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !viewImpl));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchView*>(viewImpl.get());
|
||||
CHECK((nullptr != view));
|
||||
|
@ -1757,7 +1753,8 @@ SECTION("test_insert") {
|
|||
{
|
||||
StorageEngineMock::inRecoveryResult = false;
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto viewImpl = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr viewImpl;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(viewImpl, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !viewImpl));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchView*>(viewImpl.get());
|
||||
CHECK((nullptr != view));
|
||||
|
@ -1806,7 +1803,8 @@ SECTION("test_open") {
|
|||
auto json = arangodb::velocypack::Parser::fromJson("{ \"id\": 123, \"name\": \"testView\", \"type\": \"testType\" }");
|
||||
|
||||
CHECK((false == TRI_IsDirectory(dataPath.c_str())));
|
||||
auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(view, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !view));
|
||||
CHECK((false == TRI_IsDirectory(dataPath.c_str())));
|
||||
view->open();
|
||||
|
@ -2515,7 +2513,7 @@ SECTION("test_unregister_link") {
|
|||
view->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; });
|
||||
CHECK((1 == cids.size()));
|
||||
CHECK((false == !vocbase.lookupView("testView")));
|
||||
CHECK((true == vocbase.dropView(view->id(), false).ok()));
|
||||
CHECK((true == view->drop().ok()));
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
CHECK((nullptr != vocbase.lookupCollection("testCollection")));
|
||||
CHECK((true == vocbase.dropCollection(logicalCollection->id(), true, -1).ok()));
|
||||
|
@ -2549,7 +2547,8 @@ SECTION("test_unregister_link") {
|
|||
// create a new view with same ID to validate links
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{}");
|
||||
auto view = arangodb::iresearch::IResearchView::make(vocbase, viewJson->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(view, vocbase, viewJson->slice(), 0).ok()));
|
||||
REQUIRE((false == !view));
|
||||
auto* viewImpl = dynamic_cast<arangodb::iresearch::IResearchView*>(view.get());
|
||||
REQUIRE((nullptr != viewImpl));
|
||||
|
@ -2577,7 +2576,8 @@ SECTION("test_self_token") {
|
|||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\" }");
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(view, vocbase, json->slice(), 0).ok()));
|
||||
CHECK((false == !view));
|
||||
auto* viewImpl = dynamic_cast<arangodb::iresearch::IResearchView*>(view.get());
|
||||
REQUIRE((nullptr != viewImpl));
|
||||
|
@ -2598,7 +2598,8 @@ SECTION("test_tracked_cids") {
|
|||
{
|
||||
s.engine.views.clear();
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto view = arangodb::iresearch::IResearchView::make(vocbase, viewJson->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr view;
|
||||
CHECK((arangodb::iresearch::IResearchView::factory().create(view, vocbase, viewJson->slice()).ok()));
|
||||
CHECK((nullptr != view));
|
||||
auto* viewImpl = dynamic_cast<arangodb::iresearch::IResearchView*>(view.get());
|
||||
REQUIRE((nullptr != viewImpl));
|
||||
|
@ -2615,8 +2616,10 @@ SECTION("test_tracked_cids") {
|
|||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto logicalView = arangodb::iresearch::IResearchView::make(vocbase, viewJson->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(logicalView, vocbase, viewJson->slice(), 0).ok()));
|
||||
REQUIRE((false == !logicalView));
|
||||
s.engine.createView(vocbase, logicalView->id(), *logicalView); // ensure link can find view
|
||||
StorageEngineMock(s.server).registerView(vocbase, logicalView); // ensure link can find view
|
||||
auto* viewImpl = dynamic_cast<arangodb::iresearch::IResearchView*>(logicalView.get());
|
||||
REQUIRE((nullptr != viewImpl));
|
||||
|
@ -2643,8 +2646,10 @@ SECTION("test_tracked_cids") {
|
|||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto logicalView = arangodb::iresearch::IResearchView::make(vocbase, viewJson->slice(), true, 0);
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::iresearch::IResearchView::factory().instantiate(logicalView, vocbase, viewJson->slice(), 0).ok()));
|
||||
REQUIRE((false == !logicalView));
|
||||
s.engine.createView(vocbase, logicalView->id(), *logicalView); // ensure link can find view
|
||||
StorageEngineMock(s.server).registerView(vocbase, logicalView); // ensure link can find view
|
||||
auto* viewImpl = dynamic_cast<arangodb::iresearch::IResearchView*>(logicalView.get());
|
||||
REQUIRE((nullptr != viewImpl));
|
||||
|
@ -3384,6 +3389,195 @@ SECTION("test_update_overwrite") {
|
|||
}
|
||||
}
|
||||
|
||||
// test rollback on meta modification failure (as an example invalid value for 'cleanupIntervalStep')
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalView = vocbase.createView(createJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
REQUIRE((logicalView->category() == arangodb::LogicalView::category()));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::iresearch::IResearchViewMetaState expectedMetaState;
|
||||
auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 0.123 }");
|
||||
|
||||
expectedMeta._cleanupIntervalStep = 52;
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == logicalView->updateProperties(updateJson->slice(), false, false).errorNumber()));
|
||||
|
||||
// not for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.get("deleted").isNone())); // no system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
}
|
||||
|
||||
// for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((11U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.hasKey("deleted") && slice.get("deleted").isBoolean() && false == slice.get("deleted").getBoolean())); // has system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((true == metaState.init(slice, error) && expectedMetaState == metaState));
|
||||
CHECK((false == slice.hasKey("links")));
|
||||
}
|
||||
}
|
||||
|
||||
// modify meta params with links to missing collections
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalView = vocbase.createView(createJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
REQUIRE((logicalView->category() == arangodb::LogicalView::category()));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::iresearch::IResearchViewMetaState expectedMetaState;
|
||||
auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 62, \"links\": { \"testCollection\": {} } }");
|
||||
|
||||
expectedMeta._cleanupIntervalStep = 52;
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == logicalView->updateProperties(updateJson->slice(), false, false).errorNumber()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
// not for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.get("deleted").isNone())); // no system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
}
|
||||
|
||||
// for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((11U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.hasKey("deleted") && slice.get("deleted").isBoolean() && false == slice.get("deleted").getBoolean())); // has system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((true == metaState.init(slice, error) && expectedMetaState == metaState));
|
||||
CHECK((false == slice.hasKey("links")));
|
||||
}
|
||||
}
|
||||
|
||||
// modify meta params with links with invalid definition
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto logicalView = vocbase.createView(createJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
REQUIRE((logicalView->category() == arangodb::LogicalView::category()));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::iresearch::IResearchViewMetaState expectedMetaState;
|
||||
auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 62, \"links\": { \"testCollection\": 42 } }");
|
||||
|
||||
expectedMeta._cleanupIntervalStep = 52;
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == logicalView->updateProperties(updateJson->slice(), false, false).errorNumber()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
// not for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.get("deleted").isNone())); // no system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
}
|
||||
|
||||
// for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((11U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.hasKey("deleted") && slice.get("deleted").isBoolean() && false == slice.get("deleted").getBoolean())); // has system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((true == metaState.init(slice, error) && expectedMetaState == metaState));
|
||||
CHECK((false == slice.hasKey("links")));
|
||||
}
|
||||
}
|
||||
|
||||
// modify meta params with links
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
|
@ -4397,26 +4591,24 @@ SECTION("test_update_partial") {
|
|||
|
||||
// test rollback on meta modification failure (as an example invalid value for 'cleanupIntervalStep')
|
||||
{
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto view = vocbase.createView(createJson->slice());
|
||||
REQUIRE((false == !view));
|
||||
REQUIRE(view->category() == arangodb::LogicalView::category());
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalView = vocbase.createView(createJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
REQUIRE((logicalView->category() == arangodb::LogicalView::category()));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::iresearch::IResearchViewMetaState expectedMetaState;
|
||||
auto updateJson = arangodb::velocypack::Parser::fromJson(std::string() + "{ \
|
||||
\"cleanupIntervalStep\": 0.123 \
|
||||
}");
|
||||
auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 0.123 }");
|
||||
|
||||
expectedMeta._cleanupIntervalStep = 52;
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == view->updateProperties(updateJson->slice(), true, false).errorNumber()));
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == logicalView->updateProperties(updateJson->slice(), true, false).errorNumber()));
|
||||
|
||||
// not for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, true, false);
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
@ -4424,11 +4616,11 @@ SECTION("test_update_partial") {
|
|||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK(slice.isObject());
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK(slice.get("name").copyString() == "testView");
|
||||
CHECK(slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name());
|
||||
CHECK(slice.get("deleted").isNone()); // no system properties
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.get("deleted").isNone())); // no system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
|
@ -4439,7 +4631,7 @@ SECTION("test_update_partial") {
|
|||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, true, true);
|
||||
logicalView->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
@ -4447,10 +4639,138 @@ SECTION("test_update_partial") {
|
|||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK(slice.isObject());
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((11U == slice.length()));
|
||||
CHECK(slice.get("name").copyString() == "testView");
|
||||
CHECK(slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name());
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.hasKey("deleted") && slice.get("deleted").isBoolean() && false == slice.get("deleted").getBoolean())); // has system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((true == metaState.init(slice, error) && expectedMetaState == metaState));
|
||||
CHECK((false == slice.hasKey("links")));
|
||||
}
|
||||
}
|
||||
|
||||
// modify meta params with links to missing collections
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalView = vocbase.createView(createJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
REQUIRE((logicalView->category() == arangodb::LogicalView::category()));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::iresearch::IResearchViewMetaState expectedMetaState;
|
||||
auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 62, \"links\": { \"testCollection\": {} } }");
|
||||
|
||||
expectedMeta._cleanupIntervalStep = 52;
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == logicalView->updateProperties(updateJson->slice(), true, false).errorNumber()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
// not for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.get("deleted").isNone())); // no system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
}
|
||||
|
||||
// for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((11U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.hasKey("deleted") && slice.get("deleted").isBoolean() && false == slice.get("deleted").getBoolean())); // has system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((true == metaState.init(slice, error) && expectedMetaState == metaState));
|
||||
CHECK((false == slice.hasKey("links")));
|
||||
}
|
||||
}
|
||||
|
||||
// modify meta params with links with invalid definition
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto logicalView = vocbase.createView(createJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
REQUIRE((logicalView->category() == arangodb::LogicalView::category()));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::iresearch::IResearchViewMetaState expectedMetaState;
|
||||
auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 62, \"links\": { \"testCollection\": 42 } }");
|
||||
|
||||
expectedMeta._cleanupIntervalStep = 52;
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == logicalView->updateProperties(updateJson->slice(), true, false).errorNumber()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
// not for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.get("deleted").isNone())); // no system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
auto tmpSlice = slice.get("links");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
}
|
||||
|
||||
// for persistence
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
arangodb::iresearch::IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((11U == slice.length()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.hasKey("deleted") && slice.get("deleted").isBoolean() && false == slice.get("deleted").getBoolean())); // has system properties
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((true == metaState.init(slice, error) && expectedMetaState == metaState));
|
||||
|
|
|
@ -261,8 +261,8 @@ SECTION("test_rename") {
|
|||
"{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": \"1\", \"collections\": [1,2,3] }");
|
||||
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_COORDINATOR, 1, "testVocbase");
|
||||
|
||||
auto view = arangodb::LogicalView::create(vocbase, json->slice(), false); // false == do not persist
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::LogicalView::instantiate(view, vocbase, json->slice(), 0).ok()));
|
||||
CHECK(nullptr != view);
|
||||
CHECK(nullptr != std::dynamic_pointer_cast<arangodb::iresearch::IResearchViewCoordinator>(view));
|
||||
CHECK(0 == view->planVersion());
|
||||
|
@ -281,7 +281,8 @@ SECTION("test_rename") {
|
|||
SECTION("visit_collections") {
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": \"1\" }");
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_COORDINATOR, 1, "testVocbase");
|
||||
auto logicalView = arangodb::LogicalView::create(vocbase, json->slice(), false); // false == do not persist
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::instantiate(logicalView, vocbase, json->slice(), 0).ok()));
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchViewCoordinator*>(logicalView.get());
|
||||
|
||||
CHECK(nullptr != view);
|
||||
|
@ -307,106 +308,234 @@ SECTION("visit_collections") {
|
|||
}
|
||||
|
||||
SECTION("test_defaults") {
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": \"1\" }");
|
||||
auto* database = arangodb::DatabaseFeature::DATABASE;
|
||||
REQUIRE(nullptr != database);
|
||||
auto* ci = arangodb::ClusterInfo::instance();
|
||||
REQUIRE((nullptr != ci));
|
||||
TRI_vocbase_t* vocbase; // will be owned by DatabaseFeature
|
||||
std::string error;
|
||||
|
||||
// create database
|
||||
{
|
||||
// simulate heartbeat thread
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == database->createDatabase(1, "testDatabase", vocbase)));
|
||||
|
||||
REQUIRE((nullptr != vocbase));
|
||||
CHECK(("testDatabase" == vocbase->name()));
|
||||
CHECK((TRI_vocbase_type_e::TRI_VOCBASE_TYPE_COORDINATOR == vocbase->type()));
|
||||
CHECK((1 == vocbase->id()));
|
||||
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createDatabaseCoordinator(
|
||||
vocbase->name(), VPackSlice::emptyObjectSlice(), error, 0.0
|
||||
)));
|
||||
CHECK(("no error" == error));
|
||||
}
|
||||
|
||||
// view definition with LogicalView (for persistence)
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_COORDINATOR, 1, "testVocbase");
|
||||
|
||||
auto view = arangodb::LogicalView::create(vocbase, json->slice(), false); // false == do not persist
|
||||
|
||||
CHECK(nullptr != view);
|
||||
CHECK(nullptr != std::dynamic_pointer_cast<arangodb::iresearch::IResearchViewCoordinator>(view));
|
||||
CHECK(0 == view->planVersion());
|
||||
CHECK("testView" == view->name());
|
||||
CHECK(false == view->deleted());
|
||||
CHECK(1 == view->id());
|
||||
CHECK(arangodb::iresearch::DATA_SOURCE_TYPE == view->type());
|
||||
CHECK(arangodb::LogicalView::category() == view->category());
|
||||
CHECK(&vocbase == &view->vocbase());
|
||||
|
||||
// visit default view
|
||||
CHECK(true == view->visitCollections([](TRI_voc_cid_t) { return false; }));
|
||||
|
||||
// +system, +properties
|
||||
{
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": \"1\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_COORDINATOR, 1, "testVocbase");
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::LogicalView::instantiate(view, vocbase, json->slice(), 0).ok()));
|
||||
|
||||
CHECK((10U == slice.length()));
|
||||
CHECK((slice.hasKey("globallyUniqueId") && slice.get("globallyUniqueId").isString() && false == slice.get("globallyUniqueId").copyString().empty()));
|
||||
CHECK(slice.get("id").copyString() == "1");
|
||||
CHECK((slice.hasKey("isSystem") && slice.get("isSystem").isBoolean() && false == slice.get("isSystem").getBoolean()));
|
||||
CHECK(slice.get("name").copyString() == "testView");
|
||||
CHECK(slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name());
|
||||
CHECK(slice.hasKey("planId"));
|
||||
CHECK(false == slice.get("deleted").getBool());
|
||||
CHECK((!slice.hasKey("links"))); // for persistence so no links
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((nullptr != view));
|
||||
CHECK((nullptr != std::dynamic_pointer_cast<arangodb::iresearch::IResearchViewCoordinator>(view)));
|
||||
CHECK((0 == view->planVersion()));
|
||||
CHECK(("testView" == view->name()));
|
||||
CHECK((false == view->deleted()));
|
||||
CHECK((1 == view->id()));
|
||||
CHECK((arangodb::iresearch::DATA_SOURCE_TYPE == view->type()));
|
||||
CHECK((arangodb::LogicalView::category() == view->category()));
|
||||
CHECK((&vocbase == &view->vocbase()));
|
||||
|
||||
// visit default view
|
||||
CHECK((true == view->visitCollections([](TRI_voc_cid_t) { return false; })));
|
||||
|
||||
// +system, +properties
|
||||
{
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, true, true);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
|
||||
CHECK((10U == slice.length()));
|
||||
CHECK((slice.hasKey("globallyUniqueId") && slice.get("globallyUniqueId").isString() && false == slice.get("globallyUniqueId").copyString().empty()));
|
||||
CHECK((slice.get("id").copyString() == "1"));
|
||||
CHECK((slice.hasKey("isSystem") && slice.get("isSystem").isBoolean() && false == slice.get("isSystem").getBoolean()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((slice.hasKey("planId")));
|
||||
CHECK((false == slice.get("deleted").getBool()));
|
||||
CHECK((!slice.hasKey("links"))); // for persistence so no links
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
}
|
||||
|
||||
// -system, +properties
|
||||
{
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK((slice.get("id").copyString() == "1"));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((!slice.hasKey("planId")));
|
||||
CHECK((!slice.hasKey("deleted")));
|
||||
CHECK((slice.hasKey("links") && slice.get("links").isObject() && 0 == slice.get("links").length()));
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
}
|
||||
|
||||
// -system, -properties
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, false, false);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
|
||||
CHECK((3 == slice.length()));
|
||||
CHECK((slice.get("id").copyString() == "1"));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((!slice.hasKey("planId")));
|
||||
CHECK((!slice.hasKey("deleted")));
|
||||
CHECK((!slice.hasKey("properties")));
|
||||
}
|
||||
|
||||
// +system, -properties
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, false, true);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK((7 == slice.length()));
|
||||
CHECK((slice.hasKey("globallyUniqueId") && slice.get("globallyUniqueId").isString() && false == slice.get("globallyUniqueId").copyString().empty()));
|
||||
CHECK((slice.get("id").copyString() == "1"));
|
||||
CHECK((slice.hasKey("isSystem") && slice.get("isSystem").isBoolean() && false == slice.get("isSystem").getBoolean()));
|
||||
CHECK((slice.get("name").copyString() == "testView"));
|
||||
CHECK((slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name()));
|
||||
CHECK((false == slice.get("deleted").getBool()));
|
||||
CHECK((slice.hasKey("planId")));
|
||||
CHECK((!slice.hasKey("properties")));
|
||||
}
|
||||
}
|
||||
|
||||
// -system, +properties
|
||||
// new view definition with links to missing collections
|
||||
{
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, true, false);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\", \"links\": { \"testCollection\": {} } }");
|
||||
auto viewId = "testView";
|
||||
|
||||
CHECK((7U == slice.length()));
|
||||
CHECK(slice.get("id").copyString() == "1");
|
||||
CHECK(slice.get("name").copyString() == "testView");
|
||||
CHECK(slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name());
|
||||
CHECK(!slice.hasKey("planId"));
|
||||
CHECK(!slice.hasKey("deleted"));
|
||||
CHECK((slice.hasKey("links") && slice.get("links").isObject() && 0 == slice.get("links").length()));
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
auto res = arangodb::iresearch::IResearchViewCoordinator::factory().create(logicalView, *vocbase, viewCreateJson->slice());
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == res.errorNumber()));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((true == !logicalView));
|
||||
}
|
||||
|
||||
// -system, -properties
|
||||
// new view definition with links with invalid definition
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, false, false);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
std::string error;
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"id\": \"1\", \"planId\": \"1\", \"name\": \"testCollection\", \"replicationFactor\": 1, \"type\": 1 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\", \"links\": { \"testCollection\": 42 } }");
|
||||
auto collectionId = std::to_string(1);
|
||||
auto viewId = "testView";
|
||||
|
||||
CHECK(3 == slice.length());
|
||||
CHECK(slice.get("id").copyString() == "1");
|
||||
CHECK(slice.get("name").copyString() == "testView");
|
||||
CHECK(slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name());
|
||||
CHECK(!slice.hasKey("planId"));
|
||||
CHECK(!slice.hasKey("deleted"));
|
||||
CHECK(!slice.hasKey("properties"));
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createCollectionCoordinator(vocbase->name(), collectionId, 0, 1, false, collectionJson->slice(), error, 0.0)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
auto dropLogicalCollection = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &collectionId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropCollectionCoordinator(vocbase->name(), collectionId, error, 0); });
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
auto res = arangodb::iresearch::IResearchViewCoordinator::factory().create(logicalView, *vocbase, viewCreateJson->slice());
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == res.errorNumber()));
|
||||
|
||||
logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((true == !logicalView));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
}
|
||||
|
||||
// +system, -properties
|
||||
// new view definition with links (collection not authorized)
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
view->toVelocyPack(builder, false, true);
|
||||
builder.close();
|
||||
auto slice = builder.slice();
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"id\": \"1\", \"planId\": \"1\", \"name\": \"testCollection\", \"replicationFactor\": 1, \"type\": 1 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\", \"links\": { \"testCollection\": {} } }");
|
||||
auto collectionId = std::to_string(1);
|
||||
auto viewId = "testView";
|
||||
|
||||
CHECK(7 == slice.length());
|
||||
CHECK((slice.hasKey("globallyUniqueId") && slice.get("globallyUniqueId").isString() && false == slice.get("globallyUniqueId").copyString().empty()));
|
||||
CHECK(slice.get("id").copyString() == "1");
|
||||
CHECK((slice.hasKey("isSystem") && slice.get("isSystem").isBoolean() && false == slice.get("isSystem").getBoolean()));
|
||||
CHECK(slice.get("name").copyString() == "testView");
|
||||
CHECK(slice.get("type").copyString() == arangodb::iresearch::DATA_SOURCE_TYPE.name());
|
||||
CHECK(false == slice.get("deleted").getBool());
|
||||
CHECK(slice.hasKey("planId"));
|
||||
CHECK(!slice.hasKey("properties"));
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createCollectionCoordinator(vocbase->name(), collectionId, 0, 1, false, collectionJson->slice(), error, 0.0)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
auto dropLogicalCollection = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &collectionId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropCollectionCoordinator(vocbase->name(), collectionId, error, 0); });
|
||||
|
||||
struct ExecContext: public arangodb::ExecContext {
|
||||
ExecContext(): arangodb::ExecContext(arangodb::ExecContext::Type::Default, "", "",
|
||||
arangodb::auth::Level::NONE, arangodb::auth::Level::NONE) {}
|
||||
} execContext;
|
||||
arangodb::ExecContextScope execContextScope(&execContext);
|
||||
auto* authFeature = arangodb::AuthenticationFeature::instance();
|
||||
auto* userManager = authFeature->userManager();
|
||||
arangodb::aql::QueryRegistry queryRegistry(0); // required for UserManager::loadFromDB()
|
||||
userManager->setQueryRegistry(&queryRegistry);
|
||||
auto resetUserManager = std::shared_ptr<arangodb::auth::UserManager>(userManager, [](arangodb::auth::UserManager* ptr)->void { ptr->removeAllUsers(); });
|
||||
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
auto res = arangodb::iresearch::IResearchViewCoordinator::factory().create(logicalView, *vocbase, viewCreateJson->slice());
|
||||
CHECK((TRI_ERROR_FORBIDDEN == res.errorNumber()));
|
||||
|
||||
logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((true == !logicalView));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
}
|
||||
|
||||
// new view definition with links
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"id\": \"1\", \"planId\": \"1\", \"name\": \"testCollection\", \"replicationFactor\": 1, \"type\": 1 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\", \"links\": { \"testCollection\": {} } }");
|
||||
auto collectionId = std::to_string(1);
|
||||
auto viewId = "testView";
|
||||
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createCollectionCoordinator(vocbase->name(), collectionId, 0, 1, false, collectionJson->slice(), error, 0.0)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
auto dropLogicalCollection = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &collectionId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropCollectionCoordinator(vocbase->name(), collectionId, error, 0); });
|
||||
|
||||
// simulate heartbeat thread (create index in current)
|
||||
{
|
||||
auto const path = "/Current/Collections/" + vocbase->name() + "/" + std::to_string(logicalCollection->id());
|
||||
auto const value = arangodb::velocypack::Parser::fromJson("{ \"shard-id-does-not-matter\": { \"indexes\" : [ { \"id\": \"1\" } ] } }");
|
||||
CHECK((arangodb::AgencyComm().setValue(path, value->slice(), 0.0).successful()));
|
||||
}
|
||||
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
CHECK((arangodb::iresearch::IResearchViewCoordinator::factory().create(logicalView, *vocbase, viewCreateJson->slice()).ok()));
|
||||
|
||||
logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
CHECK((false == logicalCollection->getIndexes().empty()));
|
||||
CHECK((false == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,11 +642,7 @@ SECTION("test_create_drop_view") {
|
|||
CHECK(nullptr == ci->getView(vocbase->name(), view->name()));
|
||||
|
||||
// drop already dropped view
|
||||
{
|
||||
auto const res = view->drop();
|
||||
CHECK(res.fail());
|
||||
//CHECK(TRI_ERROR_... == res.errorNumber()) FIXME
|
||||
}
|
||||
CHECK((view->drop().ok()));
|
||||
}
|
||||
|
||||
// create and drop view
|
||||
|
@ -562,11 +687,7 @@ SECTION("test_create_drop_view") {
|
|||
CHECK(nullptr == ci->getView(vocbase->name(), view->name()));
|
||||
|
||||
// drop already dropped view
|
||||
{
|
||||
auto const res = view->drop();
|
||||
CHECK(res.fail());
|
||||
//CHECK(TRI_ERROR_... == res.errorNumber()) FIXME
|
||||
}
|
||||
CHECK((view->drop().ok()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -657,7 +778,7 @@ SECTION("test_drop_with_link") {
|
|||
user.grantCollection(vocbase->name(), "testCollection", arangodb::auth::Level::NONE); // for missing collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
CHECK((TRI_ERROR_FORBIDDEN == vocbase->dropView(logicalView->id(), false).errorNumber()));
|
||||
CHECK((TRI_ERROR_FORBIDDEN == logicalView->drop().errorNumber()));
|
||||
logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
CHECK((false == logicalCollection->getIndexes().empty()));
|
||||
|
@ -671,7 +792,7 @@ SECTION("test_drop_with_link") {
|
|||
user.grantCollection(vocbase->name(), "testCollection", arangodb::auth::Level::RO); // for missing collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
CHECK((TRI_ERROR_NO_ERROR == vocbase->dropView(logicalView->id(), false).errorNumber()));
|
||||
CHECK((true == logicalView->drop().ok()));
|
||||
logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
|
@ -933,7 +1054,8 @@ SECTION("test_update_links_partial_remove") {
|
|||
|
||||
// create view
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto view = vocbase->createView(viewJson->slice());
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::LogicalView::create(view, *vocbase, viewJson->slice()).ok()));
|
||||
REQUIRE(view);
|
||||
auto const viewId = std::to_string(view->planId());
|
||||
CHECK("42" == viewId);
|
||||
|
@ -1497,7 +1619,8 @@ SECTION("test_update_links_partial_add") {
|
|||
|
||||
// create view
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto view = vocbase->createView(viewJson->slice());
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::LogicalView::create(view, *vocbase, viewJson->slice()).ok()));
|
||||
REQUIRE(view);
|
||||
auto const viewId = std::to_string(view->planId());
|
||||
CHECK("42" == viewId);
|
||||
|
@ -1983,7 +2106,8 @@ SECTION("test_update_links_partial_add") {
|
|||
auto const collectionId = "1";
|
||||
logicalCollection1 = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection1));
|
||||
auto logicalView = vocbase->createView(viewJson->slice());
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::create(logicalView, *vocbase, viewJson->slice()).ok()));
|
||||
REQUIRE((false == !logicalView));
|
||||
|
||||
CHECK((true == logicalCollection1->getIndexes().empty()));
|
||||
|
@ -2103,7 +2227,8 @@ SECTION("test_update_links_replace") {
|
|||
|
||||
// create view
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto view = vocbase->createView(viewJson->slice());
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::LogicalView::create(view, *vocbase, viewJson->slice()).ok()));
|
||||
REQUIRE(view);
|
||||
auto const viewId = std::to_string(view->planId());
|
||||
CHECK("42" == viewId);
|
||||
|
@ -2670,7 +2795,8 @@ SECTION("test_update_links_clear") {
|
|||
|
||||
// create view
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto view = vocbase->createView(viewJson->slice());
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::LogicalView::create(view, *vocbase, viewJson->slice()).ok()));
|
||||
REQUIRE(view);
|
||||
auto const viewId = std::to_string(view->planId());
|
||||
CHECK("42" == viewId);
|
||||
|
@ -3071,7 +3197,9 @@ SECTION("test_drop_link") {
|
|||
// update link
|
||||
{
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto view = std::dynamic_pointer_cast<arangodb::iresearch::IResearchViewCoordinator>(vocbase->createView(viewJson->slice()));
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::create(logicalView, *vocbase, viewJson->slice()).ok()));
|
||||
auto view = std::dynamic_pointer_cast<arangodb::iresearch::IResearchViewCoordinator>(logicalView);
|
||||
REQUIRE(view);
|
||||
auto const viewId = std::to_string(view->planId());
|
||||
CHECK("42" == viewId);
|
||||
|
@ -3259,7 +3387,8 @@ SECTION("test_drop_link") {
|
|||
auto const collectionId = "1";
|
||||
auto logicalCollection1 = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection1));
|
||||
auto logicalView = vocbase->createView(viewCreateJson->slice());
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::create(logicalView, *vocbase, viewCreateJson->slice()).ok()));
|
||||
REQUIRE((false == !logicalView));
|
||||
auto const viewId = std::to_string(logicalView->planId());
|
||||
|
||||
|
@ -3315,6 +3444,83 @@ SECTION("test_update_overwrite") {
|
|||
CHECK(("no error" == error));
|
||||
}
|
||||
|
||||
// modify meta params with links to missing collections
|
||||
{
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto viewUpdateJson = arangodb::velocypack::Parser::fromJson("{ \"links\": { \"testCollection\": {} } }");
|
||||
auto viewId = std::to_string(42);
|
||||
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createViewCoordinator(vocbase->name(), viewId, viewCreateJson->slice(), error)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
auto dropLogicalView = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &viewId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropViewCoordinator(vocbase->name(), viewId, error); });
|
||||
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
expectedMeta._cleanupIntervalStep = 10;
|
||||
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == logicalView->updateProperties(viewUpdateJson->slice(), false, false).errorNumber()));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true); // 'forPersistence' to avoid auth check
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
error.clear();
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
}
|
||||
|
||||
// modify meta params with links with invalid definition
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"id\": \"1\", \"planId\": \"1\", \"name\": \"testCollection\", \"replicationFactor\": 1, \"type\": 1 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto viewUpdateJson = arangodb::velocypack::Parser::fromJson("{ \"links\": { \"testCollection\": 42 } }");
|
||||
auto collectionId = std::to_string(1);
|
||||
auto viewId = std::to_string(42);
|
||||
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createCollectionCoordinator(vocbase->name(), collectionId, 0, 1, false, collectionJson->slice(), error, 0.0)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
auto dropLogicalCollection = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &collectionId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropCollectionCoordinator(vocbase->name(), collectionId, error, 0); });
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createViewCoordinator(vocbase->name(), viewId, viewCreateJson->slice(), error)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
auto dropLogicalView = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &viewId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropViewCoordinator(vocbase->name(), viewId, error); });
|
||||
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
expectedMeta._cleanupIntervalStep = 10;
|
||||
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == logicalView->updateProperties(viewUpdateJson->slice(), false, false).errorNumber()));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true); // 'forPersistence' to avoid auth check
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
error.clear();
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
}
|
||||
|
||||
// modify meta params with links (collection not authorized)
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"id\": \"1\", \"planId\": \"1\", \"name\": \"testCollection\", \"replicationFactor\": 1, \"type\": 1 }");
|
||||
|
@ -3815,6 +4021,83 @@ SECTION("test_update_partial") {
|
|||
CHECK(("no error" == error));
|
||||
}
|
||||
|
||||
// modify meta params with links to missing collections
|
||||
{
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto viewUpdateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 62, \"links\": { \"testCollection\": {} } }");
|
||||
auto viewId = std::to_string(42);
|
||||
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createViewCoordinator(vocbase->name(), viewId, viewCreateJson->slice(), error)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
auto dropLogicalView = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &viewId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropViewCoordinator(vocbase->name(), viewId, error); });
|
||||
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
expectedMeta._cleanupIntervalStep = 10;
|
||||
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == logicalView->updateProperties(viewUpdateJson->slice(), true, false).errorNumber()));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true); // 'forPersistence' to avoid auth check
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
error.clear();
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
}
|
||||
|
||||
// modify meta params with links with invalid definition
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"id\": \"1\", \"planId\": \"1\", \"name\": \"testCollection\", \"replicationFactor\": 1, \"type\": 1 }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
auto viewUpdateJson = arangodb::velocypack::Parser::fromJson("{ \"cleanupIntervalStep\": 62, \"links\": { \"testCollection\": 42 } }");
|
||||
auto collectionId = std::to_string(1);
|
||||
auto viewId = std::to_string(42);
|
||||
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createCollectionCoordinator(vocbase->name(), collectionId, 0, 1, false, collectionJson->slice(), error, 0.0)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalCollection = ci->getCollection(vocbase->name(), collectionId);
|
||||
REQUIRE((false == !logicalCollection));
|
||||
auto dropLogicalCollection = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &collectionId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropCollectionCoordinator(vocbase->name(), collectionId, error, 0); });
|
||||
error.clear();
|
||||
CHECK((TRI_ERROR_NO_ERROR == ci->createViewCoordinator(vocbase->name(), viewId, viewCreateJson->slice(), error)));
|
||||
CHECK((error.empty()));
|
||||
auto logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
auto dropLogicalView = std::shared_ptr<arangodb::ClusterInfo>(ci, [vocbase, &viewId](arangodb::ClusterInfo* ci)->void { std::string error; ci->dropViewCoordinator(vocbase->name(), viewId, error); });
|
||||
|
||||
CHECK((true == logicalCollection->getIndexes().empty()));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::iresearch::IResearchViewMeta expectedMeta;
|
||||
expectedMeta._cleanupIntervalStep = 10;
|
||||
|
||||
CHECK((TRI_ERROR_BAD_PARAMETER == logicalView->updateProperties(viewUpdateJson->slice(), true, false).errorNumber()));
|
||||
logicalView = ci->getView(vocbase->name(), viewId);
|
||||
REQUIRE((false == !logicalView));
|
||||
CHECK((true == logicalView->visitCollections([](TRI_voc_cid_t)->bool { return false; })));
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
logicalView->toVelocyPack(builder, true, true); // 'forPersistence' to avoid auth check
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
arangodb::iresearch::IResearchViewMeta meta;
|
||||
error.clear();
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
}
|
||||
|
||||
// modify meta params with links (collection not authorized)
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"id\": \"1\", \"planId\": \"1\", \"name\": \"testCollection\", \"replicationFactor\": 1 }");
|
||||
|
@ -4391,4 +4674,4 @@ SECTION("IResearchViewNode::createBlock") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -195,14 +195,34 @@ TEST_CASE("IResearchViewDBServerTest", "[cluster][iresearch][iresearch-view]") {
|
|||
(void)(s);
|
||||
|
||||
SECTION("test_drop") {
|
||||
auto* database = arangodb::DatabaseFeature::DATABASE;
|
||||
REQUIRE(nullptr != database);
|
||||
auto* ci = arangodb::ClusterInfo::instance();
|
||||
REQUIRE(nullptr != ci);
|
||||
std::string error;
|
||||
TRI_vocbase_t* vocbase; // will be owned by DatabaseFeature
|
||||
|
||||
// create database
|
||||
{
|
||||
// simulate heartbeat thread
|
||||
REQUIRE(TRI_ERROR_NO_ERROR == database->createDatabase(1, "testDatabase", vocbase));
|
||||
|
||||
REQUIRE(nullptr != vocbase);
|
||||
CHECK("testDatabase" == vocbase->name());
|
||||
CHECK(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL == vocbase->type());
|
||||
CHECK(1 == vocbase->id());
|
||||
|
||||
CHECK(TRI_ERROR_NO_ERROR == ci->createDatabaseCoordinator(
|
||||
vocbase->name(), VPackSlice::emptyObjectSlice(), error, 0.0
|
||||
));
|
||||
CHECK("no error" == error);
|
||||
}
|
||||
|
||||
// drop empty
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().create(wiew, *vocbase, json->slice()).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -214,8 +234,8 @@ SECTION("test_drop") {
|
|||
{
|
||||
auto const wiewId = std::to_string(ci->uniqid() + 1); // +1 because LogicalView creation will generate a new ID
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().create(wiew, *vocbase, json->slice()).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -225,8 +245,8 @@ SECTION("test_drop") {
|
|||
auto jsonShard = arangodb::velocypack::Parser::fromJson(
|
||||
"{ \"id\": 100, \"name\": \"" + shardViewName + "\", \"type\": \"arangosearch\", \"isSystem\": true }"
|
||||
);
|
||||
CHECK((true == !vocbase.lookupView(shardViewName)));
|
||||
auto shardView = vocbase.createView(jsonShard->slice());
|
||||
CHECK((true == !vocbase->lookupView(shardViewName)));
|
||||
auto shardView = vocbase->createView(jsonShard->slice());
|
||||
CHECK(shardView);
|
||||
|
||||
auto view = impl->ensure(123);
|
||||
|
@ -235,9 +255,9 @@ SECTION("test_drop") {
|
|||
CHECK(view == shardView);
|
||||
static auto visitor = [](TRI_voc_cid_t)->bool { return false; };
|
||||
CHECK((false == impl->visitCollections(visitor)));
|
||||
CHECK((false == !vocbase.lookupView(view->id())));
|
||||
CHECK((false == !vocbase->lookupView(view->id())));
|
||||
CHECK((true == impl->drop().ok()));
|
||||
CHECK((true == !vocbase.lookupView(viewId)));
|
||||
CHECK((true == !vocbase->lookupView(viewId)));
|
||||
CHECK((true == impl->visitCollections(visitor)));
|
||||
}
|
||||
|
||||
|
@ -245,8 +265,8 @@ SECTION("test_drop") {
|
|||
{
|
||||
auto const wiewId = std::to_string(ci->uniqid() + 1); // +1 because LogicalView creation will generate a new ID
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().create(wiew, *vocbase, json->slice()).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -256,8 +276,8 @@ SECTION("test_drop") {
|
|||
auto jsonShard = arangodb::velocypack::Parser::fromJson(
|
||||
"{ \"id\": 100, \"name\": \"" + shardViewName + "\", \"type\": \"arangosearch\", \"isSystem\": true }"
|
||||
);
|
||||
CHECK((true == !vocbase.lookupView(shardViewName)));
|
||||
auto shardView = vocbase.createView(jsonShard->slice());
|
||||
CHECK((true == !vocbase->lookupView(shardViewName)));
|
||||
auto shardView = vocbase->createView(jsonShard->slice());
|
||||
CHECK(shardView);
|
||||
|
||||
auto view = impl->ensure(123);
|
||||
|
@ -265,14 +285,14 @@ SECTION("test_drop") {
|
|||
CHECK(view == shardView);
|
||||
static auto visitor = [](TRI_voc_cid_t)->bool { return false; };
|
||||
CHECK((false == impl->visitCollections(visitor)));
|
||||
CHECK((false == !vocbase.lookupView(view->id())));
|
||||
CHECK((false == !vocbase->lookupView(view->id())));
|
||||
|
||||
auto before = StorageEngineMock::before;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::before = before; });
|
||||
StorageEngineMock::before = []()->void { throw std::exception(); };
|
||||
|
||||
CHECK_THROWS((impl->drop()));
|
||||
CHECK((false == !vocbase.lookupView(view->id())));
|
||||
CHECK((false == !vocbase->lookupView(view->id())));
|
||||
CHECK((false == impl->visitCollections(visitor)));
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +300,8 @@ SECTION("test_drop") {
|
|||
SECTION("test_drop_cid") {
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -349,7 +370,8 @@ SECTION("test_drop_database") {
|
|||
SECTION("test_ensure") {
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"collections\": [ 3, 4, 5 ] }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -377,7 +399,8 @@ SECTION("test_make") {
|
|||
auto const wiewId = ci->uniqid() + 1; // +1 because LogicalView creation will generate a new ID
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -396,7 +419,8 @@ SECTION("test_make") {
|
|||
auto json = arangodb::velocypack::Parser::fromJson("{ \"id\": 100, \"name\": \"_iresearch_123_456\", \"type\": \"arangosearch\", \"isSystem\": true }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
CHECK((true == !vocbase.lookupView("testView")));
|
||||
auto view = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr view;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(view, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !view));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchView*>(view.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -419,7 +443,8 @@ SECTION("test_open") {
|
|||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -435,7 +460,8 @@ SECTION("test_open") {
|
|||
std::string dataPath = (((irs::utf8_path()/=s.testFilesystemPath)/=std::string("databases"))/=std::string("arangosearch-123")).utf8();
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -483,7 +509,8 @@ SECTION("test_query") {
|
|||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE(nullptr != logicalCollection);
|
||||
auto logicalWiew = vocbase.createView(createJson->slice());
|
||||
arangodb::LogicalView::ptr logicalWiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(logicalWiew, vocbase, createJson->slice(), 42).ok()));
|
||||
REQUIRE((false == !logicalWiew));
|
||||
auto* wiewImpl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(logicalWiew.get());
|
||||
REQUIRE((false == !wiewImpl));
|
||||
|
@ -736,7 +763,8 @@ SECTION("test_rename") {
|
|||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -775,7 +803,8 @@ SECTION("test_rename") {
|
|||
auto const wiewId = std::to_string(ci->uniqid() + 1); // +1 because LogicalView creation will generate a new ID
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -826,7 +855,8 @@ SECTION("test_toVelocyPack") {
|
|||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"unusedKey\": \"unusedValue\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -847,7 +877,8 @@ SECTION("test_toVelocyPack") {
|
|||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"unusedKey\": \"unusedValue\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -868,7 +899,8 @@ SECTION("test_toVelocyPack") {
|
|||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"unusedKey\": \"unusedValue\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -1376,7 +1408,8 @@ SECTION("test_visitCollections") {
|
|||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -1390,7 +1423,8 @@ SECTION("test_visitCollections") {
|
|||
auto const wiewId = std::to_string(ci->uniqid() + 1); // +1 because LogicalView creation will generate a new ID
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto wiew = arangodb::iresearch::IResearchViewDBServer::make(vocbase, json->slice(), true, 42);
|
||||
arangodb::LogicalView::ptr wiew;
|
||||
REQUIRE((arangodb::iresearch::IResearchViewDBServer::factory().instantiate(wiew, vocbase, json->slice(), 42).ok()));
|
||||
CHECK((false == !wiew));
|
||||
auto* impl = dynamic_cast<arangodb::iresearch::IResearchViewDBServer*>(wiew.get());
|
||||
CHECK((nullptr != impl));
|
||||
|
@ -1424,4 +1458,4 @@ SECTION("test_visitCollections") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -61,22 +61,35 @@ struct TestView: public arangodb::LogicalView {
|
|||
return _appendVelocyPackResult;
|
||||
}
|
||||
virtual arangodb::Result drop() override { return arangodb::Result(); }
|
||||
static std::shared_ptr<LogicalView> make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
arangodb::LogicalView::PreCommitCallback const& preCommit
|
||||
) {
|
||||
auto view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
return preCommit(view) ? view : nullptr;
|
||||
}
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result rename(std::string&& newName, bool doSync) override { name(std::move(newName)); return arangodb::Result(); }
|
||||
virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const& properties, bool partialUpdate, bool doSync) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
|
||||
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
|
||||
};
|
||||
|
||||
struct ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
view = vocbase.createView(definition);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -88,6 +101,7 @@ struct RestUsersHandlerSetup {
|
|||
arangodb::application_features::ApplicationServer server;
|
||||
std::unique_ptr<TRI_vocbase_t> system;
|
||||
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
|
||||
ViewFactory viewFactory;
|
||||
|
||||
RestUsersHandlerSetup(): engine(server), server(nullptr, nullptr) {
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
|
@ -131,7 +145,7 @@ struct RestUsersHandlerSetup {
|
|||
|
||||
viewTypesFeature->emplace(
|
||||
arangodb::LogicalDataSource::Type::emplace(arangodb::velocypack::StringRef("testViewType")),
|
||||
TestView::make
|
||||
viewFactory
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,23 +50,36 @@ struct TestView: public arangodb::LogicalView {
|
|||
builder.add("properties", _properties.slice());
|
||||
return _appendVelocyPackResult;
|
||||
}
|
||||
virtual arangodb::Result drop() override { return arangodb::Result(); }
|
||||
static std::shared_ptr<LogicalView> make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
arangodb::LogicalView::PreCommitCallback const& preCommit
|
||||
) {
|
||||
auto view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
return preCommit(view) ? view : nullptr;
|
||||
}
|
||||
virtual arangodb::Result drop() override { return vocbase().dropView(id(), true); }
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result rename(std::string&& newName, bool doSync) override { name(std::move(newName)); return arangodb::Result(); }
|
||||
virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const& properties, bool partialUpdate, bool doSync) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
|
||||
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
|
||||
};
|
||||
|
||||
struct ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
view = vocbase.createView(definition);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -77,6 +90,7 @@ struct RestViewHandlerSetup {
|
|||
StorageEngineMock engine;
|
||||
arangodb::application_features::ApplicationServer server;
|
||||
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
|
||||
ViewFactory viewFactory;
|
||||
|
||||
RestViewHandlerSetup(): engine(server), server(nullptr, nullptr) {
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
|
@ -113,7 +127,7 @@ struct RestViewHandlerSetup {
|
|||
|
||||
viewTypesFeature->emplace(
|
||||
arangodb::LogicalDataSource::Type::emplace(arangodb::velocypack::StringRef("testViewType")),
|
||||
TestView::make
|
||||
viewFactory
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,51 +36,40 @@
|
|||
|
||||
namespace {
|
||||
|
||||
std::shared_ptr<arangodb::LogicalView> makeTestView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
bool /*isNew*/,
|
||||
uint64_t planVersion,
|
||||
arangodb::LogicalView::PreCommitCallback const& preCommit
|
||||
) {
|
||||
struct Impl: public arangodb::LogicalViewStorageEngine {
|
||||
Impl(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
uint64_t planVersion
|
||||
): arangodb::LogicalViewStorageEngine(vocbase, info, planVersion) {
|
||||
}
|
||||
virtual arangodb::Result appendVelocyPackDetailed(
|
||||
arangodb::velocypack::Builder&,
|
||||
bool
|
||||
) const override {
|
||||
return arangodb::Result();
|
||||
}
|
||||
arangodb::Result create() {
|
||||
return LogicalViewStorageEngine::create(*this);
|
||||
}
|
||||
virtual arangodb::Result dropImpl() override { return arangodb::Result(); }
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result updateProperties(
|
||||
arangodb::velocypack::Slice const&,
|
||||
bool
|
||||
) override {
|
||||
return arangodb::Result();
|
||||
}
|
||||
virtual bool visitCollections(
|
||||
std::function<bool(TRI_voc_cid_t)> const&
|
||||
) const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct TestView: public arangodb::LogicalView {
|
||||
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
|
||||
: arangodb::LogicalView(vocbase, definition, planVersion) {
|
||||
}
|
||||
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder&, bool , bool) const override { return arangodb::Result(); }
|
||||
virtual arangodb::Result drop() override { deleted(true); return vocbase().dropView(id(), true); }
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result rename(std::string&& newName, bool doSync) override { name(std::move(newName)); return arangodb::Result(); }
|
||||
virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const&, bool, bool) override { return arangodb::Result(); }
|
||||
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
|
||||
};
|
||||
|
||||
auto view = std::make_shared<Impl>(vocbase, info, planVersion);
|
||||
struct ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
view = vocbase.createView(definition);
|
||||
|
||||
return
|
||||
(!preCommit || preCommit(std::static_pointer_cast<arangodb::LogicalView>(view)))
|
||||
&& view->create().ok()
|
||||
? view : nullptr;
|
||||
}
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -92,6 +81,7 @@ struct CollectionNameResolverSetup {
|
|||
StorageEngineMock engine;
|
||||
arangodb::application_features::ApplicationServer server;
|
||||
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
|
||||
ViewFactory viewFactory;
|
||||
|
||||
CollectionNameResolverSetup(): engine(server), server(nullptr, nullptr) {
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
|
@ -123,7 +113,7 @@ struct CollectionNameResolverSetup {
|
|||
arangodb::LogicalDataSource::Type::emplace(
|
||||
arangodb::velocypack::StringRef("testViewType")
|
||||
),
|
||||
makeTestView
|
||||
viewFactory
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -241,7 +231,7 @@ SECTION("test_getDataSource") {
|
|||
}
|
||||
|
||||
CHECK((true == vocbase.dropCollection(collection->id(), true, 0).ok()));
|
||||
CHECK((true == vocbase.dropView(view->id(), true).ok()));
|
||||
CHECK((true == view->drop().ok()));
|
||||
CHECK((true == collection->deleted()));
|
||||
CHECK((true == view->deleted()));
|
||||
|
||||
|
@ -280,4 +270,4 @@ SECTION("test_getDataSource") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -80,22 +80,35 @@ struct TestView: public arangodb::LogicalView {
|
|||
return _appendVelocyPackResult;
|
||||
}
|
||||
virtual arangodb::Result drop() override { return arangodb::Result(); }
|
||||
static std::shared_ptr<LogicalView> make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
arangodb::LogicalView::PreCommitCallback const& preCommit
|
||||
) {
|
||||
auto view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
return preCommit(view) ? view : nullptr;
|
||||
}
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result rename(std::string&& newName, bool doSync) override { name(std::move(newName)); return arangodb::Result(); }
|
||||
virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const& properties, bool partialUpdate, bool doSync) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
|
||||
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
|
||||
};
|
||||
|
||||
struct ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
view = vocbase.createView(definition);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -107,6 +120,7 @@ struct V8UsersSetup {
|
|||
arangodb::application_features::ApplicationServer server;
|
||||
std::unique_ptr<TRI_vocbase_t> system;
|
||||
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
|
||||
ViewFactory viewFactory;
|
||||
|
||||
V8UsersSetup(): engine(server), server(nullptr, nullptr) {
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
|
@ -153,7 +167,7 @@ struct V8UsersSetup {
|
|||
|
||||
viewTypesFeature->emplace(
|
||||
arangodb::LogicalDataSource::Type::emplace(arangodb::velocypack::StringRef("testViewType")),
|
||||
TestView::make
|
||||
viewFactory
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -455,4 +469,4 @@ SECTION("test_collection_auth") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -77,23 +77,36 @@ struct TestView: public arangodb::LogicalView {
|
|||
builder.add("properties", _properties.slice());
|
||||
return _appendVelocyPackResult;
|
||||
}
|
||||
virtual arangodb::Result drop() override { return arangodb::Result(); }
|
||||
static std::shared_ptr<LogicalView> make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
bool isNew,
|
||||
uint64_t planVersion,
|
||||
arangodb::LogicalView::PreCommitCallback const& preCommit
|
||||
) {
|
||||
auto view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
return preCommit(view) ? view : nullptr;
|
||||
}
|
||||
virtual arangodb::Result drop() override { return vocbase().dropView(id(), true); }
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result rename(std::string&& newName, bool doSync) override { name(std::move(newName)); return arangodb::Result(); }
|
||||
virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const& properties, bool partialUpdate, bool doSync) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
|
||||
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
|
||||
};
|
||||
|
||||
struct ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
view = vocbase.createView(definition);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -104,6 +117,7 @@ struct V8ViewsSetup {
|
|||
StorageEngineMock engine;
|
||||
arangodb::application_features::ApplicationServer server;
|
||||
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
|
||||
ViewFactory viewFactory;
|
||||
|
||||
V8ViewsSetup(): engine(server), server(nullptr, nullptr) {
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
|
@ -142,7 +156,7 @@ struct V8ViewsSetup {
|
|||
|
||||
viewTypesFeature->emplace(
|
||||
arangodb::LogicalDataSource::Type::emplace(arangodb::velocypack::StringRef("testViewType")),
|
||||
TestView::make
|
||||
viewFactory
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1403,4 +1417,4 @@ SECTION("test_auth") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -37,51 +37,40 @@
|
|||
|
||||
namespace {
|
||||
|
||||
std::shared_ptr<arangodb::LogicalView> makeTestView(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
bool /*isNew*/,
|
||||
uint64_t planVersion,
|
||||
arangodb::LogicalView::PreCommitCallback const& preCommit
|
||||
) {
|
||||
struct Impl: public arangodb::LogicalViewStorageEngine {
|
||||
Impl(
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& info,
|
||||
uint64_t planVersion
|
||||
): LogicalViewStorageEngine(vocbase, info, planVersion) {
|
||||
}
|
||||
virtual arangodb::Result appendVelocyPackDetailed(
|
||||
arangodb::velocypack::Builder&,
|
||||
bool
|
||||
) const override {
|
||||
return arangodb::Result();
|
||||
}
|
||||
arangodb::Result create() {
|
||||
return LogicalViewStorageEngine::create(*this);
|
||||
}
|
||||
virtual arangodb::Result dropImpl() override { return arangodb::Result(); }
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result updateProperties(
|
||||
arangodb::velocypack::Slice const&,
|
||||
bool
|
||||
) override {
|
||||
return arangodb::Result();
|
||||
}
|
||||
virtual bool visitCollections(
|
||||
std::function<bool(TRI_voc_cid_t)> const&
|
||||
) const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct TestView: public arangodb::LogicalView {
|
||||
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
|
||||
: arangodb::LogicalView(vocbase, definition, planVersion) {
|
||||
}
|
||||
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder&, bool , bool) const override { return arangodb::Result(); }
|
||||
virtual arangodb::Result drop() override { deleted(true); return vocbase().dropView(id(), true); }
|
||||
virtual void open() override {}
|
||||
virtual arangodb::Result rename(std::string&& newName, bool doSync) override { name(std::move(newName)); return arangodb::Result(); }
|
||||
virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const&, bool, bool) override { return arangodb::Result(); }
|
||||
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
|
||||
};
|
||||
|
||||
auto view = std::make_shared<Impl>(vocbase, info, planVersion);
|
||||
struct ViewFactory: public arangodb::ViewFactory {
|
||||
virtual arangodb::Result create(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) const override {
|
||||
view = vocbase.createView(definition);
|
||||
|
||||
return
|
||||
(!preCommit || preCommit(std::static_pointer_cast<arangodb::LogicalView>(view)))
|
||||
&& view->create().ok()
|
||||
? view : nullptr;
|
||||
}
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
arangodb::LogicalView::ptr& view,
|
||||
TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
uint64_t planVersion
|
||||
) const override {
|
||||
view = std::make_shared<TestView>(vocbase, definition, planVersion);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -93,6 +82,7 @@ struct VocbaseSetup {
|
|||
StorageEngineMock engine;
|
||||
arangodb::application_features::ApplicationServer server;
|
||||
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
|
||||
ViewFactory viewFactory;
|
||||
|
||||
VocbaseSetup(): engine(server), server(nullptr, nullptr) {
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
|
@ -124,7 +114,7 @@ struct VocbaseSetup {
|
|||
arangodb::LogicalDataSource::Type::emplace(
|
||||
arangodb::velocypack::StringRef("testViewType")
|
||||
),
|
||||
makeTestView
|
||||
viewFactory
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -346,7 +336,7 @@ SECTION("test_lookupDataSource") {
|
|||
}
|
||||
|
||||
CHECK((true == vocbase.dropCollection(collection->id(), true, 0).ok()));
|
||||
CHECK((true == vocbase.dropView(view->id(), true).ok()));
|
||||
CHECK((true == view->drop().ok()));
|
||||
CHECK((true == collection->deleted()));
|
||||
CHECK((true == view->deleted()));
|
||||
|
||||
|
@ -387,4 +377,4 @@ SECTION("test_lookupDataSource") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -1,5 +1,5 @@
|
|||
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
||||
/*global fail, assertUndefined, assertNotEqual, assertEqual, assertTrue, assertFalse*/
|
||||
/*global fail, assertUndefined, assertEqual, assertNotEqual, assertTrue, assertFalse*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
|
@ -65,8 +65,10 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._drop("TestCollection0");
|
||||
db._dropView("TestView");
|
||||
db._create("TestCollection0");
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
db._createView("TestView", "arangosearch", {links:{"TestCollection0":{}}});
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
db._createView("TestView", "arangosearch", {links:{"TestCollection0":{ includeAllFields:true}}});
|
||||
var view = db._view("TestView");
|
||||
assertTrue(null != view);
|
||||
assertEqual(Object.keys(view.properties().links).length, 1);
|
||||
|
@ -80,9 +82,10 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._dropView("TestView");
|
||||
db._create("TestCollection0");
|
||||
|
||||
var addLink = { links: { "TestCollection0": {} } };
|
||||
var addLink = { links: { "TestCollection0": { includeAllFields:true} } };
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
view.properties(addLink, true); // partial update
|
||||
let properties = view.properties();
|
||||
|
@ -109,10 +112,11 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._create("TestCollection0");
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
|
||||
var addLink = { links: { "TestCollection0": {} } };
|
||||
var addLink = { links: { "TestCollection0": { includeAllFields:true} } };
|
||||
var removeLink = { links: { "TestCollection0": null } };
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
view.properties(addLink, true); // partial update
|
||||
let properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
|
@ -137,7 +141,8 @@ function IResearchFeatureDDLTestSuite () {
|
|||
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
db._create("TestCollection0");
|
||||
var addLink = { links: { "TestCollection0": {} } };
|
||||
db.TestCollection0.save({ name : 'foo' });
|
||||
var addLink = { links: { "TestCollection0": { includeAllFields: true } } };
|
||||
view.properties(addLink, true); // partial update
|
||||
let properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
|
@ -159,23 +164,29 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._create("TestCollection2");
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
db.TestCollection1.save({ name : i.toString() });
|
||||
db.TestCollection2.save({ name : i.toString() });
|
||||
}
|
||||
|
||||
var properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(0, Object.keys(properties.links).length);
|
||||
|
||||
var meta = { links: { "TestCollection0": {} } };
|
||||
var meta = { links: { "TestCollection0": { includeAllFields:true } } };
|
||||
view.properties(meta, true); // partial update
|
||||
properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(1, Object.keys(properties.links).length);
|
||||
|
||||
meta = { links: { "TestCollection1": {} } };
|
||||
meta = { links: { "TestCollection1": { includeAllFields:true } } };
|
||||
view.properties(meta, true); // partial update
|
||||
properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(2, Object.keys(properties.links).length);
|
||||
|
||||
meta = { links: { "TestCollection2": {} } };
|
||||
meta = { links: { "TestCollection2": { includeAllFields:true } } };
|
||||
view.properties(meta, false); // full update
|
||||
properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
|
@ -240,8 +251,14 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._create("TestCollection2");
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
db.TestCollection1.save({ name : i.toString() });
|
||||
db.TestCollection2.save({ name : i.toString() });
|
||||
}
|
||||
|
||||
var meta = { links: {
|
||||
"TestCollection0": {},
|
||||
"TestCollection0": { },
|
||||
"TestCollection1": { analyzers: [ "text_en"], includeAllFields: true, trackListPositions: true, storeValues: "full" },
|
||||
"TestCollection2": { fields: {
|
||||
"b": { fields: { "b1": {} } },
|
||||
|
@ -398,11 +415,11 @@ function IResearchFeatureDDLTestSuite () {
|
|||
var meta = { links: { "TestCollection0": { includeAllFields: true } } };
|
||||
view.properties(meta, true); // partial update
|
||||
|
||||
var result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true} SORT doc.name RETURN doc").toArray();
|
||||
var result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true } SORT doc.name RETURN doc").toArray();
|
||||
assertEqual(0, result.length);
|
||||
|
||||
col0.save({ name: "quarter", text: "quick over" });
|
||||
result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true} SORT doc.name RETURN doc").toArray();
|
||||
result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true } SORT doc.name RETURN doc").toArray();
|
||||
assertEqual(1, result.length);
|
||||
assertEqual("quarter", result[0].name);
|
||||
|
||||
|
@ -420,7 +437,7 @@ function IResearchFeatureDDLTestSuite () {
|
|||
meta = { links: { "TestCollection0": { includeAllFields: true } } };
|
||||
view.properties(meta, true); // partial update
|
||||
|
||||
result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true} SORT doc.name RETURN doc").toArray();
|
||||
result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true } SORT doc.name RETURN doc").toArray();
|
||||
assertEqual(4, result.length);
|
||||
assertEqual("full", result[0].name);
|
||||
assertEqual("half", result[1].name);
|
||||
|
@ -446,7 +463,7 @@ function IResearchFeatureDDLTestSuite () {
|
|||
} };
|
||||
view.properties(meta, true); // partial update
|
||||
|
||||
result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true} SORT doc.name RETURN doc").toArray();
|
||||
result = db._query("FOR doc IN TestView OPTIONS { waitForSync: true } SORT doc.name RETURN doc").toArray();
|
||||
assertEqual(4, result.length);
|
||||
assertEqual("full", result[0].name);
|
||||
assertEqual("half", result[1].name);
|
||||
|
|
|
@ -65,8 +65,10 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._drop("TestCollection0");
|
||||
db._dropView("TestView");
|
||||
db._create("TestCollection0");
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
db._createView("TestView", "arangosearch", {links:{"TestCollection0":{}}});
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
db._createView("TestView", "arangosearch", {links:{"TestCollection0":{ includeAllFields:true}}});
|
||||
var view = db._view("TestView");
|
||||
assertTrue(null != view);
|
||||
assertEqual(Object.keys(view.properties().links).length, 1);
|
||||
|
@ -80,9 +82,10 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._dropView("TestView");
|
||||
db._create("TestCollection0");
|
||||
|
||||
var addLink = { links: { "TestCollection0": {} } };
|
||||
var addLink = { links: { "TestCollection0": { includeAllFields:true} } };
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
view.properties(addLink, true); // partial update
|
||||
let properties = view.properties();
|
||||
|
@ -109,10 +112,11 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._create("TestCollection0");
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
|
||||
var addLink = { links: { "TestCollection0": {} } };
|
||||
var addLink = { links: { "TestCollection0": { includeAllFields:true} } };
|
||||
var removeLink = { links: { "TestCollection0": null } };
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
view.properties(addLink, true); // partial update
|
||||
let properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
|
@ -137,7 +141,8 @@ function IResearchFeatureDDLTestSuite () {
|
|||
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
db._create("TestCollection0");
|
||||
var addLink = { links: { "TestCollection0": {} } };
|
||||
db.TestCollection0.save({ name : 'foo' });
|
||||
var addLink = { links: { "TestCollection0": { includeAllFields: true } } };
|
||||
view.properties(addLink, true); // partial update
|
||||
let properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
|
@ -159,28 +164,40 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._create("TestCollection2");
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
db.TestCollection1.save({ name : i.toString() });
|
||||
db.TestCollection2.save({ name : i.toString() });
|
||||
}
|
||||
|
||||
var properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(0, Object.keys(properties.links).length);
|
||||
|
||||
var meta = { links: { "TestCollection0": {} } };
|
||||
var meta = { links: { "TestCollection0": { includeAllFields:true } } };
|
||||
view.properties(meta, true); // partial update
|
||||
properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(1, Object.keys(properties.links).length);
|
||||
|
||||
meta = { links: { "TestCollection1": {} } };
|
||||
meta = { links: { "TestCollection1": { includeAllFields:true } } };
|
||||
view.properties(meta, true); // partial update
|
||||
properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(2, Object.keys(properties.links).length);
|
||||
|
||||
meta = { links: { "TestCollection2": {} } };
|
||||
meta = { links: { "TestCollection2": { includeAllFields:true } } };
|
||||
view.properties(meta, false); // full update
|
||||
properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(1, Object.keys(properties.links).length);
|
||||
|
||||
// create with links
|
||||
db._dropView("TestView");
|
||||
view = db._createView("TestView", "arangosearch", meta);
|
||||
properties = view.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(1, Object.keys(properties.links).length);
|
||||
|
||||
// consolidate
|
||||
db._dropView("TestView");
|
||||
|
@ -234,8 +251,14 @@ function IResearchFeatureDDLTestSuite () {
|
|||
db._create("TestCollection2");
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
db.TestCollection0.save({ name : i.toString() });
|
||||
db.TestCollection1.save({ name : i.toString() });
|
||||
db.TestCollection2.save({ name : i.toString() });
|
||||
}
|
||||
|
||||
var meta = { links: {
|
||||
"TestCollection0": {},
|
||||
"TestCollection0": { },
|
||||
"TestCollection1": { analyzers: [ "text_en"], includeAllFields: true, trackListPositions: true, storeValues: "full" },
|
||||
"TestCollection2": { fields: {
|
||||
"b": { fields: { "b1": {} } },
|
||||
|
|
Loading…
Reference in New Issue