5#include <userver/utils/meta.hpp> 
    7#include <userver/storages/mysql/impl/io/result_binder.hpp> 
    9#include <userver/storages/mysql/convert.hpp> 
   11USERVER_NAMESPACE_BEGIN
 
   13namespace storages::
mysql::impl::io {
 
   15template <
typename Container>
 
   16class InPlaceStorage 
final {
 
   18  explicit InPlaceStorage(ResultBinder& binder);
 
   20  void Reserve(std::size_t size);
 
   22  template <
typename ExtractionTag>
 
   23  impl::bindings::OutputBindings& BindNextRow();
 
   27  void RollbackLastRow();
 
   29  Container&& ExtractData();
 
   33  ResultBinder& binder_;
 
   36template <
typename Container, 
typename MapFrom>
 
   37class ProxyingStorage 
final {
 
   39  explicit ProxyingStorage(ResultBinder& binder);
 
   41  void Reserve(std::size_t size);
 
   43  template <
typename ExtractionTag>
 
   44  impl::bindings::OutputBindings& BindNextRow();
 
   48  void RollbackLastRow();
 
   50  Container&& ExtractData();
 
   53  static constexpr bool kIsMapped =
 
   54      !std::is_same_v<
typename Container::value_type, MapFrom>;
 
   58  ResultBinder& binder_;
 
   63  ExtractorBase(std::size_t size);
 
   65  virtual void Reserve(std::size_t size) = 0;
 
   67  virtual OutputBindingsFwd& BindNextRow() = 0;
 
   68  virtual void CommitLastRow() = 0;
 
   69  virtual void RollbackLastRow() = 0;
 
   71  virtual std::size_t ColumnsCount() 
const = 0;
 
   73  void UpdateBinds(
void* binds_array);
 
   81template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
   82class TypedExtractor 
final : 
public ExtractorBase {
 
   86  void Reserve(std::size_t size) 
final;
 
   88  impl::bindings::OutputBindings& BindNextRow() 
final;
 
   90  void CommitLastRow() 
final;
 
   92  void RollbackLastRow() 
final;
 
   94  std::size_t ColumnsCount() 
const final;
 
   96  Container&& ExtractData();
 
   99  static constexpr std::size_t GetColumnsCount() {
 
  100    if constexpr (std::is_same_v<ExtractionTag, 
RowTag>) {
 
  101      return boost::pfr::tuple_size_v<MapFrom>;
 
  102    } 
else if constexpr (std::is_same_v<ExtractionTag, 
FieldTag>) {
 
  105      static_assert(!
sizeof(ExtractionTag), 
"should be unreachable");
 
  109  static constexpr bool kIsMapped =
 
  110      !std::is_same_v<
typename Container::value_type, MapFrom>;
 
  113  static constexpr bool kCanBindInPlace =
 
  114      std::is_same_v<Container, std::vector<MapFrom>>;
 
  120  using InternalStorageType =
 
  121      std::conditional_t<!kIsMapped && kCanBindInPlace,
 
  122                         InPlaceStorage<Container>,
 
  123                         ProxyingStorage<Container, MapFrom>>;
 
  124  InternalStorageType storage_;
 
  127template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
  128TypedExtractor<Container, MapFrom, ExtractionTag>::TypedExtractor()
 
  129    : ExtractorBase{GetColumnsCount()},
 
  130      storage_{InternalStorageType{binder_}} {}
 
  132template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
  133void TypedExtractor<Container, MapFrom, ExtractionTag>::Reserve(
 
  135  storage_.Reserve(size);
 
  138template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
  139impl::bindings::OutputBindings&
 
  140TypedExtractor<Container, MapFrom, ExtractionTag>::BindNextRow() {
 
  141  return storage_.
template BindNextRow<ExtractionTag>();
 
  144template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
  145void TypedExtractor<Container, MapFrom, ExtractionTag>::CommitLastRow() {
 
  146  storage_.CommitLastRow();
 
  149template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
  150void TypedExtractor<Container, MapFrom, ExtractionTag>::RollbackLastRow() {
 
  151  storage_.RollbackLastRow();
 
  154template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
  155std::size_t TypedExtractor<Container, MapFrom, ExtractionTag>::ColumnsCount()
 
  157  return GetColumnsCount();
 
  160template <
typename Container, 
typename MapFrom, 
typename ExtractionTag>
 
  161Container&& TypedExtractor<Container, MapFrom, ExtractionTag>::ExtractData() {
 
  162  return storage_.ExtractData();
 
  165template <
typename Container>
 
  166InPlaceStorage<Container>::InPlaceStorage(ResultBinder& binder)
 
  169template <
typename Container>
 
  170void InPlaceStorage<Container>::Reserve(std::size_t size) {
 
  173  data_.reserve(size + 1);
 
  176template <
typename Container>
 
  177template <
typename ExtractionTag>
 
  178impl::bindings::OutputBindings& InPlaceStorage<Container>::BindNextRow() {
 
  179  data_.emplace_back();
 
  180  return binder_.BindTo(data_.back(), ExtractionTag{});
 
  183template <
typename Container>
 
  184void InPlaceStorage<Container>::CommitLastRow() {
 
  188template <
typename Container>
 
  189void InPlaceStorage<Container>::RollbackLastRow() {
 
  193template <
typename Container>
 
  194Container&& InPlaceStorage<Container>::ExtractData() {
 
  195  return std::move(data_);
 
  198template <
typename Container, 
typename MapFrom>
 
  199ProxyingStorage<Container, MapFrom>::ProxyingStorage(ResultBinder& binder)
 
  202template <
typename Container, 
typename MapFrom>
 
  203void ProxyingStorage<Container, MapFrom>::Reserve(std::size_t size) {
 
  204  if constexpr (meta::kIsReservable<Container>) {
 
  209template <
typename Container, 
typename MapFrom>
 
  210template <
typename ExtractionTag>
 
  211impl::bindings::OutputBindings&
 
  212ProxyingStorage<Container, MapFrom>::BindNextRow() {
 
  213  return binder_.BindTo(row_, ExtractionTag{});
 
  216template <
typename Container, 
typename MapFrom>
 
  217void ProxyingStorage<Container, MapFrom>::CommitLastRow() {
 
  218  if constexpr (kIsMapped) {
 
  219    *meta::Inserter(data_) =
 
  220        storages::
mysql::
convert::DoConvert<
typename Container::value_type>(
 
  223    *meta::Inserter(data_) = std::move(row_);
 
  227template <
typename Container, 
typename MapFrom>
 
  228void ProxyingStorage<Container, MapFrom>::RollbackLastRow() {
 
  232template <
typename Container, 
typename MapFrom>
 
  233Container&& ProxyingStorage<Container, MapFrom>::ExtractData() {
 
  234  return std::move(data_);