1
0
Fork 0

issue 526.6: implement REST and V8 handlers for the iresearch analyzer feature (#8626)

* issue 526.6: implement REST and V8 handlers for the iresearch analyzer feature

* address typo

* remove excess comments

* temporarily comment out tests failing on MacOS

* temporarily comment out more MacOS-only test failures
This commit is contained in:
Vasiliy 2019-04-02 19:23:28 +03:00 committed by Andrey Abramov
parent 4af7fa8f46
commit f4919dc173
22 changed files with 4826 additions and 540 deletions

View File

@ -77,6 +77,8 @@ add_library(${LIB_ARANGO_IRESEARCH}
IResearch/VelocyPackHelper.cpp IResearch/VelocyPackHelper.h IResearch/VelocyPackHelper.cpp IResearch/VelocyPackHelper.h
IResearch/ExpressionFilter.cpp IResearch/ExpressionFilter.h IResearch/ExpressionFilter.cpp IResearch/ExpressionFilter.h
IResearch/AqlHelper.cpp IResearch/AqlHelper.h IResearch/AqlHelper.cpp IResearch/AqlHelper.h
RestHandler/RestAnalyzerHandler.cpp RestHandler/RestAnalyzerHandler.h
V8Server/v8-analyzers.cpp V8Server/v8-analyzers.h
) )
target_compile_definitions(${LIB_ARANGO_IRESEARCH} target_compile_definitions(${LIB_ARANGO_IRESEARCH}

View File

@ -731,16 +731,10 @@ IResearchAnalyzerFeature::IResearchAnalyzerFeature(arangodb::application_feature
auto split = splitAnalyzerName(name); auto split = splitAnalyzerName(name);
return !split.first.null() // have a vocbase return split.first.null() // static analyzer (always allowed)
&& ctx->canUseDatabase(split.first, level) // can use vocbase || (ctx->canUseDatabase(split.first, level) // can use vocbase
&& ctx->canUseCollection(split.first, ANALYZER_COLLECTION_NAME, level); // can use analyzers && ctx->canUseCollection(split.first, ANALYZER_COLLECTION_NAME, level) // can use analyzers
} );
std::pair<IResearchAnalyzerFeature::AnalyzerPool::ptr, bool> IResearchAnalyzerFeature::emplace(
irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties,
irs::flags const& features /*= irs::flags::empty_instance()*/
) noexcept {
return emplace(name, type, properties, true, features);
} }
std::pair<IResearchAnalyzerFeature::AnalyzerPool::ptr, bool> IResearchAnalyzerFeature::emplace( std::pair<IResearchAnalyzerFeature::AnalyzerPool::ptr, bool> IResearchAnalyzerFeature::emplace(
@ -1616,255 +1610,6 @@ arangodb::Result IResearchAnalyzerFeature::loadAnalyzers( // load
return arangodb::Result(); return arangodb::Result();
} }
bool IResearchAnalyzerFeature::loadConfiguration() {
if (arangodb::ServerState::instance()->isRunningInCluster()) {
// the following code will not be working in the cluster
// safe to access since loadConfiguration(...) is called from start() which
// is single-thread
return _customAnalyzers.empty();
}
auto vocbase = getSystemDatabase();
if (!vocbase) {
LOG_TOPIC("3cc73", WARN, arangodb::iresearch::TOPIC)
<< "failure to get system database while loading arangosearch analyzer "
"persisted configuration";
return false;
}
arangodb::SingleCollectionTransaction trx(
arangodb::transaction::StandaloneContext::Create(*vocbase),
ANALYZER_COLLECTION_NAME, arangodb::AccessMode::Type::READ);
auto res = trx.begin();
if (!res.ok()) {
LOG_TOPIC("16400", WARN, arangodb::iresearch::TOPIC)
<< "failure to start transaction while loading arangosearch analyzer "
"persisted configuration";
return false;
}
auto* collection = trx.documentCollection();
if (!collection) {
LOG_TOPIC("ead4b", WARN, arangodb::iresearch::TOPIC)
<< "failure to get collection while loading arangosearch analyzer "
"persisted configuration";
trx.abort();
return false;
}
std::unordered_map<irs::string_ref, AnalyzerPool::ptr> initialized;
auto visitor = [this, &trx, collection, &initialized](LocalDocumentId const& token) -> bool {
ManagedDocumentResult result;
if (!collection->readDocument(&trx, token, result)) {
LOG_TOPIC("377b5", WARN, arangodb::iresearch::TOPIC)
<< "skipping failed read of an arangosearch analyzer persisted "
"configuration token: "
<< token.id();
return true; // failed to read document, skip
}
arangodb::velocypack::Slice slice(result.vpack());
if (!slice.isObject() || !slice.hasKey(arangodb::StaticStrings::KeyString) ||
!slice.get(arangodb::StaticStrings::KeyString).isString() ||
!slice.hasKey("name") || !slice.get("name").isString() || !slice.hasKey("type") ||
!slice.get("type").isString() || !slice.hasKey("properties") ||
!(slice.get("properties").isNull() || slice.get("properties").isString() ||
slice.get("properties").isArray() || slice.get("properties").isObject())) {
LOG_TOPIC("e8578", WARN, arangodb::iresearch::TOPIC)
<< "skipping invalid arangosearch analyzer persisted configuration "
"entry: "
<< slice.toJson();
return true; // not a valid configuration, skip
}
auto key = getStringRef(slice.get(arangodb::StaticStrings::KeyString));
auto name = getStringRef(slice.get("name"));
auto type = getStringRef(slice.get("type"));
irs::string_ref properties;
auto propertiesSlice = slice.get("properties");
std::string tmpString;
// encode jSON array/object as a string for analyzers that support jSON
if (propertiesSlice.isArray() || propertiesSlice.isObject()) {
tmpString = propertiesSlice.toJson(); // format as a jSON encoded string
properties = tmpString;
} else {
properties = getStringRef(propertiesSlice);
}
auto normalizedName = // normalized name
collection->vocbase().name() + "::" + std::string(name);
auto& staticAnalyzersMap = getStaticAnalyzers();
if (staticAnalyzersMap.find(irs::make_hashed_ref(name, std::hash<irs::string_ref>())) == staticAnalyzersMap.end()) {
name = normalizedName; // use normalized name if it's not a static analyzer
}
auto entry = emplace(name, type, properties,
false); // do not persist since this config is already
// coming from the persisted store
auto& pool = entry.first;
if (!pool) {
LOG_TOPIC("91db1", WARN, arangodb::iresearch::TOPIC)
<< "failure creating an arangosearch analyzer instance for name '"
<< name << "' type '" << type << "' properties '" << properties << "'";
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_BAD_PARAMETER,
std::string(
"failure creating an arangosearch analyzer instance for name '") +
std::string(name) + "' type '" + std::string(type) +
"' properties '" + std::string(properties) + "'");
}
if (!entry.second && initialized.find(name) != initialized.end()) {
LOG_TOPIC("1eb5e", WARN, arangodb::iresearch::TOPIC)
<< "name collision detected while registering an arangosearch "
"analizer name '"
<< name << "' type '" << type << "' properties '" << properties
<< "', previous registration type '" << pool->_type
<< "' properties '" << pool->_properties << "'";
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_BAD_PARAMETER,
std::string("name collision detected while registering an "
"arangosearch analizer name '") +
std::string(name) + "' type '" + std::string(type) +
"' properties '" + std::string(properties) +
"', previous registration type '" + std::string(pool->_type) +
"' properties '" + std::string(pool->_properties) + "'");
}
static auto& staticAnalyzers = getStaticAnalyzers();
if (!entry.second &&
staticAnalyzers.find(irs::make_hashed_ref(name, std::hash<irs::string_ref>())) !=
staticAnalyzers.end()) {
if (type != pool->_type || properties != pool->_properties) {
LOG_TOPIC("d3a5e", WARN, arangodb::iresearch::TOPIC)
<< "name collision with a static analyzer detected while "
"registering an arangosearch analizer name '"
<< name << "' type '" << type << "' properties '" << properties
<< "', previous registration type '" << pool->_type
<< "' properties '" << pool->_properties << "'";
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL,
std::string("name collision with a static analyzer detected while "
"registering an arangosearch analizer name '") +
std::string(name) + "' type '" + std::string(type) +
"' properties '" + std::string(properties) +
"', previous registration type '" + std::string(pool->_type) +
"' properties '" + std::string(pool->_properties) + "'");
}
LOG_TOPIC("a0a10", WARN, arangodb::iresearch::TOPIC)
<< "name collision with a static analyzer detected while registering "
"an arangosearch analizer name '"
<< name << "' type '" << type << "' properties '" << properties << "'";
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL,
std::string("name collision with a static analyzer detected while "
"registering an arangosearch analizer name '") +
std::string(name) + "' type '" + std::string(type) +
"' properties '" + std::string(properties) + "'");
} else if (!pool->init(type, properties)) {
LOG_TOPIC("6fac5", WARN, arangodb::iresearch::TOPIC)
<< "failure initializing an arangosearch analyzer instance for name '"
<< name << "' type '" << type << "' properties '" << properties << "'";
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_BAD_PARAMETER,
std::string("failure initializing an arangosearch analyzer instance "
"for name '") +
std::string(name) + "' type '" + std::string(type) +
"' properties '" + std::string(properties) + "'");
}
initialized.emplace(std::piecewise_construct,
std::forward_as_tuple(pool->name()), // emplace with ref at string in pool
std::forward_as_tuple(pool));
pool->setKey(key);
return true; // process next
};
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex); // the cache could return the same pool asynchronously
// before '_key' updated/rolled back below
bool revert = true;
auto cleanup = irs::make_finally([&revert, &initialized]() -> void {
if (revert) {
for (auto& entry : initialized) {
auto& pool = entry.second;
// reset pool configuration back to uninitialized
// safe to reset since loadConfiguration(...) is called from start()
// which is single-thread
if (pool) {
pool->_config.clear(); // noexcept
pool->_key = irs::string_ref::NIL; // noexcept
pool->_type = irs::string_ref::NIL; // noexcept
pool->_properties = irs::string_ref::NIL; // noexcept
}
}
}
});
try {
collection->invokeOnAllElements(&trx, visitor);
// ensure all records were initialized
for (auto& entry : _customAnalyzers) {
if (initialized.find(entry.first) == initialized.end()) {
LOG_TOPIC("38291", WARN, arangodb::iresearch::TOPIC)
<< "uninitialized AnalyzerPool deletected while validating "
"analyzers, arangosearch analyzer name '"
<< entry.first << "'";
return false; // found an uninitialized analyzer
}
}
if (!trx.commit().ok()) {
LOG_TOPIC("7a050", WARN, arangodb::iresearch::TOPIC)
<< "failure to commit transaction while loading AnalyzerFeature "
"configuration";
return false;
}
revert = false;
return true;
} catch (arangodb::basics::Exception& e) {
LOG_TOPIC("40979", WARN, arangodb::iresearch::TOPIC)
<< "caught exception while loading configuration: " << e.code() << " "
<< e.what();
IR_LOG_EXCEPTION();
} catch (std::exception& e) {
LOG_TOPIC("36c78", WARN, arangodb::iresearch::TOPIC)
<< "caught exception while loading configuration: " << e.what();
IR_LOG_EXCEPTION();
} catch (...) {
LOG_TOPIC("47651", WARN, arangodb::iresearch::TOPIC)
<< "caught exception while loading configuration";
IR_LOG_EXCEPTION();
}
return false;
}
/*static*/ std::string const& IResearchAnalyzerFeature::name() noexcept { /*static*/ std::string const& IResearchAnalyzerFeature::name() noexcept {
return FEATURE_NAME; return FEATURE_NAME;
} }
@ -1957,7 +1702,7 @@ arangodb::Result IResearchAnalyzerFeature::remove( // remove analyzer
if (!force && pool.use_count() > 1) { // +1 for ref in '_analyzers' if (!force && pool.use_count() > 1) { // +1 for ref in '_analyzers'
return arangodb::Result( // result return arangodb::Result( // result
TRI_ERROR_FORBIDDEN, // code TRI_ERROR_ARANGO_CONFLICT, // code
std::string("analyzer in-use while removing arangosearch analyzer '") + std::string(name)+ "'" std::string("analyzer in-use while removing arangosearch analyzer '") + std::string(name)+ "'"
); );
} }
@ -2008,7 +1753,7 @@ arangodb::Result IResearchAnalyzerFeature::remove( // remove analyzer
if (!vocbase) { if (!vocbase) {
return arangodb::Result( // result return arangodb::Result( // result
TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND, // code TRI_ERROR_ARANGO_DATABASE_NOT_FOUND, // code
std::string("failure to find vocbase while removing arangosearch analyzer '") + std::string(name)+ "'" std::string("failure to find vocbase while removing arangosearch analyzer '") + std::string(name)+ "'"
); );
} }
@ -2309,7 +2054,7 @@ arangodb::Result IResearchAnalyzerFeature::storeAnalyzer(AnalyzerPool& pool) {
} }
bool IResearchAnalyzerFeature::visit( // visit analyzers bool IResearchAnalyzerFeature::visit( // visit analyzers
VisitorType const& visitor, // visitor std::function<bool(AnalyzerPool::ptr const& analyzer)> const& visitor, // visitor
TRI_vocbase_t const* vocbase /*= nullptr*/ // analyzers for vocbase TRI_vocbase_t const* vocbase /*= nullptr*/ // analyzers for vocbase
) const { ) const {
if (vocbase) { // do not trigger load for all-databases requests if (vocbase) { // do not trigger load for all-databases requests
@ -2337,7 +2082,7 @@ bool IResearchAnalyzerFeature::visit( // visit analyzers
for (auto& entry: analyzers) { for (auto& entry: analyzers) {
if (entry.second // have entry if (entry.second // have entry
&& (!vocbase || splitAnalyzerName(entry.first).first == vocbase->name()) // requested vocbase && (!vocbase || splitAnalyzerName(entry.first).first == vocbase->name()) // requested vocbase
&& !visitor(entry.first, entry.second->_type, entry.second->_properties, entry.second->features()) // termination request && !visitor(entry.second) // termination request
) { ) {
return false; return false;
} }
@ -2351,4 +2096,4 @@ bool IResearchAnalyzerFeature::visit( // visit analyzers
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -108,12 +108,6 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
arangodb::auth::Level const& level // access level arangodb::auth::Level const& level // access level
); );
// FIXME TODO remove
std::pair<AnalyzerPool::ptr, bool> emplace(
irs::string_ref const& name, irs::string_ref const& type,
irs::string_ref const& properties,
irs::flags const& features = irs::flags::empty_instance()) noexcept;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief emplace an analyzer as per the specified parameters /// @brief emplace an analyzer as per the specified parameters
/// @param result the result of the successful emplacement (out-param) /// @param result the result of the successful emplacement (out-param)
@ -203,9 +197,8 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
/// @param vocbase only visit analysers for this vocbase (nullptr == all) /// @param vocbase only visit analysers for this vocbase (nullptr == all)
/// @return visitation compleated fully /// @return visitation compleated fully
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
typedef std::function<bool(irs::string_ref const& analyzer, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)> VisitorType;
bool visit( // visit analyzers bool visit( // visit analyzers
VisitorType const& visitor, // visitor std::function<bool(AnalyzerPool::ptr const& analyzer)> const& visitor, // visitor
TRI_vocbase_t const* vocbase = nullptr // analyzers for vocbase TRI_vocbase_t const* vocbase = nullptr // analyzers for vocbase
) const; ) const;
@ -281,8 +274,6 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
irs::string_ref const& database = irs::string_ref::NIL // database to load irs::string_ref const& database = irs::string_ref::NIL // database to load
); );
bool loadConfiguration();
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief store the definition for the speicifed pool in the corresponding /// @brief store the definition for the speicifed pool in the corresponding
/// vocbase /// vocbase

View File

@ -177,11 +177,6 @@ class IResearchView final: public arangodb::LogicalView {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
bool visitCollections(CollectionVisitor const& visitor) const override; bool visitCollections(CollectionVisitor const& visitor) const override;
//////////////////////////////////////////////////////////////////////////////
/// @brief persist data store states for all known links to permanent storage
//////////////////////////////////////////////////////////////////////////////
arangodb::Result commit();
protected: protected:
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -224,6 +219,11 @@ class IResearchView final: public arangodb::LogicalView {
IResearchViewMeta&& meta // view meta IResearchViewMeta&& meta // view meta
); );
//////////////////////////////////////////////////////////////////////////////
/// @brief persist data store states for all known links to permanent storage
//////////////////////////////////////////////////////////////////////////////
arangodb::Result commit();
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief called when a view's properties are updated (i.e. delta-modified) /// @brief called when a view's properties are updated (i.e. delta-modified)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -241,4 +241,4 @@ class IResearchView final: public arangodb::LogicalView {
} // iresearch } // iresearch
} // arangodb } // arangodb
#endif #endif

View File

@ -0,0 +1,504 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2019 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
#include "RestAnalyzerHandler.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "IResearch/IResearchAnalyzerFeature.h"
#include "IResearch/VelocyPackHelper.h"
#include "RestServer/SystemDatabaseFeature.h"
#include "utils/string.hpp"
#include "velocypack/Iterator.h"
namespace {
std::string ANALYZER_FEAURES_FIELD("features");
std::string ANALYZER_NAME_FIELD("name");
std::string ANALYZER_PROPERTIES_FIELD("properties");
std::string ANALYZER_TYPE_FIELD("type");
}
namespace arangodb {
namespace iresearch {
RestAnalyzerHandler::RestAnalyzerHandler( // constructor
arangodb::GeneralRequest* request, // request
arangodb::GeneralResponse* response // response
): RestVocbaseBaseHandler(request, response) {
}
void RestAnalyzerHandler::createAnalyzer( // create
IResearchAnalyzerFeature& analyzers, // analyzer feature
TRI_vocbase_t const* sysVocbase // system vocbase
) {
TRI_ASSERT(_request); // ensured by execute()
if (_request->payload().isEmptyObject()) {
generateError( // generate error
arangodb::rest::ResponseCode::BAD, TRI_ERROR_HTTP_CORRUPTED_JSON // args
);
return;
}
bool success = false;
auto body = parseVPackBody(success);
if (!success) {
return; // parseVPackBody(...) calls generateError(...)
}
if (!body.isObject()) {
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
"expecting body to be of the form { name: <string>, type: <string>[, properties: <object|string>[, features: <string-array>]] }"
));
return;
}
irs::string_ref name;
std::string nameBuf;
auto nameSlice = body.get(ANALYZER_NAME_FIELD);
if (nameSlice.isString()) {
name = getStringRef(nameSlice);
} else if (!nameSlice.isNull()) {
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
"invalid 'name', expecting body to be of the form { name: <string>, type: <string>[, properties: <object|string>[, features: <string-array>]] }"
));
return;
}
if (sysVocbase) {
nameBuf = IResearchAnalyzerFeature::normalize(name, _vocbase, *sysVocbase); // normalize
name = nameBuf;
};
irs::string_ref type;
auto typeSlice = body.get(ANALYZER_TYPE_FIELD);
if (typeSlice.isString()) {
type = getStringRef(typeSlice);
} else if (!typeSlice.isNull()) {
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
"invalid 'type', expecting body to be of the form { name: <string>, type: <string>[, properties: <object|string>[, features: <string-array>]] }"
));
return;
}
irs::string_ref properties;
std::string propertiesBuf;
if (body.hasKey(ANALYZER_PROPERTIES_FIELD)) { // optional parameter
auto propertiesSlice = body.get(ANALYZER_PROPERTIES_FIELD);
if (propertiesSlice.isObject()) {
propertiesBuf = propertiesSlice.toString();
properties = propertiesBuf;
} else if (propertiesSlice.isString()) {
properties = getStringRef(propertiesSlice);
} else if (!propertiesSlice.isNull()) {
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
"invalid 'properties', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
));
return;
}
}
irs::flags features;
if (body.hasKey(ANALYZER_FEAURES_FIELD)) { // optional parameter
auto featuresSlice = body.get(ANALYZER_FEAURES_FIELD);
if (featuresSlice.isArray()) {
for (arangodb::velocypack::ArrayIterator itr(featuresSlice);
itr.valid();
++itr
) {
auto value = *itr;
if (!value.isString()) {
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
"invalid value in 'features', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
));
return;
}
auto* feature = irs::attribute::type_id::get(getStringRef(value));
if (!feature) {
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
"unknown value in 'features', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
));
return;
}
features.add(*feature);
}
} else {
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
"invalid 'features', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
));
return;
}
}
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!IResearchAnalyzerFeature::canUse(name, auth::Level::RW)) {
generateError( // generate error
arangodb::rest::ResponseCode::FORBIDDEN, // HTTP code
TRI_ERROR_FORBIDDEN, // code
std::string("insufficient rights while creating analyzer: ") + body.toString() // message
);
return;
}
IResearchAnalyzerFeature::EmplaceResult result;
auto res = analyzers.emplace(result, name, type, properties, features);
if (!res.ok()) {
generateError(res);
return;
}
if (!result.first) {
generateError( // generate error
arangodb::rest::ResponseCode::BAD, // HTTP code
TRI_errno(), // code
std::string("failure while creating analyzer: ") + body.toString() // message
);
return;
}
auto pool = result.first;
arangodb::velocypack::Builder builder;
builder.openObject();
addStringRef(builder, ANALYZER_NAME_FIELD, pool->name());
addStringRef(builder, ANALYZER_TYPE_FIELD, pool->type());
addStringRef(builder, ANALYZER_PROPERTIES_FIELD, pool->properties());
builder.add( // add features
ANALYZER_FEAURES_FIELD, // key
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Array) // value
);
for (auto& feature: pool->features()) {
TRI_ASSERT(feature); // has to be non-nullptr
addStringRef(builder, feature->name());
}
builder.close();
builder.close();
generateResult( // generate result
result.second // new analyzer v.s. existing analyzer
? arangodb::rest::ResponseCode::CREATED : arangodb::rest::ResponseCode::OK,
builder.slice() // analyzer definition
);
}
arangodb::RestStatus RestAnalyzerHandler::execute() {
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
IResearchAnalyzerFeature // feature type
>();
if (!analyzers) {
generateError( // generate error
arangodb::rest::ResponseCode::BAD, // HTTP code
TRI_ERROR_INTERNAL, // code
std::string("failure to find feature '") + IResearchAnalyzerFeature::name() + "' while executing REST request for: " + ANALYZER_PATH
);
return arangodb::RestStatus::DONE;
}
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::SystemDatabaseFeature // featue type
>();
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
if (!_request) {
generateError( // generate error
arangodb::rest::ResponseCode::METHOD_NOT_ALLOWED, // HTTP code
TRI_ERROR_HTTP_BAD_PARAMETER // error code
);
return arangodb::RestStatus::DONE;
}
auto& suffixes = _request->suffixes();
switch (_request->requestType()) {
case arangodb::rest::RequestType::DELETE_REQ:
if (suffixes.size() == 1) {
if (!sysVocbase) {
removeAnalyzer(*analyzers, suffixes[0]); // verbatim (assume already normalized)
return arangodb::RestStatus::DONE;
}
removeAnalyzer( // remove
*analyzers, // feature
IResearchAnalyzerFeature::normalize(suffixes[0], _vocbase, *sysVocbase) // normalize
);
return arangodb::RestStatus::DONE;
}
generateError( // generate error
arangodb::rest::ResponseCode::BAD, // HTTP code
TRI_ERROR_BAD_PARAMETER, // code
std::string("expecting DELETE ") + ANALYZER_PATH + "/<analyzer-name>[#force=true]" // mesage
);
return arangodb::RestStatus::DONE;
case arangodb::rest::RequestType::GET:
if (suffixes.empty()) {
getAnalyzers(*analyzers);
return arangodb::RestStatus::DONE;
}
if (suffixes.size() == 1) {
if (!sysVocbase) {
getAnalyzer(*analyzers, suffixes[0]);
return arangodb::RestStatus::DONE;
}
getAnalyzer( // get
*analyzers, // feature
IResearchAnalyzerFeature::normalize(suffixes[0], _vocbase, *sysVocbase) // normalize
);
return arangodb::RestStatus::DONE;
}
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
std::string("expecting GET ") + ANALYZER_PATH + "[/<analyzer-name>]" // mesage
));
return arangodb::RestStatus::DONE;
case arangodb::rest::RequestType::POST:
if (suffixes.empty()) {
createAnalyzer(*analyzers, sysVocbase.get());
return arangodb::RestStatus::DONE;
}
generateError(arangodb::Result( // generate error
TRI_ERROR_BAD_PARAMETER, // code
std::string("expecting POST ") + ANALYZER_PATH // mesage
));
return arangodb::RestStatus::DONE;
default:
generateError(arangodb::Result( // generate error
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED // error code
));
}
return arangodb::RestStatus::DONE;
}
void RestAnalyzerHandler::getAnalyzer( // get analyzer
IResearchAnalyzerFeature& analyzers, // analyzer feature
std::string const& name // analyzer name (normalized)
) {
TRI_ASSERT(_request); // ensured by execute()
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!IResearchAnalyzerFeature::canUse(name, auth::Level::RO)) {
generateError(arangodb::Result( // generate error
TRI_ERROR_FORBIDDEN, // code
std::string("insufficient rights while getting analyzer: ") + name // message
));
return;
}
auto pool = analyzers.get(name);
if (!pool) {
generateError(arangodb::Result( // generate error
TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND, // code
std::string("unable to find analyzer: ") + name // mesage
));
return;
}
arangodb::velocypack::Builder builder;
builder.openObject();
addStringRef(builder, ANALYZER_NAME_FIELD, pool->name());
addStringRef(builder, ANALYZER_TYPE_FIELD, pool->type());
addStringRef(builder, ANALYZER_PROPERTIES_FIELD, pool->properties());
builder.add( // add features
ANALYZER_FEAURES_FIELD, // key
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Array) // value
);
for (auto& feature: pool->features()) {
TRI_ASSERT(feature); // has to be non-nullptr
addStringRef(builder, feature->name());
}
builder.close();
builder.close();
// generate result + 'error' field + 'code' field
// 2nd param must be Builder and not Slice
generateOk(arangodb::rest::ResponseCode::OK, builder);
}
void RestAnalyzerHandler::getAnalyzers( // get all analyzers
IResearchAnalyzerFeature& analyzers // analyzer feature
) {
// ...........................................................................
// end of parameter parsing
// ...........................................................................
typedef arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr AnalyzerPoolPtr;
arangodb::velocypack::Builder builder;
auto visitor = [&builder](AnalyzerPoolPtr const& analyzer)->bool {
if (!analyzer) {
return true; // continue with next analyzer
}
builder.openObject();
addStringRef(builder, ANALYZER_NAME_FIELD, analyzer->name());
addStringRef(builder, ANALYZER_TYPE_FIELD, analyzer->type());
addStringRef(builder, ANALYZER_PROPERTIES_FIELD, analyzer->properties());
builder.add( // add features
ANALYZER_FEAURES_FIELD, // key
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Array) // value
);
for (auto& feature: analyzer->features()) {
TRI_ASSERT(feature); // has to be non-nullptr
addStringRef(builder, feature->name());
}
builder.close();
builder.close();
return true; // continue with next analyzer
};
builder.openArray();
if (IResearchAnalyzerFeature::canUse(_vocbase, auth::Level::RO)) {
analyzers.visit(visitor, &_vocbase);
}
auto* sysDBFeature = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::SystemDatabaseFeature // feature type
>();
// include analyzers from the system vocbase if possible
if (sysDBFeature) {
auto sysVocbase = sysDBFeature->use();
if (sysVocbase // have system vocbase
&& sysVocbase->name() != _vocbase.name() // not same vocbase as current
&& IResearchAnalyzerFeature::canUse(*sysVocbase, auth::Level::RO)) {
analyzers.visit(visitor, sysVocbase.get());
}
}
builder.close();
// generate result (wrapped inside 'result') + 'error' field + 'code' field
// 2nd param must be Slice and not Builder
generateOk(arangodb::rest::ResponseCode::OK, builder.slice());
}
void RestAnalyzerHandler::removeAnalyzer( // remove
IResearchAnalyzerFeature& analyzers, // analyzer feature
std::string const& name // analyzer name (normalized)
) {
TRI_ASSERT(_request); // ensured by execute()
auto force = _request->parsedValue("force", false);
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!IResearchAnalyzerFeature::canUse(name, auth::Level::RW)) {
generateError(arangodb::Result( // generate error
TRI_ERROR_FORBIDDEN, // code
std::string("insufficient rights while removing analyzer: ") + name // message
));
return;
}
auto res = analyzers.remove(name, force);
if (!res.ok()) {
generateError(res);
return;
}
arangodb::velocypack::Builder builder;
builder.openObject();
builder.add(ANALYZER_NAME_FIELD, arangodb::velocypack::Value(name));
builder.close();
// generate result + 'error' field + 'code' field
// 2nd param must be Builder and not Slice
generateOk(arangodb::rest::ResponseCode::OK, builder);
}
} // iresearch
} // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -0,0 +1,70 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2019 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_REST_HANDLER_REST_ANALYZER_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_ANALYZER_HANDLER_H 1
#include "RestHandler/RestVocbaseBaseHandler.h"
namespace arangodb {
namespace iresearch {
class IResearchAnalyzerFeature; // forward declaration
class RestAnalyzerHandler final: public RestVocbaseBaseHandler {
public:
// @note RestHandlerFactory::createHandler(...) passes raw pointers for
// request/response to RestHandlerCreator::createNoData(...)
RestAnalyzerHandler( // constructor
arangodb::GeneralRequest* request, // request
arangodb::GeneralResponse* response // response
);
virtual arangodb::RestStatus execute() override;
virtual arangodb::RequestLane lane() const override {
return arangodb::RequestLane::CLIENT_SLOW;
}
virtual char const* name() const override { return "RestAnalyzerHandler"; }
private:
void createAnalyzer(
IResearchAnalyzerFeature& analyzers, // analyzer feature
TRI_vocbase_t const* sysVocbase // system vocbase
);
void getAnalyzer(
IResearchAnalyzerFeature& analyzers, // analyzer feature
std::string const& name // analyzer name (normalized)
);
void getAnalyzers(IResearchAnalyzerFeature& analyzers);
void removeAnalyzer(
IResearchAnalyzerFeature& analyzers, // analyzer feature
std::string const& name // analyzer name (normalized)
);
};
} // iresearch
} // arangodb
#endif

View File

@ -0,0 +1,705 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2019 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
#include "v8-analyzers.h"
#include "Basics/StringUtils.h"
#include "IResearch/IResearchAnalyzerFeature.h"
#include "IResearch/VelocyPackHelper.h"
#include "RestServer/SystemDatabaseFeature.h"
#include "Transaction/V8Context.h"
#include "V8/v8-conv.h"
#include "V8/v8-globals.h"
#include "V8/v8-vpack.h"
#include "V8Server/v8-externals.h"
#include "V8Server/v8-vocbaseprivate.h"
#include "VocBase/vocbase.h"
#include "velocypack/Parser.h"
namespace {
////////////////////////////////////////////////////////////////////////////////
/// @brief unwraps an analyser wrapped via WrapAnalyzer(...)
/// @return collection or nullptr on failure
////////////////////////////////////////////////////////////////////////////////
arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool* UnwrapAnalyzer( // unwrap
v8::Isolate* isolate, // isolate
v8::Local<v8::Object> const& holder // holder
) {
return TRI_UnwrapClass<arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool>( // unwrap class
holder, WRP_IRESEARCH_ANALYZER_TYPE, TRI_IGETC // args
);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief wraps an Analyzer
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Object> WrapAnalyzer( // wrap analyzer
v8::Isolate* isolate, // isolate
arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer // analyzer
) {
v8::EscapableHandleScope scope(isolate);
TRI_GET_GLOBALS();
TRI_GET_GLOBAL(IResearchAnalyzerTempl, v8::ObjectTemplate);
auto result = IResearchAnalyzerTempl->NewInstance();
if (result.IsEmpty()) {
return scope.Escape<v8::Object>(result);
}
auto itr = TRI_v8_global_t::SharedPtrPersistent::emplace(*isolate, analyzer);
auto& entry = itr.first;
result->SetInternalField( // required for TRI_UnwrapClass(...)
SLOT_CLASS_TYPE, v8::Integer::New(isolate, WRP_IRESEARCH_ANALYZER_TYPE) // args
);
result->SetInternalField(SLOT_CLASS, entry.get());
return scope.Escape<v8::Object>(result);
}
void JS_AnalyzerFeatures(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto* analyzer = UnwrapAnalyzer(isolate, args.Holder());
if (!analyzer) {
TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract analyzer");
}
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(analyzer->name(), arangodb::auth::Level::RO)) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_FORBIDDEN, // code
"insufficient rights to get analyzer" // message
);
}
try {
auto i = 0;
auto result = v8::Array::New(isolate);
for (auto& feature: analyzer->features()) {
if (feature) { // valid
if (feature->name().null()) {
result->Set(i++, v8::Null(isolate));
} else {
result->Set( // set value
i++, TRI_V8_STD_STRING(isolate, std::string(feature->name())) // args
);
}
}
}
TRI_V8_RETURN(result);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"cannot access analyzer features" // message
);
}
TRI_V8_TRY_CATCH_END
}
void JS_AnalyzerName(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto* analyzer = UnwrapAnalyzer(isolate, args.Holder());
if (!analyzer) {
TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract analyzer");
}
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(analyzer->name(), arangodb::auth::Level::RO)) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_FORBIDDEN, // code
"insufficient rights to get analyzer" // message
);
}
try {
auto result = TRI_V8_STD_STRING(isolate, analyzer->name());
TRI_V8_RETURN(result);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"cannot access analyzer name" // message
);
}
TRI_V8_TRY_CATCH_END
}
void JS_AnalyzerProperties(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto* analyzer = UnwrapAnalyzer(isolate, args.Holder());
if (!analyzer) {
TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract analyzer");
}
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(analyzer->name(), arangodb::auth::Level::RO)) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_FORBIDDEN, // code
"insufficient rights to get analyzer" // message
);
}
try {
if (analyzer->properties().null()) {
TRI_V8_RETURN(v8::Null(isolate));
}
auto result = // result
TRI_V8_STD_STRING(isolate, std::string(analyzer->properties()));
TRI_V8_RETURN(result);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"cannot access analyzer properties" // message
);
}
TRI_V8_TRY_CATCH_END
}
void JS_AnalyzerType(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto* analyzer = UnwrapAnalyzer(isolate, args.Holder());
if (!analyzer) {
TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract analyzer");
}
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(analyzer->name(), arangodb::auth::Level::RO)) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_FORBIDDEN, // code
"insufficient rights to get analyzer" // message
);
}
try {
if (analyzer->type().null()) {
TRI_V8_RETURN(v8::Null(isolate));
}
auto result = TRI_V8_STD_STRING(isolate, std::string(analyzer->type()));
TRI_V8_RETURN(result);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"cannot access analyzer type" // message
);
}
TRI_V8_TRY_CATCH_END
}
void JS_Create(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto& vocbase = GetContextVocBase(isolate);
if (vocbase.isDangling()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
// we require at least 2 but no more than 4 arguments
// save(name: <string>, type: <string>[, parameters: <json>[, features: <string-array>]]);
if (args.Length() < 2 // too few args
|| args.Length() > 4 // too many args
|| !args[0]->IsString() // not a string
|| !args[1]->IsString() // not a string
) {
TRI_V8_THROW_EXCEPTION_USAGE("save(<name>, <type>[, <properties>[, <features>]])");
}
PREVENT_EMBEDDED_TRANSACTION();
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::iresearch::IResearchAnalyzerFeature // feature type
>();
if (!analyzers) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
std::string("failure to find feature '") + arangodb::iresearch::IResearchAnalyzerFeature::name() + "'" // message
);
}
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::SystemDatabaseFeature // featue type
>();
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
auto name = TRI_ObjectToString(isolate, args[0]);
std::string nameBuf;
if (sysVocbase) {
nameBuf = arangodb::iresearch::IResearchAnalyzerFeature::normalize( // normalize
name, vocbase, *sysVocbase // args
);
name = nameBuf;
};
auto type = TRI_ObjectToString(isolate, args[1]);
irs::string_ref properties;
std::string propertiesBuf;
if (args.Length() > 2) { // have properties
if (args[2]->IsString()) {
propertiesBuf = TRI_ObjectToString(isolate, args[2]);
properties = propertiesBuf;
} else if (args[2]->IsObject()) {
auto value = // value
args[2]->ToObject(TRI_IGETC).FromMaybe(v8::Local<v8::Object>());
arangodb::velocypack::Builder builder;
auto res = TRI_V8ToVPack(isolate, builder, value, false);
if (TRI_ERROR_NO_ERROR != res) {
TRI_V8_THROW_EXCEPTION(res);
}
propertiesBuf = builder.toString();
properties = propertiesBuf;
} else if (!args[2]->IsNull()) {
TRI_V8_THROW_TYPE_ERROR("<properties> must be an object");
}
}
irs::flags features;
if (args.Length() > 3) { // have features
if (!args[3]->IsArray()) {
TRI_V8_THROW_TYPE_ERROR("<features> must be an array");
}
auto value = v8::Local<v8::Array>::Cast(args[3]);
for (uint32_t i = 0, count = value->Length(); i < count; ++i) {
auto subValue = value->Get(i);
if (!subValue->IsString()) {
TRI_V8_THROW_TYPE_ERROR("<feature> must be a string");
}
auto* feature = // feature
irs::attribute::type_id::get(TRI_ObjectToString(isolate, subValue));
if (!feature) {
TRI_V8_THROW_TYPE_ERROR("<feature> not supported");
}
features.add(*feature);
}
}
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(name, arangodb::auth::Level::RW)) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_FORBIDDEN, // code
"insufficient rights to create analyzer" // message
);
}
try {
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
auto res = analyzers->emplace(result, name, type, properties, features);
if (!res.ok()) {
TRI_V8_THROW_EXCEPTION(res);
}
if (!result.first) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"problem creating view" // message
);
}
auto v8Result = WrapAnalyzer(isolate, result.first);
if (v8Result.IsEmpty()) {
TRI_V8_THROW_EXCEPTION_MEMORY();
}
TRI_V8_RETURN(v8Result);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"cannot create analyzer" // message
);
}
TRI_V8_TRY_CATCH_END
}
void JS_Get(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto& vocbase = GetContextVocBase(isolate);
if (vocbase.isDropped()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
// expecting one argument
// analyzer(name: <string>);
if (args.Length() != 1 || !args[0]->IsString()) {
TRI_V8_THROW_EXCEPTION_USAGE("analyser(<name>)");
}
PREVENT_EMBEDDED_TRANSACTION();
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::iresearch::IResearchAnalyzerFeature // feature type
>();
if (!analyzers) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
std::string("failure to find feature '") + arangodb::iresearch::IResearchAnalyzerFeature::name() + "'" // message
);
}
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::SystemDatabaseFeature // featue type
>();
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
auto name = TRI_ObjectToString(isolate, args[0]);
std::string nameBuf;
if (sysVocbase) {
nameBuf = arangodb::iresearch::IResearchAnalyzerFeature::normalize( // normalize
name, vocbase, *sysVocbase // args
);
name = nameBuf;
};
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(name, arangodb::auth::Level::RO)) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_FORBIDDEN, // code
"insufficient rights to get analyzer" // message
);
}
try {
auto analyzer = analyzers->get(name);
if (!analyzer) {
TRI_V8_RETURN_NULL();
}
auto result = WrapAnalyzer(isolate, analyzer);
if (result.IsEmpty()) {
TRI_V8_THROW_EXCEPTION_MEMORY();
}
TRI_V8_RETURN(result);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot get analyzer");
}
TRI_V8_TRY_CATCH_END
}
void JS_List(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto& vocbase = GetContextVocBase(isolate);
if (vocbase.isDropped()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::iresearch::IResearchAnalyzerFeature // feature type
>();
if (!analyzers) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
std::string("failure to find feature '") + arangodb::iresearch::IResearchAnalyzerFeature::name() + "'" // message
);
}
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::SystemDatabaseFeature // featue type
>();
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
// ...........................................................................
// end of parameter parsing
// ...........................................................................
typedef arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr AnalyzerPoolPtr;
static const auto nameLess = []( // analyzer name less
AnalyzerPoolPtr const& lhs, // left hand side
AnalyzerPoolPtr const& rhs // right hand side
)->bool {
return arangodb::basics::StringUtils::tolower(lhs->name()) < arangodb::basics::StringUtils::tolower(rhs->name());
};
std::vector<AnalyzerPoolPtr> result;
auto visitor = [&result](AnalyzerPoolPtr const& analyzer)->bool {
if (analyzer) {
result.emplace_back(analyzer);
}
return true; // continue with next analyzer
};
try {
if (arangodb::iresearch::IResearchAnalyzerFeature::canUse(vocbase, arangodb::auth::Level::RO)) {
analyzers->visit(visitor, &vocbase);
}
// include analyzers from the system vocbase if possible
if (sysVocbase // have system vocbase
&& sysVocbase->name() != vocbase.name() // not same vocbase as current
&& arangodb::iresearch::IResearchAnalyzerFeature::canUse(*sysVocbase, arangodb::auth::Level::RO)) {
analyzers->visit(visitor, sysVocbase.get());
}
std::sort(result.begin(), result.end(), nameLess);
auto v8Result = v8::Array::New(isolate);
for (size_t i = 0, count = result.size(); i < count; ++i) {
auto analyzer = WrapAnalyzer(isolate, result[i]);
if (analyzer.IsEmpty()) {
TRI_V8_THROW_EXCEPTION_MEMORY();
}
v8Result->Set(i, analyzer);
}
TRI_V8_RETURN(v8Result);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot list analyzers");
}
TRI_V8_TRY_CATCH_END
}
void JS_Remove(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto& vocbase = GetContextVocBase(isolate);
if (vocbase.isDangling()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
// we require 1 string argument and an optional boolean argument
// remove(name: <string>[, force: <bool>])
if (args.Length() < 1 // too few args
|| args.Length() > 2 // too many args
|| !args[0]->IsString() // not a string
) {
TRI_V8_THROW_EXCEPTION_USAGE("remove(<name> [, <force>])");
}
PREVENT_EMBEDDED_TRANSACTION();
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::iresearch::IResearchAnalyzerFeature // feature type
>();
if (!analyzers) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
std::string("failure to find feature '") + arangodb::iresearch::IResearchAnalyzerFeature::name() + "'" // message
);
}
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::SystemDatabaseFeature // featue type
>();
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
auto name = TRI_ObjectToString(isolate, args[0]);
std::string nameBuf;
if (sysVocbase) {
nameBuf = arangodb::iresearch::IResearchAnalyzerFeature::normalize( // normalize
name, vocbase, *sysVocbase // args
);
name = nameBuf;
};
bool force = false;
if (args.Length() > 1) {
if (!args[1]->IsBoolean() && !args[1]->IsBooleanObject()) {
TRI_V8_THROW_TYPE_ERROR("<force> must be a boolean");
}
force = TRI_ObjectToBoolean(isolate, args[1]);
}
// ...........................................................................
// end of parameter parsing
// ...........................................................................
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(name, arangodb::auth::Level::RW)) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_FORBIDDEN, // code
"insufficient rights to remove analyzer" // message
);
}
try {
auto res = analyzers->remove(name, force);
if (!res.ok()) {
TRI_V8_THROW_EXCEPTION(res);
}
TRI_V8_RETURN_UNDEFINED();
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), ex.what());
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"cannot remove analyzer" // message
);
}
TRI_V8_TRY_CATCH_END
}
}
namespace arangodb {
namespace iresearch {
void TRI_InitV8Analyzers(
v8::Handle<v8::Context> context, // v8 context
TRI_vocbase_t& vocbase, // vocbase
TRI_v8_global_t& v8g, // v8 globals
v8::Isolate& isolate, // v8 isolate
v8::Handle<v8::ObjectTemplate> ArangoDBNS // v8 handler root
) {
// 'analyzers' feature functions
{
auto fnTemplate = v8::FunctionTemplate::New(&isolate);
fnTemplate->SetClassName(TRI_V8_ASCII_STRING(&isolate, "ArangoAnalyzersCtor"));
auto objTemplate = fnTemplate->InstanceTemplate();
objTemplate->SetInternalFieldCount(0);
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "analyzer"), JS_Get);
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "remove"), JS_Remove);
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "save"), JS_Create);
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "toArray"), JS_List);
v8g.IResearchAnalyzersTempl.Reset(&isolate, objTemplate);
}
// individual analyzer functions
{
auto fnTemplate = v8::FunctionTemplate::New(&isolate);
fnTemplate->SetClassName(TRI_V8_ASCII_STRING(&isolate, "ArangoAnalyzer"));
auto objTemplate = fnTemplate->InstanceTemplate();
objTemplate->SetInternalFieldCount(2); // SLOT_CLASS_TYPE + SLOT_CLASS
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "features"), JS_AnalyzerFeatures);
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "name"), JS_AnalyzerName);
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "properties"), JS_AnalyzerProperties);
TRI_AddMethodVocbase(&isolate, objTemplate, TRI_V8_ASCII_STRING(&isolate, "type"), JS_AnalyzerType);
v8g.IResearchAnalyzerTempl.Reset(&isolate, objTemplate);
TRI_AddGlobalFunctionVocbase(&isolate, TRI_V8_ASCII_STRING(&isolate, "ArangoAnalyzer"), fnTemplate->GetFunction());
}
}
} // iresearch
} // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2019 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_V8_SERVER_V8_ANALYZERS_H
#define ARANGOD_V8_SERVER_V8_ANALYZERS_H 1
#include <v8.h>
struct TRI_v8_global_t; // forward declaration
struct TRI_vocbase_t; // forward declaration
namespace arangodb {
namespace iresearch {
////////////////////////////////////////////////////////////////////////////////
/// @brief add analyzer related handlers to 'ArangoDBNS'
////////////////////////////////////////////////////////////////////////////////
void TRI_InitV8Analyzers(
v8::Handle<v8::Context> context, // v8 context
TRI_vocbase_t& vocbase, // vocbase
TRI_v8_global_t& v8g, // v8 globals
v8::Isolate& isolate, // v8 isolate
v8::Handle<v8::ObjectTemplate> ArangoDBNS // v8 handler root
);
} // iresearch
} // arangodb
#endif

View File

@ -31,7 +31,6 @@
#include "v8-collection.h" #include "v8-collection.h"
using namespace arangodb; using namespace arangodb;
using namespace arangodb::basics;
/// @brief check if a name belongs to a collection /// @brief check if a name belongs to a collection
bool EqualCollection(CollectionNameResolver const* resolver, std::string const& collectionName, bool EqualCollection(CollectionNameResolver const* resolver, std::string const& collectionName,
@ -60,62 +59,6 @@ bool EqualCollection(CollectionNameResolver const* resolver, std::string const&
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief wraps a LogicalCollection
/// Note that if collection is a local collection, then the object will never
/// be freed. If it is not a local collection (coordinator case), then delete
/// will be called when the V8 object is garbage collected.
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Object> WrapCollection(v8::Isolate* isolate,
std::shared_ptr<arangodb::LogicalCollection> const& collection) {
v8::EscapableHandleScope scope(isolate);
TRI_GET_GLOBALS();
TRI_GET_GLOBAL(VocbaseColTempl, v8::ObjectTemplate);
v8::Handle<v8::Object> result = VocbaseColTempl->NewInstance();
if (!result.IsEmpty()) {
auto* ptr = collection.get();
auto itr = v8g->JSDatasources.emplace(
std::piecewise_construct, std::forward_as_tuple(collection.get()),
std::forward_as_tuple(isolate, collection,
[ptr]() -> void { // FIXME TODO find a way to move this callback
// code into DataSourcePersistent
TRI_ASSERT(!ptr->vocbase().isDangling());
ptr->vocbase().release(); // decrease the reference-counter for
// the database
}));
auto& entry = itr.first->second;
if (itr.second) { // FIXME TODO find a way to move this code into
// DataSourcePersistent
TRI_ASSERT(!ptr->vocbase().isDangling());
ptr->vocbase().forceUse(); // increase the reference-counter for the database
}
result->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate, WRP_VOCBASE_COL_TYPE));
result->SetInternalField(SLOT_CLASS, entry.get());
result->SetInternalField(SLOT_EXTERNAL, entry.get());
TRI_GET_GLOBAL_STRING(_IdKey);
TRI_GET_GLOBAL_STRING(_DbNameKey);
TRI_GET_GLOBAL_STRING(VersionKeyHidden);
result
->DefineOwnProperty(TRI_IGETC, _IdKey,
TRI_V8UInt64String<TRI_voc_cid_t>(isolate,
collection->id()),
v8::ReadOnly)
.FromMaybe(true); // Ignoring result
result->Set(_DbNameKey, TRI_V8_STD_STRING(isolate, collection->vocbase().name()));
result
->DefineOwnProperty(TRI_IGETC, VersionKeyHidden,
v8::Integer::NewFromUnsigned(isolate, 5), v8::DontEnum)
.FromMaybe(false); // ignore return value
}
return scope.Escape<v8::Object>(result);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief unwrap a LogicalCollection wrapped via WrapCollection(...) /// @brief unwrap a LogicalCollection wrapped via WrapCollection(...)
/// @return collection or nullptr on failure /// @return collection or nullptr on failure
@ -124,3 +67,59 @@ arangodb::LogicalCollection* UnwrapCollection(v8::Isolate* isolate,
v8::Local<v8::Object> const& holder) { v8::Local<v8::Object> const& holder) {
return TRI_UnwrapClass<arangodb::LogicalCollection>(holder, WRP_VOCBASE_COL_TYPE, TRI_IGETC); return TRI_UnwrapClass<arangodb::LogicalCollection>(holder, WRP_VOCBASE_COL_TYPE, TRI_IGETC);
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief wraps a LogicalCollection
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Object> WrapCollection( // wrap collection
v8::Isolate* isolate, // isolate
std::shared_ptr<arangodb::LogicalCollection> const& collection // collection
) {
v8::EscapableHandleScope scope(isolate);
TRI_GET_GLOBALS();
TRI_GET_GLOBAL(VocbaseColTempl, v8::ObjectTemplate);
v8::Handle<v8::Object> result = VocbaseColTempl->NewInstance();
if (result.IsEmpty()) {
return scope.Escape<v8::Object>(result);
}
auto value = std::shared_ptr<void>( // persistent value
collection.get(), // value
[collection](void*)->void { // ensure collection shared_ptr is not deallocated
TRI_ASSERT(!collection->vocbase().isDangling());
collection->vocbase().release(); // decrease the reference-counter for the database
}
);
auto itr = TRI_v8_global_t::SharedPtrPersistent::emplace(*isolate, value);
auto& entry = itr.first;
TRI_ASSERT(!collection->vocbase().isDangling());
collection->vocbase().forceUse(); // increase the reference-counter for the database (will be decremented by 'value' distructor above, valid for both new and existing mappings)
result->SetInternalField(// required for TRI_UnwrapClass(...)
SLOT_CLASS_TYPE, v8::Integer::New(isolate, WRP_VOCBASE_COL_TYPE) // args
);
result->SetInternalField(SLOT_CLASS, entry.get());
TRI_GET_GLOBAL_STRING(_IdKey);
TRI_GET_GLOBAL_STRING(_DbNameKey);
TRI_GET_GLOBAL_STRING(VersionKeyHidden);
result->DefineOwnProperty( // define own property
TRI_IGETC, // context
_IdKey, // key
TRI_V8UInt64String<TRI_voc_cid_t>(isolate, collection->id()), // value
v8::ReadOnly // attributes
).FromMaybe(false); // Ignore result...
result->Set( // set value
_DbNameKey, TRI_V8_STD_STRING(isolate, collection->vocbase().name()) // args
);
result->DefineOwnProperty( // define own property
TRI_IGETC, // context
VersionKeyHidden, // key
v8::Integer::NewFromUnsigned(isolate, 5), // value
v8::DontEnum // attributes
).FromMaybe(false); // ignore return value
return scope.Escape<v8::Object>(result);
}

View File

@ -2470,7 +2470,7 @@ void TRI_InitV8Collections(v8::Handle<v8::Context> context, TRI_vocbase_t* vocba
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoCollection")); ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoCollection"));
rt = ft->InstanceTemplate(); rt = ft->InstanceTemplate();
rt->SetInternalFieldCount(3); rt->SetInternalFieldCount(2); // SLOT_CLASS_TYPE + SLOT_CLASS
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "count"), JS_CountVocbaseCol); TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "count"), JS_CountVocbaseCol);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "document"), TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "document"),

View File

@ -36,14 +36,18 @@ static int32_t const WRP_VOCBASE_TYPE = 1;
/// Layout: /// Layout:
/// - SLOT_CLASS_TYPE /// - SLOT_CLASS_TYPE
/// - SLOT_CLASS /// - SLOT_CLASS
/// - SLOT_EXTERNAL
static int32_t const WRP_VOCBASE_COL_TYPE = 2; static int32_t const WRP_VOCBASE_COL_TYPE = 2;
/// @brief wrapped class for LogicalView /// @brief wrapped class for LogicalView
/// Layout: /// Layout:
/// - SLOT_CLASS_TYPE /// - SLOT_CLASS_TYPE
/// - SLOT_CLASS /// - SLOT_CLASS
/// - SLOT_EXTERNAL
static int32_t const WRP_VOCBASE_VIEW_TYPE = 3; static int32_t const WRP_VOCBASE_VIEW_TYPE = 3;
#endif /// @brief wrapped class for IResearch Analyzer
/// Layout:
/// - SLOT_CLASS_TYPE
/// - SLOT_CLASS
static int32_t const WRP_IRESEARCH_ANALYZER_TYPE = 4;
#endif

View File

@ -71,59 +71,58 @@ arangodb::LogicalView* UnwrapView(v8::Isolate* isolate, v8::Local<v8::Object> co
return TRI_UnwrapClass<arangodb::LogicalView>(holder, WRP_VOCBASE_VIEW_TYPE, TRI_IGETC); return TRI_UnwrapClass<arangodb::LogicalView>(holder, WRP_VOCBASE_VIEW_TYPE, TRI_IGETC);
} }
} // namespace
using namespace arangodb;
using namespace arangodb::basics;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief wraps a LogicalView /// @brief wraps a LogicalView
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Object> WrapView(v8::Isolate* isolate, v8::Handle<v8::Object> WrapView( // wrap view
std::shared_ptr<arangodb::LogicalView> const& view) { v8::Isolate* isolate, // isolate
std::shared_ptr<arangodb::LogicalView> const& view // view
) {
v8::EscapableHandleScope scope(isolate); v8::EscapableHandleScope scope(isolate);
TRI_GET_GLOBALS(); TRI_GET_GLOBALS();
TRI_GET_GLOBAL(VocbaseViewTempl, v8::ObjectTemplate); TRI_GET_GLOBAL(VocbaseViewTempl, v8::ObjectTemplate);
v8::Handle<v8::Object> result = VocbaseViewTempl->NewInstance(); v8::Handle<v8::Object> result = VocbaseViewTempl->NewInstance();
if (!result.IsEmpty()) { if (result.IsEmpty()) {
auto* ptr = view.get(); return scope.Escape<v8::Object>(result);
auto itr = v8g->JSDatasources.emplace(
std::piecewise_construct, std::forward_as_tuple(view.get()),
std::forward_as_tuple(isolate, view,
[ptr]() -> void { // FIXME TODO find a way to move this callback
// code into DataSourcePersistent
TRI_ASSERT(!ptr->vocbase().isDangling());
ptr->vocbase().release(); // decrease the reference-counter for
// the database
}));
auto& entry = itr.first->second;
if (itr.second) { // FIXME TODO find a way to move this code into
// DataSourcePersistent
TRI_ASSERT(!ptr->vocbase().isDangling());
ptr->vocbase().forceUse(); // increase the reference-counter for the database
}
result->SetInternalField(SLOT_CLASS_TYPE,
v8::Integer::New(isolate, WRP_VOCBASE_VIEW_TYPE));
result->SetInternalField(SLOT_CLASS, entry.get());
result->SetInternalField(SLOT_EXTERNAL, entry.get());
TRI_GET_GLOBAL_STRING(_IdKey);
TRI_GET_GLOBAL_STRING(_DbNameKey);
result
->DefineOwnProperty(TRI_IGETC, _IdKey,
TRI_V8UInt64String<TRI_voc_cid_t>(isolate, view->id()),
v8::ReadOnly)
.FromMaybe(false); // Ignore result...
result->Set(_DbNameKey, TRI_V8_STD_STRING(isolate, view->vocbase().name()));
} }
auto value = std::shared_ptr<void>( // persistent value
view.get(), // value
[view](void*)->void { // ensure view shared_ptr is not deallocated
TRI_ASSERT(!view->vocbase().isDangling());
view->vocbase().release(); // decrease the reference-counter for the database
}
);
auto itr = TRI_v8_global_t::SharedPtrPersistent::emplace(*isolate, value);
auto& entry = itr.first;
TRI_ASSERT(!view->vocbase().isDangling());
view->vocbase().forceUse(); // increase the reference-counter for the database (will be decremented by 'value' distructor above, valid for both new and existing mappings)
result->SetInternalField(// required for TRI_UnwrapClass(...)
SLOT_CLASS_TYPE, v8::Integer::New(isolate, WRP_VOCBASE_VIEW_TYPE) // args
);
result->SetInternalField(SLOT_CLASS, entry.get());
TRI_GET_GLOBAL_STRING(_IdKey);
TRI_GET_GLOBAL_STRING(_DbNameKey);
result->DefineOwnProperty( // define own property
TRI_IGETC, // context
_IdKey, // key
TRI_V8UInt64String<TRI_voc_cid_t>(isolate, view->id()), // value
v8::ReadOnly // attributes
).FromMaybe(false); // Ignore result...
result->Set(_DbNameKey, TRI_V8_STD_STRING(isolate, view->vocbase().name()));
return scope.Escape<v8::Object>(result); return scope.Escape<v8::Object>(result);
} }
} // namespace
using namespace arangodb;
using namespace arangodb::basics;
static void JS_CreateViewVocbase(v8::FunctionCallbackInfo<v8::Value> const& args) { static void JS_CreateViewVocbase(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate); TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
@ -712,7 +711,7 @@ void TRI_InitV8Views(v8::Handle<v8::Context> context, TRI_vocbase_t* vocbase,
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoView")); ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoView"));
rt = ft->InstanceTemplate(); rt = ft->InstanceTemplate();
rt->SetInternalFieldCount(3); rt->SetInternalFieldCount(2); // SLOT_CLASS_TYPE + SLOT_CLASS
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "drop"), JS_DropViewVocbaseObj); TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "drop"), JS_DropViewVocbaseObj);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "name"), JS_NameViewVocbase); TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "name"), JS_NameViewVocbase);

View File

@ -213,39 +213,53 @@ TRI_v8_global_t::TRI_v8_global_t(v8::Isolate* isolate)
_ToKey.Reset(isolate, TRI_V8_ASCII_STRING(isolate, "_to")); _ToKey.Reset(isolate, TRI_V8_ASCII_STRING(isolate, "_to"));
} }
TRI_v8_global_t::DataSourcePersistent::DataSourcePersistent( TRI_v8_global_t::SharedPtrPersistent::SharedPtrPersistent( // constructor
v8::Isolate* isolate, std::shared_ptr<arangodb::LogicalDataSource> const& datasource, v8::Isolate& isolateRef, // isolate
std::function<void()>&& cleanupCallback) std::shared_ptr<void> const& value // value
: _cleanupCallback(std::move(cleanupCallback)), ): _isolate(isolateRef), _value(value) {
_datasource(datasource), auto* isolate = &isolateRef;
_isolate(isolate) {
TRI_GET_GLOBALS(); TRI_GET_GLOBALS();
_persistent.Reset(isolate, v8::External::New(isolate, datasource.get()));
_persistent.SetWeak(this,
[](v8::WeakCallbackInfo<DataSourcePersistent> const& data) -> void {
auto isolate = data.GetIsolate();
auto* persistent = data.GetParameter();
persistent->_cleanupCallback(); _persistent.Reset(isolate, v8::External::New(isolate, value.get()));
_persistent.SetWeak( // set weak reference
this, // parameter
[](v8::WeakCallbackInfo<SharedPtrPersistent> const& data)->void { // callback
auto isolate = data.GetIsolate();
auto* persistent = data.GetParameter();
TRI_GET_GLOBALS();
TRI_GET_GLOBALS(); auto* key = persistent->_value.get(); // same key as used in emplace(...)
isolate = nullptr; auto count = v8g->JSSharedPtrs.erase(key);
auto* key = persistent->_datasource.get(); // same key as was used for TRI_ASSERT(count); // zero indicates that v8g was probably deallocated before calling the v8::WeakCallbackInfo::Callback
// v8g->JSDatasources.emplace(...) },
auto count = v8g->JSDatasources.erase(key); v8::WeakCallbackType::kFinalizer // callback type
TRI_ASSERT(count); // zero indicates that v8g was probably deallocated );
// before calling the v8::WeakCallbackInfo::Callback
},
v8::WeakCallbackType::kFinalizer);
v8g->increaseActiveExternals(); v8g->increaseActiveExternals();
} }
TRI_v8_global_t::DataSourcePersistent::~DataSourcePersistent() { TRI_v8_global_t::SharedPtrPersistent::~SharedPtrPersistent() {
auto* isolate = _isolate; auto* isolate = &_isolate;
TRI_GET_GLOBALS(); TRI_GET_GLOBALS();
v8g->decreaseActiveExternals(); v8g->decreaseActiveExternals();
_persistent.Reset(); // dispose and clear the persistent handle (SIGSEGV here may _persistent.Reset(); // dispose and clear the persistent handle (SIGSEGV here may indicate that v8::Isolate was already deallocated)
// indicate that v8::Isolate was already deallocated) }
/*static*/ std::pair<TRI_v8_global_t::SharedPtrPersistent&, bool> TRI_v8_global_t::SharedPtrPersistent::emplace( // emplace a persistent shared pointer
v8::Isolate& isolateRef, // isolate
std::shared_ptr<void> const& value // persistent pointer
) {
auto* isolate = &isolateRef;
TRI_GET_GLOBALS();
auto entry = v8g->JSSharedPtrs.emplace( // ensure shared_ptr is not deallocated
std::piecewise_construct, // piecewise construct
std::forward_as_tuple(value.get()), // key
std::forward_as_tuple(isolateRef, value) // value
);
return std::pair<SharedPtrPersistent&, bool>( // result
entry.first->second, entry.second // args
);
} }
TRI_v8_global_t::~TRI_v8_global_t() {} TRI_v8_global_t::~TRI_v8_global_t() {}

View File

@ -414,26 +414,27 @@ inline v8::Local<v8::String> TRI_ObjectToString(v8::Local<v8::Context> &context,
/// @brief globals stored in the isolate /// @brief globals stored in the isolate
struct TRI_v8_global_t { struct TRI_v8_global_t {
/// @brief wrapper around a v8::Persistent to hold a shared_ptr and cleanup /// @brief wrapper around a v8::Persistent to hold a shared_ptr and cleanup
class DataSourcePersistent { class SharedPtrPersistent {
public: public:
DataSourcePersistent(v8::Isolate* isolate, SharedPtrPersistent( // constructor used ONLY by SharedPtrPersistent::emplace(...)
std::shared_ptr<arangodb::LogicalDataSource> const& datasource, v8::Isolate& isolate, // isolate
std::function<void()>&& cleanupCallback // function to call at the end of the Persistent std::shared_ptr<void> const& value // value
// WeakCallbackInfo::Callback (to avoid linking
// against arangod)
); );
DataSourcePersistent(DataSourcePersistent&&) = delete; SharedPtrPersistent(SharedPtrPersistent&&) = delete;
DataSourcePersistent(DataSourcePersistent const&) = delete; SharedPtrPersistent(SharedPtrPersistent const&) = delete;
~DataSourcePersistent(); ~SharedPtrPersistent();
DataSourcePersistent& operator=(DataSourcePersistent&&) = delete; SharedPtrPersistent& operator=(SharedPtrPersistent&&) = delete;
DataSourcePersistent& operator=(DataSourcePersistent const&) = delete; SharedPtrPersistent& operator=(SharedPtrPersistent const&) = delete;
v8::Local<v8::External> get() const { return _persistent.Get(_isolate); } static std::pair<SharedPtrPersistent&, bool> emplace( // emplace persistent shared pointer
v8::Isolate& isolate, // isolate
std::shared_ptr<void> const& value // value
);
v8::Local<v8::External> get() const { return _persistent.Get(&_isolate); }
private: private:
std::function<void()> _cleanupCallback; v8::Isolate& _isolate;
std::shared_ptr<arangodb::LogicalDataSource> _datasource;
v8::Isolate* _isolate;
v8::Persistent<v8::External> _persistent; v8::Persistent<v8::External> _persistent;
std::shared_ptr<void> _value;
}; };
explicit TRI_v8_global_t(v8::Isolate*); explicit TRI_v8_global_t(v8::Isolate*);
@ -449,9 +450,6 @@ struct TRI_v8_global_t {
/// @brief decrease the number of active externals /// @brief decrease the number of active externals
inline void decreaseActiveExternals() { --_activeExternals; } inline void decreaseActiveExternals() { --_activeExternals; }
/// @brief datasource mapping for weak pointers
std::unordered_map<void*, DataSourcePersistent> JSDatasources;
/// @brief agency template /// @brief agency template
v8::Persistent<v8::ObjectTemplate> AgencyTempl; v8::Persistent<v8::ObjectTemplate> AgencyTempl;
@ -504,6 +502,9 @@ struct TRI_v8_global_t {
/// @brief stream query cursor templace /// @brief stream query cursor templace
v8::Persistent<v8::FunctionTemplate> StreamQueryCursorTempl; v8::Persistent<v8::FunctionTemplate> StreamQueryCursorTempl;
v8::Persistent<v8::ObjectTemplate> IResearchAnalyzerTempl; // IResearch analyzer instance template
v8::Persistent<v8::ObjectTemplate> IResearchAnalyzersTempl; // IResearch analyzers feature template
/// @brief "Buffer" constant /// @brief "Buffer" constant
v8::Persistent<v8::String> BufferConstant; v8::Persistent<v8::String> BufferConstant;
@ -744,6 +745,12 @@ struct TRI_v8_global_t {
/// @brief whether or not useDatabase() is allowed /// @brief whether or not useDatabase() is allowed
bool _allowUseDatabase; bool _allowUseDatabase;
private:
/// @brief shared pointer mapping for weak pointers, holds shared pointers so
/// they don't get deallocated while in use by V8
/// @note used ONLY by the SharedPtrPersistent class
std::unordered_map<void*, SharedPtrPersistent> JSSharedPtrs;
}; };
/// @brief creates a global context /// @brief creates a global context
@ -829,4 +836,4 @@ bool TRI_AddGlobalFunctionVocbase(v8::Isolate* isolate, v8::Handle<v8::String> n
bool TRI_AddGlobalVariableVocbase(v8::Isolate* isolate, v8::Handle<v8::String> name, bool TRI_AddGlobalVariableVocbase(v8::Isolate* isolate, v8::Handle<v8::String> name,
v8::Handle<v8::Value> value); v8::Handle<v8::Value> value);
#endif #endif

View File

@ -62,10 +62,12 @@ set(IRESEARCH_TESTS_SOURCES
IResearch/RestHandlerMock.cpp IResearch/RestHandlerMock.cpp
IResearch/IResearchViewNode-test.cpp IResearch/IResearchViewNode-test.cpp
IResearch/VelocyPackHelper-test.cpp IResearch/VelocyPackHelper-test.cpp
RestHandler/RestAnalyzerHandler-test.cpp
RestHandler/RestUsersHandler-test.cpp RestHandler/RestUsersHandler-test.cpp
RestHandler/RestViewHandler-test.cpp RestHandler/RestViewHandler-test.cpp
RestServer/FlushFeature-test.cpp RestServer/FlushFeature-test.cpp
Utils/CollectionNameResolver-test.cpp Utils/CollectionNameResolver-test.cpp
V8Server/v8-analyzers-test.cpp
V8Server/v8-users-test.cpp V8Server/v8-users-test.cpp
V8Server/v8-views-test.cpp V8Server/v8-views-test.cpp
VocBase/LogicalDataSource-test.cpp VocBase/LogicalDataSource-test.cpp

View File

@ -1061,15 +1061,17 @@ SECTION("test_persistence") {
feature.start(); feature.start();
feature.visit([&expected](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected](
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
auto itr = expected.find(name); auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.first == type)); CHECK((itr->second.first == analyzer->type()));
CHECK((itr->second.second == properties)); CHECK((itr->second.second == analyzer->properties()));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -1148,18 +1150,22 @@ SECTION("test_persistence") {
feature.start(); feature.start();
/* /*
feature.visit([&expected](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected](
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
auto itr = expected.find(name); auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.first == type)); CHECK((itr->second.first == analyzer->type()));
CHECK((itr->second.second == properties)); CHECK((itr->second.second == analyzer->properties()));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
CHECK((expected.empty())); CHECK((expected.empty()));
*/ */
} }
@ -1197,15 +1203,17 @@ SECTION("test_persistence") {
feature.start(); feature.start();
/* /*
feature.visit([&expected](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected](
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
auto itr = expected.find(name); auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.first == type)); CHECK((itr->second.first == analyzer->type()));
CHECK((itr->second.second == properties)); CHECK((itr->second.second == analyzer->properties()));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -1239,17 +1247,19 @@ SECTION("test_persistence") {
feature.start(); feature.start();
/* /*
feature.visit([&expected](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected](
arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
// FIXME TODO remove block // FIXME TODO remove block
if (name != "identity" && if (analyzer->name() != "identity"
staticAnalyzers().find(name) != staticAnalyzers().end()) { && staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
auto itr = expected.find(name); auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.first == type)); CHECK((itr->second.first == analyzer->type()));
CHECK((itr->second.second == properties)); CHECK((itr->second.second == analyzer->properties()));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -1264,20 +1274,23 @@ SECTION("test_persistence") {
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
feature.start(); feature.start();
/*
feature.visit([&expected](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected](
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
auto itr = expected.find(name); auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.first == type)); CHECK((itr->second.first == analyzer->type()));
CHECK((itr->second.second == properties)); CHECK((itr->second.second == analyzer->properties()));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
CHECK((expected.empty())); CHECK((expected.empty()));
*/
} }
} }
@ -1895,12 +1908,14 @@ SECTION("test_start") {
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -1933,12 +1948,14 @@ SECTION("test_start") {
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
expected.emplace(std::piecewise_construct, std::forward_as_tuple("test_analyzer"), std::forward_as_tuple(irs::string_ref::NIL, irs::string_ref::NIL)); expected.emplace(std::piecewise_construct, std::forward_as_tuple("test_analyzer"), std::forward_as_tuple(irs::string_ref::NIL, irs::string_ref::NIL));
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -1976,12 +1993,14 @@ SECTION("test_start") {
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
/* /*
expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc"));
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -2023,12 +2042,14 @@ SECTION("test_start") {
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
/* /*
expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc"));
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -2055,17 +2076,20 @@ SECTION("test_start") {
CHECK((nullptr == vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); CHECK((nullptr == vocbase->lookupCollection(ANALYZER_COLLECTION_NAME)));
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
/*
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
CHECK((expected.empty())); CHECK((expected.empty()));
*/
} }
// test feature start load configuration (no configuration collection, static analyzers) // test feature start load configuration (no configuration collection, static analyzers)
@ -2088,17 +2112,20 @@ SECTION("test_start") {
CHECK((nullptr == vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); CHECK((nullptr == vocbase->lookupCollection(ANALYZER_COLLECTION_NAME)));
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
/*
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
CHECK((expected.empty())); CHECK((expected.empty()));
*/
} }
// test feature start load configuration (with configuration collection) // test feature start load configuration (with configuration collection)
@ -2130,12 +2157,14 @@ SECTION("test_start") {
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
/* /*
expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc"));
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -2174,12 +2203,14 @@ SECTION("test_start") {
auto expected = staticAnalyzers(); auto expected = staticAnalyzers();
/* /*
expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc"));
feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties, irs::flags const& features)->bool { feature.visit([&expected, &feature](
auto itr = expected.find(name); arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
)->bool {
auto itr = expected.find(analyzer->name());
CHECK((itr != expected.end())); CHECK((itr != expected.end()));
CHECK((itr->second.type == type)); CHECK((itr->second.type == analyzer->type()));
CHECK((itr->second.properties == properties)); CHECK((itr->second.properties == analyzer->properties()));
CHECK((itr->second.features.is_subset_of(feature.get(name)->features()))); CHECK((itr->second.features.is_subset_of(feature.get(analyzer->name())->features())));
expected.erase(itr); expected.erase(itr);
return true; return true;
}); });
@ -3720,17 +3751,14 @@ SECTION("test_visit") {
{ "test_analyzer2", "abc2", {} }, { "test_analyzer2", "abc2", {} },
}; };
auto result = feature.visit([&expected]( auto result = feature.visit([&expected](
irs::string_ref const& name, arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
irs::string_ref const& type,
irs::string_ref const& properties,
irs::flags const& features
)->bool { )->bool {
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
CHECK((type == "TestAnalyzer")); CHECK((analyzer->type() == "TestAnalyzer"));
CHECK((1 == expected.erase(ExpectedType(name, properties, features)))); CHECK((1 == expected.erase(ExpectedType(analyzer->name(), analyzer->properties(), analyzer->features()))));
return true; return true;
}); });
CHECK((true == result)); CHECK((true == result));
@ -3745,17 +3773,14 @@ SECTION("test_visit") {
{ "test_analyzer2", "abc2", {} }, { "test_analyzer2", "abc2", {} },
}; };
auto result = feature.visit([&expected]( auto result = feature.visit([&expected](
irs::string_ref const& name, arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
irs::string_ref const& type,
irs::string_ref const& properties,
irs::flags const& features
)->bool { )->bool {
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
CHECK((type == "TestAnalyzer")); CHECK((analyzer->type() == "TestAnalyzer"));
CHECK((1 == expected.erase(ExpectedType(name, properties, features)))); CHECK((1 == expected.erase(ExpectedType(analyzer->name(), analyzer->properties(), analyzer->features()))));
return false; return false;
}); });
CHECK((false == result)); CHECK((false == result));
@ -3785,17 +3810,14 @@ SECTION("test_visit") {
std::set<ExpectedType> expected = {}; std::set<ExpectedType> expected = {};
auto result = feature.visit( auto result = feature.visit(
[&expected]( [&expected](
irs::string_ref const& name, arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
irs::string_ref const& type,
irs::string_ref const& properties,
irs::flags const& features
)->bool { )->bool {
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
CHECK((type == "TestAnalyzer")); CHECK((analyzer->type() == "TestAnalyzer"));
CHECK((1 == expected.erase(ExpectedType(name, properties, features)))); CHECK((1 == expected.erase(ExpectedType(analyzer->name(), analyzer->properties(), analyzer->features()))));
return true; return true;
}, },
vocbase0 vocbase0
@ -3812,17 +3834,14 @@ SECTION("test_visit") {
}; };
auto result = feature.visit( auto result = feature.visit(
[&expected]( [&expected](
irs::string_ref const& name, arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr const& analyzer
irs::string_ref const& type,
irs::string_ref const& properties,
irs::flags const& features
)->bool { )->bool {
if (staticAnalyzers().find(name) != staticAnalyzers().end()) { if (staticAnalyzers().find(analyzer->name()) != staticAnalyzers().end()) {
return true; // skip static analyzers return true; // skip static analyzers
} }
CHECK((type == "TestAnalyzer")); CHECK((analyzer->type() == "TestAnalyzer"));
CHECK((1 == expected.erase(ExpectedType(name, properties, features)))); CHECK((1 == expected.erase(ExpectedType(analyzer->name(), analyzer->properties(), analyzer->features()))));
return true; return true;
}, },
vocbase2 vocbase2
@ -3841,4 +3860,4 @@ SECTION("test_visit") {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -41,6 +41,8 @@
#include "IResearch/IResearchCommon.h" #include "IResearch/IResearchCommon.h"
#include "IResearch/IResearchFeature.h" #include "IResearch/IResearchFeature.h"
#include "IResearch/IResearchFilterFactory.h" #include "IResearch/IResearchFilterFactory.h"
#include "IResearch/IResearchLink.h"
#include "IResearch/IResearchLinkHelper.h"
#include "IResearch/IResearchView.h" #include "IResearch/IResearchView.h"
#include "IResearch/IResearchAnalyzerFeature.h" #include "IResearch/IResearchAnalyzerFeature.h"
#include "Logger/Logger.h" #include "Logger/Logger.h"
@ -206,6 +208,8 @@ TEST_CASE("IResearchQueryInRange", "[iresearch][iresearch-query]") {
TRI_vocbase_t 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");
std::vector<arangodb::velocypack::Builder> insertedDocs; std::vector<arangodb::velocypack::Builder> insertedDocs;
std::shared_ptr<arangodb::LogicalCollection> collection0;
std::shared_ptr<arangodb::LogicalCollection> collection1;
arangodb::LogicalView* view; arangodb::LogicalView* view;
// create collection0 // create collection0
@ -213,6 +217,7 @@ TEST_CASE("IResearchQueryInRange", "[iresearch][iresearch-query]") {
auto createJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection0\" }"); auto createJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection0\" }");
auto collection = vocbase.createCollection(createJson->slice()); auto collection = vocbase.createCollection(createJson->slice());
REQUIRE((nullptr != collection)); REQUIRE((nullptr != collection));
collection0 = collection;
std::vector<std::shared_ptr<arangodb::velocypack::Builder>> docs { std::vector<std::shared_ptr<arangodb::velocypack::Builder>> docs {
arangodb::velocypack::Parser::fromJson("{ \"seq\": -6, \"value\": null }"), arangodb::velocypack::Parser::fromJson("{ \"seq\": -6, \"value\": null }"),
@ -246,6 +251,7 @@ TEST_CASE("IResearchQueryInRange", "[iresearch][iresearch-query]") {
auto createJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection1\" }"); auto createJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection1\" }");
auto collection = vocbase.createCollection(createJson->slice()); auto collection = vocbase.createCollection(createJson->slice());
REQUIRE((nullptr != collection)); REQUIRE((nullptr != collection));
collection1 = collection;
irs::utf8_path resource; irs::utf8_path resource;
resource/=irs::string_ref(IResearch_test_resource_dir); resource/=irs::string_ref(IResearch_test_resource_dir);
@ -294,7 +300,8 @@ TEST_CASE("IResearchQueryInRange", "[iresearch][iresearch-query]") {
std::set<TRI_voc_cid_t> cids; std::set<TRI_voc_cid_t> cids;
impl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); impl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; });
CHECK((2 == cids.size())); CHECK((2 == cids.size()));
CHECK(impl->commit().ok()); CHECK((arangodb::iresearch::IResearchLinkHelper::find(*collection0, *view)->commit().ok()));
CHECK((arangodb::iresearch::IResearchLinkHelper::find(*collection1, *view)->commit().ok()));
} }
// d.value > false && d.value <= true // d.value > false && d.value <= true
@ -708,4 +715,4 @@ TEST_CASE("IResearchQueryInRange", "[iresearch][iresearch-query]") {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -36,7 +36,11 @@
#include "Aql/ExecutionPlan.h" #include "Aql/ExecutionPlan.h"
#include "Aql/QueryRegistry.h" #include "Aql/QueryRegistry.h"
#include "Aql/Query.h" #include "Aql/Query.h"
#include "Cluster/ClusterFeature.h"
#include "IResearch/IResearchLink.h"
#include "IResearch/IResearchLinkHelper.h"
#include "V8/v8-globals.h" #include "V8/v8-globals.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h" #include "VocBase/LogicalView.h"
#include "VocBase/ManagedDocumentResult.h" #include "VocBase/ManagedDocumentResult.h"
@ -116,7 +120,6 @@ bool findEmptyNodes(
struct IResearchQueryStringTermSetup { struct IResearchQueryStringTermSetup {
StorageEngineMock engine; StorageEngineMock engine;
arangodb::application_features::ApplicationServer server; arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features; std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryStringTermSetup(): engine(server), server(nullptr, nullptr) { IResearchQueryStringTermSetup(): engine(server), server(nullptr, nullptr) {
@ -134,6 +137,7 @@ struct IResearchQueryStringTermSetup {
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr); irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features // setup required application features
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true); features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::AuthenticationFeature(server), true); features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabasePathFeature(server), false); features.emplace_back(new arangodb::DatabasePathFeature(server), false);
@ -141,8 +145,7 @@ struct IResearchQueryStringTermSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false); features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE); features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true); features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true); features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -154,6 +157,11 @@ struct IResearchQueryStringTermSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif #endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) { for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first); arangodb::application_features::ApplicationServer::server->addFeature(f.first);
} }
@ -162,6 +170,12 @@ struct IResearchQueryStringTermSetup {
f.first->prepare(); f.first->prepare();
} }
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) { for (auto& f : features) {
if (f.second) { if (f.second) {
f.first->start(); f.first->start();
@ -199,21 +213,22 @@ struct IResearchQueryStringTermSetup {
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature< auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature arangodb::iresearch::IResearchAnalyzerFeature
>(); >();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "testVocbase::test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath"); auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
} }
~IResearchQueryStringTermSetup() { ~IResearchQueryStringTermSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT); arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT); arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr; arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features // destroy application features
for (auto& f : features) { for (auto& f : features) {
@ -227,6 +242,7 @@ struct IResearchQueryStringTermSetup {
} }
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT); arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
} }
}; // IResearchQuerySetup }; // IResearchQuerySetup
@ -321,7 +337,7 @@ TEST_CASE("IResearchQueryTestOptimization", "[iresearch][iresearch-query]") {
} }
CHECK((trx.commit().ok())); CHECK((trx.commit().ok()));
CHECK(view->commit().ok()); CHECK((arangodb::iresearch::IResearchLinkHelper::find(*logicalCollection1, *view)->commit().ok()));
} }
// a IN [ x ] && a == y, x < y // a IN [ x ] && a == y, x < y
@ -8498,4 +8514,4 @@ TEST_CASE("IResearchQueryTestOptimization", "[iresearch][iresearch-query]") {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -45,6 +45,7 @@ struct GeneralRequestMock: public arangodb::GeneralRequest {
virtual arangodb::velocypack::StringRef rawPayload() const override; virtual arangodb::velocypack::StringRef rawPayload() const override;
virtual arangodb::velocypack::Slice payload(arangodb::velocypack::Options const* options = &arangodb::velocypack::Options::Defaults) override; virtual arangodb::velocypack::Slice payload(arangodb::velocypack::Options const* options = &arangodb::velocypack::Options::Defaults) override;
virtual arangodb::Endpoint::TransportType transportType() override; virtual arangodb::Endpoint::TransportType transportType() override;
std::unordered_map<std::string, std::string>& values() { return _values; }
}; };
struct GeneralResponseMock: public arangodb::GeneralResponse { struct GeneralResponseMock: public arangodb::GeneralResponse {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -457,7 +457,6 @@ SECTION("test_auth") {
arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE)); arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE));
arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get())); arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get()));
arangoView->SetInternalField(SLOT_EXTERNAL, v8::External::New(isolate.get(), logicalView.get()));
std::vector<v8::Local<v8::Value>> args = { std::vector<v8::Local<v8::Value>> args = {
}; };
@ -593,7 +592,6 @@ SECTION("test_auth") {
arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE)); arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE));
arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get())); arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get()));
arangoView->SetInternalField(SLOT_EXTERNAL, v8::External::New(isolate.get(), logicalView.get()));
std::vector<v8::Local<v8::Value>> args = { std::vector<v8::Local<v8::Value>> args = {
TRI_V8_ASCII_STRING(isolate.get(), "testView1"), TRI_V8_ASCII_STRING(isolate.get(), "testView1"),
}; };
@ -771,7 +769,6 @@ SECTION("test_auth") {
arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE)); arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE));
arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get())); arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get()));
arangoView->SetInternalField(SLOT_EXTERNAL, v8::External::New(isolate.get(), logicalView.get()));
std::vector<v8::Local<v8::Value>> args = { std::vector<v8::Local<v8::Value>> args = {
TRI_VPackToV8(isolate.get(), arangodb::velocypack::Parser::fromJson("{ \"key\": \"value\" }")->slice()), TRI_VPackToV8(isolate.get(), arangodb::velocypack::Parser::fromJson("{ \"key\": \"value\" }")->slice()),
}; };
@ -1130,7 +1127,6 @@ SECTION("test_auth") {
arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE)); arangoView->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(isolate.get(), WRP_VOCBASE_VIEW_TYPE));
arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get())); arangoView->SetInternalField(SLOT_CLASS, v8::External::New(isolate.get(), logicalView.get()));
arangoView->SetInternalField(SLOT_EXTERNAL, v8::External::New(isolate.get(), logicalView.get()));
std::vector<v8::Local<v8::Value>> args = { std::vector<v8::Local<v8::Value>> args = {
}; };
@ -1418,4 +1414,4 @@ SECTION("test_auth") {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------