Scorum
db_accessor.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <chainbase/database_index.hpp>
4 #include <chainbase/segment_manager.hpp>
5 
9 #include <scorum/utils/function_view.hpp>
10 #include <scorum/utils/any_range.hpp>
11 #include <scorum/utils/algorithm/foreach_mut.hpp>
12 
13 namespace scorum {
14 namespace chain {
15 
16 struct by_id;
17 
18 namespace dba {
19 template <typename TObject> using modifier_type = utils::function_view<void(TObject&)>;
20 template <typename TObject> using predicate_type = utils::function_view<bool(const TObject&)>;
21 template <typename TObject> using cref_type = std::reference_wrapper<const TObject>;
22 
23 namespace detail {
24 
25 template <typename TObject> size_t size(db_index& db_idx)
26 {
27  return db_idx.get_index<typename chainbase::get_index_type<TObject>::type, by_id>().size();
28 }
29 
30 template <typename TObject> const TObject& create(db_index& db_idx, modifier_type<TObject> modifier)
31 {
32  return db_idx.template create<TObject>([&](TObject& o) { modifier(o); });
33 }
34 
35 template <typename TObject> const TObject& get_single(db_index& db_idx)
36 {
37  try
38  {
39  return db_idx.template get<TObject>();
40  }
41  FC_CAPTURE_AND_RETHROW()
42 }
43 
44 template <typename TObject> const TObject& update(db_index& db_idx, const TObject& o, modifier_type<TObject> modifier)
45 {
46  db_idx.modify(o, [&](TObject& o) { modifier(o); });
47  return o;
48 }
49 
50 template <typename TObject> const TObject& update_single(db_index& db_idx, modifier_type<TObject> modifier)
51 {
52  const auto& o = get_single<TObject>(db_idx);
53  db_idx.modify(o, [&](TObject& o) { modifier(o); });
54  return o;
55 }
56 
57 template <typename TObject> void remove(db_index& db_idx, const TObject& o)
58 {
59  db_idx.remove(o);
60 }
61 
62 template <typename TObject> void remove_all(db_index& db_idx, utils::bidir_range<const TObject> items)
63 {
64  utils::foreach_mut(items, [&](const TObject& o) { //
65  db_idx.remove(o);
66  });
67 }
68 
69 template <typename TObject> void remove_single(db_index& db_idx)
70 {
71  db_idx.remove(get_single<TObject>(db_idx));
72 }
73 
74 template <typename TObject> bool is_empty(db_index& db_idx)
75 {
76  return nullptr == db_idx.template find<TObject>();
77 }
78 
79 template <typename TObject, typename IndexBy, typename Key> const TObject& get_by(db_index& db_idx, const Key& arg)
80 {
81  try
82  {
83  return db_idx.template get<TObject, IndexBy>(arg);
84  }
85  FC_CAPTURE_AND_RETHROW()
86 }
87 
88 template <typename TObject, typename IndexBy, typename Key> const TObject* find_by(db_index& db_idx, const Key& arg)
89 {
90  try
91  {
92  return db_idx.template find<TObject, IndexBy>(arg);
93  }
94  FC_CAPTURE_AND_RETHROW()
95 }
96 
97 template <typename TObject, typename IndexBy, typename Key> bool is_exists_by(db_index& db_idx, const Key& arg)
98 {
99  try
100  {
101  return nullptr != db_idx.template find<TObject, IndexBy>(arg);
102  }
103  FC_CAPTURE_AND_RETHROW()
104 }
105 
106 template <typename TObject, typename IndexBy, typename TKey>
107 utils::forward_range<const TObject> hashed_get_range_by(db_index& db_idx, const TKey& key)
108 {
109  const auto& idx = db_idx.get_index<typename chainbase::get_index_type<TObject>::type, IndexBy>();
110  return idx.equal_range(key);
111 }
112 
113 template <typename TObject, typename IndexBy, typename TKey>
114 utils::bidir_range<const TObject> ordered_get_range_by(db_index& db_idx, const TKey& key)
115 {
116  const auto& idx = db_idx.get_index<typename chainbase::get_index_type<TObject>::type, IndexBy>();
117  return idx.equal_range(key);
118 }
119 
120 template <typename TIdx, typename TKey> auto get_lower_bound(TIdx& idx, const detail::bound<TKey>& bound);
121 template <typename TIdx, typename TKey> auto get_upper_bound(TIdx& idx, const detail::bound<TKey>& bound);
122 
123 template <typename TObject, typename IndexBy, typename TKeyLhs, typename TKeyRhs = TKeyLhs>
124 utils::bidir_range<const TObject>
126 {
127  const auto& idx = db_idx.get_index<typename chainbase::get_index_type<TObject>::type, IndexBy>();
128 
129  auto from = get_lower_bound(idx, lower);
130  auto to = get_upper_bound(idx, upper);
131 
132  return { from, to };
133 }
134 
135 template <typename TObject, typename IndexBy> utils::bidir_range<const TObject> get_all_by(db_index& db_idx)
136 {
137  const auto& idx = db_idx.get_index<typename chainbase::get_index_type<TObject>::type, IndexBy>();
138 
139  return { idx.begin(), idx.end() };
140 }
141 
142 template <typename TIdx, typename TKey> auto get_lower_bound(TIdx& idx, const detail::bound<TKey>& bound)
143 {
144  switch (bound.kind)
145  {
147  return idx.begin();
148  case bound_kind::ge:
149  case bound_kind::le:
150  return idx.lower_bound(bound.value.get());
151  case bound_kind::gt:
152  case bound_kind::lt:
153  return idx.upper_bound(bound.value.get());
154  default:
155  FC_ASSERT(false, "Not implemented.");
156  }
157 }
158 
159 template <typename TIdx, typename TKey> auto get_upper_bound(TIdx& idx, const detail::bound<TKey>& bound)
160 {
161  switch (bound.kind)
162  {
164  return idx.end();
165  case bound_kind::ge:
166  case bound_kind::le:
167  return idx.upper_bound(bound.value.get());
168  case bound_kind::gt:
169  case bound_kind::lt:
170  return idx.lower_bound(bound.value.get());
171  default:
172  FC_ASSERT(false, "Not implemented.");
173  }
174 }
175 }
176 
177 template <typename TObject> class db_accessor
178 {
179 public:
180  explicit db_accessor(db_index& db_idx)
181  : _db_idx(db_idx)
182  {
183  }
184 
185 public:
186  using object_type = TObject;
187  using modifier_type = utils::function_view<void(object_type&)>;
188  using predicate_type = utils::function_view<bool(const object_type&)>;
189  using object_cref_type = std::reference_wrapper<const TObject>;
190 
191  size_t size() const
192  {
193  return detail::size<TObject>(_db_idx);
194  }
195 
197  {
198  return detail::create(_db_idx, modifier);
199  }
200 
202  {
203  return detail::update_single<TObject>(_db_idx, modifier);
204  }
205 
206  const object_type& update(const object_type& o, modifier_type modifier)
207  {
208  return detail::update(_db_idx, o, modifier);
209  }
210 
211  void remove()
212  {
213  detail::remove_single<TObject>(_db_idx);
214  }
215 
216  void remove(const object_type& o)
217  {
218  detail::remove(_db_idx, o);
219  }
220 
221  void remove_all(utils::bidir_range<const object_type> items)
222  {
223  detail::remove_all(_db_idx, items);
224  }
225 
226  bool is_empty() const
227  {
228  return detail::is_empty<TObject>(_db_idx);
229  }
230 
231  const object_type& get() const
232  {
233  return detail::get_single<TObject>(_db_idx);
234  }
235 
236  template <class IndexBy, class Key> const object_type& get_by(const Key& arg) const
237  {
238  return detail::get_by<TObject, IndexBy, Key>(_db_idx, arg);
239  }
240 
241  template <class IndexBy, class Key> const object_type* find_by(const Key& arg) const
242  {
243  return detail::find_by<TObject, IndexBy, Key>(_db_idx, arg);
244  }
245 
246  template <class IndexBy, class Key> bool is_exists_by(const Key& arg) const
247  {
248  return detail::is_exists_by<TObject, IndexBy, Key>(_db_idx, arg);
249  }
250 
251  // TODO: using different get_range_by for different indeces (implement using SFINAE):
252  // for ordered indices using get_range_by which returns bidirectional range
253  // for hashed indices using get_range_by which returns forward range
254  template <typename IndexBy, typename TKey> utils::bidir_range<const object_type> get_range_by(const TKey& key) const
255  {
256  return detail::get_range_by<TObject, IndexBy, TKey>(_db_idx, key <= _x, _x <= key);
257  }
258 
259  template <typename IndexBy, typename TKeyLhs, typename TKeyRhs = TKeyLhs>
260  utils::bidir_range<const object_type> get_range_by(const detail::bound<TKeyLhs>& lower,
261  const detail::bound<TKeyRhs>& upper) const
262  {
263  return detail::get_range_by<TObject, IndexBy, TKeyLhs, TKeyRhs>(_db_idx, lower, upper);
264  }
265 
266  template <typename IndexBy, typename TKey>
267  utils::bidir_range<const object_type> get_range_by(unbounded_placeholder lower,
268  const detail::bound<TKey>& upper) const
269  {
270  return detail::get_range_by<TObject, IndexBy, TKey, TKey>(_db_idx, lower, upper);
271  }
272 
273  template <typename IndexBy, typename TKey>
274  utils::bidir_range<const object_type> get_range_by(const detail::bound<TKey>& lower,
275  unbounded_placeholder upper) const
276  {
277  return detail::get_range_by<TObject, IndexBy, TKey, TKey>(_db_idx, lower, upper);
278  }
279 
280  template <typename IndexBy, typename TKey = index_key_type<TObject, IndexBy>>
281  utils::bidir_range<const object_type> get_range_by(unbounded_placeholder lower, unbounded_placeholder upper) const
282  {
283  return detail::get_range_by<TObject, IndexBy, TKey, TKey>(_db_idx, lower, upper);
284  }
285 
286  template <typename IndexBy> utils::bidir_range<const object_type> get_all_by() const
287  {
288  return detail::get_all_by<TObject, IndexBy>(_db_idx);
289  }
290 
291 private:
292  db_index& _db_idx;
293 };
294 }
295 }
296 }
utils::bidir_range< const object_type > get_range_by(const detail::bound< TKeyLhs > &lower, const detail::bound< TKeyRhs > &upper) const
const object_type & create(modifier_type modifier)
const object_type & get_by(const Key &arg) const
utils::bidir_range< const object_type > get_range_by(const TKey &key) const
const object_type * find_by(const Key &arg) const
bool is_exists_by(const Key &arg) const
void remove_all(utils::bidir_range< const object_type > items)
void remove(const object_type &o)
utils::bidir_range< const object_type > get_all_by() const
utils::bidir_range< const object_type > get_range_by(const detail::bound< TKey > &lower, unbounded_placeholder upper) const
utils::bidir_range< const object_type > get_range_by(unbounded_placeholder lower, unbounded_placeholder upper) const
const object_type & update(const object_type &o, modifier_type modifier)
utils::function_view< void(object_type &)> modifier_type
utils::function_view< bool(const object_type &)> predicate_type
const object_type & update(modifier_type modifier)
const object_type & get() const
std::reference_wrapper< const TObject > object_cref_type
utils::bidir_range< const object_type > get_range_by(unbounded_placeholder lower, const detail::bound< TKey > &upper) const
utils::bidir_range< const TObject > get_all_by(db_index &db_idx)
bool is_exists_by(db_index &db_idx, const Key &arg)
Definition: db_accessor.hpp:97
const TObject & update_single(db_index &db_idx, modifier_type< TObject > modifier)
Definition: db_accessor.hpp:50
utils::forward_range< const TObject > hashed_get_range_by(db_index &db_idx, const TKey &key)
const TObject * find_by(db_index &db_idx, const Key &arg)
Definition: db_accessor.hpp:88
bool is_empty(db_index &db_idx)
Definition: db_accessor.hpp:74
void remove_all(db_index &db_idx, utils::bidir_range< const TObject > items)
Definition: db_accessor.hpp:62
utils::bidir_range< const TObject > get_range_by(db_index &db_idx, const detail::bound< TKeyLhs > &lower, const detail::bound< TKeyRhs > &upper)
utils::bidir_range< const TObject > ordered_get_range_by(db_index &db_idx, const TKey &key)
const TObject & get_by(db_index &db_idx, const Key &arg)
Definition: db_accessor.hpp:79
auto get_lower_bound(TIdx &idx, const detail::bound< TKey > &bound)
size_t size(db_index &db_idx)
Definition: db_accessor.hpp:25
const TObject & create(db_index &db_idx, modifier_type< TObject > modifier)
Definition: db_accessor.hpp:30
const TObject & update(db_index &db_idx, const TObject &o, modifier_type< TObject > modifier)
Definition: db_accessor.hpp:44
auto get_upper_bound(TIdx &idx, const detail::bound< TKey > &bound)
const TObject & get_single(db_index &db_idx)
Definition: db_accessor.hpp:35
void remove_single(db_index &db_idx)
Definition: db_accessor.hpp:69
void remove(db_index &db_idx, const TObject &o)
Definition: db_accessor.hpp:57
utils::function_view< bool(const TObject &)> predicate_type
Definition: db_accessor.hpp:20
utils::function_view< void(TObject &)> modifier_type
Definition: db_accessor.hpp:19
const param_placeholder _x
std::reference_wrapper< const TObject > cref_type
Definition: db_accessor.hpp:21
Definition: asset.cpp:15
boost::optional< const T & > value