mirror of
https://github.com/KingDuckZ/dindexer.git
synced 2025-02-17 11:45:50 +00:00
Implement HSCAN Redis command.
This commit is contained in:
parent
e0a82cce2d
commit
c7eeddabf1
5 changed files with 80 additions and 11 deletions
|
@ -129,4 +129,8 @@ namespace redis {
|
|||
auto Command::scan() -> scan_range {
|
||||
return scan_range(scan_iterator(this, false), scan_iterator(this, true));
|
||||
}
|
||||
|
||||
auto Command::hscan (boost::string_ref parKey) -> hscan_range {
|
||||
return hscan_range(hscan_iterator(this, parKey, false), hscan_iterator(this, parKey, true));
|
||||
}
|
||||
} //namespace redis
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <vector>
|
||||
#include <utility>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
struct redisContext;
|
||||
|
||||
|
@ -38,6 +39,8 @@ namespace redis {
|
|||
public:
|
||||
typedef ScanIterator<std::string, ScanSingleValues<std::string>> scan_iterator;
|
||||
typedef boost::iterator_range<scan_iterator> scan_range;
|
||||
typedef ScanIterator<std::pair<std::string, std::string>, ScanPairs<std::pair<std::string, std::string>>> hscan_iterator;
|
||||
typedef boost::iterator_range<hscan_iterator> hscan_range;
|
||||
|
||||
Command ( std::string&& parAddress, uint16_t parPort );
|
||||
~Command ( void ) noexcept;
|
||||
|
@ -52,6 +55,7 @@ namespace redis {
|
|||
|
||||
//Single Redis command wrappers
|
||||
scan_range scan ( void );
|
||||
hscan_range hscan ( boost::string_ref parKey );
|
||||
|
||||
private:
|
||||
using RedisConnection = std::unique_ptr<redisContext, void(*)(redisContext*)>;
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace redis {
|
|||
return m_command->run(parCommand, boost::lexical_cast<std::string>(parScanContext));
|
||||
}
|
||||
|
||||
RedisReplyType ScanIteratorBaseClass::run (const char* parCommand, const std::string& parParameter, long long parScanContext) {
|
||||
RedisReplyType ScanIteratorBaseClass::run (const char* parCommand, const boost::string_ref& parParameter, long long parScanContext) {
|
||||
return m_command->run(parCommand, parParameter, boost::lexical_cast<std::string>(parScanContext));
|
||||
}
|
||||
} //namespace implem
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace redis {
|
||||
template <typename V, typename ValueFetch>
|
||||
|
@ -42,7 +43,7 @@ namespace redis {
|
|||
|
||||
bool is_connected ( void ) const;
|
||||
RedisReplyType run ( const char* parCommand, long long parScanContext );
|
||||
RedisReplyType run ( const char* parCommand, const std::string& parParameter, long long parScanContext );
|
||||
RedisReplyType run ( const char* parCommand, const boost::string_ref& parParameter, long long parScanContext );
|
||||
|
||||
bool is_equal ( const ScanIteratorBaseClass& parOther ) const { return m_command == parOther.m_command; }
|
||||
|
||||
|
@ -52,9 +53,10 @@ namespace redis {
|
|||
} //namespace implem
|
||||
|
||||
template <typename V, typename ValueFetch>
|
||||
class ScanIterator : private implem::ScanIteratorBaseClass, public implem::ScanIteratorBaseIterator<V, ValueFetch> {
|
||||
class ScanIterator : private implem::ScanIteratorBaseClass, public implem::ScanIteratorBaseIterator<V, ValueFetch>, private ValueFetch {
|
||||
friend class boost::iterator_core_access;
|
||||
typedef implem::ScanIteratorBaseIterator<V, ValueFetch> base_iterator;
|
||||
define_has_method(scan_target, ScanTarget);
|
||||
public:
|
||||
typedef typename base_iterator::difference_type difference_type;
|
||||
typedef typename base_iterator::value_type value_type;
|
||||
|
@ -62,11 +64,12 @@ namespace redis {
|
|||
typedef typename base_iterator::reference reference;
|
||||
typedef typename base_iterator::iterator_category iterator_category;
|
||||
|
||||
template <typename Dummy=ValueFetch, typename=typename std::enable_if<not HasScanTargetMethod<Dummy>::value>::type>
|
||||
ScanIterator ( Command* parCommand, bool parEnd );
|
||||
template <typename Dummy=ValueFetch, typename=typename std::enable_if<HasScanTargetMethod<Dummy>::value>::type>
|
||||
ScanIterator ( Command* parCommand, boost::string_ref parKey, bool parEnd );
|
||||
|
||||
private:
|
||||
define_has_method(scan_target, ScanTarget);
|
||||
|
||||
template <typename T>
|
||||
RedisReplyType forward_scan_command ( typename std::enable_if<HasScanTargetMethod<T>::value, int>::type parDummy );
|
||||
template <typename T>
|
||||
|
@ -77,7 +80,7 @@ namespace redis {
|
|||
bool equal ( const ScanIterator& parOther ) const;
|
||||
const V& dereference ( void ) const;
|
||||
|
||||
std::vector<RedisReplyType> m_reply;
|
||||
std::vector<value_type> m_reply;
|
||||
long long m_scan_context;
|
||||
std::size_t m_curr_index;
|
||||
};
|
||||
|
@ -89,6 +92,22 @@ namespace redis {
|
|||
|
||||
static const T& make_value ( const RedisReplyType* parItem );
|
||||
};
|
||||
|
||||
template <typename P, typename A=decltype(P().first), typename B=decltype(P().second)>
|
||||
struct ScanPairs {
|
||||
typedef P PairType;
|
||||
|
||||
explicit ScanPairs ( boost::string_ref parScanTarget ) : m_scan_target(parScanTarget) {}
|
||||
|
||||
static constexpr const char* command ( void ) { return "HSCAN"; }
|
||||
static constexpr const std::size_t step = 2;
|
||||
|
||||
static PairType make_value ( const RedisReplyType* parItem );
|
||||
boost::string_ref scan_target ( void );
|
||||
|
||||
private:
|
||||
boost::string_ref m_scan_target;
|
||||
};
|
||||
} //namespace redis
|
||||
|
||||
#include "scan_iterator.inl"
|
||||
|
|
|
@ -24,8 +24,31 @@ namespace redis {
|
|||
} //namespace implem
|
||||
|
||||
template <typename V, typename ValueFetch>
|
||||
template <typename Dummy, typename>
|
||||
ScanIterator<V, ValueFetch>::ScanIterator (Command* parCommand, bool parEnd) :
|
||||
implem::ScanIteratorBaseClass(parCommand),
|
||||
implem::ScanIteratorBaseIterator<V, ValueFetch>(),
|
||||
ValueFetch(),
|
||||
m_reply(),
|
||||
m_scan_context(0),
|
||||
m_curr_index(0)
|
||||
{
|
||||
if (not parEnd) {
|
||||
m_curr_index = 1; //Some arbitrary value so is_end()==false
|
||||
assert(not is_end());
|
||||
this->increment();
|
||||
}
|
||||
else {
|
||||
assert(is_end());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V, typename ValueFetch>
|
||||
template <typename Dummy, typename>
|
||||
ScanIterator<V, ValueFetch>::ScanIterator (Command* parCommand, boost::string_ref parKey, bool parEnd) :
|
||||
implem::ScanIteratorBaseClass(parCommand),
|
||||
implem::ScanIteratorBaseIterator<V, ValueFetch>(),
|
||||
ValueFetch(parKey),
|
||||
m_reply(),
|
||||
m_scan_context(0),
|
||||
m_curr_index(0)
|
||||
|
@ -50,10 +73,10 @@ namespace redis {
|
|||
assert(not is_end());
|
||||
static_assert(ValueFetch::step > 0, "Can't have an increase step of 0");
|
||||
|
||||
if (m_curr_index + ValueFetch::step < m_reply.size()) {
|
||||
m_curr_index += ValueFetch::step;
|
||||
if (m_curr_index + 1 < m_reply.size()) {
|
||||
++m_curr_index;
|
||||
}
|
||||
else if (m_curr_index + ValueFetch::step == m_reply.size() and not m_scan_context) {
|
||||
else if (m_curr_index + 1 == m_reply.size() and not m_scan_context) {
|
||||
m_reply.clear();
|
||||
m_curr_index = 0;
|
||||
}
|
||||
|
@ -70,7 +93,15 @@ namespace redis {
|
|||
new_context = get_integer_autoconv_if_str(array_reply[0]);
|
||||
} while (new_context and array_reply.empty());
|
||||
|
||||
m_reply = get_array(array_reply[1]);
|
||||
const auto variant_array = get_array(array_reply[1]);
|
||||
assert(variant_array.size() % ValueFetch::step == 0);
|
||||
const std::size_t expected_reply_count = variant_array.size() / ValueFetch::step;
|
||||
m_reply.clear();
|
||||
m_reply.reserve(expected_reply_count);
|
||||
for (std::size_t z = 0; z < variant_array.size(); z += ValueFetch::step) {
|
||||
m_reply.push_back(ValueFetch::make_value(variant_array.data() + z));
|
||||
}
|
||||
assert(expected_reply_count == m_reply.size());
|
||||
m_scan_context = new_context;
|
||||
m_curr_index = 0;
|
||||
}
|
||||
|
@ -95,7 +126,7 @@ namespace redis {
|
|||
assert(not m_reply.empty());
|
||||
assert(m_curr_index < m_reply.size());
|
||||
|
||||
return ValueFetch::make_value(m_reply.data() + m_curr_index);
|
||||
return m_reply[m_curr_index];
|
||||
}
|
||||
|
||||
template <typename V, typename ValueFetch>
|
||||
|
@ -115,4 +146,15 @@ namespace redis {
|
|||
assert(parItem);
|
||||
return get<T>(*parItem);
|
||||
}
|
||||
|
||||
template <typename P, typename A, typename B>
|
||||
P ScanPairs<P, A, B>::make_value (const RedisReplyType* parItem) {
|
||||
assert(parItem);
|
||||
return PairType(get<A>(parItem[0]), get<B>(parItem[1]));
|
||||
}
|
||||
|
||||
template <typename P, typename A, typename B>
|
||||
boost::string_ref ScanPairs<P, A, B>::scan_target() {
|
||||
return m_scan_target;
|
||||
}
|
||||
} //namespace redis
|
||||
|
|
Loading…
Add table
Reference in a new issue