LCOV - code coverage report
Current view: top level - irohad/ametsuchi/impl - postgres_wsv_query.cpp (source / functions) Hit Total Coverage
Test: coverage_cleared.info Lines: 112 147 76.2 %
Date: 2018-12-05 17:11:35 Functions: 69 78 88.5 %

          Line data    Source code
       1             : /**
       2             :  * Copyright Soramitsu Co., Ltd. All Rights Reserved.
       3             :  * SPDX-License-Identifier: Apache-2.0
       4             :  */
       5             : 
       6             : #include "ametsuchi/impl/postgres_wsv_query.hpp"
       7             : 
       8             : #include <soci/boost-tuple.h>
       9             : #include "ametsuchi/impl/soci_utils.hpp"
      10             : #include "backend/protobuf/permissions.hpp"
      11             : #include "common/result.hpp"
      12             : #include "cryptography/public_key.hpp"
      13             : 
      14             : namespace iroha {
      15             :   namespace ametsuchi {
      16             : 
      17             :     using shared_model::interface::types::AccountDetailKeyType;
      18             :     using shared_model::interface::types::AccountIdType;
      19             :     using shared_model::interface::types::AddressType;
      20             :     using shared_model::interface::types::AssetIdType;
      21             :     using shared_model::interface::types::DetailType;
      22             :     using shared_model::interface::types::DomainIdType;
      23             :     using shared_model::interface::types::JsonType;
      24             :     using shared_model::interface::types::PrecisionType;
      25             :     using shared_model::interface::types::PubkeyType;
      26             :     using shared_model::interface::types::QuorumType;
      27             :     using shared_model::interface::types::RoleIdType;
      28             : 
      29             :     PostgresWsvQuery::PostgresWsvQuery(
      30             :         soci::session &sql,
      31             :         std::shared_ptr<shared_model::interface::CommonObjectsFactory> factory)
      32         638 :         : sql_(sql), factory_(factory), log_(logger::log("PostgresWsvQuery")) {}
      33             : 
      34             :     PostgresWsvQuery::PostgresWsvQuery(
      35             :         std::unique_ptr<soci::session> sql,
      36             :         std::shared_ptr<shared_model::interface::CommonObjectsFactory> factory)
      37        2065 :         : psql_(std::move(sql)),
      38        2065 :           sql_(*psql_),
      39        2065 :           factory_(factory),
      40        2065 :           log_(logger::log("PostgresWsvQuery")) {}
      41             : 
      42             :     template <typename T>
      43             :     boost::optional<std::shared_ptr<T>> PostgresWsvQuery::fromResult(
      44             :         shared_model::interface::CommonObjectsFactory::FactoryResult<
      45             :             std::unique_ptr<T>> &&result) {
      46        3908 :       return result.match(
      47             :           [](iroha::expected::Value<std::unique_ptr<T>> &v) {
      48        3908 :             return boost::make_optional(std::shared_ptr<T>(std::move(v.value)));
      49           0 :           },
      50             :           [&](iroha::expected::Error<std::string> &e)
      51             :               -> boost::optional<std::shared_ptr<T>> {
      52           0 :             log_->error(e.error);
      53           0 :             return boost::none;
      54             :           });
      55             :     }
      56             : 
      57             :     template <typename T, typename F>
      58             :     auto PostgresWsvQuery::execute(F &&f) -> boost::optional<soci::rowset<T>> {
      59             :       try {
      60        1928 :         return soci::rowset<T>{std::forward<F>(f)()};
      61           0 :       } catch (const std::exception &e) {
      62           0 :         log_->error("Failed to execute query: {}", e.what());
      63           0 :         return boost::none;
      64           0 :       }
      65        1928 :     }
      66             : 
      67             :     bool PostgresWsvQuery::hasAccountGrantablePermission(
      68             :         const AccountIdType &permitee_account_id,
      69             :         const AccountIdType &account_id,
      70             :         shared_model::interface::permissions::Grantable permission) {
      71             :       const auto perm_str =
      72          11 :           shared_model::interface::GrantablePermissionSet({permission})
      73          11 :               .toBitstring();
      74             :       using T = boost::tuple<int>;
      75             :       auto result = execute<T>([&] {
      76          11 :         return (sql_.prepare
      77          11 :                     << "SELECT count(*) FROM "
      78             :                        "account_has_grantable_permissions WHERE "
      79             :                        "permittee_account_id = :permittee_account_id AND "
      80             :                        "account_id = "
      81             :                        ":account_id "
      82             :                        " AND permission & :permission = :permission ",
      83          11 :                 soci::use(permitee_account_id, "permittee_account_id"),
      84          11 :                 soci::use(account_id, "account_id"),
      85          11 :                 soci::use(perm_str, "permission"));
      86           0 :       });
      87             : 
      88          11 :       return flatMapValue(
      89             :                  result,
      90             :                  [](auto &count) { return boost::make_optional(count == 1); })
      91          11 :           .value_or(false);
      92             :     }
      93             : 
      94             :     boost::optional<std::vector<RoleIdType>> PostgresWsvQuery::getAccountRoles(
      95             :         const AccountIdType &account_id) {
      96             :       using T = boost::tuple<RoleIdType>;
      97             :       auto result = execute<T>([&] {
      98          12 :         return (sql_.prepare << "SELECT role_id FROM account_has_roles WHERE "
      99          12 :                                 "account_id = :account_id",
     100          12 :                 soci::use(account_id));
     101           0 :       });
     102             : 
     103          12 :       return mapValues<std::vector<RoleIdType>>(
     104             :           result, [&](auto &role_id) { return role_id; });
     105          12 :     }
     106             : 
     107             :     boost::optional<shared_model::interface::RolePermissionSet>
     108             :     PostgresWsvQuery::getRolePermissions(const RoleIdType &role_name) {
     109             :       using T = boost::tuple<std::string>;
     110             :       auto result = execute<T>([&] {
     111           4 :         return (sql_.prepare
     112             :                     << "SELECT permission FROM role_has_permissions WHERE "
     113           4 :                        "role_id = :role_name",
     114           4 :                 soci::use(role_name));
     115           0 :       });
     116             : 
     117             :       return result | [&](auto &&st)
     118             :                  -> boost::optional<
     119             :                      shared_model::interface::RolePermissionSet> {
     120           4 :         auto range = boost::make_iterator_range(st);
     121             : 
     122           4 :         if (range.empty()) {
     123           2 :           return shared_model::interface::RolePermissionSet{};
     124             :         }
     125             : 
     126             :         return apply(range.front(), [](auto &permission) {
     127           2 :           return shared_model::interface::RolePermissionSet(permission);
     128             :         });
     129           4 :       };
     130           4 :     }
     131             : 
     132             :     boost::optional<std::vector<RoleIdType>> PostgresWsvQuery::getRoles() {
     133             :       using T = boost::tuple<RoleIdType>;
     134           2 :       auto result = execute<T>(
     135             :           [&] { return (sql_.prepare << "SELECT role_id FROM role"); });
     136             : 
     137           2 :       return mapValues<std::vector<RoleIdType>>(
     138             :           result, [&](auto &role_id) { return role_id; });
     139           2 :     }
     140             : 
     141             :     boost::optional<std::shared_ptr<shared_model::interface::Account>>
     142             :     PostgresWsvQuery::getAccount(const AccountIdType &account_id) {
     143             :       using T = boost::tuple<DomainIdType, QuorumType, JsonType>;
     144             :       auto result = execute<T>([&] {
     145          19 :         return (sql_.prepare << "SELECT domain_id, quorum, data "
     146             :                                 "FROM account WHERE account_id = "
     147          19 :                                 ":account_id",
     148          19 :                 soci::use(account_id, "account_id"));
     149           0 :       });
     150             : 
     151          19 :       return flatMapValue(
     152             :           result, [&](auto &domain_id, auto quorum, auto &data) {
     153          16 :             return this->fromResult(
     154          19 :                 factory_->createAccount(account_id, domain_id, quorum, data));
     155           0 :           });
     156          19 :     }
     157             : 
     158             :     boost::optional<std::string> PostgresWsvQuery::getAccountDetail(
     159             :         const std::string &account_id,
     160             :         const AccountDetailKeyType &key,
     161             :         const AccountIdType &writer) {
     162             :       using T = boost::tuple<DetailType>;
     163          11 :       boost::optional<soci::rowset<T>> result;
     164             : 
     165          11 :       if (key.empty() and writer.empty()) {
     166             :         // retrieve all values for a specified account
     167           8 :         std::string empty_json = "{}";
     168             :         result = execute<T>([&] {
     169           8 :           return (sql_.prepare
     170           8 :                       << "SELECT data#>>:empty_json FROM account WHERE "
     171             :                          "account_id = "
     172           8 :                          ":account_id;",
     173           8 :                   soci::use(empty_json),
     174           8 :                   soci::use(account_id));
     175           0 :         });
     176           8 :       } else if (not key.empty() and not writer.empty()) {
     177             :         // retrieve values for the account, under the key and added by the
     178             :         // writer
     179           1 :         std::string filled_json = "{\"" + writer + "\"" + ", \"" + key + "\"}";
     180             :         result = execute<T>([&] {
     181           1 :           return (sql_.prepare
     182           1 :                       << "SELECT json_build_object(:writer::text, "
     183             :                          "json_build_object(:key::text, (SELECT data #>> "
     184             :                          ":filled_json "
     185           1 :                          "FROM account WHERE account_id = :account_id)));",
     186           1 :                   soci::use(writer),
     187           1 :                   soci::use(key),
     188           1 :                   soci::use(filled_json),
     189           1 :                   soci::use(account_id));
     190           0 :         });
     191           2 :       } else if (not writer.empty()) {
     192             :         // retrieve values added by the writer under all keys
     193             :         result = execute<T>([&] {
     194           1 :           return (
     195           1 :               sql_.prepare
     196           1 :                   << "SELECT json_build_object(:writer::text, (SELECT data -> "
     197           1 :                      ":writer FROM account WHERE account_id = :account_id));",
     198           1 :               soci::use(writer, "writer"),
     199           1 :               soci::use(account_id, "account_id"));
     200           0 :         });
     201           1 :       } else {
     202             :         // retrieve values from all writers under the key
     203             :         result = execute<T>([&] {
     204           1 :           return (
     205           1 :               sql_.prepare
     206           1 :                   << "SELECT json_object_agg(key, value) AS json FROM (SELECT "
     207             :                      "json_build_object(kv.key, json_build_object(:key::text, "
     208             :                      "kv.value -> :key)) FROM jsonb_each((SELECT data FROM "
     209             :                      "account "
     210             :                      "WHERE account_id = :account_id)) kv WHERE kv.value ? "
     211             :                      ":key) "
     212             :                      "AS "
     213           1 :                      "jsons, json_each(json_build_object);",
     214           1 :               soci::use(key, "key"),
     215           1 :               soci::use(account_id, "account_id"));
     216           0 :         });
     217             :       }
     218             : 
     219          11 :       return flatMapValue(
     220             :           result, [&](auto &json) { return boost::make_optional(json); });
     221          11 :     }
     222             : 
     223             :     boost::optional<std::vector<PubkeyType>> PostgresWsvQuery::getSignatories(
     224             :         const AccountIdType &account_id) {
     225             :       using T = boost::tuple<std::string>;
     226             :       auto result = execute<T>([&] {
     227         146 :         return (sql_.prepare
     228         146 :                     << "SELECT public_key FROM account_has_signatory WHERE "
     229         146 :                        "account_id = :account_id",
     230         146 :                 soci::use(account_id));
     231           0 :       });
     232             : 
     233             :       return mapValues<std::vector<PubkeyType>>(result, [&](auto &public_key) {
     234         182 :         return shared_model::crypto::PublicKey{
     235         182 :             shared_model::crypto::Blob::fromHexString(public_key)};
     236           0 :       });
     237         146 :     }
     238             : 
     239             :     boost::optional<std::shared_ptr<shared_model::interface::Asset>>
     240             :     PostgresWsvQuery::getAsset(const AssetIdType &asset_id) {
     241             :       using T = boost::tuple<DomainIdType, PrecisionType>;
     242             :       auto result = execute<T>([&] {
     243           3 :         return (
     244           3 :             sql_.prepare
     245           3 :                 << "SELECT domain_id, precision FROM asset WHERE asset_id = "
     246           3 :                    ":asset_id",
     247           3 :             soci::use(asset_id));
     248           0 :       });
     249             : 
     250             :       return flatMapValue(result, [&](auto &domain_id, auto precision) {
     251           1 :         return this->fromResult(
     252           3 :             factory_->createAsset(asset_id, domain_id, precision));
     253           0 :       });
     254           3 :     }
     255             : 
     256             :     boost::optional<
     257             :         std::vector<std::shared_ptr<shared_model::interface::AccountAsset>>>
     258             :     PostgresWsvQuery::getAccountAssets(const AccountIdType &account_id) {
     259             :       using T = boost::tuple<AssetIdType, std::string>;
     260             :       auto result = execute<T>([&] {
     261           0 :         return (sql_.prepare
     262           0 :                     << "SELECT asset_id, amount FROM account_has_asset "
     263           0 :                        "WHERE account_id = :account_id",
     264           0 :                 soci::use(account_id));
     265           0 :       });
     266             : 
     267           0 :       return flatMapValues<
     268             :           std::vector<std::shared_ptr<shared_model::interface::AccountAsset>>>(
     269             :           result, [&](auto &asset_id, auto &amount) {
     270           0 :             return this->fromResult(factory_->createAccountAsset(
     271           0 :                 account_id, asset_id, shared_model::interface::Amount(amount)));
     272           0 :           });
     273           0 :     }
     274             : 
     275             :     boost::optional<std::shared_ptr<shared_model::interface::AccountAsset>>
     276             :     PostgresWsvQuery::getAccountAsset(const AccountIdType &account_id,
     277             :                                       const AssetIdType &asset_id) {
     278             :       using T = boost::tuple<std::string>;
     279             :       auto result = execute<T>([&] {
     280          29 :         return (
     281          29 :             sql_.prepare
     282          29 :                 << "SELECT amount FROM account_has_asset WHERE account_id = "
     283          29 :                    ":account_id AND asset_id = :asset_id",
     284          29 :             soci::use(account_id),
     285          29 :             soci::use(asset_id));
     286           0 :       });
     287             : 
     288             :       return flatMapValue(result, [&](auto &amount) {
     289          29 :         return this->fromResult(factory_->createAccountAsset(
     290          29 :             account_id, asset_id, shared_model::interface::Amount(amount)));
     291           0 :       });
     292          29 :     }
     293             : 
     294             :     boost::optional<std::shared_ptr<shared_model::interface::Domain>>
     295             :     PostgresWsvQuery::getDomain(const DomainIdType &domain_id) {
     296             :       using T = boost::tuple<RoleIdType>;
     297             :       auto result = execute<T>([&] {
     298           6 :         return (sql_.prepare << "SELECT default_role FROM domain "
     299           6 :                                 "WHERE domain_id = :id LIMIT 1",
     300           6 :                 soci::use(domain_id));
     301           0 :       });
     302             : 
     303             :       return flatMapValue(result, [&](auto &default_role) {
     304           3 :         return this->fromResult(
     305           6 :             factory_->createDomain(domain_id, default_role));
     306           0 :       });
     307           6 :     }
     308             : 
     309             :     boost::optional<std::vector<std::shared_ptr<shared_model::interface::Peer>>>
     310             :     PostgresWsvQuery::getPeers() {
     311             :       using T = boost::tuple<std::string, AddressType>;
     312             :       auto result = execute<T>([&] {
     313        1928 :         return (sql_.prepare << "SELECT public_key, address FROM peer");
     314             :       });
     315             : 
     316        1928 :       return flatMapValues<
     317             :           std::vector<std::shared_ptr<shared_model::interface::Peer>>>(
     318             :           result, [&](auto &public_key, auto &address) {
     319        3908 :             return this->fromResult(factory_->createPeer(
     320        3908 :                 address,
     321        3908 :                 shared_model::crypto::PublicKey{
     322        3908 :                     shared_model::crypto::Blob::fromHexString(public_key)}));
     323           0 :           });
     324        1928 :     }
     325             :   }  // namespace ametsuchi
     326             : }  // namespace iroha

Generated by: LCOV version 1.13