Files
scylladb/query-result-set.hh
Pekka Enberg f17a8a7a92 query: Add support for result sets
Add a query::result_set class that contains per-row cells that can be
accessed by column name. Partition keys, clustering keys, and static
values are duplicated for every row for convenience.

Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
2015-04-28 15:49:34 +03:00

103 lines
3.3 KiB
C++

/*
* Copyright 2015 Cloudius Systems
*/
#pragma once
#include "query-result-reader.hh"
#include "core/shared_ptr.hh"
#include <experimental/optional>
#include <stdexcept>
#include <boost/any.hpp>
namespace query {
class no_such_column : public std::runtime_error {
public:
using runtime_error::runtime_error;
};
class null_column_value : public std::runtime_error {
public:
using runtime_error::runtime_error;
};
// Result set row is a set of cells that are associated with a row
// including regular column cells, partition keys, as well as static values.
class result_set_row {
schema_ptr _schema;
std::unordered_map<sstring, boost::any> _cells;
public:
result_set_row(schema_ptr schema, std::unordered_map<sstring, boost::any>&& cells)
: _schema{schema}
, _cells{std::move(cells)}
{ }
// Look up a deserialized row cell value by column name.
template<typename T>
std::experimental::optional<T>
get(const sstring& column_name) const throw (no_such_column) {
auto it = _cells.find(column_name);
if (it == _cells.end()) {
throw no_such_column(column_name);
}
if (it->second.empty()) {
return std::experimental::nullopt;
}
return std::experimental::optional<T>{boost::any_cast<T>(it->second)};
}
template<typename T>
T get_nonnull(const sstring& column_name) const throw (no_such_column, null_column_value) {
auto v = get<T>(column_name);
if (v) {
return *v;
}
throw null_column_value(column_name);
}
};
// Result set is an in-memory representation of query results in
// deserialized format. To obtain a result set, use the result_set_builder
// class as a visitor to query_result::consume() function.
class result_set {
std::vector<result_set_row> _rows;
public:
result_set(const std::vector<result_set_row>& rows)
: _rows{std::move(rows)}
{ }
bool empty() const {
return _rows.empty();
}
const result_set_row& row(size_t idx) const throw (std::out_of_range) {
if (idx >= _rows.size()) {
throw std::out_of_range("no such row in result set: " + std::to_string(idx));
}
return _rows[idx];
}
};
// Result set builder is passed as a visitor to query_result::consume()
// function. You can call the build() method to obtain a result set that
// contains cells from the visited results.
class result_set_builder {
schema_ptr _schema;
std::vector<result_set_row> _rows;
std::unordered_map<sstring, boost::any> _pkey_cells;
public:
result_set_builder(schema_ptr schema);
lw_shared_ptr<result_set> build() const;
void accept_new_partition(const partition_key& key, uint32_t row_count);
void accept_new_partition(uint32_t row_count);
void accept_new_row(const clustering_key& key, const result_row_view& static_row, const result_row_view& row);
void accept_new_row(const result_row_view &static_row, const result_row_view &row);
void accept_partition_end(const result_row_view& static_row);
private:
std::unordered_map<sstring, boost::any> deserialize(const partition_key& key);
std::unordered_map<sstring, boost::any> deserialize(const clustering_key& key);
std::unordered_map<sstring, boost::any> deserialize(const result_row_view& row, bool is_static);
};
}