mirror of https://gitee.com/bigwinds/arangodb
issue 526.3: update analyzer feature to store analyzer definitions in per-vocbase system collections (#8452)
* issue 526.3: update analyzer feature to store analyzer definitions in per-vocbase system collections * address merge issues * address another merge issue
This commit is contained in:
parent
48ad71dc94
commit
405b60c2b7
|
@ -374,10 +374,17 @@ bool iresearchAnalyzerLegacyAnalyzers( // upgrade task
|
|||
std::string(vocbase.name()).append(2, ANALYZER_PREFIX_DELIM).append(entry.first);
|
||||
auto& type = legacyAnalyzerType;
|
||||
auto& properties = entry.second;
|
||||
auto result = // result
|
||||
analyzers->emplace(name, type, properties, legacyAnalyzerFeatures);
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
auto res = analyzers->emplace( // add analyzer
|
||||
result, name, type, properties, legacyAnalyzerFeatures // args
|
||||
);
|
||||
|
||||
if (!result.first) {
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure while registering a legacy static analyzer '" << name << "' with vocbase '" << vocbase.name() << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
|
||||
success = false;
|
||||
} else if (!result.first) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure while registering a legacy static analyzer '" << name << "' with vocbase '" << vocbase.name() << "'";
|
||||
|
||||
|
@ -620,6 +627,49 @@ IResearchAnalyzerFeature::IResearchAnalyzerFeature(arangodb::application_feature
|
|||
);
|
||||
}
|
||||
|
||||
/*static*/ bool IResearchAnalyzerFeature::canUse( // check permissions
|
||||
irs::string_ref const& analyzer, // analyzer name
|
||||
TRI_vocbase_t const& defaultVocbase, // fallback vocbase if not part of name
|
||||
arangodb::auth::Level const& level // access level
|
||||
) {
|
||||
auto* ctx = arangodb::ExecContext::CURRENT;
|
||||
|
||||
if (!ctx) {
|
||||
return true; // authentication not enabled
|
||||
}
|
||||
|
||||
auto& staticAnalyzers = getStaticAnalyzers();
|
||||
|
||||
if (staticAnalyzers.find(irs::make_hashed_ref(analyzer, std::hash<irs::string_ref>())) != staticAnalyzers.end()) {
|
||||
return true; // special case for singleton static analyzers (always allowed)
|
||||
}
|
||||
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
arangodb::SystemDatabaseFeature // featue type
|
||||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
std::pair<irs::string_ref, irs::string_ref> split;
|
||||
|
||||
if (sysVocbase) {
|
||||
split = splitAnalyzerName( // split analyzer name
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::normalize( // normalize
|
||||
analyzer, defaultVocbase, *sysVocbase // args
|
||||
)
|
||||
);
|
||||
} else {
|
||||
split = splitAnalyzerName(analyzer);
|
||||
}
|
||||
|
||||
// FIXME TODO remove temporary workaround once emplace(...) and all tests are updated
|
||||
if (split.first.null()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !split.first.null() // have a vocbase
|
||||
&& ctx->canUseDatabase(split.first, level) // can use vocbase
|
||||
&& 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()*/
|
||||
|
@ -757,6 +807,16 @@ std::pair<IResearchAnalyzerFeature::AnalyzerPool::ptr, bool> IResearchAnalyzerFe
|
|||
return std::make_pair(AnalyzerPool::ptr(), false);
|
||||
}
|
||||
|
||||
arangodb::Result IResearchAnalyzerFeature::emplace( // emplace an analyzer
|
||||
EmplaceResult& result, // emplacement result on success (out-parameter)
|
||||
irs::string_ref const& name, // analyzer name
|
||||
irs::string_ref const& type, // analyzer type
|
||||
irs::string_ref const& properties, // analyzer properties
|
||||
irs::flags const& features /*= irs::flags::empty_instance()*/ // analyzer features
|
||||
) {
|
||||
return ensure(result, name, type, properties, features, true);
|
||||
}
|
||||
|
||||
IResearchAnalyzerFeature::AnalyzerPool::ptr IResearchAnalyzerFeature::ensure( // get analyzer or placeholder
|
||||
irs::string_ref const& name // analyzer name
|
||||
) {
|
||||
|
@ -768,6 +828,107 @@ IResearchAnalyzerFeature::AnalyzerPool::ptr IResearchAnalyzerFeature::ensure( //
|
|||
: emplace(name, irs::string_ref::NIL, irs::string_ref::NIL, false).first;
|
||||
}
|
||||
|
||||
arangodb::Result IResearchAnalyzerFeature::ensure( // ensure analyzer existence if possible
|
||||
EmplaceResult& result, // emplacement result on success (out-param)
|
||||
irs::string_ref const& name, // analyzer name
|
||||
irs::string_ref const& type, // analyzer type
|
||||
irs::string_ref const& properties, // analyzer properties
|
||||
irs::flags const& features, // analyzer features
|
||||
bool allowCreation
|
||||
) {
|
||||
try {
|
||||
static const auto generator = []( // key + value generator
|
||||
irs::hashed_string_ref const& key, // source key
|
||||
AnalyzerPool::ptr const& value // source value
|
||||
)->irs::hashed_string_ref {
|
||||
auto pool = std::make_shared<AnalyzerPool>(key); // allocate pool
|
||||
const_cast<AnalyzerPool::ptr&>(value) = pool; // lazy-instantiate pool to avoid allocation if pool is already present
|
||||
return pool ? irs::hashed_string_ref(key.hash(), pool->name()) : key; // reuse hash but point ref at value in pool
|
||||
};
|
||||
WriteMutex mutex(_mutex);
|
||||
SCOPED_LOCK(mutex);
|
||||
|
||||
auto itr = irs::map_utils::try_emplace_update_key( // emplace and update key
|
||||
_analyzers, // destination
|
||||
generator, // key generator
|
||||
irs::make_hashed_ref(name, std::hash<irs::string_ref>()) // key
|
||||
);
|
||||
bool erase = itr.second; // an insertion took place
|
||||
auto cleanup = irs::make_finally([&erase, this, &itr]()->void {
|
||||
if (erase) {
|
||||
_analyzers.erase(itr.first); // ensure no broken analyzers are left behind
|
||||
}
|
||||
});
|
||||
auto pool = itr.first->second;
|
||||
|
||||
if (!pool) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("failure creating an arangosearch analyzer instance for name '") + std::string(name) + "' type '" + std::string(type) + "' properties '" + std::string(properties) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
// new pool creation
|
||||
if (itr.second) {
|
||||
if (!pool->init(type, properties, features)) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("failure initializing an arangosearch analyzer instance for name '") + std::string(name) + "' type '" + std::string(type) + "' properties '" + std::string(properties) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
if (!allowCreation) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("forbidden implicit creation of an arangosearch analyzer instance for name '") + std::string(name) + "' type '" + std::string(type) + "' properties '" + std::string(properties) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
// persist only on coordinator and single-server
|
||||
auto res = arangodb::ServerState::instance()->isCoordinator() // coordinator
|
||||
|| arangodb::ServerState::instance()->isSingleServer() // single-server
|
||||
? storeAnalyzer(*pool) : arangodb::Result();
|
||||
|
||||
if (res.ok()) {
|
||||
result = std::make_pair(pool, itr.second);
|
||||
erase = false; // successful pool creation, cleanup not required
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// pool exists but with different configuration
|
||||
if (type != pool->type() // different type
|
||||
|| properties != pool->properties() // different properties
|
||||
|| features != pool->features() // different features
|
||||
) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
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()) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
result = std::make_pair(pool, itr.second);
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
return arangodb::Result( // result
|
||||
e.code(), // code
|
||||
std::string("caught exception while registering an arangosearch analizer name '") + std::string(name) + "' type '" + std::string(type) + "' properties '" + std::string(properties) + "': " + std::to_string(e.code()) + " " + e.what()
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("caught exception while registering an arangosearch analizer name '") + std::string(name) + "' type '" + std::string(type) + "' properties '" + std::string(properties) + "': " + e.what()
|
||||
);
|
||||
} catch (...) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("caught exception while registering an arangosearch analizer name '") + std::string(name) + "' type '" + std::string(type) + "' properties '" + std::string(properties) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
size_t IResearchAnalyzerFeature::erase(irs::string_ref const& name) noexcept {
|
||||
try {
|
||||
WriteMutex mutex(_mutex);
|
||||
|
@ -921,6 +1082,33 @@ IResearchAnalyzerFeature::AnalyzerPool::ptr IResearchAnalyzerFeature::get( // fi
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
IResearchAnalyzerFeature::AnalyzerPool::ptr IResearchAnalyzerFeature::get( // find analyzer
|
||||
irs::string_ref const& name, // analyzer name
|
||||
irs::string_ref const& type, // analyzer type
|
||||
irs::string_ref const& properties, // analyzer properties
|
||||
irs::flags const& features // analyzer features
|
||||
) {
|
||||
EmplaceResult result;
|
||||
auto res = ensure( // find and validate analyzer
|
||||
result, // result
|
||||
name, // analyzer name
|
||||
type, // analyzer type
|
||||
properties, // analyzer properties
|
||||
features, // analyzer features
|
||||
arangodb::ServerState::instance()->isDBServer() // create analyzer only if on db-server
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure to get arangosearch analyzer name '" << name << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
TRI_set_errno(TRI_ERROR_INTERNAL);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result.first;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a container of statically defined/initialized analyzers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1301,6 +1489,11 @@ bool IResearchAnalyzerFeature::loadConfiguration() {
|
|||
auto split = splitAnalyzerName(name);
|
||||
|
||||
if (expandVocbasePrefix) {
|
||||
// FIXME TODO remove temporary workaround once emplace(...) and all tests are updated
|
||||
if (split.first.null()) {
|
||||
return split.second;
|
||||
}
|
||||
|
||||
if (split.first.null()) {
|
||||
return std::string(activeVocbase.name()).append(2, ANALYZER_PREFIX_DELIM).append(split.second);
|
||||
}
|
||||
|
@ -1479,6 +1672,16 @@ arangodb::Result IResearchAnalyzerFeature::storeAnalyzer(AnalyzerPool& pool) {
|
|||
);
|
||||
}
|
||||
|
||||
auto* engine = arangodb::EngineSelectorFeature::ENGINE;
|
||||
|
||||
// do not allow persistence while in recovery
|
||||
if (engine && engine->inRecovery()) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("failure to persist arangosearch analyzer '") + pool.name()+ "' configuration while storage engine in recovery"
|
||||
);
|
||||
}
|
||||
|
||||
auto split = splitAnalyzerName(pool.name());
|
||||
auto* vocbase = dbFeature->useDatabase(split.first);
|
||||
|
||||
|
@ -1601,7 +1804,7 @@ arangodb::Result IResearchAnalyzerFeature::storeAnalyzer(AnalyzerPool& pool) {
|
|||
pool.setKey(getStringRef(key));
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
e.code(), // code
|
||||
std::string("caught exception while persisting configuration for arangosearch analyzer name '") + pool.name() + "': " + std::to_string(e.code()) + " "+ e.what()
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
|
|
|
@ -59,6 +59,7 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
|||
class AnalyzerPool : private irs::util::noncopyable {
|
||||
public:
|
||||
typedef std::shared_ptr<AnalyzerPool> ptr;
|
||||
explicit AnalyzerPool(irs::string_ref const& name);
|
||||
irs::flags const& features() const noexcept { return _features; }
|
||||
irs::analysis::analyzer::ptr get() const noexcept; // nullptr == error creating analyzer
|
||||
std::string const& name() const noexcept { return _name; }
|
||||
|
@ -78,13 +79,11 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
|||
// AnalyzerBuilder::make(...))
|
||||
std::string _config; // non-null type + non-null properties + key
|
||||
irs::flags _features; // cached analyzer features
|
||||
irs::string_ref _key; // the key of the persisted configuration for this
|
||||
// pool, null == not persisted
|
||||
irs::string_ref _key; // the key of the persisted configuration for this pool, null == static analyzer
|
||||
std::string _name; // ArangoDB alias for an IResearch analyzer configuration
|
||||
irs::string_ref _properties; // IResearch analyzer configuration
|
||||
irs::string_ref _type; // IResearch analyzer name
|
||||
|
||||
explicit AnalyzerPool(irs::string_ref const& name);
|
||||
bool init(irs::string_ref const& type, irs::string_ref const& properties,
|
||||
irs::flags const& features = irs::flags::empty_instance());
|
||||
void setKey(irs::string_ref const& type);
|
||||
|
@ -100,11 +99,47 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
|||
arangodb::auth::Level const& level // access level
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @return analyzer with the given prefixed name (or unprefixed and resides
|
||||
/// in defaultVocbase) is granted 'level' access
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static bool canUse( // check permissions
|
||||
irs::string_ref const& analyzer, // analyzer name
|
||||
TRI_vocbase_t const& defaultVocbase, // fallback vocbase if not part of name
|
||||
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
|
||||
/// @param result the result of the successful emplacement (out-param)
|
||||
/// first - the emplaced pool
|
||||
/// second - if an insertion of an new analyzer occured
|
||||
/// @param name analyzer name (already normalized)
|
||||
/// @param type the underlying IResearch analyzer type
|
||||
/// @param properties the configuration for the underlying IResearch type
|
||||
/// @param features the expected features the analyzer should produce
|
||||
/// @param implicitCreation false == treat as error if creation is required
|
||||
/// @return success
|
||||
/// @note emplacement while inRecovery() will not allow adding new analyzers
|
||||
/// valid because for existing links the analyzer definition should
|
||||
/// already have been persisted and feature administration is not
|
||||
/// allowed during recovery
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
typedef std::pair<AnalyzerPool::ptr, bool> EmplaceResult;
|
||||
arangodb::Result emplace( // emplace an analyzer
|
||||
EmplaceResult& result, // emplacement result on success (out-param)
|
||||
irs::string_ref const& name, // analyzer name
|
||||
irs::string_ref const& type, // analyzer type
|
||||
irs::string_ref const& properties, // analyzer properties
|
||||
irs::flags const& features = irs::flags::empty_instance() // analyzer features
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get analyzer or placeholder
|
||||
/// before start() returns pool placeholder,
|
||||
|
@ -112,6 +147,7 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
|||
/// after start() returns same as get(...)
|
||||
/// @param name analyzer name (used verbatim)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// FIXME TODO remove
|
||||
AnalyzerPool::ptr ensure(irs::string_ref const& name);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -126,6 +162,23 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
AnalyzerPool::ptr get(irs::string_ref const& name) const noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief find analyzer
|
||||
/// @param name analyzer name (already normalized)
|
||||
/// @param type the underlying IResearch analyzer type
|
||||
/// @param properties the configuration for the underlying IResearch type
|
||||
/// @param features the expected features the analyzer should produce
|
||||
/// @return analyzer matching the specified parameters or nullptr
|
||||
/// @note will construct and cache the analyzer if missing only on db-server
|
||||
/// persistence in the cases of inRecovery or !storage engine will fail
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
AnalyzerPool::ptr get( // find analyzer
|
||||
irs::string_ref const& name, // analyzer name
|
||||
irs::string_ref const& type, // analyzer type
|
||||
irs::string_ref const& properties, // analyzer properties
|
||||
irs::flags const& features // analyzer features
|
||||
);
|
||||
|
||||
static AnalyzerPool::ptr identity() noexcept; // the identity analyzer
|
||||
static std::string const& name() noexcept;
|
||||
|
||||
|
@ -165,12 +218,42 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
|||
mutable irs::async_utils::read_write_mutex _mutex;
|
||||
bool _started;
|
||||
|
||||
// FIXME TODO remove
|
||||
std::pair<AnalyzerPool::ptr, bool> emplace(
|
||||
irs::string_ref const& name, irs::string_ref const& type,
|
||||
irs::string_ref const& properties, bool initAndPersist,
|
||||
irs::flags const& features = irs::flags::empty_instance()) noexcept;
|
||||
|
||||
static Analyzers const& getStaticAnalyzers();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ensure an analyzer as per the specified parameters exists if
|
||||
/// possible
|
||||
/// @param result the result of the successful emplacement (out-param)
|
||||
/// first - the emplaced pool
|
||||
/// second - if an insertion of an new analyzer occured
|
||||
/// @param name analyzer name (already normalized)
|
||||
/// @param type the underlying IResearch analyzer type
|
||||
/// @param properties the configuration for the underlying IResearch type
|
||||
/// @param features the expected features the analyzer should produce
|
||||
/// @param allowCreation false == treat as an error if creation is required
|
||||
/// @return success
|
||||
/// @note ensure while inRecovery() will not allow new analyzer persistance
|
||||
/// valid because for existing links the analyzer definition should
|
||||
/// already have been persisted and feature administration is not
|
||||
/// allowed during recovery
|
||||
/// @note for db-server analyzers are not persisted
|
||||
/// valid because the authoritative analyzer source is from coordinators
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
arangodb::Result ensure( // ensure analyzer existence if possible
|
||||
EmplaceResult& result, // emplacement result on success (out-param)
|
||||
irs::string_ref const& name, // analyzer name
|
||||
irs::string_ref const& type, // analyzer type
|
||||
irs::string_ref const& properties, // analyzer properties
|
||||
irs::flags const& features, // analyzer features
|
||||
bool allowCreation
|
||||
);
|
||||
|
||||
bool loadConfiguration();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "IResearchKludge.h"
|
||||
#include "IResearchPrimaryKeyFilter.h"
|
||||
#include "Logger/LogMacros.h"
|
||||
#include "RestServer/SystemDatabaseFeature.h"
|
||||
|
||||
using namespace arangodb::iresearch;
|
||||
|
||||
|
@ -176,7 +177,22 @@ IResearchAnalyzerFeature::AnalyzerPool::ptr extractAnalyzerFromArg(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
analyzer = analyzerFeature->get(analyzerId);
|
||||
if (ctx.trx) {
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
arangodb::SystemDatabaseFeature // featue type
|
||||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
|
||||
if (sysVocbase) {
|
||||
analyzer = analyzerFeature->get( // get analyzer
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::normalize( // normalize
|
||||
analyzerId, ctx.trx->vocbase(), *sysVocbase // args
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
analyzer = analyzerFeature->get(analyzerId); // verbatim
|
||||
}
|
||||
|
||||
if (!analyzer) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
|
@ -1956,4 +1972,4 @@ namespace iresearch {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -672,41 +672,40 @@ arangodb::Result IResearchLink::drop() {
|
|||
bool exists;
|
||||
|
||||
// remove persisted data store directory if present
|
||||
if (!_dataStore._path.exists_directory(exists) ||
|
||||
(exists && !_dataStore._path.remove())) {
|
||||
return arangodb::Result(TRI_ERROR_INTERNAL,
|
||||
std::string(
|
||||
"failed to remove arangosearch link '") +
|
||||
std::to_string(id()) + "'");
|
||||
if (!_dataStore._path.exists_directory(exists)
|
||||
|| (exists && !_dataStore._path.remove())) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failed to remove arangosearch link '") + std::to_string(id()) + "'"
|
||||
);
|
||||
}
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
return arangodb::Result(
|
||||
e.code(),
|
||||
std::string("caught exception while removing arangosearch link '") +
|
||||
std::to_string(id()) + "': " + e.what());
|
||||
e.code(),
|
||||
std::string("caught exception while removing arangosearch link '") + std::to_string(id()) + "': " + e.what()
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while removing arangosearch link '") +
|
||||
std::to_string(id()) + "': " + e.what());
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while removing arangosearch link '") + std::to_string(id()) + "': " + e.what()
|
||||
);
|
||||
} catch (...) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while removing arangosearch link '") +
|
||||
std::to_string(id()) + "'");
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while removing arangosearch link '") + std::to_string(id()) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
bool IResearchLink::hasBatchInsert() const { return true; }
|
||||
|
||||
bool IResearchLink::hasSelectivityEstimate() const {
|
||||
return false; // selectivity can only be determined per query since multiple
|
||||
// fields are indexed
|
||||
bool IResearchLink::hasBatchInsert() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
TRI_idx_iid_t IResearchLink::id() const noexcept { return _id; }
|
||||
bool IResearchLink::hasSelectivityEstimate() const {
|
||||
return false; // selectivity can only be determined per query since multiple fields are indexed
|
||||
}
|
||||
|
||||
arangodb::Result IResearchLink::init(
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
|
@ -719,16 +718,19 @@ arangodb::Result IResearchLink::init(
|
|||
std::string error;
|
||||
IResearchLinkMeta meta;
|
||||
|
||||
if (!meta.init(definition, error)) {
|
||||
if (!meta.init(definition, error, &(collection().vocbase()))) { // definition should already be normalized and analyzers created if required
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error parsing view link parameters from json: ") + error);
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error parsing view link parameters from json: ") + error
|
||||
);
|
||||
}
|
||||
|
||||
if (!definition.isObject() || !definition.get(StaticStrings::ViewIdField).isString()) {
|
||||
return arangodb::Result(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("error finding view for link '") +
|
||||
std::to_string(_id) + "'");
|
||||
if (!definition.isObject() // not object
|
||||
|| !definition.get(StaticStrings::ViewIdField).isString()) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND, // code
|
||||
std::string("error finding view for link '") + std::to_string(_id) + "'" // message
|
||||
);
|
||||
}
|
||||
|
||||
auto viewId = definition.get(StaticStrings::ViewIdField).copyString();
|
||||
|
@ -767,11 +769,25 @@ arangodb::Result IResearchLink::init(
|
|||
viewId = view->guid(); // ensue that this is a GUID (required by
|
||||
// operator==(IResearchView))
|
||||
|
||||
if (!view->emplace(_collection.id(), _collection.name(), definition)) {
|
||||
return arangodb::Result(TRI_ERROR_INTERNAL,
|
||||
std::string("failed to link with view '") + view->name() +
|
||||
"' while initializing link '" +
|
||||
std::to_string(_id) + "'");
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
|
||||
// FIXME TODO move this logic into IResearchViewCoordinator
|
||||
if (!meta.json(builder, false)) { // generate user-visible definition
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("failed to generate link definition while initializing link '") + std::to_string(_id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
builder.close();
|
||||
|
||||
if (!view->emplace(_collection.id(), _collection.name(), builder.slice())) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("failed to link with view '") + view->name() + "' while initializing link '" + std::to_string(_id) + "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (arangodb::ServerState::instance()->isDBServer()) { // db-server link
|
||||
|
@ -1427,27 +1443,13 @@ bool IResearchLink::isSorted() const {
|
|||
return false; // IResearch does not provide a fixed default sort order
|
||||
}
|
||||
|
||||
bool IResearchLink::json(arangodb::velocypack::Builder& builder) const {
|
||||
if (!builder.isOpenObject() || !_meta.json(builder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.add(arangodb::StaticStrings::IndexId,
|
||||
arangodb::velocypack::Value(std::to_string(_id)));
|
||||
builder.add(arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(IResearchLinkHelper::type()));
|
||||
builder.add(StaticStrings::ViewIdField, arangodb::velocypack::Value(_viewGuid));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IResearchLink::load() {
|
||||
// Note: this function is only used by RocksDB
|
||||
}
|
||||
|
||||
bool IResearchLink::matchesDefinition(VPackSlice const& slice) const {
|
||||
if (!slice.isObject() || !slice.hasKey(StaticStrings::ViewIdField)) {
|
||||
return false; // slice has no view identifier field
|
||||
return false; // slice has no view identifier field
|
||||
}
|
||||
|
||||
auto viewId = slice.get(StaticStrings::ViewIdField);
|
||||
|
@ -1455,27 +1457,26 @@ bool IResearchLink::matchesDefinition(VPackSlice const& slice) const {
|
|||
// NOTE: below will not match if 'viewId' is 'id' or 'name',
|
||||
// but ViewIdField should always contain GUID
|
||||
if (!viewId.isString() || !viewId.isEqualString(_viewGuid)) {
|
||||
return false; // IResearch View identifiers of current object and slice do
|
||||
// not match
|
||||
return false; // IResearch View identifiers of current object and slice do not match
|
||||
}
|
||||
|
||||
IResearchLinkMeta other;
|
||||
std::string errorField;
|
||||
|
||||
return other.init(slice, errorField) && _meta == other;
|
||||
return other.init(slice, errorField, &(collection().vocbase())) // for db-server analyzer validation should have already apssed on coordinator (missing analyzer == no match)
|
||||
&& _meta == other;
|
||||
}
|
||||
|
||||
size_t IResearchLink::memory() const {
|
||||
auto size = sizeof(IResearchLink); // includes empty members from parent
|
||||
auto size = sizeof(IResearchLink); // includes empty members from parent
|
||||
|
||||
size += _meta.memory();
|
||||
|
||||
{
|
||||
SCOPED_LOCK(_asyncSelf->mutex()); // '_dataStore' can be asynchronously modified
|
||||
SCOPED_LOCK(_asyncSelf->mutex()); // '_dataStore' can be asynchronously modified
|
||||
|
||||
if (_dataStore) {
|
||||
// FIXME TODO this is incorrect since '_storePersisted' is on disk and not
|
||||
// in memory
|
||||
// FIXME TODO this is incorrect since '_storePersisted' is on disk and not in memory
|
||||
size += directoryMemory(*(_dataStore._directory), id());
|
||||
size += _dataStore._path.native().size() * sizeof(irs::utf8_path::native_char_t);
|
||||
}
|
||||
|
@ -1484,6 +1485,30 @@ size_t IResearchLink::memory() const {
|
|||
return size;
|
||||
}
|
||||
|
||||
arangodb::Result IResearchLink::properties( // get link properties
|
||||
arangodb::velocypack::Builder& builder, // output buffer
|
||||
bool forPersistence // properties for persistance
|
||||
) const {
|
||||
if (!builder.isOpenObject() || !_meta.json(builder, forPersistence)) {
|
||||
return arangodb::Result(TRI_ERROR_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
builder.add(
|
||||
arangodb::StaticStrings::IndexId,
|
||||
arangodb::velocypack::Value(std::to_string(_id))
|
||||
);
|
||||
builder.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(IResearchLinkHelper::type())
|
||||
);
|
||||
builder.add(
|
||||
StaticStrings::ViewIdField,
|
||||
arangodb::velocypack::Value(_viewGuid)
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
arangodb::Result IResearchLink::properties(IResearchViewMeta const& meta) {
|
||||
SCOPED_LOCK(_asyncSelf->mutex()); // '_dataStore' can be asynchronously modified
|
||||
|
||||
|
@ -1747,4 +1772,4 @@ arangodb::Result IResearchLink::unload() {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -113,51 +113,55 @@ class IResearchLink {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief called when the iResearch Link is dropped
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
arangodb::Result drop(); // arangodb::Index override
|
||||
arangodb::Result drop(); // arangodb::Index override
|
||||
|
||||
bool hasBatchInsert() const; // arangodb::Index override
|
||||
bool hasSelectivityEstimate() const; // arangodb::Index override
|
||||
bool hasBatchInsert() const; // arangodb::Index override
|
||||
bool hasSelectivityEstimate() const; // arangodb::Index override
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the identifier for this link
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
TRI_idx_iid_t id() const noexcept { return _id; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief insert an ArangoDB document into an iResearch View using '_meta'
|
||||
/// params
|
||||
/// @brief insert an ArangoDB document into an iResearch View using '_meta' params
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
arangodb::Result insert(arangodb::transaction::Methods& trx,
|
||||
arangodb::LocalDocumentId const& documentId,
|
||||
arangodb::velocypack::Slice const& doc,
|
||||
arangodb::Index::OperationMode mode); // arangodb::Index override
|
||||
|
||||
bool isSorted() const; // arangodb::Index override
|
||||
arangodb::Result insert( // insert document
|
||||
arangodb::transaction::Methods& trx, // transaction
|
||||
arangodb::LocalDocumentId const& documentId, // document identifier
|
||||
arangodb::velocypack::Slice const& doc, // document
|
||||
arangodb::Index::OperationMode mode // insert mode
|
||||
); // arangodb::Index override
|
||||
|
||||
bool isHidden() const; // arangodb::Index override
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the identifier for this link
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
TRI_idx_iid_t id() const noexcept;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief fill and return a jSON description of a IResearchLink object
|
||||
/// elements are appended to an existing object
|
||||
/// @return success or set TRI_set_errno(...) and return false
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool json(arangodb::velocypack::Builder& builder) const;
|
||||
bool isSorted() const; // arangodb::Index override
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief called when the iResearch Link is loaded into memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void load(); // arangodb::Index override
|
||||
void load(); // arangodb::Index override
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief index comparator, used by the coordinator to detect if the specified
|
||||
/// definition is the same as this link
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool matchesDefinition(arangodb::velocypack::Slice const& slice) const; // arangodb::Index override
|
||||
bool matchesDefinition( // matches
|
||||
arangodb::velocypack::Slice const& slice // other definition
|
||||
) const; // arangodb::Index override
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief amount of memory in bytes occupied by this iResearch Link
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
size_t memory() const; // arangodb::Index override
|
||||
size_t memory() const; // arangodb::Index override
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief fill and return a jSON description of a IResearchLink object
|
||||
/// elements are appended to an existing object
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
arangodb::Result properties( // get link properties
|
||||
arangodb::velocypack::Builder& builder, // output buffer
|
||||
bool forPersistence // properties for persistance
|
||||
) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief update runtine data processing properties (not persisted)
|
||||
|
|
|
@ -125,25 +125,27 @@ IResearchLinkCoordinator::IResearchLinkCoordinator(TRI_idx_iid_t id, LogicalColl
|
|||
_sparse = true; // always sparse
|
||||
}
|
||||
|
||||
void IResearchLinkCoordinator::toVelocyPack(
|
||||
arangodb::velocypack::Builder& builder,
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags) const {
|
||||
void IResearchLinkCoordinator::toVelocyPack( // generate definition
|
||||
arangodb::velocypack::Builder& builder, // destination buffer
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags // definition flags
|
||||
) const {
|
||||
if (builder.isOpenObject()) {
|
||||
THROW_ARANGO_EXCEPTION(
|
||||
arangodb::Result(TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("failed to generate link definition for "
|
||||
"arangosearch view Cluster link '") +
|
||||
std::to_string(arangodb::Index::id()) + "'"));
|
||||
THROW_ARANGO_EXCEPTION(arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("failed to generate link definition for arangosearch view Cluster link '") + std::to_string(arangodb::Index::id()) + "'"
|
||||
));
|
||||
}
|
||||
|
||||
auto forPersistence = // definition for persistence
|
||||
arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::Internals);
|
||||
|
||||
builder.openObject();
|
||||
|
||||
if (!json(builder)) {
|
||||
THROW_ARANGO_EXCEPTION(
|
||||
arangodb::Result(TRI_ERROR_INTERNAL,
|
||||
std::string("failed to generate link definition for "
|
||||
"arangosearch view Cluster link '") +
|
||||
std::to_string(arangodb::Index::id()) + "'"));
|
||||
if (!properties(builder, forPersistence).ok()) {
|
||||
THROW_ARANGO_EXCEPTION(arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("failed to generate link definition for arangosearch view Cluster link '") + std::to_string(arangodb::Index::id()) + "'"
|
||||
));
|
||||
}
|
||||
|
||||
if (arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::Figures)) {
|
||||
|
|
|
@ -97,7 +97,7 @@ class IResearchLinkCoordinator final : public arangodb::ClusterIndex, public IRe
|
|||
/// @brief fill and return a JSON description of a IResearchLink object
|
||||
/// @param withFigures output 'figures' section with e.g. memory size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
using Index::toVelocyPack; // for Index::toVelocyPack(bool, unsigned)
|
||||
using Index::toVelocyPack; // for std::shared_ptr<Builder> Index::toVelocyPack(bool, Index::Serialize)
|
||||
virtual void toVelocyPack(arangodb::velocypack::Builder& builder,
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags) const override;
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include "Basics/StaticStrings.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Logger/LogMacros.h"
|
||||
#include "StorageEngine/EngineSelectorFeature.h"
|
||||
#include "StorageEngine/StorageEngine.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/CollectionNameResolver.h"
|
||||
|
@ -47,8 +49,39 @@ namespace {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string const& LINK_TYPE = arangodb::iresearch::DATA_SOURCE_TYPE.name();
|
||||
|
||||
bool createLink(arangodb::LogicalCollection& collection, arangodb::LogicalView const& view,
|
||||
arangodb::velocypack::Slice definition) {
|
||||
arangodb::Result canUseAnalyzers( // validate
|
||||
arangodb::iresearch::IResearchLinkMeta const& meta, // metadata
|
||||
TRI_vocbase_t const& defaultVocbase // default vocbase
|
||||
) {
|
||||
for (auto& entry: meta._analyzers) {
|
||||
if (entry // valid entry
|
||||
&& !arangodb::iresearch::IResearchAnalyzerFeature::canUse(entry->name(), defaultVocbase, arangodb::auth::Level::RO)
|
||||
) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_FORBIDDEN, // code
|
||||
std::string("read access is forbidden to arangosearch analyzer '") + entry->name() + "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& field: meta._fields) {
|
||||
TRI_ASSERT(field.value().get()); // ensured by UniqueHeapInstance constructor
|
||||
auto& entry = field.value();
|
||||
auto res = canUseAnalyzers(*entry, defaultVocbase);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
bool createLink( // create link
|
||||
arangodb::LogicalCollection& collection, // link collection
|
||||
arangodb::LogicalView const& view, // link view
|
||||
arangodb::velocypack::Slice definition // link definition
|
||||
) {
|
||||
bool isNew = false;
|
||||
auto link = collection.createIndex(definition, isNew);
|
||||
LOG_TOPIC_IF(DEBUG, arangodb::iresearch::TOPIC, link)
|
||||
|
@ -57,21 +90,29 @@ bool createLink(arangodb::LogicalCollection& collection, arangodb::LogicalView c
|
|||
return link && isNew;
|
||||
}
|
||||
|
||||
bool createLink(arangodb::LogicalCollection& collection,
|
||||
arangodb::iresearch::IResearchViewCoordinator const& view,
|
||||
arangodb::velocypack::Slice definition) {
|
||||
static const std::function<bool(irs::string_ref const& key)> acceptor =
|
||||
[](irs::string_ref const& key) -> bool {
|
||||
bool createLink( // create link
|
||||
arangodb::LogicalCollection& collection, // link collection
|
||||
arangodb::iresearch::IResearchViewCoordinator const& view, // link view
|
||||
arangodb::velocypack::Slice definition // link definition
|
||||
) {
|
||||
static const std::function<bool(irs::string_ref const& key)> acceptor = [](
|
||||
irs::string_ref const& key // json key
|
||||
)->bool {
|
||||
// ignored fields
|
||||
return key != arangodb::StaticStrings::IndexType &&
|
||||
key != arangodb::iresearch::StaticStrings::ViewIdField;
|
||||
return key != arangodb::StaticStrings::IndexType // type field
|
||||
&& key != arangodb::iresearch::StaticStrings::ViewIdField; // view id field
|
||||
};
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
builder.add(arangodb::StaticStrings::IndexType, arangodb::velocypack::Value(LINK_TYPE));
|
||||
builder.add(arangodb::iresearch::StaticStrings::ViewIdField,
|
||||
arangodb::velocypack::Value(view.guid()));
|
||||
builder.add( // add
|
||||
arangodb::StaticStrings::IndexType, // key
|
||||
arangodb::velocypack::Value(LINK_TYPE) // value
|
||||
);
|
||||
builder.add( // add
|
||||
arangodb::iresearch::StaticStrings::ViewIdField, // key
|
||||
arangodb::velocypack::Value(view.guid()) // value
|
||||
);
|
||||
|
||||
if (!arangodb::iresearch::mergeSliceSkipKeys(builder, definition, acceptor)) {
|
||||
return false;
|
||||
|
@ -81,41 +122,49 @@ bool createLink(arangodb::LogicalCollection& collection,
|
|||
|
||||
arangodb::velocypack::Builder tmp;
|
||||
|
||||
return arangodb::methods::Indexes::ensureIndex(&collection, builder.slice(), true, tmp)
|
||||
.ok();
|
||||
return arangodb::methods::Indexes::ensureIndex( // ensure index
|
||||
&collection, builder.slice(), true, tmp // args
|
||||
).ok();
|
||||
}
|
||||
|
||||
template <typename ViewType>
|
||||
bool dropLink(arangodb::LogicalCollection& collection,
|
||||
arangodb::iresearch::IResearchLink const& link) {
|
||||
// don't need to create an extra transaction inside
|
||||
// arangodb::methods::Indexes::drop(...)
|
||||
template<typename ViewType>
|
||||
bool dropLink( // drop link
|
||||
arangodb::LogicalCollection& collection, // link collection
|
||||
arangodb::iresearch::IResearchLink const& link // link to drop
|
||||
) {
|
||||
// don't need to create an extra transaction inside arangodb::methods::Indexes::drop(...)
|
||||
return collection.dropIndex(link.id());
|
||||
}
|
||||
|
||||
template <>
|
||||
bool dropLink<arangodb::iresearch::IResearchViewCoordinator>(
|
||||
arangodb::LogicalCollection& collection, arangodb::iresearch::IResearchLink const& link) {
|
||||
template<>
|
||||
bool dropLink<arangodb::iresearch::IResearchViewCoordinator>( // drop link
|
||||
arangodb::LogicalCollection& collection, // link collection
|
||||
arangodb::iresearch::IResearchLink const& link // link to drop
|
||||
) {
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
builder.add(arangodb::StaticStrings::IndexId, arangodb::velocypack::Value(link.id()));
|
||||
builder.add( // add
|
||||
arangodb::StaticStrings::IndexId, // key
|
||||
arangodb::velocypack::Value(link.id()) // value
|
||||
);
|
||||
builder.close();
|
||||
|
||||
return arangodb::methods::Indexes::drop(&collection, builder.slice()).ok();
|
||||
}
|
||||
|
||||
template <typename ViewType>
|
||||
arangodb::Result modifyLinks(std::unordered_set<TRI_voc_cid_t>& modified,
|
||||
TRI_vocbase_t& vocbase, ViewType& view,
|
||||
arangodb::velocypack::Slice const& links,
|
||||
std::unordered_set<TRI_voc_cid_t> const& stale = {}) {
|
||||
arangodb::Result modifyLinks( // modify links
|
||||
std::unordered_set<TRI_voc_cid_t>& modified, // modified collection ids
|
||||
ViewType& view, // modified view
|
||||
arangodb::velocypack::Slice const& links, // modified link definitions
|
||||
std::unordered_set<TRI_voc_cid_t> const& stale = {} // stale links
|
||||
) {
|
||||
if (!links.isObject()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string(
|
||||
"error parsing link parameters from json for arangosearch view '") +
|
||||
view.name() + "'");
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("error parsing link parameters from json for arangosearch view '") + view.name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
struct State {
|
||||
|
@ -155,21 +204,42 @@ arangodb::Result modifyLinks(std::unordered_set<TRI_voc_cid_t>& modified,
|
|||
linkModifications.emplace_back(collectionsToLock.size());
|
||||
collectionsToLock.emplace_back(collectionName);
|
||||
|
||||
continue; // only removal requested
|
||||
continue; // only removal requested
|
||||
}
|
||||
|
||||
static const std::function<bool(irs::string_ref const& key)> acceptor =
|
||||
[](irs::string_ref const& key) -> bool {
|
||||
arangodb::velocypack::Builder normalized;
|
||||
|
||||
normalized.openObject();
|
||||
|
||||
auto res = arangodb::iresearch::IResearchLinkHelper::normalize( // normalize to validate analyzer definitions
|
||||
normalized, link, true, view.vocbase() // args
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
normalized.close();
|
||||
link = normalized.slice(); // use normalized definition for index creation
|
||||
|
||||
static const std::function<bool(irs::string_ref const& key)> acceptor = [](
|
||||
irs::string_ref const& key // json key
|
||||
)->bool {
|
||||
// ignored fields
|
||||
return key != arangodb::StaticStrings::IndexType &&
|
||||
key != arangodb::iresearch::StaticStrings::ViewIdField;
|
||||
return key != arangodb::StaticStrings::IndexType // type field
|
||||
&& key != arangodb::iresearch::StaticStrings::ViewIdField; // view id field
|
||||
};
|
||||
arangodb::velocypack::Builder namedJson;
|
||||
|
||||
namedJson.openObject();
|
||||
namedJson.add(arangodb::StaticStrings::IndexType, arangodb::velocypack::Value(LINK_TYPE));
|
||||
namedJson.add(arangodb::iresearch::StaticStrings::ViewIdField,
|
||||
arangodb::velocypack::Value(view.guid()));
|
||||
namedJson.add( // add
|
||||
arangodb::StaticStrings::IndexType, // key
|
||||
arangodb::velocypack::Value(LINK_TYPE) // value
|
||||
);
|
||||
namedJson.add( // add
|
||||
arangodb::iresearch::StaticStrings::ViewIdField, // key
|
||||
arangodb::velocypack::Value(view.guid()) // value
|
||||
);
|
||||
|
||||
if (!arangodb::iresearch::mergeSliceSkipKeys(namedJson, link, acceptor)) {
|
||||
return arangodb::Result(
|
||||
|
@ -183,7 +253,7 @@ arangodb::Result modifyLinks(std::unordered_set<TRI_voc_cid_t>& modified,
|
|||
std::string error;
|
||||
arangodb::iresearch::IResearchLinkMeta linkMeta;
|
||||
|
||||
if (!linkMeta.init(namedJson.slice(), error)) { // analyzers in definition should already be normalized
|
||||
if (!linkMeta.init(namedJson.slice(), error)) { // normalized and validated above via normalize(...)
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error parsing link parameters from json for arangosearch view '") + view.name() + "' collection '" + collectionName + "' error '" + error + "'"
|
||||
|
@ -195,7 +265,8 @@ arangodb::Result modifyLinks(std::unordered_set<TRI_voc_cid_t>& modified,
|
|||
linkDefinitions.emplace_back(std::move(namedJson), std::move(linkMeta));
|
||||
}
|
||||
|
||||
auto trxCtx = arangodb::transaction::StandaloneContext::Create(vocbase);
|
||||
auto trxCtx = // transaction context
|
||||
arangodb::transaction::StandaloneContext::Create(view.vocbase());
|
||||
|
||||
// add removals for any 'stale' links not found in the 'links' definition
|
||||
for (auto& id: stale) {
|
||||
|
@ -212,17 +283,14 @@ arangodb::Result modifyLinks(std::unordered_set<TRI_voc_cid_t>& modified,
|
|||
}
|
||||
|
||||
if (collectionsToLock.empty()) {
|
||||
return arangodb::Result(); // nothing to update
|
||||
return arangodb::Result(); // nothing to update
|
||||
}
|
||||
|
||||
static std::vector<std::string> const EMPTY;
|
||||
arangodb::ExecContextScope scope(
|
||||
arangodb::ExecContext::superuser()); // required to remove links from
|
||||
// non-RW collections
|
||||
arangodb::ExecContextScope scope(arangodb::ExecContext::superuser()); // required to remove links from non-RW collections
|
||||
|
||||
{
|
||||
std::unordered_set<TRI_voc_cid_t> collectionsToRemove; // track removal for potential reindex
|
||||
std::unordered_set<TRI_voc_cid_t> collectionsToUpdate; // track reindex requests
|
||||
std::unordered_set<TRI_voc_cid_t> collectionsToRemove; // track removal for potential reindex
|
||||
std::unordered_set<TRI_voc_cid_t> collectionsToUpdate; // track reindex requests
|
||||
|
||||
// resolve corresponding collection and link
|
||||
for (auto itr = linkModifications.begin(); itr != linkModifications.end();) {
|
||||
|
@ -466,8 +534,8 @@ namespace iresearch {
|
|||
IResearchLinkMeta lhsMeta;
|
||||
IResearchLinkMeta rhsMeta;
|
||||
|
||||
return lhsMeta.init(lhs, errorField) // left side meta valid
|
||||
&& rhsMeta.init(rhs, errorField) // right side meta valid
|
||||
return lhsMeta.init(lhs, errorField) // left side meta valid (for db-server analyzer validation should have already apssed on coordinator)
|
||||
&& rhsMeta.init(rhs, errorField) // right side meta valid (for db-server analyzer validation should have already apssed on coordinator)
|
||||
&& lhsMeta == rhsMeta; // left meta equal right meta
|
||||
}
|
||||
|
||||
|
@ -519,8 +587,6 @@ namespace iresearch {
|
|||
bool isCreation, // definition for index creation
|
||||
TRI_vocbase_t const& vocbase // index vocbase
|
||||
) {
|
||||
UNUSED(isCreation);
|
||||
|
||||
if (!normalized.isOpenObject()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
|
@ -531,17 +597,35 @@ namespace iresearch {
|
|||
std::string error;
|
||||
IResearchLinkMeta meta;
|
||||
|
||||
if (!meta.init(definition, error, IResearchLinkMeta::DEFAULT(), &vocbase)) {
|
||||
// @note: implicit analyzer validation via IResearchLinkMeta done in 2 places:
|
||||
// IResearchLinkHelper::normalize(...) if creating via collection API
|
||||
// ::modifyLinks(...) (via call to normalize(...) prior to getting
|
||||
// superuser) if creating via IResearchLinkHelper API
|
||||
if (!meta.init(definition, error, &vocbase)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error parsing arangosearch link parameters from json: ") + error
|
||||
);
|
||||
}
|
||||
|
||||
auto res = canUseAnalyzers(meta, vocbase); // same validation as in modifyLinks(...) for Views API
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType, arangodb::velocypack::Value(LINK_TYPE)
|
||||
);
|
||||
|
||||
// copy over IResearch Link identifier
|
||||
if (definition.hasKey(arangodb::StaticStrings::IndexId)) {
|
||||
normalized.add( // preserve field
|
||||
arangodb::StaticStrings::IndexId, // key
|
||||
definition.get(arangodb::StaticStrings::IndexId) // value
|
||||
);
|
||||
}
|
||||
|
||||
// copy over IResearch View identifier
|
||||
if (definition.hasKey(StaticStrings::ViewIdField)) {
|
||||
normalized.add(
|
||||
|
@ -549,7 +633,14 @@ namespace iresearch {
|
|||
);
|
||||
}
|
||||
|
||||
return meta.json(normalized)
|
||||
if (definition.hasKey(arangodb::StaticStrings::IndexInBackground)) {
|
||||
normalized.add( // preserve field
|
||||
arangodb::StaticStrings::IndexInBackground, // key
|
||||
definition.get(arangodb::StaticStrings::IndexInBackground) // value
|
||||
);
|
||||
}
|
||||
|
||||
return meta.json(normalized, isCreation) // 'isCreation' is set when forPersistence
|
||||
? arangodb::Result()
|
||||
: arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
|
@ -610,18 +701,13 @@ namespace iresearch {
|
|||
IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
|
||||
if (!linkDefinition.isNull() && !meta.init(linkDefinition, errorField)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
errorField.empty()
|
||||
? (std::string(
|
||||
"while validating arangosearch link definition, error: "
|
||||
"invalid link definition for collection '") +
|
||||
collectionName.copyString() + "': " + linkDefinition.toString())
|
||||
: (std::string(
|
||||
"while validating arangosearch link definition, error: "
|
||||
"invalid link definition for collection '") +
|
||||
collectionName.copyString() + "' error in attribute: " + errorField));
|
||||
if (!linkDefinition.isNull() && !meta.init(linkDefinition, errorField)) { // for db-server analyzer validation should have already apssed on coordinator
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
errorField.empty()
|
||||
? (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "': " + linkDefinition.toString())
|
||||
: (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "' error in attribute: " + errorField)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -649,55 +735,61 @@ namespace iresearch {
|
|||
}
|
||||
|
||||
/*static*/ arangodb::Result IResearchLinkHelper::updateLinks(
|
||||
std::unordered_set<TRI_voc_cid_t>& modified, TRI_vocbase_t& vocbase,
|
||||
arangodb::LogicalView& view, arangodb::velocypack::Slice const& links,
|
||||
std::unordered_set<TRI_voc_cid_t>& modified,
|
||||
arangodb::LogicalView& view,
|
||||
arangodb::velocypack::Slice const& links,
|
||||
std::unordered_set<TRI_voc_cid_t> const& stale /*= {}*/
|
||||
) {
|
||||
LOG_TOPIC(TRACE, arangodb::iresearch::TOPIC)
|
||||
<< "beginning IResearchLinkHelper::updateLinks";
|
||||
try {
|
||||
if (arangodb::ServerState::instance()->isCoordinator()) {
|
||||
return modifyLinks<IResearchViewCoordinator>(modified, vocbase,
|
||||
LogicalView::cast<IResearchViewCoordinator>(view),
|
||||
links, stale);
|
||||
return modifyLinks<IResearchViewCoordinator>( // modify
|
||||
modified, // modified cids
|
||||
LogicalView::cast<IResearchViewCoordinator>(view), // modified view
|
||||
links, // link modifications
|
||||
stale // stale links
|
||||
);
|
||||
}
|
||||
|
||||
return modifyLinks<IResearchView>(modified, vocbase,
|
||||
LogicalView::cast<IResearchView>(view), links, stale);
|
||||
return modifyLinks<IResearchView>( // modify
|
||||
modified, // modified cids
|
||||
LogicalView::cast<IResearchView>(view), // modified view
|
||||
links, // link modifications
|
||||
stale // stale links
|
||||
);
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while updating links for arangosearch view '"
|
||||
<< view.name() << "': " << e.code() << " " << e.what();
|
||||
<< "caught exception while updating links for arangosearch view '" << view.name() << "': " << e.code() << " " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
e.code(), std::string("error updating links for arangosearch view '") +
|
||||
view.name() + "'");
|
||||
e.code(),
|
||||
std::string("error updating links for arangosearch view '") + view.name() + "'"
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while updating links for arangosearch view '"
|
||||
<< view.name() << "': " << e.what();
|
||||
<< "caught exception while updating links for arangosearch view '" << view.name() << "': " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating links for arangosearch view '") +
|
||||
view.name() + "'");
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating links for arangosearch view '") + view.name() + "'"
|
||||
);
|
||||
} catch (...) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while updating links for arangosearch view '"
|
||||
<< view.name() << "'";
|
||||
<< "caught exception while updating links for arangosearch view '" << view.name() << "'";
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating links for arangosearch view '") +
|
||||
view.name() + "'");
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating links for arangosearch view '") + view.name() + "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace iresearch
|
||||
} // namespace arangodb
|
||||
} // iresearch
|
||||
} // arangodb
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
|
|
|
@ -56,24 +56,33 @@ struct IResearchLinkHelper {
|
|||
/// @brief compare two link definitions for equivalience if used to create a
|
||||
/// link instance
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static bool equal(arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs);
|
||||
static bool equal( // equal definition
|
||||
arangodb::velocypack::Slice const& lhs, // left hand side
|
||||
arangodb::velocypack::Slice const& rhs // right hand side
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finds link between specified collection and view with the given id
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static std::shared_ptr<IResearchLink> find(arangodb::LogicalCollection const& collection,
|
||||
TRI_idx_iid_t id);
|
||||
static std::shared_ptr<IResearchLink> find( // find link
|
||||
arangodb::LogicalCollection const& collection, // collection to search
|
||||
TRI_idx_iid_t id // index to find
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finds first link between specified collection and view
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static std::shared_ptr<IResearchLink> find(arangodb::LogicalCollection const& collection,
|
||||
LogicalView const& view);
|
||||
static std::shared_ptr<IResearchLink> find( // find link
|
||||
arangodb::LogicalCollection const& collection, // collection to search
|
||||
LogicalView const& view // link for view to find
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate and copy required fields from the 'definition' into
|
||||
/// 'normalized'
|
||||
/// @note missing analyzers will be created if exceuted on db-server
|
||||
/// @note engine == nullptr then SEGFAULT in Methods constructor during insert
|
||||
/// @note true == inRecovery() then AnalyzerFeature will not allow persistence
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::Result normalize( // normalize definition
|
||||
arangodb::velocypack::Builder& normalized, // normalized definition (out-param)
|
||||
|
@ -94,34 +103,40 @@ struct IResearchLinkHelper {
|
|||
/// * collection permissions
|
||||
/// * valid link meta
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::Result validateLinks(TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& links);
|
||||
static arangodb::Result validateLinks( // validate links
|
||||
TRI_vocbase_t& vocbase, // link vocbase
|
||||
arangodb::velocypack::Slice const& links // links to validate
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief visits all links in a collection
|
||||
/// @return full visitation compleated
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static bool visit(arangodb::LogicalCollection const& collection,
|
||||
std::function<bool(IResearchLink& link)> const& visitor);
|
||||
static bool visit( // visit links
|
||||
arangodb::LogicalCollection const& collection, // collection to visit
|
||||
std::function<bool(IResearchLink& link)> const& visitor // visitor to call
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief updates the collections in 'vocbase' to match the specified
|
||||
/// IResearchLink definitions
|
||||
/// @param modified set of modified collection IDs
|
||||
/// @param viewId the view to associate created links with
|
||||
/// @param view the view to associate created links with
|
||||
/// @param links the link modification definitions, null link == link removal
|
||||
/// @param stale links to remove if there is no creation definition in 'links'
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::Result updateLinks(std::unordered_set<TRI_voc_cid_t>& modified,
|
||||
TRI_vocbase_t& vocbase, arangodb::LogicalView& view,
|
||||
arangodb::velocypack::Slice const& links,
|
||||
std::unordered_set<TRI_voc_cid_t> const& stale = {});
|
||||
static arangodb::Result updateLinks( // update links
|
||||
std::unordered_set<TRI_voc_cid_t>& modified, // odified cids
|
||||
arangodb::LogicalView& view, // modified view
|
||||
arangodb::velocypack::Slice const& links, // link definitions to apply
|
||||
std::unordered_set<TRI_voc_cid_t> const& stale = {} //stale view links
|
||||
);
|
||||
|
||||
private:
|
||||
IResearchLinkHelper() = delete;
|
||||
}; // IResearchLinkHelper
|
||||
}; // IResearchLinkHelper
|
||||
|
||||
} // namespace iresearch
|
||||
} // namespace arangodb
|
||||
} // iresearch
|
||||
} // arangodb
|
||||
|
||||
#endif // ARANGODB_IRESEARCH__IRESEARCH_LINK_HELPER_H
|
||||
#endif // ARANGODB_IRESEARCH__IRESEARCH_LINK_HELPER_H
|
||||
|
|
|
@ -176,8 +176,8 @@ bool IResearchLinkMeta::operator!=(IResearchLinkMeta const& other) const noexcep
|
|||
bool IResearchLinkMeta::init( // initialize meta
|
||||
arangodb::velocypack::Slice const& slice, // definition
|
||||
std::string& errorField, // field causing error (out-param)
|
||||
IResearchLinkMeta const& defaults /*= DEFAULT()*/, // inherited defaults
|
||||
TRI_vocbase_t const* defaultVocbase /*= nullptr*/, // fallback vocbase
|
||||
IResearchLinkMeta const& defaults /*= DEFAULT()*/, // inherited defaults
|
||||
Mask* mask /*= nullptr*/ // initialized fields (out-param)
|
||||
) {
|
||||
if (!slice.isObject()) {
|
||||
|
@ -213,42 +213,157 @@ bool IResearchLinkMeta::init( // initialize meta
|
|||
_analyzers.clear(); // reset to match read values exactly
|
||||
|
||||
for (arangodb::velocypack::ArrayIterator itr(field); itr.valid(); ++itr) {
|
||||
auto key = *itr;
|
||||
auto value = *itr;
|
||||
|
||||
if (!key.isString()) {
|
||||
errorField = fieldName + "=>[" +
|
||||
arangodb::basics::StringUtils::itoa(itr.index()) + "]";
|
||||
if (value.isString()) {
|
||||
auto name = value.copyString();
|
||||
|
||||
if (defaultVocbase) {
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
arangodb::SystemDatabaseFeature // featue type
|
||||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
|
||||
if (sysVocbase) {
|
||||
name = IResearchAnalyzerFeature::normalize( // normalize
|
||||
name, *defaultVocbase, *sysVocbase // args
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
auto analyzer = analyzers->get(name);
|
||||
|
||||
if (!analyzer) {
|
||||
errorField = fieldName + "=>" + std::string(name);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// inserting two identical values for name is a poor-man's boost multiplier
|
||||
_analyzers.emplace_back(analyzer);
|
||||
|
||||
continue; //process next analyzer
|
||||
}
|
||||
|
||||
if (!value.isObject()) {
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto name = getStringRef(key);
|
||||
IResearchAnalyzerFeature::AnalyzerPool::ptr analyzer;
|
||||
std::string name;
|
||||
|
||||
// get analyzer or placeholder
|
||||
if (defaultVocbase) {
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
arangodb::SystemDatabaseFeature // featue type
|
||||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
{
|
||||
// required string value
|
||||
static const std::string subFieldName("name");
|
||||
|
||||
if (sysVocbase) {
|
||||
analyzer = analyzers->ensure(IResearchAnalyzerFeature::normalize( // normalize
|
||||
name, *defaultVocbase, *sysVocbase // args
|
||||
));
|
||||
if (!value.hasKey(subFieldName) // missing required filed
|
||||
|| !value.get(subFieldName).isString()) {
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]=>" + subFieldName;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
name = value.get(subFieldName).copyString();
|
||||
|
||||
if (defaultVocbase) {
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
arangodb::SystemDatabaseFeature // featue type
|
||||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
|
||||
if (sysVocbase) {
|
||||
name = IResearchAnalyzerFeature::normalize( // normalize
|
||||
name, *defaultVocbase, *sysVocbase // args
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
analyzer = analyzers->ensure(name); // verbatim (assume already normalized)
|
||||
}
|
||||
|
||||
irs::string_ref type;
|
||||
|
||||
{
|
||||
// required string value
|
||||
static const std::string subFieldName("type");
|
||||
|
||||
if (!value.hasKey(subFieldName) // missing required filed
|
||||
|| !value.get(subFieldName).isString()) {
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]=>" + subFieldName;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
type = getStringRef(value.get(subFieldName));
|
||||
}
|
||||
|
||||
irs::string_ref properties;
|
||||
|
||||
{
|
||||
// optional string value
|
||||
static const std::string subFieldName("properties");
|
||||
|
||||
if (value.hasKey(subFieldName)) {
|
||||
auto subField = value.get(subFieldName);
|
||||
|
||||
if (!subField.isString()) {
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]=>" + subFieldName;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
properties = getStringRef(subField);
|
||||
}
|
||||
}
|
||||
|
||||
irs::flags features;
|
||||
|
||||
{
|
||||
// optional string list
|
||||
static const std::string subFieldName("features");
|
||||
|
||||
if (value.hasKey(subFieldName)) {
|
||||
auto subField = value.get(subFieldName);
|
||||
|
||||
if (!subField.isArray()) {
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]=>" + subFieldName;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (arangodb::velocypack::ArrayIterator subItr(subField);
|
||||
subItr.valid();
|
||||
++subItr) {
|
||||
auto subValue = *subItr;
|
||||
|
||||
if (!subValue.isString()) {
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]=>" + subFieldName + "=>[" + std::to_string(subItr.index()) + + "]";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto featureName = getStringRef(subValue);
|
||||
auto* feature = irs::attribute::type_id::get(featureName);
|
||||
|
||||
if (!feature) {
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]=>" + subFieldName + "=>" + std::string(featureName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
features.add(*feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto analyzer = analyzers->get(name, type, properties, features); // get analyzer potentially creating it (e.g. on db-server)
|
||||
|
||||
if (!analyzer) {
|
||||
errorField = fieldName + "=>" + std::string(name);
|
||||
errorField = fieldName + "=>[" + std::to_string(itr.index()) + "]";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// inserting two identical values for name is a poor-man's boost
|
||||
// multiplier
|
||||
// inserting two identical values for name is a poor-man's boost multiplier
|
||||
_analyzers.emplace_back(analyzer);
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +490,7 @@ bool IResearchLinkMeta::init( // initialize meta
|
|||
|
||||
std::string childErrorField;
|
||||
|
||||
if (!_fields[name]->init(value, errorField, subDefaults, defaultVocbase)) {
|
||||
if (!_fields[name]->init(value, errorField, defaultVocbase, subDefaults)) {
|
||||
errorField = fieldName + "=>" + name + "=>" + childErrorField;
|
||||
|
||||
return false;
|
||||
|
@ -389,6 +504,7 @@ bool IResearchLinkMeta::init( // initialize meta
|
|||
|
||||
bool IResearchLinkMeta::json( // append meta jSON
|
||||
arangodb::velocypack::Builder& builder, // output buffer (out-param)
|
||||
bool writeAnalyzerDefinition, // output fill analyzer definition instead of just name
|
||||
IResearchLinkMeta const* ignoreEqual /*= nullptr*/, // values to ignore if equal
|
||||
TRI_vocbase_t const* defaultVocbase /*= nullptr*/, // fallback vocbase
|
||||
Mask const* mask /*= nullptr*/ // values to ignore always
|
||||
|
@ -408,6 +524,8 @@ bool IResearchLinkMeta::json( // append meta jSON
|
|||
continue; // skip null analyzers
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if (defaultVocbase) {
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
arangodb::SystemDatabaseFeature // feature type
|
||||
|
@ -418,14 +536,35 @@ bool IResearchLinkMeta::json( // append meta jSON
|
|||
return false;
|
||||
}
|
||||
|
||||
analyzersBuilder.add(arangodb::velocypack::Value(
|
||||
IResearchAnalyzerFeature::normalize( // normalize
|
||||
entry->name(), *defaultVocbase, *sysVocbase, false // args
|
||||
) // normalized value
|
||||
));
|
||||
name = IResearchAnalyzerFeature::normalize( // normalize
|
||||
entry->name(), *defaultVocbase, *sysVocbase, false // args
|
||||
);
|
||||
} else {
|
||||
analyzersBuilder.add(arangodb::velocypack::Value(entry->name())); // verbatim (assume already normalized)
|
||||
name = entry->name(); // verbatim (assume already normalized)
|
||||
}
|
||||
|
||||
if (!writeAnalyzerDefinition) {
|
||||
analyzersBuilder.add(arangodb::velocypack::Value(std::move(name)));
|
||||
|
||||
continue; // nothing else to output for analyzer
|
||||
}
|
||||
|
||||
analyzersBuilder.openObject();
|
||||
analyzersBuilder.add("name", arangodb::velocypack::Value(name));
|
||||
analyzersBuilder.add("type", toValuePair(entry->type()));
|
||||
analyzersBuilder.add("properties", toValuePair(entry->properties()));
|
||||
analyzersBuilder.add(
|
||||
"features", // key
|
||||
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Array) // value
|
||||
);
|
||||
|
||||
for (auto& feature: entry->features()) {
|
||||
TRI_ASSERT(feature); // has to be non-nullptr
|
||||
analyzersBuilder.add(toValuePair(feature->name()));
|
||||
}
|
||||
|
||||
analyzersBuilder.close();
|
||||
analyzersBuilder.close();
|
||||
}
|
||||
|
||||
analyzersBuilder.close();
|
||||
|
@ -447,7 +586,7 @@ bool IResearchLinkMeta::json( // append meta jSON
|
|||
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Object)
|
||||
);
|
||||
|
||||
if (!entry.value()->json(fieldsBuilder, &subDefaults, defaultVocbase, &fieldMask)) {
|
||||
if (!entry.value()->json(fieldsBuilder, writeAnalyzerDefinition, &subDefaults, defaultVocbase, &fieldMask)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -123,8 +123,8 @@ struct IResearchLinkMeta {
|
|||
bool init( // initialize meta
|
||||
arangodb::velocypack::Slice const& slice, // definition
|
||||
std::string& errorField, // field causing error (out-param)
|
||||
IResearchLinkMeta const& defaults = DEFAULT(), // inherited defaults
|
||||
TRI_vocbase_t const* defaultVocbase = nullptr, // fallback vocbase
|
||||
IResearchLinkMeta const& defaults = DEFAULT(), // inherited defaults
|
||||
Mask* mask = nullptr // initialized fields (out-param)
|
||||
);
|
||||
|
||||
|
@ -139,6 +139,7 @@ struct IResearchLinkMeta {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool json( // append meta jSON
|
||||
arangodb::velocypack::Builder& builder, // output buffer (out-param)
|
||||
bool writeAnalyzerDefinition, // output full analyzer definition instead of just name
|
||||
IResearchLinkMeta const* ignoreEqual = nullptr, // values to ignore if equal
|
||||
TRI_vocbase_t const* defaultVocbase = nullptr, // fallback vocbase
|
||||
Mask const* mask = nullptr // values to ignore always
|
||||
|
|
|
@ -134,24 +134,27 @@ IResearchMMFilesLink::IResearchMMFilesLink(TRI_idx_iid_t iid,
|
|||
return factory;
|
||||
}
|
||||
|
||||
void IResearchMMFilesLink::toVelocyPack(arangodb::velocypack::Builder& builder,
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags) const {
|
||||
void IResearchMMFilesLink::toVelocyPack( // generate definition
|
||||
arangodb::velocypack::Builder& builder, // destination buffer
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags // definition flags
|
||||
) const {
|
||||
if (builder.isOpenObject()) {
|
||||
THROW_ARANGO_EXCEPTION(
|
||||
arangodb::Result(TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("failed to generate link definition for "
|
||||
"arangosearch view MMFiles link '") +
|
||||
std::to_string(arangodb::Index::id()) + "'"));
|
||||
THROW_ARANGO_EXCEPTION(arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("failed to generate link definition for arangosearch view MMFiles link '") + std::to_string(arangodb::Index::id()) + "'"
|
||||
));
|
||||
}
|
||||
|
||||
auto forPersistence = // definition for persistence
|
||||
arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::Internals);
|
||||
|
||||
builder.openObject();
|
||||
|
||||
if (!json(builder)) {
|
||||
THROW_ARANGO_EXCEPTION(
|
||||
arangodb::Result(TRI_ERROR_INTERNAL,
|
||||
std::string("failed to generate link definition for "
|
||||
"arangosearch view MMFiles link '") +
|
||||
std::to_string(arangodb::Index::id()) + "'"));
|
||||
if (!properties(builder, forPersistence).ok()) {
|
||||
THROW_ARANGO_EXCEPTION(arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("failed to generate link definition for arangosearch view MMFiles link '") + std::to_string(arangodb::Index::id()) + "'"
|
||||
));
|
||||
}
|
||||
|
||||
if (arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::Figures)) {
|
||||
|
|
|
@ -107,7 +107,7 @@ class IResearchMMFilesLink final : public arangodb::MMFilesIndex, public IResear
|
|||
/// @brief fill and return a JSON description of a IResearchLink object
|
||||
/// @param withFigures output 'figures' section with e.g. memory size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
using Index::toVelocyPack; // for Index::toVelocyPack(bool, unsigned)
|
||||
using Index::toVelocyPack; // for std::shared_ptr<Builder> Index::toVelocyPack(bool, Index::Serialize)
|
||||
virtual void toVelocyPack(arangodb::velocypack::Builder& builder,
|
||||
std::underlying_type<arangodb::Index::Serialize>::type) const override;
|
||||
|
||||
|
|
|
@ -214,24 +214,27 @@ IResearchRocksDBLink::IResearchRocksDBLink(TRI_idx_iid_t iid,
|
|||
return factory;
|
||||
}
|
||||
|
||||
void IResearchRocksDBLink::toVelocyPack(arangodb::velocypack::Builder& builder,
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags) const {
|
||||
void IResearchRocksDBLink::toVelocyPack( // generate definition
|
||||
arangodb::velocypack::Builder& builder, // destination buffer
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags // definition flags
|
||||
) const {
|
||||
if (builder.isOpenObject()) {
|
||||
THROW_ARANGO_EXCEPTION(
|
||||
arangodb::Result(TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("failed to generate link definition for "
|
||||
"arangosearch view RocksDB link '") +
|
||||
std::to_string(arangodb::Index::id()) + "'"));
|
||||
THROW_ARANGO_EXCEPTION(arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("failed to generate link definition for arangosearch view RocksDB link '") + std::to_string(arangodb::Index::id()) + "'"
|
||||
));
|
||||
}
|
||||
|
||||
auto forPersistence = // definition for persistence
|
||||
arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::Internals);
|
||||
|
||||
builder.openObject();
|
||||
|
||||
if (!json(builder)) {
|
||||
THROW_ARANGO_EXCEPTION(
|
||||
arangodb::Result(TRI_ERROR_INTERNAL,
|
||||
std::string("failed to generate link definition for "
|
||||
"arangosearch view RocksDB link '") +
|
||||
std::to_string(arangodb::Index::id()) + "'"));
|
||||
if (!properties(builder, forPersistence).ok()) {
|
||||
THROW_ARANGO_EXCEPTION(arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("failed to generate link definition for arangosearch view RocksDB link '") + std::to_string(arangodb::Index::id()) + "'"
|
||||
));
|
||||
}
|
||||
|
||||
if (arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::Internals)) {
|
||||
|
|
|
@ -101,7 +101,7 @@ class IResearchRocksDBLink final : public arangodb::RocksDBIndex, public IResear
|
|||
/// @brief fill and return a JSON description of a IResearchLink object
|
||||
/// @param withFigures output 'figures' section with e.g. memory size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
using Index::toVelocyPack; // for Index::toVelocyPack(bool, unsigned)
|
||||
using Index::toVelocyPack; // for std::shared_ptr<Builder> Index::toVelocyPack(bool, Index::Serialize)
|
||||
virtual void toVelocyPack(arangodb::velocypack::Builder& builder,
|
||||
std::underlying_type<arangodb::Index::Serialize>::type flags) const override;
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ void ensureLink(arangodb::DatabaseFeature& db,
|
|||
|
||||
json.openObject();
|
||||
|
||||
if (!link->json(json)) {
|
||||
if (!link->properties(json, true).ok()) { // link definition used for recreation and persistence
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failed to generate jSON definition for link '" << iid
|
||||
<< "' to the collection '" << cid << "' in the database '" << dbId;
|
||||
|
|
|
@ -172,31 +172,24 @@ struct IResearchView::ViewFactory : public arangodb::ViewFactory {
|
|||
try {
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
|
||||
res = IResearchLinkHelper::updateLinks(collections, vocbase, *impl, links);
|
||||
res = IResearchLinkHelper::updateLinks(collections, *impl, links);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to create links while creating arangosearch view '"
|
||||
<< impl->name() << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
<< "failed to create links while creating arangosearch view '" << impl->name() << "': " << res.errorNumber() << " " << res.errorMessage();
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating "
|
||||
"arangosearch view '"
|
||||
<< impl->name() << "': " << e.code() << " " << e.what();
|
||||
<< "caught exception while creating links while creating arangosearch view '" << impl->name() << "': " << e.code() << " " << e.what();
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating "
|
||||
"arangosearch view '"
|
||||
<< impl->name() << "': " << e.what();
|
||||
<< "caught exception while creating links while creating arangosearch view '" << impl->name() << "': " << e.what();
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating links while creating "
|
||||
"arangosearch view '"
|
||||
<< impl->name() << "'";
|
||||
<< "caught exception while creating links while creating arangosearch view '" << impl->name() << "'";
|
||||
}
|
||||
|
||||
view = impl;
|
||||
|
@ -433,7 +426,7 @@ arangodb::Result IResearchView::appendVelocyPackImpl( // append JSON
|
|||
|
||||
linkBuilder.openObject();
|
||||
|
||||
if (!link->json(linkBuilder)) {
|
||||
if (!link->properties(linkBuilder, false).ok()) { // link definitions are not output if forPersistence
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to generate json for arangosearch link '" << link->id() << "' while generating json for arangosearch view '" << name() << "'";
|
||||
|
||||
|
@ -544,24 +537,28 @@ arangodb::Result IResearchView::dropImpl() {
|
|||
|
||||
{
|
||||
if (!_updateLinksLock.try_lock()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_FAILED, // FIXME use specific error code
|
||||
std::string("failed to remove arangosearch view '") + name());
|
||||
// FIXME use specific error code
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_FAILED, //code
|
||||
std::string("failed to remove arangosearch view '") + name() // message
|
||||
);
|
||||
}
|
||||
|
||||
ADOPT_SCOPED_LOCK_NAMED(_updateLinksLock, lock);
|
||||
|
||||
res = IResearchLinkHelper::updateLinks(collections, vocbase(), *this,
|
||||
arangodb::velocypack::Slice::emptyObjectSlice(),
|
||||
stale);
|
||||
res = IResearchLinkHelper::updateLinks( // update links
|
||||
collections, // modified collection ids
|
||||
*this, // modified view
|
||||
arangodb::velocypack::Slice::emptyObjectSlice(), // link definitions to apply
|
||||
stale // stale links
|
||||
);
|
||||
}
|
||||
|
||||
if (!res.ok()) {
|
||||
return arangodb::Result(
|
||||
res.errorNumber(),
|
||||
std::string(
|
||||
"failed to remove links while removing arangosearch view '") +
|
||||
name() + "': " + res.errorMessage());
|
||||
return arangodb::Result( // result
|
||||
res.errorNumber(), // code
|
||||
std::string("failed to remove links while removing arangosearch view '") + name() + "': " + res.errorMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1036,71 +1033,68 @@ arangodb::Result IResearchView::updateProperties(arangodb::velocypack::Slice con
|
|||
|
||||
// ...........................................................................
|
||||
// update links if requested (on a best-effort basis)
|
||||
// indexing of collections is done in different threads so no locks can be
|
||||
// held and rollback is not possible as a result it's also possible for
|
||||
// links to be simultaneously modified via a different callflow (e.g. from
|
||||
// collections)
|
||||
// indexing of collections is done in different threads so no locks can be held and rollback is not possible
|
||||
// as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections)
|
||||
// ...........................................................................
|
||||
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
|
||||
if (partialUpdate) {
|
||||
mtx.unlock(); // release lock
|
||||
mtx.unlock(); // release lock
|
||||
|
||||
SCOPED_LOCK(_updateLinksLock);
|
||||
|
||||
return IResearchLinkHelper::updateLinks(collections, vocbase(), *this, links);
|
||||
return IResearchLinkHelper::updateLinks(collections, *this, links);
|
||||
}
|
||||
|
||||
std::unordered_set<TRI_voc_cid_t> stale;
|
||||
|
||||
for (auto& entry : _links) {
|
||||
for (auto& entry: _links) {
|
||||
stale.emplace(entry.first);
|
||||
}
|
||||
|
||||
mtx.unlock(); // release lock
|
||||
mtx.unlock(); // release lock
|
||||
|
||||
SCOPED_LOCK(_updateLinksLock);
|
||||
|
||||
return IResearchLinkHelper::updateLinks(collections, vocbase(), *this, links, stale);
|
||||
return IResearchLinkHelper::updateLinks(collections, *this, links, stale);
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "caught exception while updating properties for arangosearch view '"
|
||||
<< name() << "': " << e.code() << " " << e.what();
|
||||
<< "caught exception while updating properties for arangosearch view '" << name() << "': " << e.code() << " " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
e.code(),
|
||||
std::string("error updating properties for arangosearch view '") +
|
||||
name() + "'");
|
||||
e.code(),
|
||||
std::string("error updating properties for arangosearch view '") + name() + "'"
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "caught exception while updating properties for arangosearch view '"
|
||||
<< name() << "': " << e.what();
|
||||
<< "caught exception while updating properties for arangosearch view '" << name() << "': " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating properties for arangosearch view '") +
|
||||
name() + "'");
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating properties for arangosearch view '") + name() + "'"
|
||||
);
|
||||
} catch (...) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "caught exception while updating properties for arangosearch view '"
|
||||
<< name() << "'";
|
||||
<< "caught exception while updating properties for arangosearch view '" << name() << "'";
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating properties for arangosearch view '") +
|
||||
name() + "'");
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error updating properties for arangosearch view '") + name() + "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool IResearchView::visitCollections(LogicalView::CollectionVisitor const& visitor) const {
|
||||
ReadMutex mutex(_mutex); // '_links' can be asynchronously modified
|
||||
bool IResearchView::visitCollections( // visit collections
|
||||
LogicalView::CollectionVisitor const& visitor // visitor to call
|
||||
) const {
|
||||
ReadMutex mutex(_mutex); // '_links' can be asynchronously modified
|
||||
SCOPED_LOCK(mutex);
|
||||
|
||||
for (auto& entry : _links) {
|
||||
for (auto& entry: _links) {
|
||||
if (!visitor(entry.first)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ struct IResearchViewCoordinator::ViewFactory : public arangodb::ViewFactory {
|
|||
try {
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
|
||||
res = IResearchLinkHelper::updateLinks(collections, vocbase, *impl, links);
|
||||
res = IResearchLinkHelper::updateLinks(collections, *impl, links);
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
|
@ -437,10 +437,12 @@ arangodb::Result IResearchViewCoordinator::properties(velocypack::Slice const& s
|
|||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
|
||||
if (partialUpdate) {
|
||||
return IResearchLinkHelper::updateLinks(collections, vocbase(), *this, links);
|
||||
return IResearchLinkHelper::updateLinks(collections, *this, links);
|
||||
}
|
||||
|
||||
return IResearchLinkHelper::updateLinks(collections, vocbase(), *this, links, currentCids);
|
||||
return IResearchLinkHelper::updateLinks( // update links
|
||||
collections, *this, links, currentCids // args
|
||||
);
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "caught exception while updating properties for arangosearch view '"
|
||||
|
@ -507,7 +509,9 @@ Result IResearchViewCoordinator::dropImpl() {
|
|||
}
|
||||
|
||||
std::unordered_set<TRI_voc_cid_t> collections;
|
||||
auto res = IResearchLinkHelper::updateLinks(collections, vocbase(), *this,
|
||||
auto res = IResearchLinkHelper::updateLinks( // update links
|
||||
collections, // modified collections
|
||||
*this, // view
|
||||
arangodb::velocypack::Slice::emptyObjectSlice(),
|
||||
currentCids);
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ bool optimizeSearchCondition(IResearchViewNode& viewNode, Query& query, Executio
|
|||
auto const conditionValid =
|
||||
!searchCondition.root() ||
|
||||
FilterFactory::filter(nullptr,
|
||||
{nullptr, nullptr, nullptr, nullptr, &viewNode.outVariable()},
|
||||
{ query.trx(), nullptr, nullptr, nullptr, &viewNode.outVariable() },
|
||||
*searchCondition.root());
|
||||
|
||||
if (!conditionValid) {
|
||||
|
@ -308,4 +308,4 @@ void scatterViewInClusterRule(arangodb::aql::Optimizer* opt,
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -23,16 +23,6 @@
|
|||
#ifndef APPLICATION_FEATURES_DATABASE_FEATURE_H
|
||||
#define APPLICATION_FEATURES_DATABASE_FEATURE_H 1
|
||||
|
||||
#if !defined(USE_CATCH_TESTS) && !defined(EXPAND_APPLICATION_FEATURES_DATABASE_FEATURE_H)
|
||||
#define DO_EXPAND_APPLICATION_FEATURES_DATABASE_FEATURE_H(VAL) VAL ## 1
|
||||
#define EXPAND_APPLICATION_FEATURES_DATABASE_FEATURE_H(VAL) DO_EXPAND_APPLICATION_FEATURES_DATABASE_FEATURE_H(VAL)
|
||||
#if defined(TEST_VIRTUAL) && (EXPAND_APPLICATION_FEATURES_DATABASE_FEATURE_H(TEST_VIRTUAL) != 1)
|
||||
#define USE_CATCH_TESTS
|
||||
#endif
|
||||
#undef EXPAND_APPLICATION_FEATURES_DATABASE_FEATURE_H
|
||||
#undef DO_EXPAND_APPLICATION_FEATURES_DATABASE_FEATURE_H
|
||||
#endif
|
||||
|
||||
#include "ApplicationFeatures/ApplicationFeature.h"
|
||||
#include "Basics/DataProtector.h"
|
||||
#include "Basics/Mutex.h"
|
||||
|
@ -91,7 +81,7 @@ class DatabaseFeature : public application_features::ApplicationFeature {
|
|||
void unprepare() override final;
|
||||
|
||||
// used by catch tests
|
||||
#ifdef USE_CATCH_TESTS
|
||||
#ifdef ARANGODB_USE_CATCH_TESTS
|
||||
inline int loadDatabases(velocypack::Slice const& databases) {
|
||||
return iterateDatabases(databases);
|
||||
}
|
||||
|
|
|
@ -235,11 +235,6 @@ void methods::Upgrade::registerTasks() {
|
|||
/*system*/ Flags::DATABASE_EXCEPT_SYSTEM,
|
||||
/*cluster*/ Flags::CLUSTER_NONE | Flags::CLUSTER_COORDINATOR_GLOBAL,
|
||||
/*database*/ DATABASE_INIT, &UpgradeTasks::addDefaultUserOther);
|
||||
addTask("setupAnalyzers", "setup _iresearch_analyzers collection",
|
||||
/*system*/ Flags::DATABASE_SYSTEM,
|
||||
/*cluster*/ Flags::CLUSTER_NONE | Flags::CLUSTER_COORDINATOR_GLOBAL,
|
||||
/*database*/ DATABASE_INIT | DATABASE_UPGRADE | DATABASE_EXISTING,
|
||||
&UpgradeTasks::setupAnalyzers);
|
||||
addTask("setupAqlFunctions", "setup _aqlfunctions collection",
|
||||
/*system*/ Flags::DATABASE_ALL,
|
||||
/*cluster*/ Flags::CLUSTER_NONE | Flags::CLUSTER_COORDINATOR_GLOBAL,
|
||||
|
|
|
@ -276,11 +276,6 @@ bool UpgradeTasks::addDefaultUserOther(TRI_vocbase_t& vocbase,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UpgradeTasks::setupAnalyzers(TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& slice) {
|
||||
return ::createSystemCollection(vocbase, "_iresearch_analyzers");
|
||||
}
|
||||
|
||||
bool UpgradeTasks::setupAqlFunctions(TRI_vocbase_t& vocbase,
|
||||
arangodb::velocypack::Slice const& slice) {
|
||||
return ::createSystemCollection(vocbase, "_aqlfunctions");
|
||||
|
|
|
@ -38,7 +38,6 @@ struct UpgradeTasks {
|
|||
static bool setupUsers(TRI_vocbase_t& vocbase, velocypack::Slice const& slice);
|
||||
static bool createUsersIndex(TRI_vocbase_t& vocbase, velocypack::Slice const& slice);
|
||||
static bool addDefaultUserOther(TRI_vocbase_t& vocbase, velocypack::Slice const& slice);
|
||||
static bool setupAnalyzers(TRI_vocbase_t& vocbase, velocypack::Slice const& slice);
|
||||
static bool setupAqlFunctions(TRI_vocbase_t& vocbase, velocypack::Slice const& slice);
|
||||
static bool createFrontend(TRI_vocbase_t& vocbase, velocypack::Slice const& slice);
|
||||
static bool setupQueues(TRI_vocbase_t& vocbase, velocypack::Slice const& slice);
|
||||
|
@ -55,4 +54,4 @@ struct UpgradeTasks {
|
|||
} // namespace methods
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -135,12 +135,6 @@ struct IResearchBlockMockSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::iresearch::IResearchAnalyzerFeature>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature =
|
||||
arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>(
|
||||
"DatabasePath");
|
||||
|
@ -532,4 +526,4 @@ TEST_CASE("ExecutionBlockMockTestChain", "[iresearch]") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -319,13 +319,6 @@ struct IResearchExpressionFilterSetup {
|
|||
return params[0];
|
||||
}});
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ struct Analyzer {
|
|||
std::map<irs::string_ref, Analyzer>const& staticAnalyzers() {
|
||||
static const std::map<irs::string_ref, Analyzer> analyzers = {
|
||||
{ "identity", { "identity", irs::string_ref::NIL, { irs::frequency::type(), irs::norm::type() } } },
|
||||
// FIXME TODO remove
|
||||
{"text_de", { "text", "{ \"locale\": \"de.UTF-8\", \"ignored_words\": [ ] }", { irs::frequency::type(), irs::norm::type(), irs::position::type() } } },
|
||||
{"text_en", { "text", "{ \"locale\": \"en.UTF-8\", \"ignored_words\": [ ] }", { irs::frequency::type(), irs::norm::type(), irs::position::type() } } },
|
||||
{"text_es", { "text", "{ \"locale\": \"es.UTF-8\", \"ignored_words\": [ ] }", { irs::frequency::type(), irs::norm::type(), irs::position::type() } } },
|
||||
|
@ -228,12 +229,18 @@ struct IResearchAnalyzerFeatureSetup {
|
|||
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<Vocbase>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE); // QueryRegistryFeature required for instantiation
|
||||
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
|
||||
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
|
||||
features.emplace_back(new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
|
||||
|
||||
#if USE_ENTERPRISE
|
||||
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
|
||||
#endif
|
||||
|
||||
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
|
||||
arangodb::application_features::ApplicationServer::server->addFeature(
|
||||
new arangodb::ClusterFeature(server)
|
||||
);
|
||||
|
||||
for (auto& f : features) {
|
||||
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
|
||||
}
|
||||
|
@ -428,9 +435,11 @@ SECTION("test_auth") {
|
|||
SECTION("test_emplace") {
|
||||
// add valid
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer0", "TestAnalyzer", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer0", "TestAnalyzer", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
auto pool = feature.get("test_analyzer0");
|
||||
CHECK((false == !pool));
|
||||
CHECK((irs::flags() == pool->features()));
|
||||
|
@ -438,81 +447,115 @@ SECTION("test_emplace") {
|
|||
|
||||
// add duplicate valid (same name+type+properties)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer1", "TestAnalyzer", "abc", irs::flags{ TestAttribute::type() }).first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer1", "TestAnalyzer", "abc", irs::flags{ TestAttribute::type() }).ok()));
|
||||
CHECK((false == !result.first));
|
||||
auto pool = feature.get("test_analyzer1");
|
||||
CHECK((false == !pool));
|
||||
CHECK((irs::flags({ TestAttribute::type() }) == pool->features()));
|
||||
CHECK((false == !feature.emplace("test_analyzer1", "TestAnalyzer", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer1", "TestAnalyzer", "abc", irs::flags{ TestAttribute::type() }).ok()));
|
||||
CHECK((false == !result.first));
|
||||
CHECK((false == !feature.get("test_analyzer1")));
|
||||
}
|
||||
|
||||
// add duplicate invalid (same name+type different properties)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer2", "TestAnalyzer", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
auto pool = feature.get("test_analyzer2");
|
||||
CHECK((false == !pool));
|
||||
CHECK((irs::flags() == pool->features()));
|
||||
CHECK((true == !feature.emplace("test_analyzer2", "TestAnalyzer", "abcd").first));
|
||||
CHECK((false == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abcd").ok()));
|
||||
CHECK((false == !feature.get("test_analyzer2")));
|
||||
}
|
||||
|
||||
// add duplicate invalid (same name+type+properties different features)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((true == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
auto pool = feature.get("test_analyzer2");
|
||||
CHECK((false == !pool));
|
||||
CHECK((irs::flags() == pool->features()));
|
||||
CHECK((false == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abc", irs::flags{ TestAttribute::type() }).ok()));
|
||||
CHECK((false == !feature.get("test_analyzer2")));
|
||||
}
|
||||
|
||||
// add duplicate invalid (same name+properties different type)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer3", "TestAnalyzer", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer3", "TestAnalyzer", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
auto pool = feature.get("test_analyzer3");
|
||||
CHECK((false == !pool));
|
||||
CHECK((irs::flags() == pool->features()));
|
||||
CHECK((true == !feature.emplace("test_analyzer3", "invalid", "abc").first));
|
||||
CHECK((false == feature.emplace(result, "test_analyzer3", "invalid", "abc").ok()));
|
||||
CHECK((false == !feature.get("test_analyzer3")));
|
||||
}
|
||||
|
||||
// add invalid (instance creation failure)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((true == !feature.emplace("test_analyzer4", "TestAnalyzer", "").first));
|
||||
CHECK((false == feature.emplace(result, "test_analyzer4", "TestAnalyzer", "").ok()));
|
||||
CHECK((true == !feature.get("test_analyzer4")));
|
||||
}
|
||||
|
||||
// add invalid (instance creation exception)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((true == !feature.emplace("test_analyzer5", "TestAnalyzer", irs::string_ref::NIL).first));
|
||||
CHECK((false == feature.emplace(result, "test_analyzer5", "TestAnalyzer", irs::string_ref::NIL).ok()));
|
||||
CHECK((true == !feature.get("test_analyzer5")));
|
||||
}
|
||||
|
||||
// add invalid (not registred)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((true == !feature.emplace("test_analyzer6", "invalid", irs::string_ref::NIL).first));
|
||||
CHECK((false == feature.emplace(result, "test_analyzer6", "invalid", irs::string_ref::NIL).ok()));
|
||||
CHECK((true == !feature.get("test_analyzer6")));
|
||||
}
|
||||
|
||||
// add invalid (feature not started)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
CHECK((true == !feature.emplace("test_analyzer7", "TestAnalyzer", "abc").first));
|
||||
auto pool = feature.ensure("test_analyzer");
|
||||
REQUIRE((false == !pool));
|
||||
CHECK((irs::flags::empty_instance() == pool->features()));
|
||||
auto analyzer = pool->get();
|
||||
CHECK((true == !analyzer));
|
||||
CHECK((false == feature.emplace(result, "test_analyzer7", "invalid", irs::string_ref::NIL).ok()));
|
||||
CHECK((true == !feature.get("test_analyzer7")));
|
||||
}
|
||||
|
||||
// add valid inRecovery (failure)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
auto before = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
CHECK((false == feature.emplace(result, "test_analyzer8", "TestAnalyzer", "abc").ok()));
|
||||
CHECK((true == !feature.get("test_analyzer8")));
|
||||
}
|
||||
|
||||
// add static analyzer
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("identity", "identity", irs::string_ref::NIL).first));
|
||||
CHECK((true == feature.emplace(result, "identity", "identity", irs::string_ref::NIL, irs::flags{ irs::frequency::type(), irs::norm::type() }).ok()));
|
||||
CHECK((false == !result.first));
|
||||
auto pool = feature.get("identity");
|
||||
CHECK((false == !pool));
|
||||
CHECK((irs::flags({irs::norm::type(), irs::frequency::type() }) == pool->features()));
|
||||
|
@ -522,8 +565,10 @@ SECTION("test_emplace") {
|
|||
|
||||
// add static analyzer (feature not started)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
CHECK((false == !feature.emplace("identity", "identity", irs::string_ref::NIL).first));
|
||||
CHECK((true == feature.emplace(result, "identity", "identity", irs::string_ref::NIL, irs::flags{ irs::frequency::type(), irs::norm::type() }).ok()));
|
||||
CHECK((false == !result.first));
|
||||
auto pool = feature.get("identity");
|
||||
CHECK((false == !pool));
|
||||
CHECK((irs::flags({irs::norm::type(), irs::frequency::type() }) == pool->features()));
|
||||
|
@ -587,6 +632,11 @@ SECTION("test_ensure") {
|
|||
}
|
||||
|
||||
SECTION("test_get") {
|
||||
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::DatabaseFeature
|
||||
>("Database");
|
||||
REQUIRE((false == !dbFeature));
|
||||
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
|
||||
|
@ -617,10 +667,11 @@ SECTION("test_get") {
|
|||
}
|
||||
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
|
||||
feature.start();
|
||||
feature.emplace("test_analyzer", "TestAnalyzer", "abc");
|
||||
REQUIRE((feature.emplace(result, "test_analyzer", "TestAnalyzer", "abc").ok()));
|
||||
|
||||
// get valid (started)
|
||||
{
|
||||
|
@ -645,6 +696,84 @@ SECTION("test_get") {
|
|||
CHECK((false == !analyzer));
|
||||
}
|
||||
}
|
||||
|
||||
// get existing with parameter match
|
||||
{
|
||||
TRI_vocbase_t* vocbase;
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbase)));
|
||||
auto dropDB = irs::make_finally([dbFeature]()->void { dbFeature->dropDatabase("testVocbase", true, true); });
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
REQUIRE((feature.emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() } ).ok()));
|
||||
|
||||
CHECK((false == !feature.get("testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() })));
|
||||
}
|
||||
|
||||
// get exisitng with type mismatch
|
||||
{
|
||||
TRI_vocbase_t* vocbase;
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbase)));
|
||||
auto dropDB = irs::make_finally([dbFeature]()->void { dbFeature->dropDatabase("testVocbase", true, true); });
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
REQUIRE((feature.emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() } ).ok()));
|
||||
|
||||
CHECK((true == !feature.get("testVocbase::test_analyzer", "identity", "abc", { irs::frequency::type() })));
|
||||
}
|
||||
|
||||
// get existing with properties mismatch
|
||||
{
|
||||
TRI_vocbase_t* vocbase;
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbase)));
|
||||
auto dropDB = irs::make_finally([dbFeature]()->void { dbFeature->dropDatabase("testVocbase", true, true); });
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
REQUIRE((feature.emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() } ).ok()));
|
||||
|
||||
CHECK((true == !feature.get("testVocbase::test_analyzer", "TestAnalyzer", "abcd", { irs::frequency::type() })));
|
||||
}
|
||||
|
||||
// get existing with features mismatch
|
||||
{
|
||||
TRI_vocbase_t* vocbase;
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbase)));
|
||||
auto dropDB = irs::make_finally([dbFeature]()->void { dbFeature->dropDatabase("testVocbase", true, true); });
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
REQUIRE((feature.emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() } ).ok()));
|
||||
|
||||
CHECK((true == !feature.get("testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::position::type() })));
|
||||
}
|
||||
|
||||
// get missing (single-server)
|
||||
{
|
||||
TRI_vocbase_t* vocbase;
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbase)));
|
||||
auto dropDB = irs::make_finally([dbFeature]()->void { dbFeature->dropDatabase("testVocbase", true, true); });
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
CHECK((true == !feature.get("testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() })));
|
||||
}
|
||||
|
||||
// get missing (coordinator)
|
||||
{
|
||||
auto before = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR);
|
||||
auto restore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
CHECK((true == !feature.get("testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() })));
|
||||
}
|
||||
|
||||
// get missing (db-server)
|
||||
{
|
||||
auto before = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER);
|
||||
auto restore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
CHECK((feature.get("testVocbase::test_analyzer", "TestAnalyzer", "abc", { irs::frequency::type() })));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test_identity") {
|
||||
|
@ -713,28 +842,28 @@ SECTION("test_normalize") {
|
|||
auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true);
|
||||
CHECK((std::string("identity") == normalized));
|
||||
}
|
||||
|
||||
/* FIXME TODO uncomment once emplace(...) and all tests are updated
|
||||
// normalize NIL (with prefix)
|
||||
{
|
||||
irs::string_ref analyzer = irs::string_ref::NIL;
|
||||
auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true);
|
||||
CHECK((std::string("active::") == normalized));
|
||||
}
|
||||
|
||||
*/
|
||||
// normalize NIL (without prefix)
|
||||
{
|
||||
irs::string_ref analyzer = irs::string_ref::NIL;
|
||||
auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, false);
|
||||
CHECK((std::string("") == normalized));
|
||||
}
|
||||
|
||||
/* FIXME TODO uncomment once emplace(...) and all tests are updated
|
||||
// normalize EMPTY (with prefix)
|
||||
{
|
||||
irs::string_ref analyzer = irs::string_ref::EMPTY;
|
||||
auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true);
|
||||
CHECK((std::string("active::") == normalized));
|
||||
}
|
||||
|
||||
*/
|
||||
// normalize EMPTY (without prefix)
|
||||
{
|
||||
irs::string_ref analyzer = irs::string_ref::EMPTY;
|
||||
|
@ -769,14 +898,14 @@ SECTION("test_normalize") {
|
|||
auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, false);
|
||||
CHECK((std::string("::name") == normalized));
|
||||
}
|
||||
|
||||
/* FIXME TODO uncomment once emplace(...) and all tests are updated
|
||||
// normalize no-delimiter + name (with prefix)
|
||||
{
|
||||
irs::string_ref analyzer = "name";
|
||||
auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true);
|
||||
CHECK((std::string("active::name") == normalized));
|
||||
}
|
||||
|
||||
*/
|
||||
// normalize no-delimiter + name (without prefix)
|
||||
{
|
||||
irs::string_ref analyzer = "name";
|
||||
|
@ -1029,9 +1158,10 @@ SECTION("test_persistence") {
|
|||
}
|
||||
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
auto result = feature.emplace("valid", "identity", "abc");
|
||||
CHECK((feature.emplace(result, "valid", "identity", "abc").ok()));
|
||||
CHECK((result.first));
|
||||
CHECK((result.second));
|
||||
}
|
||||
|
@ -1124,6 +1254,182 @@ SECTION("test_persistence") {
|
|||
CHECK((expected.empty()));
|
||||
}
|
||||
}
|
||||
|
||||
// emplace on single-server (should persist)
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
CHECK((true == feature.emplace(result, "test_analyzerA", "TestAnalyzer", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
CHECK((false == !feature.get("test_analyzerA")));
|
||||
CHECK((false == !s.system->lookupCollection("_iresearch_analyzers")));
|
||||
arangodb::OperationOptions options;
|
||||
arangodb::SingleCollectionTransaction trx(
|
||||
arangodb::transaction::StandaloneContext::Create(*vocbase),
|
||||
"_iresearch_analyzers",
|
||||
arangodb::AccessMode::Type::WRITE
|
||||
);
|
||||
CHECK((trx.begin().ok()));
|
||||
auto queryResult = trx.all("_iresearch_analyzers", 0, 2, options);
|
||||
CHECK((true == queryResult.ok()));
|
||||
auto slice = arangodb::velocypack::Slice(queryResult.buffer->data());
|
||||
CHECK((slice.isArray() && 1 == slice.length()));
|
||||
CHECK((trx.truncate("_iresearch_analyzers", options).ok()));
|
||||
CHECK((trx.commit().ok()));
|
||||
}
|
||||
|
||||
// emplace on coordinator (should persist)
|
||||
{
|
||||
auto before = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR);
|
||||
auto restore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
|
||||
|
||||
// create a new instance of an ApplicationServer and fill it with the required features
|
||||
// cannot use the existing server since its features already have some state
|
||||
std::shared_ptr<arangodb::application_features::ApplicationServer> originalServer(
|
||||
arangodb::application_features::ApplicationServer::server,
|
||||
[](arangodb::application_features::ApplicationServer* ptr)->void {
|
||||
arangodb::application_features::ApplicationServer::server = ptr;
|
||||
}
|
||||
);
|
||||
arangodb::application_features::ApplicationServer::server = nullptr; // avoid "ApplicationServer initialized twice"
|
||||
arangodb::application_features::ApplicationServer server(nullptr, nullptr);
|
||||
arangodb::iresearch::IResearchAnalyzerFeature* feature;
|
||||
arangodb::DatabaseFeature* dbFeature;
|
||||
arangodb::SystemDatabaseFeature* sysDatabase;
|
||||
server.addFeature(new arangodb::ClusterFeature(server)); // required to create ClusterInfo instance
|
||||
server.addFeature(dbFeature = new arangodb::DatabaseFeature(server)); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
server.addFeature(new arangodb::QueryRegistryFeature(server)); // required for constructing TRI_vocbase_t
|
||||
server.addFeature(new arangodb::ShardingFeature(server)); // required for Collections::create(...)
|
||||
server.addFeature(sysDatabase = new arangodb::SystemDatabaseFeature(server)); // required for IResearchAnalyzerFeature::start()
|
||||
server.addFeature(new arangodb::UpgradeFeature(server, nullptr, {})); // required for upgrade tasks
|
||||
server.addFeature(new arangodb::V8DealerFeature(server)); // required for DatabaseFeature::createDatabase(...)
|
||||
server.addFeature(new arangodb::application_features::CommunicationFeaturePhase(server)); // required for SimpleHttpClient::doRequest()
|
||||
server.addFeature(feature = new arangodb::iresearch::IResearchAnalyzerFeature(server)); // required for running upgrade task
|
||||
|
||||
// create system vocbase (before feature start)
|
||||
{
|
||||
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
|
||||
CHECK((TRI_ERROR_NO_ERROR == dbFeature->loadDatabases(databases->slice())));
|
||||
sysDatabase->start(); // get system database from DatabaseFeature
|
||||
}
|
||||
|
||||
auto system = sysDatabase->use();
|
||||
|
||||
server.getFeature<arangodb::ClusterFeature>("Cluster")->prepare(); // create ClusterInfo instance
|
||||
server.getFeature<arangodb::ShardingFeature>("Sharding")->prepare(); // required for Collections::create(...), register sharding types
|
||||
arangodb::AgencyCommManager::MANAGER->start(); // initialize agency
|
||||
|
||||
ClusterCommMock clusterComm;
|
||||
auto scopedClusterComm = ClusterCommMock::setInstance(clusterComm);
|
||||
auto* ci = arangodb::ClusterInfo::instance();
|
||||
REQUIRE((nullptr != ci));
|
||||
|
||||
// simulate heartbeat thread
|
||||
// (create dbserver in current) required by ClusterMethods::persistCollectionInAgency(...)
|
||||
// (create collection in current) required by ClusterMethods::persistCollectionInAgency(...)
|
||||
// (create dummy collection in plan to fill ClusterInfo::_shardServers) required by ClusterMethods::persistCollectionInAgency(...)
|
||||
{
|
||||
auto const srvPath = "/Current/DBServers";
|
||||
auto const srvValue = arangodb::velocypack::Parser::fromJson("{ \"dbserver-key-does-not-matter\": \"dbserver-value-does-not-matter\" }");
|
||||
CHECK(arangodb::AgencyComm().setValue(srvPath, srvValue->slice(), 0.0).successful());
|
||||
auto const colPath = "/Current/Collections/_system/2"; // '2' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace)
|
||||
auto const colValue = arangodb::velocypack::Parser::fromJson("{ \"same-as-dummy-shard-id\": { \"servers\": [ \"same-as-dummy-shard-server\" ] } }");
|
||||
CHECK(arangodb::AgencyComm().setValue(colPath, colValue->slice(), 0.0).successful());
|
||||
auto const dummyPath = "/Plan/Collections";
|
||||
auto const dummyValue = arangodb::velocypack::Parser::fromJson("{ \"_system\": { \"collection-id-does-not-matter\": { \"name\": \"dummy\", \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }");
|
||||
CHECK(arangodb::AgencyComm().setValue(dummyPath, dummyValue->slice(), 0.0).successful());
|
||||
}
|
||||
|
||||
// insert response for expected extra analyzer
|
||||
{
|
||||
arangodb::ClusterCommResult response;
|
||||
response.operationID = clusterComm.nextOperationId();
|
||||
response.status = arangodb::ClusterCommOpStatus::CL_COMM_RECEIVED;
|
||||
response.answer_code = arangodb::rest::ResponseCode::CREATED;
|
||||
response.answer = std::make_shared<GeneralRequestMock>(*vocbase);
|
||||
static_cast<GeneralRequestMock*>(response.answer.get())->_payload = *arangodb::velocypack::Parser::fromJson(std::string("{ \"_key\": \"") + std::to_string(response.operationID) + "\" }"); // unique arbitrary key
|
||||
clusterComm._responses[0].emplace_back(std::move(response));
|
||||
}
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
CHECK((true == feature->emplace(result, "_system::test_analyzerB", "TestAnalyzer", "abc").ok()));
|
||||
CHECK((nullptr != ci->getCollection(system->name(), "_iresearch_analyzers")));
|
||||
CHECK((1 == clusterComm._requests.size()));
|
||||
auto& entry = *(clusterComm._requests.begin());
|
||||
CHECK((entry.second._body));
|
||||
auto body = arangodb::velocypack::Parser::fromJson(*(entry.second._body));
|
||||
auto slice = body->slice();
|
||||
CHECK((slice.isObject()));
|
||||
CHECK((slice.get("name").isString()));
|
||||
CHECK((std::string("test_analyzerB") == slice.get("name").copyString()));
|
||||
}
|
||||
|
||||
// emplace on db-server(should not persist)
|
||||
{
|
||||
auto before = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER);
|
||||
auto restore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
|
||||
|
||||
// create a new instance of an ApplicationServer and fill it with the required features
|
||||
// cannot use the existing server since its features already have some state
|
||||
std::shared_ptr<arangodb::application_features::ApplicationServer> originalServer(
|
||||
arangodb::application_features::ApplicationServer::server,
|
||||
[](arangodb::application_features::ApplicationServer* ptr)->void {
|
||||
arangodb::application_features::ApplicationServer::server = ptr;
|
||||
}
|
||||
);
|
||||
arangodb::application_features::ApplicationServer::server = nullptr; // avoid "ApplicationServer initialized twice"
|
||||
arangodb::application_features::ApplicationServer server(nullptr, nullptr);
|
||||
arangodb::iresearch::IResearchAnalyzerFeature* feature;
|
||||
arangodb::DatabaseFeature* dbFeature;
|
||||
arangodb::SystemDatabaseFeature* sysDatabase;
|
||||
server.addFeature(new arangodb::ClusterFeature(server)); // required to create ClusterInfo instance
|
||||
server.addFeature(dbFeature = new arangodb::DatabaseFeature(server)); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
server.addFeature(new arangodb::QueryRegistryFeature(server)); // required for constructing TRI_vocbase_t
|
||||
server.addFeature(new arangodb::ShardingFeature(server)); // required for Collections::create(...)
|
||||
server.addFeature(sysDatabase = new arangodb::SystemDatabaseFeature(server)); // required for IResearchAnalyzerFeature::start()
|
||||
server.addFeature(new arangodb::UpgradeFeature(server, nullptr, {})); // required for upgrade tasks
|
||||
server.addFeature(new arangodb::V8DealerFeature(server)); // required for DatabaseFeature::createDatabase(...)
|
||||
server.addFeature(new arangodb::application_features::CommunicationFeaturePhase(server)); // required for SimpleHttpClient::doRequest()
|
||||
server.addFeature(feature = new arangodb::iresearch::IResearchAnalyzerFeature(server)); // required for running upgrade task
|
||||
|
||||
// create system vocbase (before feature start)
|
||||
{
|
||||
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
|
||||
CHECK((TRI_ERROR_NO_ERROR == dbFeature->loadDatabases(databases->slice())));
|
||||
sysDatabase->start(); // get system database from DatabaseFeature
|
||||
}
|
||||
|
||||
auto system = sysDatabase->use();
|
||||
|
||||
server.getFeature<arangodb::ClusterFeature>("Cluster")->prepare(); // create ClusterInfo instance
|
||||
server.getFeature<arangodb::ShardingFeature>("Sharding")->prepare(); // required for Collections::create(...), register sharding types
|
||||
arangodb::AgencyCommManager::MANAGER->start(); // initialize agency
|
||||
|
||||
ClusterCommMock clusterComm;
|
||||
auto scopedClusterComm = ClusterCommMock::setInstance(clusterComm);
|
||||
auto* ci = arangodb::ClusterInfo::instance();
|
||||
REQUIRE((nullptr != ci));
|
||||
|
||||
// simulate heartbeat thread
|
||||
// (create dbserver in current) required by ClusterMethods::persistCollectionInAgency(...)
|
||||
// (create collection in current) required by ClusterMethods::persistCollectionInAgency(...)
|
||||
// (create dummy collection in plan to fill ClusterInfo::_shardServers) required by ClusterMethods::persistCollectionInAgency(...)
|
||||
{
|
||||
auto const srvPath = "/Current/DBServers";
|
||||
auto const srvValue = arangodb::velocypack::Parser::fromJson("{ \"dbserver-key-does-not-matter\": \"dbserver-value-does-not-matter\" }");
|
||||
CHECK(arangodb::AgencyComm().setValue(srvPath, srvValue->slice(), 0.0).successful());
|
||||
auto const dummyPath = "/Plan/Collections";
|
||||
auto const dummyValue = arangodb::velocypack::Parser::fromJson("{ \"_system\": { \"collection-id-does-not-matter\": { \"name\": \"dummy\", \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }");
|
||||
CHECK(arangodb::AgencyComm().setValue(dummyPath, dummyValue->slice(), 0.0).successful());
|
||||
}
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
CHECK((true == feature->emplace(result, "_system::test_analyzerC", "TestAnalyzer", "abc").ok()));
|
||||
CHECK_THROWS((ci->getCollection(system->name(), "_iresearch_analyzers"))); // throws on missing collection, not ClusterInfo persisted
|
||||
CHECK((true == !system->lookupCollection("_iresearch_analyzers"))); // not locally persisted
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test_remove") {
|
||||
|
@ -1262,9 +1568,11 @@ SECTION("test_start") {
|
|||
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr == collection));
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer", "identity", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr != collection));
|
||||
}
|
||||
|
@ -1303,9 +1611,11 @@ SECTION("test_start") {
|
|||
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr == collection));
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer", "identity", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr != collection));
|
||||
}
|
||||
|
@ -1412,9 +1722,11 @@ SECTION("test_start") {
|
|||
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr == collection));
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer", "identity", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr != collection));
|
||||
}
|
||||
|
@ -1450,9 +1762,11 @@ SECTION("test_start") {
|
|||
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr == collection));
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(s.server);
|
||||
feature.start();
|
||||
CHECK((false == !feature.emplace("test_analyzer", "identity", "abc").first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok()));
|
||||
CHECK((false == !result.first));
|
||||
collection = vocbase->lookupCollection("_iresearch_analyzers");
|
||||
CHECK((nullptr != collection));
|
||||
}
|
||||
|
@ -1532,8 +1846,10 @@ SECTION("test_tokens") {
|
|||
CHECK((nullptr != functions->byName("TOKENS")));
|
||||
}
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
analyzers->start();
|
||||
REQUIRE((false == !analyzers->emplace("test_analyzer", "TestAnalyzer", "abc").first));
|
||||
REQUIRE((true == analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc").ok()));
|
||||
REQUIRE((false == !result.first));
|
||||
|
||||
// test tokenization
|
||||
{
|
||||
|
@ -2125,7 +2441,7 @@ SECTION("test_upgrade_static_legacy") {
|
|||
}
|
||||
|
||||
sysDatabase->unprepare(); // unset system vocbase
|
||||
CHECK_THROWS((!ci->getCollection(vocbase->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection
|
||||
CHECK_THROWS((ci->getCollection(vocbase->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection
|
||||
CHECK((arangodb::methods::Upgrade::clusterBootstrap(*vocbase).ok())); // run upgrade
|
||||
CHECK((false == !ci->getCollection(vocbase->name(), ANALYZER_COLLECTION_NAME)));
|
||||
CHECK((true == clusterComm._responses.empty()));
|
||||
|
@ -2901,9 +3217,13 @@ SECTION("test_visit") {
|
|||
|
||||
feature.start();
|
||||
|
||||
CHECK((false == !feature.emplace("test_analyzer0", "TestAnalyzer", "abc0").first));
|
||||
CHECK((false == !feature.emplace("test_analyzer1", "TestAnalyzer", "abc1").first));
|
||||
CHECK((false == !feature.emplace("test_analyzer2", "TestAnalyzer", "abc2").first));
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
CHECK((true == feature.emplace(result, "test_analyzer0", "TestAnalyzer", "abc0").ok()));
|
||||
CHECK((false == !result.first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer1", "TestAnalyzer", "abc1").ok()));
|
||||
CHECK((false == !result.first));
|
||||
CHECK((true == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abc2").ok()));
|
||||
CHECK((false == !result.first));
|
||||
|
||||
// full visitation
|
||||
{
|
||||
|
@ -2962,9 +3282,13 @@ SECTION("test_visit") {
|
|||
|
||||
// add database-prefixed analyzers
|
||||
{
|
||||
CHECK((false == !feature.emplace("vocbase2::test_analyzer3", "TestAnalyzer", "abc3").first));
|
||||
CHECK((false == !feature.emplace("vocbase2::test_analyzer4", "TestAnalyzer", "abc4").first));
|
||||
CHECK((false == !feature.emplace("vocbase1::test_analyzer5", "TestAnalyzer", "abc5").first));
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
CHECK((true == feature.emplace(result, "vocbase2::test_analyzer3", "TestAnalyzer", "abc3").ok()));
|
||||
CHECK((false == !result.first));
|
||||
CHECK((true == feature.emplace(result, "vocbase2::test_analyzer4", "TestAnalyzer", "abc4").ok()));
|
||||
CHECK((false == !result.first));
|
||||
CHECK((true == feature.emplace(result, "vocbase1::test_analyzer5", "TestAnalyzer", "abc5").ok()));
|
||||
CHECK((false == !result.first));
|
||||
}
|
||||
|
||||
// full visitation limited to a vocbase (empty)
|
||||
|
|
|
@ -172,12 +172,13 @@ struct IResearchDocumentSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
// ensure that there will be no exception on 'emplace'
|
||||
InvalidAnalyzer::returnNullFromMake = false;
|
||||
|
||||
analyzers->emplace("iresearch-document-empty", "iresearch-document-empty", "en", irs::flags{ TestAttribute::type() }); // cache analyzer
|
||||
analyzers->emplace("iresearch-document-invalid", "iresearch-document-invalid", "en", irs::flags{ TestAttribute::type() }); // cache analyzer
|
||||
analyzers->emplace(result, "iresearch-document-empty", "iresearch-document-empty", "en", irs::flags{ TestAttribute::type() }); // cache analyzer
|
||||
analyzers->emplace(result, "iresearch-document-invalid", "iresearch-document-invalid", "en", irs::flags{ TestAttribute::type() }); // cache analyzer
|
||||
|
||||
// suppress log messages since tests check error conditions
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
|
||||
|
@ -1390,8 +1391,9 @@ SECTION("FieldIterator_nullptr_analyzer") {
|
|||
// ensure that there will be no exception on 'emplace'
|
||||
InvalidAnalyzer::returnNullFromMake = false;
|
||||
|
||||
analyzers.emplace("empty", "iresearch-document-empty", "en", irs::flags{TestAttribute::type()});
|
||||
analyzers.emplace("invalid", "iresearch-document-invalid", "en", irs::flags{TestAttribute::type()});
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
analyzers.emplace(result, "empty", "iresearch-document-empty", "en", irs::flags{TestAttribute::type()});
|
||||
analyzers.emplace(result, "invalid", "iresearch-document-invalid", "en", irs::flags{TestAttribute::type()});
|
||||
}
|
||||
|
||||
// last analyzer invalid
|
||||
|
@ -2014,4 +2016,4 @@ SECTION("test_rid_filter") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -609,6 +609,7 @@ SECTION("test_upgrade0_1") {
|
|||
REQUIRE((irs::utf8_path(dbPathFeature->directory()).mkdir()));
|
||||
REQUIRE((arangodb::basics::VelocyPackHelper::velocyPackToFile(StorageEngineMock::versionFilenameResult, versionJson->slice(), false)));
|
||||
|
||||
s.engine.views.clear();
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((false == !logicalCollection));
|
||||
|
@ -1091,4 +1092,4 @@ SECTION("test_async") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -214,8 +214,9 @@ struct IResearchFilterSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestCharAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace(result, "test_analyzer", "TestCharAnalyzer", "abc"); // cache analyzer
|
||||
}
|
||||
|
||||
~IResearchFilterSetup() {
|
||||
|
@ -256,4 +257,4 @@ TEST_CASE("IResearchFilterTest", "[iresearch][iresearch-filter]") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -146,12 +146,6 @@ struct IResearchFilterSetup {
|
|||
return params[0];
|
||||
}});
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestCharAnalyzer", "abc"); // cache analyzer
|
||||
|
||||
// suppress log messages since tests check error conditions
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
|
||||
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
|
||||
|
@ -3639,4 +3633,4 @@ SECTION("BinaryAnd") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -147,12 +147,6 @@ struct IResearchFilterSetup {
|
|||
return params[0];
|
||||
}});
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestCharAnalyzer", "abc"); // cache analyzer
|
||||
|
||||
// suppress log messages since tests check error conditions
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
|
||||
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
|
||||
|
@ -3669,4 +3663,4 @@ SECTION("BinaryLT") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -149,12 +149,6 @@ struct IResearchFilterSetup {
|
|||
return params[0];
|
||||
}});
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestCharAnalyzer", "abc"); // cache analyzer
|
||||
|
||||
// suppress log messages since tests check error conditions
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
|
||||
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
|
||||
|
@ -2273,4 +2267,4 @@ SECTION("StartsWith") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -146,12 +146,6 @@ struct IResearchFilterSetup {
|
|||
return params[0];
|
||||
}});
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestCharAnalyzer", "abc"); // cache analyzer
|
||||
|
||||
// suppress log messages since tests check error conditions
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
|
||||
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
|
||||
|
@ -3951,4 +3945,4 @@ SECTION("BinaryNotIn") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -182,9 +182,10 @@ struct IResearchIndexSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace("test_A", "TestInsertAnalyzer", "X"); // cache analyzer
|
||||
analyzers->emplace("test_B", "TestInsertAnalyzer", "Y"); // cache analyzer
|
||||
analyzers->emplace(result, "test_A", "TestInsertAnalyzer", "X"); // cache analyzer
|
||||
analyzers->emplace(result, "test_B", "TestInsertAnalyzer", "Y"); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "utils/utf8_path.hpp"
|
||||
|
||||
#include "Aql/AqlFunctionFeature.h"
|
||||
#include "Aql/QueryRegistry.h"
|
||||
|
||||
#if USE_ENTERPRISE
|
||||
#include "Enterprise/Ldap/LdapFeature.h"
|
||||
|
@ -47,17 +48,20 @@
|
|||
#include "Logger/Logger.h"
|
||||
#include "Logger/LogTopic.h"
|
||||
#include "MMFiles/MMFilesWalRecoverState.h"
|
||||
#include "RestServer/AqlFeature.h"
|
||||
#include "RestServer/DatabaseFeature.h"
|
||||
#include "RestServer/DatabasePathFeature.h"
|
||||
#include "RestServer/FlushFeature.h"
|
||||
#include "RestServer/QueryRegistryFeature.h"
|
||||
#include "RestServer/ServerIdFeature.h"
|
||||
#include "RestServer/SystemDatabaseFeature.h"
|
||||
#include "RestServer/TraverserEngineRegistryFeature.h"
|
||||
#include "RestServer/ViewTypesFeature.h"
|
||||
#include "Sharding/ShardingFeature.h"
|
||||
#include "StorageEngine/EngineSelectorFeature.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/ExecContext.h"
|
||||
#include "V8Server/V8DealerFeature.h"
|
||||
#include "VocBase/KeyGenerator.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
|
@ -91,6 +95,7 @@ struct IResearchLinkSetup {
|
|||
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
|
||||
|
||||
// setup required application features
|
||||
features.emplace_back(new arangodb::AqlFeature(server), true); // required for UserManager::loadFromDB()
|
||||
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
|
||||
features.emplace_back(new arangodb::DatabaseFeature(server), false);
|
||||
features.emplace_back(new arangodb::ShardingFeature(server), false);
|
||||
|
@ -99,6 +104,7 @@ struct IResearchLinkSetup {
|
|||
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, system.get()), false); // required for IResearchAnalyzerFeature
|
||||
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // required for AqlFeature::stop()
|
||||
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
|
||||
features.emplace_back(new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
|
||||
features.emplace_back(new arangodb::iresearch::IResearchAnalyzerFeature(server), true);
|
||||
|
@ -133,6 +139,12 @@ struct IResearchLinkSetup {
|
|||
TransactionStateMock::beginTransactionCount = 0;
|
||||
TransactionStateMock::commitTransactionCount = 0;
|
||||
|
||||
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());
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
testFilesystemPath = dbPathFeature->directory();
|
||||
|
|
|
@ -22,19 +22,126 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "common.h"
|
||||
#include "shared.hpp"
|
||||
#include "Aql/QueryRegistry.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Cluster/ClusterFeature.h"
|
||||
|
||||
#if USE_ENTERPRISE
|
||||
#include "Enterprise/Ldap/LdapFeature.h"
|
||||
#endif
|
||||
|
||||
#include "GeneralServer/AuthenticationFeature.h"
|
||||
#include "IResearch/IResearchAnalyzerFeature.h"
|
||||
#include "IResearch/IResearchCommon.h"
|
||||
#include "IResearch/IResearchFeature.h"
|
||||
#include "IResearch/IResearchLinkHelper.h"
|
||||
#include "Mocks/StorageEngineMock.h"
|
||||
#include "RestServer/AqlFeature.h"
|
||||
#include "RestServer/DatabaseFeature.h"
|
||||
#include "RestServer/DatabasePathFeature.h"
|
||||
#include "RestServer/QueryRegistryFeature.h"
|
||||
#include "RestServer/SystemDatabaseFeature.h"
|
||||
#include "RestServer/TraverserEngineRegistryFeature.h"
|
||||
#include "RestServer/ViewTypesFeature.h"
|
||||
#include "StorageEngine/EngineSelectorFeature.h"
|
||||
#include "Utils/ExecContext.h"
|
||||
#include "utils/misc.hpp"
|
||||
#include "V8Server/V8DealerFeature.h"
|
||||
#include "velocypack/Parser.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- setup / tear-down
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct IResearchLinkHelperSetup {
|
||||
IResearchLinkHelperSetup() {
|
||||
StorageEngineMock engine;
|
||||
arangodb::application_features::ApplicationServer server;
|
||||
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
|
||||
std::string testFilesystemPath;
|
||||
|
||||
IResearchLinkHelperSetup(): engine(server), server(nullptr, nullptr) {
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
|
||||
// suppress INFO {authentication} Authentication is turned on (system only), authentication for unix sockets is turned on
|
||||
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::WARN);
|
||||
|
||||
// suppress log messages since tests check error conditions
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
|
||||
|
||||
features.emplace_back(new arangodb::AqlFeature(server), true); // required for UserManager::loadFromDB()
|
||||
features.emplace_back(new arangodb::AuthenticationFeature(server), false); // required for authentication tests
|
||||
features.emplace_back(new arangodb::DatabaseFeature(server), false);
|
||||
features.emplace_back(new arangodb::DatabasePathFeature(server), false); // required for IResearchLink::init(...)
|
||||
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // required for constructing TRI_vocbase_t
|
||||
features.emplace_back(new arangodb::SystemDatabaseFeature(server), false); // required by IResearchAnalyzerFeature::storeAnalyzer(...)
|
||||
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // required for AqlFeature::stop()
|
||||
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
|
||||
features.emplace_back(new arangodb::ViewTypesFeature(server), false); // required for LogicalView::instantiate(...)
|
||||
features.emplace_back(new arangodb::iresearch::IResearchAnalyzerFeature(server), false); // required for IResearchLinkMeta::init(...)
|
||||
features.emplace_back(new arangodb::iresearch::IResearchFeature(server), false); // required for creating views of type 'iresearch'
|
||||
|
||||
#if USE_ENTERPRISE
|
||||
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
|
||||
#endif
|
||||
|
||||
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
|
||||
arangodb::application_features::ApplicationServer::server->addFeature(
|
||||
new arangodb::ClusterFeature(server)
|
||||
);
|
||||
|
||||
for (auto& f: features) {
|
||||
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
|
||||
}
|
||||
|
||||
for (auto& f: features) {
|
||||
f.first->prepare();
|
||||
}
|
||||
|
||||
for (auto& f: features) {
|
||||
if (f.second) {
|
||||
f.first->start();
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::SystemDatabaseFeature
|
||||
>();
|
||||
sysDatabase->start(); // load system database after loadDatabases()
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
testFilesystemPath = dbPathFeature->directory();
|
||||
|
||||
long systemError;
|
||||
std::string systemErrorStr;
|
||||
TRI_CreateDirectory(testFilesystemPath.c_str(), systemError, systemErrorStr);
|
||||
}
|
||||
|
||||
~IResearchLinkHelperSetup() {
|
||||
arangodb::application_features::ApplicationServer::server = nullptr;
|
||||
|
||||
for (auto& f: features) {
|
||||
if (f.second) {
|
||||
f.first->stop();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& f: features) {
|
||||
f.first->unprepare();
|
||||
}
|
||||
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
|
||||
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
|
||||
arangodb::EngineSelectorFeature::ENGINE = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -132,6 +239,205 @@ SECTION("test_equals") {
|
|||
}
|
||||
}
|
||||
|
||||
SECTION("test_normalize") {
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::SystemDatabaseFeature
|
||||
>();
|
||||
auto sysVocbase = sysDatabase->use();
|
||||
|
||||
// create analyzer collection
|
||||
{
|
||||
static std::string const ANALYZER_COLLECTION_NAME("_iresearch_analyzers");
|
||||
|
||||
if (!sysVocbase->lookupCollection(ANALYZER_COLLECTION_NAME)) {
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson(std::string("{ \"name\": \"") + ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true }");
|
||||
auto logicalCollection = sysVocbase->createCollection(collectionJson->slice());
|
||||
REQUIRE((false == !logicalCollection));
|
||||
}
|
||||
}
|
||||
|
||||
// analyzer single-server
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"analyzers\": [ { \"name\": \"testAnalyzer0\", \"type\": \"identity\" } ] }");
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
CHECK((true == !analyzers->get("testAnalyzer1")));
|
||||
}
|
||||
|
||||
// analyzer single-server (inRecovery) fail persist in recovery
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"analyzers\": [ { \"name\": \"testAnalyzer1\", \"type\": \"identity\" } ] }");
|
||||
auto before = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
CHECK((true == !analyzers->get("testAnalyzer2")));
|
||||
}
|
||||
|
||||
// analyzer single-server (no engine) fail persist if not storage engine, else SEGFAULT in Methods(...)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"analyzers\": [ { \"name\": \"testAnalyzer2\", \"type\": \"identity\" } ] }");
|
||||
auto* before = arangodb::EngineSelectorFeature::ENGINE;
|
||||
arangodb::EngineSelectorFeature::ENGINE = nullptr;
|
||||
auto restore = irs::make_finally([&before]()->void { arangodb::EngineSelectorFeature::ENGINE = before; });
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
CHECK((true == !analyzers->get("testAnalyzer3")));
|
||||
}
|
||||
|
||||
// analyzer coordinator
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"analyzers\": [ { \"name\": \"testAnalyzer3\", \"type\": \"identity\" } ] }");
|
||||
auto serverRoleBefore = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR);
|
||||
auto serverRoleRestore = irs::make_finally([&serverRoleBefore]()->void { arangodb::ServerState::instance()->setRole(serverRoleBefore); });
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
CHECK((true == !analyzers->get("testAnalyzer4")));
|
||||
}
|
||||
|
||||
// analyzer coordinator (inRecovery) fail persist in recovery
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"analyzers\": [ { \"name\": \"testAnalyzer5\", \"type\": \"identity\" } ] }");
|
||||
auto serverRoleBefore = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR);
|
||||
auto serverRoleRestore = irs::make_finally([&serverRoleBefore]()->void { arangodb::ServerState::instance()->setRole(serverRoleBefore); });
|
||||
auto inRecoveryBefore = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&inRecoveryBefore]()->void { StorageEngineMock::inRecoveryResult = inRecoveryBefore; });
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
CHECK((true == !analyzers->get("testAnalyzer5")));
|
||||
}
|
||||
|
||||
// analyzer coordinator (no engine)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"analyzers\": [ { \"name\": \"testAnalyzer6\", \"type\": \"identity\" } ] }");
|
||||
auto serverRoleBefore = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR);
|
||||
auto serverRoleRestore = irs::make_finally([&serverRoleBefore]()->void { arangodb::ServerState::instance()->setRole(serverRoleBefore); });
|
||||
auto* engineBefore = arangodb::EngineSelectorFeature::ENGINE;
|
||||
arangodb::EngineSelectorFeature::ENGINE = nullptr;
|
||||
auto restore = irs::make_finally([&engineBefore]()->void { arangodb::EngineSelectorFeature::ENGINE = engineBefore; });
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
CHECK((true == !analyzers->get("testAnalyzer6")));
|
||||
}
|
||||
|
||||
// analyzer db-server
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"analyzers\": [ { \"name\": \"testAnalyzer7\", \"type\": \"identity\" } ] }");
|
||||
auto before = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER);
|
||||
auto serverRoleRestore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((true == !analyzers->get("testAnalyzer7")));
|
||||
CHECK((true == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
CHECK((false == !analyzers->get("testAnalyzer7")));
|
||||
}
|
||||
|
||||
// meta has analyzer which is not authorised
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"43\", \"analyzers\": [ \"::unAuthorsedAnalyzer\" ] }");
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
REQUIRE((analyzers->emplace(result, arangodb::StaticStrings::SystemDatabase + "::unAuthorsedAnalyzer", "identity", irs::string_ref::NIL).ok()));
|
||||
REQUIRE((false == !result.first));
|
||||
|
||||
// not authorised
|
||||
{
|
||||
struct ExecContext: public arangodb::ExecContext {
|
||||
ExecContext(): arangodb::ExecContext(arangodb::ExecContext::Type::Default, "", "", arangodb::auth::Level::NONE, arangodb::auth::Level::NONE) {}
|
||||
} execContext;
|
||||
arangodb::ExecContextScope execContextScope(&execContext);
|
||||
auto* authFeature = arangodb::AuthenticationFeature::instance();
|
||||
auto* userManager = authFeature->userManager();
|
||||
arangodb::aql::QueryRegistry queryRegistry(0); // required for UserManager::loadFromDB()
|
||||
userManager->setQueryRegistry(&queryRegistry);
|
||||
auto resetUserManager = std::shared_ptr<arangodb::auth::UserManager>(userManager, [](arangodb::auth::UserManager* ptr)->void { ptr->removeAllUsers(); });
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
}
|
||||
|
||||
// authorsed
|
||||
{
|
||||
arangodb::velocypack::Builder builder;
|
||||
builder.openObject();
|
||||
CHECK((true == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test_updateLinks") {
|
||||
// meta has analyzer which is not authorised
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 101 }");
|
||||
auto linkUpdateJson = arangodb::velocypack::Parser::fromJson("{ \"testCollection\": { \"type\": \"arangosearch\", \"view\": \"43\", \"analyzers\": [ \"::unAuthorsedAnalyzer\" ] } }");
|
||||
auto viewCreateJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": 43, \"type\": \"arangosearch\" }");
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
REQUIRE((nullptr != analyzers));
|
||||
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::DatabaseFeature
|
||||
>("Database");
|
||||
TRI_vocbase_t* vocbase;
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbase))); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
REQUIRE((nullptr != vocbase));
|
||||
auto dropDB = irs::make_finally([dbFeature]()->void { dbFeature->dropDatabase("testVocbase", true, true); });
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
REQUIRE((analyzers->emplace(result, arangodb::StaticStrings::SystemDatabase + "::unAuthorsedAnalyzer", "identity", irs::string_ref::NIL).ok()));
|
||||
REQUIRE((false == !result.first));
|
||||
|
||||
auto logicalCollection = vocbase->createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto logicalView = vocbase->createView(viewCreateJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
|
||||
// not authorized
|
||||
{
|
||||
struct ExecContext: public arangodb::ExecContext {
|
||||
ExecContext(): arangodb::ExecContext(arangodb::ExecContext::Type::Default, "", "", arangodb::auth::Level::NONE, arangodb::auth::Level::NONE) {}
|
||||
} execContext;
|
||||
arangodb::ExecContextScope execContextScope(&execContext);
|
||||
auto* authFeature = arangodb::AuthenticationFeature::instance();
|
||||
auto* userManager = authFeature->userManager();
|
||||
arangodb::aql::QueryRegistry queryRegistry(0); // required for UserManager::loadFromDB()
|
||||
userManager->setQueryRegistry(&queryRegistry);
|
||||
auto resetUserManager = std::shared_ptr<arangodb::auth::UserManager>(userManager, [](arangodb::auth::UserManager* ptr)->void { ptr->removeAllUsers(); });
|
||||
|
||||
std::unordered_set<TRI_voc_cid_t> modified;
|
||||
CHECK((0 == logicalCollection->getIndexes().size()));
|
||||
CHECK((false == arangodb::iresearch::IResearchLinkHelper::updateLinks(modified, *logicalView, linkUpdateJson->slice()).ok()));
|
||||
CHECK((0 == logicalCollection->getIndexes().size()));
|
||||
}
|
||||
|
||||
// authorzed
|
||||
{
|
||||
std::unordered_set<TRI_voc_cid_t> modified;
|
||||
CHECK((0 == logicalCollection->getIndexes().size()));
|
||||
CHECK((true == arangodb::iresearch::IResearchLinkHelper::updateLinks(modified, *logicalView, linkUpdateJson->slice()).ok()));
|
||||
CHECK((1 == logicalCollection->getIndexes().size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate tests
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -63,11 +63,12 @@
|
|||
|
||||
namespace {
|
||||
|
||||
struct TestAttribute: public irs::attribute {
|
||||
struct TestAttributeZ: public irs::attribute {
|
||||
DECLARE_ATTRIBUTE_TYPE();
|
||||
};
|
||||
|
||||
DEFINE_ATTRIBUTE_TYPE(TestAttribute);
|
||||
DEFINE_ATTRIBUTE_TYPE(TestAttributeZ);
|
||||
REGISTER_ATTRIBUTE(TestAttributeZ);
|
||||
|
||||
class EmptyAnalyzer: public irs::analysis::analyzer {
|
||||
public:
|
||||
|
@ -82,7 +83,7 @@ public:
|
|||
|
||||
private:
|
||||
irs::attribute_view _attrs;
|
||||
TestAttribute _attr;
|
||||
TestAttributeZ _attr;
|
||||
};
|
||||
|
||||
DEFINE_ANALYZER_TYPE_NAMED(EmptyAnalyzer, "empty");
|
||||
|
@ -153,9 +154,10 @@ struct IResearchLinkMetaSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace("empty", "empty", "en", irs::flags{ TestAttribute::type() }); // cache the 'empty' analyzer
|
||||
analyzers->emplace("testVocbase::empty", "empty", "de", irs::flags{ TestAttribute::type() }); // cache the 'empty' analyzer for 'testVocbase'
|
||||
analyzers->emplace(result, "empty", "empty", "en", irs::flags{ TestAttributeZ::type() }); // cache the 'empty' analyzer
|
||||
analyzers->emplace(result, "testVocbase::empty", "empty", "de", irs::flags{ TestAttributeZ::type() }); // cache the 'empty' analyzer for 'testVocbase'
|
||||
|
||||
// suppress log messages since tests check error conditions
|
||||
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
|
||||
|
@ -228,7 +230,7 @@ SECTION("test_inheritDefaults") {
|
|||
defaults._fields["abc"]->_fields["xyz"] = arangodb::iresearch::IResearchLinkMeta();
|
||||
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{}");
|
||||
CHECK(true == meta.init(json->slice(), tmpString, defaults));
|
||||
CHECK(true == meta.init(json->slice(), tmpString, nullptr, defaults));
|
||||
CHECK(1U == meta._fields.size());
|
||||
|
||||
for (auto& field: meta._fields) {
|
||||
|
@ -290,7 +292,7 @@ SECTION("test_readDefaults") {
|
|||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string tmpString;
|
||||
CHECK((true == meta.init(json->slice(), tmpString, arangodb::iresearch::IResearchLinkMeta::DEFAULT(), &vocbase)));
|
||||
CHECK((true == meta.init(json->slice(), tmpString, &vocbase)));
|
||||
CHECK((true == meta._fields.empty()));
|
||||
CHECK((false == meta._includeAllFields));
|
||||
CHECK((false == meta._trackListPositions));
|
||||
|
@ -361,7 +363,7 @@ SECTION("test_readCustomizedValues") {
|
|||
CHECK(1U == actual._analyzers.size());
|
||||
CHECK((*(actual._analyzers.begin())));
|
||||
CHECK(("empty" == (*(actual._analyzers.begin()))->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*(actual._analyzers.begin()))->features()));
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*(actual._analyzers.begin()))->features()));
|
||||
CHECK(false == !actual._analyzers.begin()->get());
|
||||
} else if ("some" == fieldOverride.key()) {
|
||||
CHECK(true == actual._fields.empty()); // not inherited
|
||||
|
@ -372,7 +374,7 @@ SECTION("test_readCustomizedValues") {
|
|||
auto itr = actual._analyzers.begin();
|
||||
CHECK((*itr));
|
||||
CHECK(("empty" == (*itr)->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*itr)->features()));
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
|
||||
CHECK(false == !itr->get());
|
||||
++itr;
|
||||
CHECK((*itr));
|
||||
|
@ -387,7 +389,7 @@ SECTION("test_readCustomizedValues") {
|
|||
auto itr = actual._analyzers.begin();
|
||||
CHECK((*itr));
|
||||
CHECK(("empty" == (*itr)->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*itr)->features()));
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
|
||||
CHECK(false == !itr->get());
|
||||
++itr;
|
||||
CHECK((*itr));
|
||||
|
@ -406,7 +408,7 @@ SECTION("test_readCustomizedValues") {
|
|||
auto itr = meta._analyzers.begin();
|
||||
CHECK((*itr));
|
||||
CHECK(("empty" == (*itr)->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*itr)->features()));
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
|
||||
CHECK(false == !itr->get());
|
||||
++itr;
|
||||
CHECK((*itr));
|
||||
|
@ -423,7 +425,7 @@ SECTION("test_readCustomizedValues") {
|
|||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string tmpString;
|
||||
CHECK((true == meta.init(json->slice(), tmpString, arangodb::iresearch::IResearchLinkMeta::DEFAULT(), &vocbase)));
|
||||
CHECK((true == meta.init(json->slice(), tmpString, &vocbase)));
|
||||
CHECK((3U == meta._fields.size()));
|
||||
|
||||
for (auto& field: meta._fields) {
|
||||
|
@ -453,8 +455,10 @@ SECTION("test_readCustomizedValues") {
|
|||
CHECK((arangodb::iresearch::ValueStorage::FULL == actual._storeValues));
|
||||
CHECK((1U == actual._analyzers.size()));
|
||||
CHECK((*(actual._analyzers.begin())));
|
||||
/* FIXME TODO uncomment once emplace(...) and all tests are updated
|
||||
CHECK(("testVocbase::empty" == (*(actual._analyzers.begin()))->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*(actual._analyzers.begin()))->features()));
|
||||
*/
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*(actual._analyzers.begin()))->features()));
|
||||
CHECK((false == !actual._analyzers.begin()->get()));
|
||||
} else if ("some" == fieldOverride.key()) {
|
||||
CHECK((true == actual._fields.empty())); // not inherited
|
||||
|
@ -464,8 +468,10 @@ SECTION("test_readCustomizedValues") {
|
|||
CHECK((2U == actual._analyzers.size()));
|
||||
auto itr = actual._analyzers.begin();
|
||||
CHECK((*itr));
|
||||
/* FIXME TODO uncomment once emplace(...) and all tests are updated
|
||||
CHECK(("testVocbase::empty" == (*itr)->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*itr)->features()));
|
||||
*/
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
|
||||
CHECK((false == !itr->get()));
|
||||
++itr;
|
||||
CHECK((*itr));
|
||||
|
@ -479,8 +485,10 @@ SECTION("test_readCustomizedValues") {
|
|||
CHECK((arangodb::iresearch::ValueStorage::FULL == actual._storeValues));
|
||||
auto itr = actual._analyzers.begin();
|
||||
CHECK((*itr));
|
||||
/* FIXME TODO uncomment once emplace(...) and all tests are updated
|
||||
CHECK(("testVocbase::empty" == (*itr)->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*itr)->features()));
|
||||
*/
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
|
||||
CHECK((false == !itr->get()));
|
||||
++itr;
|
||||
CHECK((*itr));
|
||||
|
@ -498,8 +506,10 @@ SECTION("test_readCustomizedValues") {
|
|||
CHECK((arangodb::iresearch::ValueStorage::FULL == meta._storeValues));
|
||||
auto itr = meta._analyzers.begin();
|
||||
CHECK((*itr));
|
||||
/* FIXME TODO uncomment once emplace(...) and all tests are updated
|
||||
CHECK(("testVocbase::empty" == (*itr)->name()));
|
||||
CHECK((irs::flags({TestAttribute::type()}) == (*itr)->features()));
|
||||
*/
|
||||
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
|
||||
CHECK((false == !itr->get()));
|
||||
++itr;
|
||||
CHECK((*itr));
|
||||
|
@ -510,14 +520,14 @@ SECTION("test_readCustomizedValues") {
|
|||
}
|
||||
|
||||
SECTION("test_writeDefaults") {
|
||||
// without active vobcase
|
||||
// without active vobcase (not fullAnalyzerDefinition)
|
||||
{
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder)));
|
||||
CHECK((true == meta.json(builder, false)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
@ -541,7 +551,40 @@ SECTION("test_writeDefaults") {
|
|||
));
|
||||
}
|
||||
|
||||
// with active vocbase
|
||||
// without active vobcase (with fullAnalyzerDefinition)
|
||||
{
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, true)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK((5U == slice.length()));
|
||||
tmpSlice = slice.get("fields");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
tmpSlice = slice.get("includeAllFields");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("none") == tmpSlice.copyString()));
|
||||
tmpSlice = slice.get("analyzers");
|
||||
CHECK((
|
||||
true == tmpSlice.isArray()
|
||||
&& 1 == tmpSlice.length()
|
||||
&& tmpSlice.at(0).isObject()
|
||||
&& tmpSlice.at(0).get("name").isString() && std::string("identity") == tmpSlice.at(0).get("name").copyString()
|
||||
&& tmpSlice.at(0).get("type").isString() && std::string("identity") == tmpSlice.at(0).get("type").copyString()
|
||||
&& tmpSlice.at(0).get("properties").isString() && std::string("") == tmpSlice.at(0).get("properties").copyString()
|
||||
&& tmpSlice.at(0).get("features").isArray() && 2 == tmpSlice.at(0).get("features").length() // frequency+norm
|
||||
));
|
||||
}
|
||||
|
||||
// with active vocbase (not fullAnalyzerDefinition)
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
|
@ -549,7 +592,7 @@ SECTION("test_writeDefaults") {
|
|||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, nullptr, &vocbase)));
|
||||
CHECK((true == meta.json(builder, false, nullptr, &vocbase)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
@ -572,21 +615,55 @@ SECTION("test_writeDefaults") {
|
|||
std::string("identity") == tmpSlice.at(0).copyString()
|
||||
));
|
||||
}
|
||||
|
||||
// with active vocbase (with fullAnalyzerDefinition)
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::velocypack::Builder builder;
|
||||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, true, nullptr, &vocbase)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK((5U == slice.length()));
|
||||
tmpSlice = slice.get("fields");
|
||||
CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length()));
|
||||
tmpSlice = slice.get("includeAllFields");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("none") == tmpSlice.copyString()));
|
||||
tmpSlice = slice.get("analyzers");
|
||||
CHECK((
|
||||
true == tmpSlice.isArray()
|
||||
&& 1 == tmpSlice.length()
|
||||
&& tmpSlice.at(0).isObject()
|
||||
&& tmpSlice.at(0).get("name").isString() && std::string("identity") == tmpSlice.at(0).get("name").copyString()
|
||||
&& tmpSlice.at(0).get("type").isString() && std::string("identity") == tmpSlice.at(0).get("type").copyString()
|
||||
&& tmpSlice.at(0).get("properties").isString() && std::string("") == tmpSlice.at(0).get("properties").copyString()
|
||||
&& tmpSlice.at(0).get("features").isArray() && 2 == tmpSlice.at(0).get("features").length() // frequency+norm
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test_writeCustomizedValues") {
|
||||
arangodb::iresearch::IResearchAnalyzerFeature analyzers(s.server);
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult emplaceResult;
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
|
||||
analyzers.emplace("identity", "identity", "");
|
||||
analyzers.emplace("empty", "empty", "en");
|
||||
analyzers.emplace(emplaceResult, "empty", "empty", "en", { irs::attribute::type_id::get("position") });
|
||||
|
||||
meta._includeAllFields = true;
|
||||
meta._trackListPositions = true;
|
||||
meta._storeValues = arangodb::iresearch::ValueStorage::FULL;
|
||||
meta._analyzers.clear();
|
||||
meta._analyzers.emplace_back(analyzers.ensure("identity"));
|
||||
meta._analyzers.emplace_back(analyzers.ensure("empty"));
|
||||
meta._analyzers.emplace_back(analyzers.get("identity"));
|
||||
meta._analyzers.emplace_back(analyzers.get("empty"));
|
||||
meta._fields["a"] = meta; // copy from meta
|
||||
meta._fields["a"]->_fields.clear(); // do not inherit fields to match jSon inheritance
|
||||
meta._fields["b"] = meta; // copy from meta
|
||||
|
@ -609,13 +686,13 @@ SECTION("test_writeCustomizedValues") {
|
|||
overrideAll._trackListPositions = false;
|
||||
overrideAll._storeValues = arangodb::iresearch::ValueStorage::NONE;
|
||||
overrideAll._analyzers.clear();
|
||||
overrideAll._analyzers.emplace_back(analyzers.ensure("empty"));
|
||||
overrideAll._analyzers.emplace_back(analyzers.get("empty"));
|
||||
overrideSome._fields.clear(); // do not inherit fields to match jSon inheritance
|
||||
overrideSome._trackListPositions = false;
|
||||
overrideSome._storeValues = arangodb::iresearch::ValueStorage::ID;
|
||||
overrideNone._fields.clear(); // do not inherit fields to match jSon inheritance
|
||||
|
||||
// without active vobcase
|
||||
// without active vobcase (not fullAnalyzerDefinition)
|
||||
{
|
||||
std::unordered_set<std::string> expectedFields = { "a", "b", "c" };
|
||||
std::unordered_set<std::string> expectedOverrides = { "default", "all", "some", "none" };
|
||||
|
@ -624,7 +701,7 @@ SECTION("test_writeCustomizedValues") {
|
|||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder)));
|
||||
CHECK((true == meta.json(builder, false)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
@ -721,7 +798,128 @@ SECTION("test_writeCustomizedValues") {
|
|||
CHECK((true == expectedAnalyzers.empty()));
|
||||
}
|
||||
|
||||
// with active vocbase
|
||||
// without active vobcase (with fullAnalyzerDefinition)
|
||||
{
|
||||
std::unordered_set<std::string> expectedFields = { "a", "b", "c" };
|
||||
std::unordered_set<std::string> expectedOverrides = { "default", "all", "some", "none" };
|
||||
std::set<std::pair<std::string, std::string>> expectedAnalyzers = {
|
||||
{ "empty", "en" },
|
||||
{ "identity", "" },
|
||||
};
|
||||
arangodb::velocypack::Builder builder;
|
||||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, true)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK((5U == slice.length()));
|
||||
tmpSlice = slice.get("fields");
|
||||
CHECK((true == tmpSlice.isObject() && 3 == tmpSlice.length()));
|
||||
|
||||
for (arangodb::velocypack::ObjectIterator itr(tmpSlice); itr.valid(); ++itr) {
|
||||
auto key = itr.key();
|
||||
auto value = itr.value();
|
||||
CHECK((true == key.isString() && 1 == expectedFields.erase(key.copyString())));
|
||||
CHECK((true == value.isObject()));
|
||||
|
||||
if (!value.hasKey("fields")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmpSlice = value.get("fields");
|
||||
|
||||
for (arangodb::velocypack::ObjectIterator overrideItr(tmpSlice); overrideItr.valid(); ++overrideItr) {
|
||||
auto fieldOverride = overrideItr.key();
|
||||
auto sliceOverride = overrideItr.value();
|
||||
CHECK((true == fieldOverride.isString() && sliceOverride.isObject()));
|
||||
CHECK((1U == expectedOverrides.erase(fieldOverride.copyString())));
|
||||
|
||||
if ("default" == fieldOverride.copyString()) {
|
||||
CHECK((4U == sliceOverride.length()));
|
||||
tmpSlice = sliceOverride.get("includeAllFields");
|
||||
CHECK((true == (false == tmpSlice.getBool())));
|
||||
tmpSlice = sliceOverride.get("trackListPositions");
|
||||
CHECK((true == (false == tmpSlice.getBool())));
|
||||
tmpSlice = sliceOverride.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("none") == tmpSlice.copyString()));
|
||||
tmpSlice = sliceOverride.get("analyzers");
|
||||
CHECK((
|
||||
true == tmpSlice.isArray()
|
||||
&& 1 == tmpSlice.length()
|
||||
&& tmpSlice.at(0).isObject()
|
||||
&& tmpSlice.at(0).get("name").isString() && std::string("identity") == tmpSlice.at(0).get("name").copyString()
|
||||
&& tmpSlice.at(0).get("type").isString() && std::string("identity") == tmpSlice.at(0).get("type").copyString()
|
||||
&& tmpSlice.at(0).get("properties").isString() && std::string("") == tmpSlice.at(0).get("properties").copyString()
|
||||
&& tmpSlice.at(0).get("features").isArray() && 2 == tmpSlice.at(0).get("features").length() // frequency+norm
|
||||
));
|
||||
} else if ("all" == fieldOverride.copyString()) {
|
||||
std::unordered_set<std::string> expectedFields = { "x", "y" };
|
||||
CHECK((5U == sliceOverride.length()));
|
||||
tmpSlice = sliceOverride.get("fields");
|
||||
CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length()));
|
||||
for (arangodb::velocypack::ObjectIterator overrideFieldItr(tmpSlice); overrideFieldItr.valid(); ++overrideFieldItr) {
|
||||
CHECK((true == overrideFieldItr.key().isString() && 1 == expectedFields.erase(overrideFieldItr.key().copyString())));
|
||||
}
|
||||
CHECK((true == expectedFields.empty()));
|
||||
tmpSlice = sliceOverride.get("includeAllFields");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = sliceOverride.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = sliceOverride.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("none") == tmpSlice.copyString()));
|
||||
tmpSlice = sliceOverride.get("analyzers");
|
||||
CHECK((
|
||||
true == tmpSlice.isArray()
|
||||
&& 1 == tmpSlice.length()
|
||||
&& tmpSlice.at(0).isObject()
|
||||
&& tmpSlice.at(0).get("name").isString() && std::string("empty") == tmpSlice.at(0).get("name").copyString()
|
||||
&& tmpSlice.at(0).get("type").isString() && std::string("empty") == tmpSlice.at(0).get("type").copyString()
|
||||
&& tmpSlice.at(0).get("properties").isString() && std::string("en") == tmpSlice.at(0).get("properties").copyString()
|
||||
&& tmpSlice.at(0).get("features").isArray() && 1 == tmpSlice.at(0).get("features").length()
|
||||
&& tmpSlice.at(0).get("features").at(0).isString() && std::string("position") == tmpSlice.at(0).get("features").at(0).copyString()
|
||||
));
|
||||
} else if ("some" == fieldOverride.copyString()) {
|
||||
CHECK((2U == sliceOverride.length()));
|
||||
tmpSlice = sliceOverride.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = sliceOverride.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("id") == tmpSlice.copyString()));
|
||||
} else if ("none" == fieldOverride.copyString()) {
|
||||
CHECK((0U == sliceOverride.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK((true == expectedOverrides.empty()));
|
||||
CHECK((true == expectedFields.empty()));
|
||||
tmpSlice = slice.get("includeAllFields");
|
||||
CHECK((true == tmpSlice.isBool() && true == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && true == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("full") == tmpSlice.copyString()));
|
||||
tmpSlice = slice.get("analyzers");
|
||||
CHECK((true == tmpSlice.isArray() && 2 == tmpSlice.length()));
|
||||
|
||||
for (arangodb::velocypack::ArrayIterator analyzersItr(tmpSlice); analyzersItr.valid(); ++analyzersItr) {
|
||||
auto value = *analyzersItr;
|
||||
CHECK((
|
||||
true == value.isObject()
|
||||
&& value.hasKey("name") && value.get("name").isString()
|
||||
&& value.hasKey("type") && value.get("type").isString()
|
||||
&& value.hasKey("properties") && value.get("properties").isString()
|
||||
&& value.hasKey("features") && value.get("features").isArray() && (1 == value.get("features").length() || 2 == value.get("features").length()) // empty/identity 1/2
|
||||
&& 1 == expectedAnalyzers.erase(std::make_pair(value.get("name").copyString(), value.get("properties").copyString()))
|
||||
));
|
||||
}
|
||||
|
||||
CHECK((true == expectedAnalyzers.empty()));
|
||||
}
|
||||
|
||||
// with active vocbase (no fullAnalyzerDefinition)
|
||||
{
|
||||
std::unordered_set<std::string> expectedFields = { "a", "b", "c" };
|
||||
std::unordered_set<std::string> expectedOverrides = { "default", "all", "some", "none" };
|
||||
|
@ -731,7 +929,7 @@ SECTION("test_writeCustomizedValues") {
|
|||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, nullptr, &vocbase)));
|
||||
CHECK((true == meta.json(builder, false, nullptr, &vocbase)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
@ -827,6 +1025,128 @@ SECTION("test_writeCustomizedValues") {
|
|||
|
||||
CHECK((true == expectedAnalyzers.empty()));
|
||||
}
|
||||
|
||||
// with active vocbase (with fullAnalyzerDefinition)
|
||||
{
|
||||
std::unordered_set<std::string> expectedFields = { "a", "b", "c" };
|
||||
std::unordered_set<std::string> expectedOverrides = { "default", "all", "some", "none" };
|
||||
std::set<std::pair<std::string, std::string>> expectedAnalyzers = {
|
||||
{ "empty", "en" },
|
||||
{ "identity", "" },
|
||||
};
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
arangodb::velocypack::Builder builder;
|
||||
arangodb::velocypack::Slice tmpSlice;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, true, nullptr, &vocbase)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK((5U == slice.length()));
|
||||
tmpSlice = slice.get("fields");
|
||||
CHECK((true == tmpSlice.isObject() && 3 == tmpSlice.length()));
|
||||
|
||||
for (arangodb::velocypack::ObjectIterator itr(tmpSlice); itr.valid(); ++itr) {
|
||||
auto key = itr.key();
|
||||
auto value = itr.value();
|
||||
CHECK((true == key.isString() && 1 == expectedFields.erase(key.copyString())));
|
||||
CHECK((true == value.isObject()));
|
||||
|
||||
if (!value.hasKey("fields")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmpSlice = value.get("fields");
|
||||
|
||||
for (arangodb::velocypack::ObjectIterator overrideItr(tmpSlice); overrideItr.valid(); ++overrideItr) {
|
||||
auto fieldOverride = overrideItr.key();
|
||||
auto sliceOverride = overrideItr.value();
|
||||
CHECK((true == fieldOverride.isString() && sliceOverride.isObject()));
|
||||
CHECK((1U == expectedOverrides.erase(fieldOverride.copyString())));
|
||||
|
||||
if ("default" == fieldOverride.copyString()) {
|
||||
CHECK((4U == sliceOverride.length()));
|
||||
tmpSlice = sliceOverride.get("includeAllFields");
|
||||
CHECK((true == (false == tmpSlice.getBool())));
|
||||
tmpSlice = sliceOverride.get("trackListPositions");
|
||||
CHECK((true == (false == tmpSlice.getBool())));
|
||||
tmpSlice = sliceOverride.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("none") == tmpSlice.copyString()));
|
||||
tmpSlice = sliceOverride.get("analyzers");
|
||||
CHECK((
|
||||
true == tmpSlice.isArray()
|
||||
&& 1 == tmpSlice.length()
|
||||
&& tmpSlice.at(0).isObject()
|
||||
&& tmpSlice.at(0).get("name").isString() && std::string("identity") == tmpSlice.at(0).get("name").copyString()
|
||||
&& tmpSlice.at(0).get("type").isString() && std::string("identity") == tmpSlice.at(0).get("type").copyString()
|
||||
&& tmpSlice.at(0).get("properties").isString() && std::string("") == tmpSlice.at(0).get("properties").copyString()
|
||||
&& tmpSlice.at(0).get("features").isArray() && 2 == tmpSlice.at(0).get("features").length() // frequency+norm
|
||||
));
|
||||
} else if ("all" == fieldOverride.copyString()) {
|
||||
std::unordered_set<std::string> expectedFields = { "x", "y" };
|
||||
CHECK((5U == sliceOverride.length()));
|
||||
tmpSlice = sliceOverride.get("fields");
|
||||
CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length()));
|
||||
for (arangodb::velocypack::ObjectIterator overrideFieldItr(tmpSlice); overrideFieldItr.valid(); ++overrideFieldItr) {
|
||||
CHECK((true == overrideFieldItr.key().isString() && 1 == expectedFields.erase(overrideFieldItr.key().copyString())));
|
||||
}
|
||||
CHECK((true == expectedFields.empty()));
|
||||
tmpSlice = sliceOverride.get("includeAllFields");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = sliceOverride.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = sliceOverride.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("none") == tmpSlice.copyString()));
|
||||
tmpSlice = sliceOverride.get("analyzers");
|
||||
CHECK((
|
||||
true == tmpSlice.isArray()
|
||||
&& 1 == tmpSlice.length()
|
||||
&& tmpSlice.at(0).isObject()
|
||||
&& tmpSlice.at(0).get("name").isString() && std::string("empty") == tmpSlice.at(0).get("name").copyString()
|
||||
&& tmpSlice.at(0).get("type").isString() && std::string("empty") == tmpSlice.at(0).get("type").copyString()
|
||||
&& tmpSlice.at(0).get("properties").isString() && std::string("en") == tmpSlice.at(0).get("properties").copyString()
|
||||
&& tmpSlice.at(0).get("features").isArray() && 1 == tmpSlice.at(0).get("features").length()
|
||||
&& tmpSlice.at(0).get("features").at(0).isString() && std::string("position") == tmpSlice.at(0).get("features").at(0).copyString()
|
||||
));
|
||||
} else if ("some" == fieldOverride.copyString()) {
|
||||
CHECK((2U == sliceOverride.length()));
|
||||
tmpSlice = sliceOverride.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && false == tmpSlice.getBool()));
|
||||
tmpSlice = sliceOverride.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("id") == tmpSlice.copyString()));
|
||||
} else if ("none" == fieldOverride.copyString()) {
|
||||
CHECK((0U == sliceOverride.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK((true == expectedOverrides.empty()));
|
||||
CHECK((true == expectedFields.empty()));
|
||||
tmpSlice = slice.get("includeAllFields");
|
||||
CHECK((true == tmpSlice.isBool() && true == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("trackListPositions");
|
||||
CHECK((true == tmpSlice.isBool() && true == tmpSlice.getBool()));
|
||||
tmpSlice = slice.get("storeValues");
|
||||
CHECK((true == tmpSlice.isString() && std::string("full") == tmpSlice.copyString()));
|
||||
tmpSlice = slice.get("analyzers");
|
||||
CHECK((true == tmpSlice.isArray() && 2 == tmpSlice.length()));
|
||||
|
||||
for (arangodb::velocypack::ArrayIterator analyzersItr(tmpSlice); analyzersItr.valid(); ++analyzersItr) {
|
||||
auto value = *analyzersItr;
|
||||
CHECK((
|
||||
true == value.isObject()
|
||||
&& value.hasKey("name") && value.get("name").isString()
|
||||
&& value.hasKey("type") && value.get("type").isString()
|
||||
&& value.hasKey("properties") && value.get("properties").isString()
|
||||
&& value.hasKey("features") && value.get("features").isArray() && (1 == value.get("features").length() || 2 == value.get("features").length()) // empty/identity 1/2
|
||||
&& 1 == expectedAnalyzers.erase(std::make_pair(value.get("name").copyString(), value.get("properties").copyString()))
|
||||
));
|
||||
}
|
||||
|
||||
CHECK((true == expectedAnalyzers.empty()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test_readMaskAll") {
|
||||
|
@ -841,7 +1161,7 @@ SECTION("test_readMaskAll") {
|
|||
\"storeValues\": \"full\", \
|
||||
\"analyzers\": [] \
|
||||
}");
|
||||
CHECK(true == meta.init(json->slice(), tmpString, arangodb::iresearch::IResearchLinkMeta::DEFAULT(), nullptr, &mask));
|
||||
CHECK(true == meta.init(json->slice(), tmpString, nullptr, arangodb::iresearch::IResearchLinkMeta::DEFAULT(), &mask));
|
||||
CHECK(true == mask._fields);
|
||||
CHECK(true == mask._includeAllFields);
|
||||
CHECK(true == mask._trackListPositions);
|
||||
|
@ -855,7 +1175,7 @@ SECTION("test_readMaskNone") {
|
|||
std::string tmpString;
|
||||
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{}");
|
||||
CHECK(true == meta.init(json->slice(), tmpString, arangodb::iresearch::IResearchLinkMeta::DEFAULT(), nullptr, &mask));
|
||||
CHECK(true == meta.init(json->slice(), tmpString, nullptr, arangodb::iresearch::IResearchLinkMeta::DEFAULT(), &mask));
|
||||
CHECK(false == mask._fields);
|
||||
CHECK(false == mask._includeAllFields);
|
||||
CHECK(false == mask._trackListPositions);
|
||||
|
@ -864,36 +1184,308 @@ SECTION("test_readMaskNone") {
|
|||
}
|
||||
|
||||
SECTION("test_writeMaskAll") {
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::iresearch::IResearchLinkMeta::Mask mask(true);
|
||||
arangodb::velocypack::Builder builder;
|
||||
// not fullAnalyzerDefinition
|
||||
{
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::iresearch::IResearchLinkMeta::Mask mask(true);
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, nullptr, nullptr, &mask)));
|
||||
builder.close();
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, false, nullptr, nullptr, &mask)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK((5U == slice.length()));
|
||||
CHECK(true == slice.hasKey("fields"));
|
||||
CHECK(true == slice.hasKey("includeAllFields"));
|
||||
CHECK(true == slice.hasKey("trackListPositions"));
|
||||
CHECK(true == slice.hasKey("storeValues"));
|
||||
CHECK(true == slice.hasKey("analyzers"));
|
||||
CHECK((5U == slice.length()));
|
||||
CHECK(true == slice.hasKey("fields"));
|
||||
CHECK(true == slice.hasKey("includeAllFields"));
|
||||
CHECK(true == slice.hasKey("trackListPositions"));
|
||||
CHECK(true == slice.hasKey("storeValues"));
|
||||
CHECK(true == slice.hasKey("analyzers"));
|
||||
}
|
||||
|
||||
// with fullAnalyzerDefinition
|
||||
{
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::iresearch::IResearchLinkMeta::Mask mask(true);
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, true, nullptr, nullptr, &mask)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK((5U == slice.length()));
|
||||
CHECK(true == slice.hasKey("fields"));
|
||||
CHECK(true == slice.hasKey("includeAllFields"));
|
||||
CHECK(true == slice.hasKey("trackListPositions"));
|
||||
CHECK(true == slice.hasKey("storeValues"));
|
||||
CHECK(true == slice.hasKey("analyzers"));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test_writeMaskNone") {
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::iresearch::IResearchLinkMeta::Mask mask(false);
|
||||
arangodb::velocypack::Builder builder;
|
||||
// not fullAnalyzerDefinition
|
||||
{
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::iresearch::IResearchLinkMeta::Mask mask(false);
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, nullptr, nullptr, &mask)));
|
||||
builder.close();
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, false, nullptr, nullptr, &mask)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK(0U == slice.length());
|
||||
CHECK(0U == slice.length());
|
||||
}
|
||||
|
||||
// with fullAnalyzerDefinition
|
||||
{
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
arangodb::iresearch::IResearchLinkMeta::Mask mask(false);
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
CHECK((true == meta.json(builder, true, nullptr, nullptr, &mask)));
|
||||
builder.close();
|
||||
|
||||
auto slice = builder.slice();
|
||||
|
||||
CHECK(0U == slice.length());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test_readAnalyzerDefinitions") {
|
||||
// missing analyzer (name only)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ \"empty1\" ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>empty1") == errorField));
|
||||
}
|
||||
|
||||
// missing analyzer (name only) inRecovery
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ \"empty1\" ] \
|
||||
}");
|
||||
auto before = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>empty1") == errorField));
|
||||
}
|
||||
|
||||
// missing analyzer (full) no name (fail) required
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]=>name") == errorField));
|
||||
}
|
||||
|
||||
// missing analyzer (full) no type (fail) required
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"missing0\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]=>type") == errorField));
|
||||
}
|
||||
|
||||
// missing analyzer (full) analyzer creation not allowed (fail)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"missing0\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]") == errorField));
|
||||
}
|
||||
|
||||
// missing analyzer (full) single-server
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"missing0\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]") == errorField));
|
||||
}
|
||||
|
||||
// missing analyzer (full) coordinator
|
||||
{
|
||||
auto before = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR);
|
||||
auto restore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
|
||||
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"missing1\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]") == errorField));
|
||||
}
|
||||
|
||||
// missing analyzer (full) db-server
|
||||
{
|
||||
auto before = arangodb::ServerState::instance()->getRole();
|
||||
arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER);
|
||||
auto restore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
|
||||
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"missing2\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((true == meta.init(json->slice(), errorField)));
|
||||
CHECK((1 == meta._analyzers.size()));
|
||||
CHECK((std::string("missing2") == meta._analyzers[0]->name()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->type()));
|
||||
CHECK((std::string("ru") == meta._analyzers[0]->properties()));
|
||||
CHECK((1 == meta._analyzers[0]->features().size()));
|
||||
CHECK((true == meta._analyzers[0]->features().check(irs::frequency::type())));
|
||||
}
|
||||
|
||||
// missing analyzer (full) inRecovery
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"missing3\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
|
||||
}");
|
||||
auto before = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]") == errorField));
|
||||
}
|
||||
|
||||
// existing analyzer (name only)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ \"empty\" ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((true == meta.init(json->slice(), errorField)));
|
||||
CHECK((1 == meta._analyzers.size()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->name()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->type()));
|
||||
CHECK((std::string("en") == meta._analyzers[0]->properties()));
|
||||
CHECK((1 == meta._analyzers[0]->features().size()));
|
||||
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
|
||||
}
|
||||
|
||||
// existing analyzer (name only) inRecovery
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ \"empty\" ] \
|
||||
}");
|
||||
auto before = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((true == meta.init(json->slice(), errorField)));
|
||||
CHECK((1 == meta._analyzers.size()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->name()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->type()));
|
||||
CHECK((std::string("en") == meta._analyzers[0]->properties()));
|
||||
CHECK((1 == meta._analyzers[0]->features().size()));
|
||||
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
|
||||
}
|
||||
|
||||
// existing analyzer (full) analyzer creation not allowed (passs)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"TestAttributeZ\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((true == meta.init(json->slice(), errorField)));
|
||||
CHECK((1 == meta._analyzers.size()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->name()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->type()));
|
||||
CHECK((std::string("en") == meta._analyzers[0]->properties()));
|
||||
CHECK((1 == meta._analyzers[0]->features().size()));
|
||||
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
|
||||
}
|
||||
|
||||
// existing analyzer (full)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"TestAttributeZ\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((true == meta.init(json->slice(), errorField)));
|
||||
CHECK((1 == meta._analyzers.size()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->name()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->type()));
|
||||
CHECK((std::string("en") == meta._analyzers[0]->properties()));
|
||||
CHECK((1 == meta._analyzers[0]->features().size()));
|
||||
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
|
||||
}
|
||||
|
||||
// existing analyzer (full) inRecovery
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"TestAttributeZ\" ] } ] \
|
||||
}");
|
||||
auto before = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((true == meta.init(json->slice(), errorField)));
|
||||
CHECK((1 == meta._analyzers.size()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->name()));
|
||||
CHECK((std::string("empty") == meta._analyzers[0]->type()));
|
||||
CHECK((std::string("en") == meta._analyzers[0]->properties()));
|
||||
CHECK((1 == meta._analyzers[0]->features().size()));
|
||||
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
|
||||
}
|
||||
|
||||
// existing analyzer (definition mismatch)
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"TestAttributeZ\" ] } ] \
|
||||
}");
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]") == errorField));
|
||||
}
|
||||
|
||||
// existing analyzer (definition mismatch) inRecovery
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"TestAttributeZ\" ] } ] \
|
||||
}");
|
||||
auto before = StorageEngineMock::inRecoveryResult;
|
||||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
arangodb::iresearch::IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
CHECK((false == meta.init(json->slice(), errorField)));
|
||||
CHECK((std::string("analyzers=>[0]") == errorField));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -192,13 +192,6 @@ struct IResearchQuerySetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
@ -241,4 +234,4 @@ TEST_CASE("IResearchQueryTest", "[iresearch][iresearch-query]") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -129,13 +129,6 @@ struct IResearchQueryAggregateSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -133,9 +133,10 @@ struct IResearchQueryAndSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
|
|
|
@ -131,13 +131,6 @@ struct IResearchQueryBooleanTermSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -133,8 +133,10 @@ struct IResearchQueryComplexBooleanSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace(
|
||||
result,
|
||||
"test_analyzer",
|
||||
"TestAnalyzer",
|
||||
"abc",
|
||||
|
@ -142,6 +144,7 @@ struct IResearchQueryComplexBooleanSetup {
|
|||
); // cache analyzer
|
||||
|
||||
analyzers->emplace(
|
||||
result,
|
||||
"test_csv_analyzer",
|
||||
"TestDelimAnalyzer",
|
||||
","
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
#endif
|
||||
|
||||
#include "Basics/files.h"
|
||||
#include "Cluster/ClusterFeature.h"
|
||||
#include "V8/v8-globals.h"
|
||||
#include "V8Server/V8DealerFeature.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/LogicalView.h"
|
||||
#include "VocBase/ManagedDocumentResult.h"
|
||||
|
@ -98,6 +100,8 @@ struct IResearchQueryExistsSetup {
|
|||
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
|
||||
|
||||
// setup required application features
|
||||
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required by IResearchFilterFactory::extractAnalyzerFromArg(...)
|
||||
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::AuthenticationFeature(server), true);
|
||||
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
|
||||
|
@ -118,6 +122,11 @@ struct IResearchQueryExistsSetup {
|
|||
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
|
||||
#endif
|
||||
|
||||
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
|
||||
arangodb::application_features::ApplicationServer::server->addFeature(
|
||||
new arangodb::ClusterFeature(server)
|
||||
);
|
||||
|
||||
for (auto& f : features) {
|
||||
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
|
||||
}
|
||||
|
@ -126,19 +135,18 @@ struct IResearchQueryExistsSetup {
|
|||
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) {
|
||||
if (f.second) {
|
||||
f.first->start();
|
||||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
@ -150,7 +158,6 @@ struct IResearchQueryExistsSetup {
|
|||
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
|
||||
arangodb::LogTopic::setLogLevel(arangodb::Logger::AQL.name(), arangodb::LogLevel::DEFAULT);
|
||||
arangodb::application_features::ApplicationServer::server = nullptr;
|
||||
arangodb::EngineSelectorFeature::ENGINE = nullptr;
|
||||
|
||||
// destroy application features
|
||||
for (auto& f : features) {
|
||||
|
@ -164,6 +171,7 @@ struct IResearchQueryExistsSetup {
|
|||
}
|
||||
|
||||
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
|
||||
arangodb::EngineSelectorFeature::ENGINE = nullptr;
|
||||
}
|
||||
}; // IResearchQuerySetup
|
||||
|
||||
|
@ -181,7 +189,21 @@ TEST_CASE("IResearchQueryTestExists", "[iresearch][iresearch-query]") {
|
|||
IResearchQueryExistsSetup s;
|
||||
UNUSED(s);
|
||||
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
REQUIRE((nullptr != analyzers));
|
||||
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::DatabaseFeature
|
||||
>("Database");
|
||||
TRI_vocbase_t* vocbasePtr;
|
||||
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbasePtr))); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
REQUIRE((nullptr != vocbasePtr));
|
||||
auto& vocbase = *vocbasePtr;
|
||||
//TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
REQUIRE((analyzers->emplace(result, "testVocbase::text_en", "text", "{ \"locale\": \"en.UTF-8\", \"ignored_words\": [ ] }", { irs::frequency::type(), irs::norm::type(), irs::position::type() }).ok()));
|
||||
REQUIRE((false == !result.first));
|
||||
std::vector<arangodb::velocypack::Builder> insertedDocs;
|
||||
arangodb::LogicalView* view;
|
||||
|
||||
|
|
|
@ -131,13 +131,6 @@ struct IResearchQueryInSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -180,9 +180,10 @@ struct IResearchQueryJoinSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
|
|
|
@ -130,13 +130,6 @@ struct IResearchQueryNullTermSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -131,13 +131,6 @@ struct IResearchQueryNumericTermSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -161,13 +161,6 @@ struct IResearchQueryOptionsSetup {
|
|||
return params[0];
|
||||
}});
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -134,8 +134,10 @@ struct IResearchQueryOrSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace(
|
||||
result,
|
||||
"test_analyzer",
|
||||
"TestAnalyzer",
|
||||
"abc",
|
||||
|
@ -143,6 +145,7 @@ struct IResearchQueryOrSetup {
|
|||
); // cache analyzer
|
||||
|
||||
analyzers->emplace(
|
||||
result,
|
||||
"test_csv_analyzer",
|
||||
"TestDelimAnalyzer",
|
||||
","
|
||||
|
|
|
@ -133,8 +133,10 @@ struct IResearchQueryPhraseSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace(
|
||||
result,
|
||||
"test_analyzer",
|
||||
"TestAnalyzer",
|
||||
"abc",
|
||||
|
@ -142,6 +144,7 @@ struct IResearchQueryPhraseSetup {
|
|||
); // cache analyzer
|
||||
|
||||
analyzers->emplace(
|
||||
result,
|
||||
"test_csv_analyzer",
|
||||
"TestDelimAnalyzer",
|
||||
","
|
||||
|
|
|
@ -179,9 +179,10 @@ struct IResearchQueryScorerSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
|
|
|
@ -130,13 +130,6 @@ struct IResearchQuerySelectAllSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -130,13 +130,6 @@ struct IResearchQueryStartsWithSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -161,13 +161,6 @@ struct IResearchQueryStringTermSetup {
|
|||
return params[0];
|
||||
}});
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -154,9 +154,10 @@ struct IResearchQueryTokensSetup {
|
|||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
||||
analyzers->emplace("testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("testVocbase::test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
|
|
|
@ -130,13 +130,6 @@ struct IResearchQueryTraversalSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -129,13 +129,6 @@ struct IResearchQueryValueSetup {
|
|||
}
|
||||
}
|
||||
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchAnalyzerFeature
|
||||
>();
|
||||
|
||||
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
|
||||
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
|
||||
|
||||
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
}
|
||||
|
|
|
@ -122,6 +122,7 @@ struct IResearchViewDBServerSetup {
|
|||
buildFeatureEntry(new arangodb::QueryRegistryFeature(server), false); // required for TRI_vocbase_t instantiation
|
||||
buildFeatureEntry(new arangodb::ShardingFeature(server), false); // required for TRI_vocbase_t instantiation
|
||||
buildFeatureEntry(new arangodb::ViewTypesFeature(server), false); // required for TRI_vocbase_t::createView(...)
|
||||
buildFeatureEntry(new arangodb::iresearch::IResearchAnalyzerFeature(server), false); // required for IResearchLinkMeta::init(...)
|
||||
buildFeatureEntry(new arangodb::iresearch::IResearchFeature(server), false); // required for instantiating IResearchView*
|
||||
buildFeatureEntry(new arangodb::ClusterFeature(server), false);
|
||||
buildFeatureEntry(new arangodb::V8DealerFeature(server), false);
|
||||
|
|
Loading…
Reference in New Issue