Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #ifndef IROHA_PROTO_QUERY_BUILDER_TEMPLATE_HPP
7 : #define IROHA_PROTO_QUERY_BUILDER_TEMPLATE_HPP
8 :
9 : #include <boost/optional.hpp>
10 : #include <boost/range/algorithm/for_each.hpp>
11 :
12 : #include "backend/protobuf/queries/proto_query.hpp"
13 : #include "builders/protobuf/unsigned_proto.hpp"
14 : #include "interfaces/common_objects/types.hpp"
15 : #include "interfaces/transaction.hpp"
16 : #include "queries.pb.h"
17 : #include "validators/default_validator.hpp"
18 :
19 : namespace shared_model {
20 : namespace proto {
21 :
22 : /**
23 : * Template query builder for creating new types of query builders by
24 : * means of replacing template parameters
25 : * @tparam S -- field counter for checking that all required fields are
26 : * set
27 : * @tparam SV -- stateless validator called when build method is invoked
28 : * @tparam BT -- build type of built object returned by build method
29 : */
30 : template <int S = 0,
31 : typename SV = validation::DefaultUnsignedQueryValidator,
32 : typename BT = UnsignedWrapper<Query>>
33 : class [[deprecated]] TemplateQueryBuilder {
34 : private:
35 : template <int, typename, typename>
36 : friend class TemplateQueryBuilder;
37 :
38 : enum RequiredFields {
39 : CreatedTime,
40 : CreatorAccountId,
41 : QueryField,
42 : QueryCounter,
43 : TOTAL
44 : };
45 :
46 : template <int s>
47 : using NextBuilder = TemplateQueryBuilder<S | (1 << s), SV, BT>;
48 :
49 : using ProtoQuery = iroha::protocol::Query;
50 :
51 : template <int Sp>
52 : TemplateQueryBuilder(const TemplateQueryBuilder<Sp, SV, BT> &o)
53 21 : : query_(o.query_), stateless_validator_(o.stateless_validator_) {}
54 :
55 : /**
56 : * Make transformation on copied content
57 : * @tparam Transformation - callable type for changing the copy
58 : * @param t - transform function for proto object
59 : * @return new builder with updated state
60 : */
61 : template <int Fields, typename Transformation>
62 : auto transform(Transformation t) const {
63 343 : NextBuilder<Fields> copy = *this;
64 343 : t(copy.query_);
65 343 : return copy;
66 343 : }
67 :
68 : /**
69 : * Make query field transformation on copied object
70 : * @tparam Transformation - callable type for changing query
71 : * @param t - transform function for proto query
72 : * @return new builder with set query
73 : */
74 : template <typename Transformation>
75 : auto queryField(Transformation t) const {
76 186 : NextBuilder<QueryField> copy = *this;
77 186 : t(copy.query_.mutable_payload());
78 186 : return copy;
79 186 : }
80 :
81 : /// Set tx pagination meta
82 : template <typename PageMetaPayload>
83 : static auto setTxPaginationMeta(
84 : PageMetaPayload *page_meta_payload,
85 : interface::types::TransactionsNumberType page_size,
86 : const boost::optional<interface::types::HashType> &first_hash =
87 : boost::none) {
88 49 : page_meta_payload->set_page_size(page_size);
89 49 : if (first_hash) {
90 4 : page_meta_payload->set_first_tx_hash(first_hash->hex());
91 4 : }
92 49 : }
93 :
94 : public:
95 : TemplateQueryBuilder(const SV &validator = SV())
96 240 : : stateless_validator_(validator) {}
97 :
98 : auto createdTime(interface::types::TimestampType created_time) const {
99 : return transform<CreatedTime>([&](auto &qry) {
100 187 : qry.mutable_payload()->mutable_meta()->set_created_time(created_time);
101 187 : });
102 : }
103 :
104 : auto creatorAccountId(
105 : const interface::types::AccountIdType &creator_account_id) const {
106 : return transform<CreatorAccountId>([&](auto &qry) {
107 243 : qry.mutable_payload()->mutable_meta()->set_creator_account_id(
108 243 : creator_account_id);
109 243 : });
110 : }
111 :
112 : auto queryCounter(interface::types::CounterType query_counter) const {
113 : return transform<QueryCounter>([&](auto &qry) {
114 213 : qry.mutable_payload()->mutable_meta()->set_query_counter(
115 213 : query_counter);
116 213 : });
117 : }
118 :
119 : auto getAccount(const interface::types::AccountIdType &account_id) const {
120 : return queryField([&](auto proto_query) {
121 39 : auto query = proto_query->mutable_get_account();
122 39 : query->set_account_id(account_id);
123 39 : });
124 : }
125 :
126 : auto getSignatories(
127 : const interface::types::AccountIdType &account_id) const {
128 : return queryField([&](auto proto_query) {
129 23 : auto query = proto_query->mutable_get_signatories();
130 23 : query->set_account_id(account_id);
131 23 : });
132 : }
133 :
134 : auto getAccountTransactions(
135 : const interface::types::AccountIdType &account_id,
136 : interface::types::TransactionsNumberType page_size,
137 : const boost::optional<interface::types::HashType> &first_hash =
138 : boost::none) const {
139 : return queryField([&](auto proto_query) {
140 24 : auto query = proto_query->mutable_get_account_transactions();
141 24 : query->set_account_id(account_id);
142 24 : setTxPaginationMeta(
143 24 : query->mutable_pagination_meta(), page_size, first_hash);
144 24 : });
145 : }
146 :
147 : auto getAccountAssetTransactions(
148 : const interface::types::AccountIdType &account_id,
149 : const interface::types::AssetIdType &asset_id,
150 : interface::types::TransactionsNumberType page_size,
151 : const boost::optional<interface::types::HashType> &first_hash =
152 : boost::none) const {
153 : return queryField([&](auto proto_query) {
154 25 : auto query = proto_query->mutable_get_account_asset_transactions();
155 25 : query->set_account_id(account_id);
156 25 : query->set_asset_id(asset_id);
157 25 : setTxPaginationMeta(
158 25 : query->mutable_pagination_meta(), page_size, first_hash);
159 25 : });
160 : }
161 :
162 : auto getAccountAssets(
163 : const interface::types::AccountIdType &account_id) const {
164 : return queryField([&](auto proto_query) {
165 23 : auto query = proto_query->mutable_get_account_assets();
166 23 : query->set_account_id(account_id);
167 23 : });
168 : }
169 :
170 : auto getAccountDetail(
171 : const interface::types::AccountIdType &account_id = "",
172 : const interface::types::AccountDetailKeyType &key = "",
173 : const interface::types::AccountIdType &writer = "") {
174 : return queryField([&](auto proto_query) {
175 24 : auto query = proto_query->mutable_get_account_detail();
176 24 : if (not account_id.empty()) {
177 23 : query->set_account_id(account_id);
178 23 : }
179 24 : if (not key.empty()) {
180 2 : query->set_key(key);
181 2 : }
182 24 : if (not writer.empty()) {
183 2 : query->set_writer(writer);
184 2 : }
185 24 : });
186 : }
187 :
188 : auto getBlock(interface::types::HeightType height) const {
189 : return queryField([&](auto proto_query) {
190 3 : auto query = proto_query->mutable_get_block();
191 3 : query->set_height(height);
192 3 : });
193 : }
194 :
195 : auto getRoles() const {
196 21 : return queryField(
197 : [&](auto proto_query) { proto_query->mutable_get_roles(); });
198 : }
199 :
200 : auto getAssetInfo(const interface::types::AssetIdType &asset_id) const {
201 : return queryField([&](auto proto_query) {
202 6 : auto query = proto_query->mutable_get_asset_info();
203 6 : query->set_asset_id(asset_id);
204 6 : });
205 : }
206 :
207 : auto getRolePermissions(
208 : const interface::types::RoleIdType &role_id) const {
209 : return queryField([&](auto proto_query) {
210 5 : auto query = proto_query->mutable_get_role_permissions();
211 5 : query->set_role_id(role_id);
212 5 : });
213 : }
214 :
215 : template <typename Collection>
216 : auto getTransactions(const Collection &hashes) const {
217 : return queryField([&](auto proto_query) {
218 40 : auto query = proto_query->mutable_get_transactions();
219 : boost::for_each(hashes, [&query](const auto &hash) {
220 41 : query->add_tx_hashes(hash.hex());
221 41 : });
222 40 : });
223 : }
224 :
225 : auto getTransactions(
226 : std::initializer_list<interface::types::HashType> hashes) const {
227 : return getTransactions(hashes);
228 : }
229 :
230 : template <typename... Hash>
231 : auto getTransactions(const Hash &... hashes) const {
232 : return getTransactions({hashes...});
233 : }
234 :
235 : auto getPendingTransactions() const {
236 : return queryField([&](auto proto_query) {
237 7 : proto_query->mutable_get_pending_transactions();
238 7 : });
239 : }
240 :
241 : auto build() const {
242 : static_assert(S == (1 << TOTAL) - 1, "Required fields are not set");
243 240 : if (not query_.has_payload()) {
244 0 : throw std::invalid_argument("Query missing payload");
245 : }
246 240 : if (query_.payload().query_case()
247 240 : == iroha::protocol::Query_Payload::QueryCase::QUERY_NOT_SET) {
248 0 : throw std::invalid_argument("Missing concrete query");
249 : }
250 240 : auto result = Query(iroha::protocol::Query(query_));
251 240 : auto answer = stateless_validator_.validate(result);
252 239 : if (answer.hasErrors()) {
253 0 : throw std::invalid_argument(answer.reason());
254 : }
255 238 : return BT(std::move(result));
256 239 : }
257 :
258 : static const int total = RequiredFields::TOTAL;
259 :
260 : private:
261 : ProtoQuery query_;
262 : SV stateless_validator_;
263 : };
264 : } // namespace proto
265 : } // namespace shared_model
266 :
267 : #endif // IROHA_PROTO_QUERY_BUILDER_TEMPLATE_HPP
|