//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2016 by EMC Corporation, All Rights Reserved /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is EMC Corporation /// /// @author Andrey Abramov /// @author Vasiliy Nabatchikov //////////////////////////////////////////////////////////////////////////////// #ifndef IRESEARCH_IQL_QUERY_BUILDER_H #define IRESEARCH_IQL_QUERY_BUILDER_H #include "shared.hpp" #include "parser_common.hpp" #include "search/filter.hpp" namespace iresearch { namespace iql { //////////////////////////////////////////////////////////////////////////////// /// @brief class for passing control to the proxied query //////////////////////////////////////////////////////////////////////////////// template class IRESEARCH_API proxy_filter_t: public iresearch::filter { public: proxy_filter_t(const type_id& type): iresearch::filter(type) {} template T& proxy(Args&&... args) { typedef typename std::enable_if< std::is_base_of::value, T >::type type; filter_ = type::make(std::forward(args)...); return static_cast(*filter_); } virtual size_t hash() const NOEXCEPT override { return !filter_ ? 0 : filter_->hash(); } virtual iresearch::filter::prepared::ptr prepare( const index_reader& rdr, const order::prepared& ord, boost_t boost, const attribute_view& ctx ) const override { return filter_->prepare(rdr, ord, boost, ctx); }; protected: virtual bool equals(const iresearch::filter& rhs) const NOEXCEPT override { const auto& typed_rhs = static_cast&>(rhs); return filter::equals(rhs) && filter_.get() == typed_rhs.filter_.get(); } protected: IRESEARCH_API_PRIVATE_VARIABLES_BEGIN PTR filter_; IRESEARCH_API_PRIVATE_VARIABLES_END }; //////////////////////////////////////////////////////////////////////////////// /// @brief proxy_filter specialized for iresearch::filter::ptr //////////////////////////////////////////////////////////////////////////////// class IRESEARCH_API proxy_filter: public proxy_filter_t { public: DECLARE_FACTORY_DEFAULT(); DECLARE_TYPE_ID(iresearch::type_id); proxy_filter(): proxy_filter_t(proxy_filter::type()) {} }; //////////////////////////////////////////////////////////////////////////////// /// @brief result of the build(...) operation /// filter set to the root of the query /// limit iff no limit requested in query then nullptr, else limit value /// error iff no error then nullptr, else the error string //////////////////////////////////////////////////////////////////////////////// struct query { iresearch::filter::ptr filter; iresearch::order* order = nullptr; size_t* limit = nullptr; std::string* error = nullptr; query(): order(nullptr), limit(nullptr), error(nullptr) {} query(query&& other): filter(std::move(other.filter)), order(other.order), limit(other.limit), error(other.error) { } }; //////////////////////////////////////////////////////////////////////////////// /// @brief helper class for transforming a textual query into an iResearch query //////////////////////////////////////////////////////////////////////////////// class IRESEARCH_API query_builder { public: //////////////////////////////////////////////////////////////////////////////// /// @brief fns to build an iResearch query branch based at 'root' for field/args /// @param root the root of the future branch /// @param locale the locale to be used for building the branch (if needed) /// @param field the field name mentioned in the IQL query /// @param cookie the user supplied cookie, passed verbatim to callees /// @param args the function arguments /// @return the branch was constructed successfully //////////////////////////////////////////////////////////////////////////////// typedef std::function branch_builder_function_t; struct IRESEARCH_API branch_builders { const branch_builder_function_t& range_ee; // range exclude/exclude - (,) const branch_builder_function_t& range_ei; // range exclude/include - (,] const branch_builder_function_t& range_ie; // range include/exclude - [,) const branch_builder_function_t& range_ii; // range include/exclude - [,] const branch_builder_function_t& similar; branch_builders( const branch_builder_function_t* range_ee = nullptr, // nullptr == default const branch_builder_function_t* range_ei = nullptr, // nullptr == default const branch_builder_function_t* range_ie = nullptr, // nullptr == default const branch_builder_function_t* range_ii = nullptr, // nullptr == default const branch_builder_function_t* similar = nullptr // nullptr == default ); branch_builders& operator=(branch_builders&) = delete; // because of refs static const branch_builders& DEFAULT(); }; //////////////////////////////////////////////////////////////////////////////// /// @brief constructor (use defaults for nullptr param values) /// @brief iql_functions user defined functions callable within the IQL query /// @brief fv_transform transform of IQL field/value into iResearch field/value //////////////////////////////////////////////////////////////////////////////// query_builder( const functions& iql_functions = functions::DEFAULT(), const branch_builders& branch_builders = branch_builders::DEFAULT() ); explicit query_builder(const branch_builders& branch_builders): query_builder(functions::DEFAULT(), branch_builders) {} query_builder& operator=(query_builder&) = delete; // because of references //////////////////////////////////////////////////////////////////////////////// /// @brief transform a textual query into an iResearch query /// @param query the query to parse/build /// @param locale the locale to use for parsing/building the query /// @param cookie a user-defined value passed verbatum to function invocations /// @param root the node to attach the query under (if not null) /// @return parsed query, iff error .error != nullptr //////////////////////////////////////////////////////////////////////////////// query build( const std::string& query, const std::locale& locale, void* cookie = nullptr, proxy_filter* root = nullptr ) const; private: const branch_builders& branch_builders_; const functions& iql_functions_; }; } } #endif