Resolve "houskeeping"

This commit is contained in:
Bartosz Wieczorek 2019-01-25 11:47:33 +01:00
parent d30ec35890
commit 70a8878fbc
11 changed files with 227 additions and 117 deletions

View File

@ -1,38 +1,37 @@
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <eedb/pg/config.hpp>
#include <eedb/pg/connection.hpp>
#include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/spdlog.h>
#include <eedb/pg/Factory.hpp>
#include <eedb/pg/config.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/WebApplicationFactory.hpp>
#include <eedb/WebServer.hpp>
#include <Wt/WEnvironment.h>
#include <string_view>
#include <eedb/chai/chai_bindings.hpp>
#include <string_view>
static auto _createSinks() {
namespace {
auto _createSinks() {
std::vector< spdlog::sink_ptr > sinks;
auto stdout_sink = spdlog::stdout_logger_mt("default");
// sinks.emplace_back(std::make_shared< spdlog::sinks::ansicolor_sink >(stdout_sink));
// sinks.emplace_back(std::make_shared< spdlog::sinks::daily_file_sink_st >("logfile", 23, 59));
sinks.emplace_back(std::make_shared< spdlog::sinks::stderr_sink_mt >());
sinks.emplace_back(std::make_shared< spdlog::sinks::rotating_file_sink_mt >("eedb.log", 1 * 1024 * 1024, 1000));
return sinks;
}
static void initializeLogs() {
void initializeLogs() {
std::vector< spdlog::sink_ptr > sinks = _createSinks();
auto combined_logger = std::make_shared< spdlog::logger >("default", begin(sinks), end(sinks));
auto combined_logger = std::make_shared< spdlog::logger >("root", begin(sinks), end(sinks));
combined_logger->set_level(spdlog::level::trace);
spdlog::register_logger(combined_logger);
}
static auto createDbConnection(std::function< bool(const std::string &, std::string &) > propRead) {
auto createDbConnection(std::function< bool(const std::string &, std::string &) > propRead) {
using std::make_unique;
using std::move;
using std::unique_ptr;
@ -44,6 +43,7 @@ static auto createDbConnection(std::function< bool(const std::string &, std::str
std::cout << "sql exception: " << e.what();
// return std::make_unique< ErrorWindow >(env)
}
return std::unique_ptr< eedb::pg::Connection >{nullptr};
}
std::unique_ptr< Wt::WApplication > createApplication(const Wt::WEnvironment & env) {
@ -72,6 +72,7 @@ std::unique_ptr< Wt::WApplication > createApplication(const Wt::WEnvironment & e
return eedb::WebApplicationFactory{}.create(std::move(factory), env);
}
} // namespace
int main(int argc, char ** argv) {
initializeLogs();

View File

@ -16,25 +16,33 @@ namespace impl {
* 'private part' of categories class
*/
class PgCategory : public ::eedb::Category {
public: /**
* @brief id
* @return id of object in database
*/
public:
/**
* @brief id
* @return id of object in database
*/
virtual int64_t id() const = 0;
/**
* @brief setParent sets parent of current category
* @param parent
*/
virtual void setParent(PgCategory * parent) = 0;
/**
* @brief detachChild
* @param child to remove from current group
*/
virtual void detachChild(PgCategory * child) = 0;
};
} // namespace impl
class Connection;
class CategoriesChildrenImpl : CategoriesChildren{
};
class CategoriesChildrenImpl : CategoriesChildren {};
class CategoryImpl : public impl::PgCategory {
public:
/// TODO should be private
private:
struct CategoryImplPrivate;
spimpl::unique_impl_ptr< CategoryImplPrivate > _priv;
@ -56,14 +64,17 @@ class CategoryImpl : public impl::PgCategory {
CategoriesChildren children() const override;
void detach();
void detach() override;
Category * attachTo(Category *parent);
Category * attachTo(Category * parent) override;
// postgresql api
public:
int64_t id() const override;
void setParent(PgCategory * parent) override;
void detachChild(PgCategory * child) override;
};
} // namespace eedb::pg

View File

@ -2,10 +2,27 @@
#include <sqlpp11/sqlpp11.h>
#include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/spdlog.h>
extern int64_t _global_root_uid;
namespace eedb::pg {
inline auto & log() {
if(not spdlog::get("postgresql_connector_logger")) {
auto stdout_log = spdlog::stdout_logger_mt("root");
stdout_log->set_level(spdlog::level::trace);
if(not spdlog::get("root")) {
spdlog::register_logger(stdout_log);
}
spdlog::register_logger(stdout_log->clone("postgresql_connector_logger"));
}
return *spdlog::get("postgresql_connector_logger");
}
inline auto app_current_user_id() {
return sqlpp::verbatim< sqlpp::integer >("app_current_user_id()");
}

View File

@ -36,7 +36,7 @@ class CategoryMock : public impl::PgCategory {
MOCK_CONST_METHOD0(path, std::string_view());
MOCK_CONST_METHOD0(parent, Category *());
MOCK_METHOD1(doAddChild, Category *( Category * ) );
Category * addChild(std::unique_ptr< Category > &&c) {
Category * addChild(std::unique_ptr< Category > && c) {
return doAddChild(c.get());
}
MOCK_CONST_METHOD0(children, CategoriesChildren());
@ -44,6 +44,7 @@ class CategoryMock : public impl::PgCategory {
MOCK_METHOD1(setParent, void(impl::PgCategory *));
MOCK_METHOD0(detach, void());
MOCK_METHOD1(attachTo, Category *( Category * ) );
MOCK_METHOD1(detachChild, void(impl::PgCategory * child));
void _init_simple(std::string name) {
_root_guard();

View File

@ -7,6 +7,8 @@
#include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/sqlpp11.h>
#include <eedb/pg/utils.hpp>
constexpr eedb::db::auth_identity t_auth_identity;
namespace eedb::pg {
@ -52,6 +54,7 @@ struct AuthIdentitiesImpl::AuthIdentitysImplPriv {
}
void update() {
log().trace("{}", __PRETTY_FUNCTION__);
for(auto & identity : db(select(t_auth_identity.identity, t_auth_identity.provider) //
.from(t_auth_identity) //
.where(userUidEq()))) {
@ -69,6 +72,7 @@ AuthIdentitiesImpl::AuthIdentitiesImpl(Connection & db, const User * owner)
: _priv{spimpl::make_unique_impl< AuthIdentitysImplPriv >(db, owner)} {}
AuthIdentity * AuthIdentitiesImpl::addIdentity(std::unique_ptr< AuthIdentity > identity) {
log().trace("{}", __PRETTY_FUNCTION__);
try {
_priv->db(insert_into(t_auth_identity) //
.set( //
@ -87,6 +91,7 @@ AuthIdentity * AuthIdentitiesImpl::addIdentity(std::unique_ptr< AuthIdentity > i
}
AuthIdentity * AuthIdentitiesImpl::byProvider(std::string_view provider) const {
log().trace("{}", __PRETTY_FUNCTION__);
AuthIdentity * ptr = _priv->byProvider(provider);
if(ptr == nullptr) {
_priv->update();
@ -96,6 +101,7 @@ AuthIdentity * AuthIdentitiesImpl::byProvider(std::string_view provider) const {
}
void AuthIdentitiesImpl::removeProvider(std::string_view provider) {
log().trace("{}", __PRETTY_FUNCTION__);
/// TODO removeProviderSignal for rest of PgAuthUdentities objects?
_priv->db(remove_from(t_auth_identity) //
.where(t_auth_identity.auth_info_id == _priv->owner->id() //

View File

@ -2,11 +2,10 @@
#include <spdlog/spdlog.h>
#include <eedb/User.hpp>
#include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/sqlpp11.h>
#include <eedb/User.hpp>
#include <eedb/pg/Category.hpp>
#include <eedb/pg/Stats.hpp>
#include <eedb/pg/connection.hpp>
@ -14,6 +13,13 @@
#include <eedb/pg/utils.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/algorithm/set_algorithm.hpp>
#include <set>
#include <eedb/pg/utils.hpp>
namespace eedb::pg {
struct CategoryImpl::CategoryImplPrivate {
@ -91,38 +97,61 @@ struct CategoryImpl::CategoryImplPrivate {
impl::PgCategory * _self{nullptr};
CategoryImplPrivate(Connection & db) : _db{db}, _parent{nullptr} {
log().trace("{}", __PRETTY_FUNCTION__);
try {
init_data(_db(select(columns()).from(table_list()).where(root_path_match()).limit(1ul)).front());
} catch(const sqlpp::postgresql::failure & f) {
throw;
log().error("Root category not found");
throw exceptions::NoRootCategoryException{f.what()};
}
}
CategoryImplPrivate(Connection & db, std::string name, std::string description) : _db{db}, _parent{nullptr} {
log().trace("{}", __PRETTY_FUNCTION__);
create(std::move(name), std::move(description));
}
template < typename Row >
CategoryImplPrivate(Connection & db, impl::PgCategory * parent, const Row & row) : _db{db}, _parent{parent} {
log().trace("{}", __PRETTY_FUNCTION__);
init_data(row);
}
void updateChildren() {
std::vector< int64_t > avalibleInCache;
avalibleInCache.reserve(_children.size());
std::transform(
_children.begin(), _children.end(), std::back_inserter(avalibleInCache), [](const auto & pair) { return pair.first; });
log().trace("{}", __PRETTY_FUNCTION__);
std::set< int64_t > avalibleInCache;
std::set< int64_t > diff;
std::set< int64_t > idInGroup;
boost::copy(_children | boost::adaptors::map_keys, std::inserter(avalibleInCache, avalibleInCache.begin()));
auto data = _db(sqlpp::select(columns()) //
.from(t_category) //
.where(parent_match() and t_category.id.not_in(sqlpp::value_list(avalibleInCache))));
.where(parent_match()));
auto make_priv = [](auto & db, auto * self, auto & row) { return spimpl::make_unique_impl< CategoryImplPrivate >(db, self, row); };
// add missing to cache
for(const auto & row : data) {
///FIXME cleanup this mess
auto categoryP = spimpl::make_unique_impl< CategoryImplPrivate >(_db);
categoryP->init_data(row);
categoryP->setParent(_self);
auto category = std::make_unique< CategoryImpl >(std::move(categoryP));
_children.emplace(category->id(), std::move(category));
if(avalibleInCache.find(row.id) == avalibleInCache.end()) {
log().debug("CategoryImplPrivate: Adding category ID {}:{} from cache", row.id, row.name.text);
auto category = std::make_unique< CategoryImpl >(make_priv(_db, _self, row));
avalibleInCache.insert(category->id());
_children.emplace(category->id(), std::move(category));
}
idInGroup.insert(row.id);
}
// remove redundant from cache
boost::set_difference(avalibleInCache, idInGroup, std::inserter(diff, diff.begin()));
for(const auto & id : diff) {
log().debug("CategoryImplPrivate: Removing category ID {} from cache", id);
_children.erase(id);
}
}
auto categories() {
log().trace("{}", __PRETTY_FUNCTION__);
updateChildren();
auto getTransform = []() { return [](auto & cat) { return cat.second.get(); }; };
@ -136,17 +165,34 @@ struct CategoryImpl::CategoryImplPrivate {
_parent = parent;
}
void detach() {
throw std::logic_error{"unimplemented"};
void detachChild(impl::PgCategory * child) {
log().trace("{}", __PRETTY_FUNCTION__);
try {
_db(update(table_list()).set(t_category.parent_id = sqlpp::null).where(t_category.id == _uid));
_parent = nullptr;
_db(update(table_list()).set(t_category.parent_id = sqlpp::null).where(t_category.id == child->id()));
} catch(sqlpp::exception) {
throw;
}
}
Category * attachTo(Category *) {
throw std::logic_error{"unimplemented"};
void detach() {
_parent = nullptr;
}
auto attachTo(Category * parent) {
log().trace("{}", __PRETTY_FUNCTION__);
/// TODO test
if(_parent) {
log().error("Category attach called on already attached category");
throw exceptions::CategoryAddException(nullptr, "Cannot change the parent of category, please detach first");
}
try {
_db(update(table_list()).set(t_category.parent_id = cast(parent)->id()).where(t_category.id == _uid));
_parent = cast(parent);
} catch(sqlpp::postgresql::unique_violation e) {
log().error("Category cannot be atached");
throw exceptions::CategoryAddException(nullptr, e.what());
}
}
Category * addChild(std::unique_ptr< Category > category) {
@ -156,13 +202,13 @@ struct CategoryImpl::CategoryImplPrivate {
// #1 is detached
// #2 is unique within parent
if(category->parent()) {
throw exceptions::CategoryAddException(std::move(category), "Cannot change the parent of category");
log().error("Category {} has beed already assigned to {}", pgCategory->id(), _self->id());
throw exceptions::CategoryAddException(std::move(category), "Cannot change the parent of category, please detach first");
}
try {
_db(sqlpp::update(table_list()).set(t_category.parent_id = _uid).where(t_category.id == pgCategory->id()));
pgCategory->setParent(_self);
return (*_children.emplace(pgCategory->id(), std::move(category)).first).second.get();
} catch(sqlpp::postgresql::unique_violation e) {
throw exceptions::CategoryAddException(std::move(category), e.what());
@ -226,12 +272,13 @@ CategoriesChildren CategoryImpl::children() const {
}
void CategoryImpl::detach() {
/// TODO set parent children as "dirty" to force cache update
_priv->parent()->detachChild(this);
_priv->detach();
}
Category * CategoryImpl::attachTo(Category * parent) {
return _priv->attachTo(parent);
_priv->attachTo(parent);
return this;
}
int64_t CategoryImpl::id() const {
@ -241,4 +288,8 @@ int64_t CategoryImpl::id() const {
void CategoryImpl::setParent(impl::PgCategory * parent) {
_priv->setParent(parent);
}
void CategoryImpl::detachChild(impl::PgCategory * child) {
_priv->detachChild(child);
}
} // namespace eedb::pg

View File

@ -15,13 +15,27 @@
#include <eedb/pg/model/system_info.h>
#include <eedb/pg/utils.hpp>
#include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/spdlog.h>
int64_t _global_root_uid;
constexpr eedb::db::category t_category;
namespace eedb::pg {
FactoryImpl::FactoryImpl(std::unique_ptr< Connection > connection) : _connection{std::move(connection)} {}
FactoryImpl::FactoryImpl(std::unique_ptr< Connection > connection) : _connection{std::move(connection)} {
auto root_logger = spdlog::get("root");
if(not root_logger) {
auto stdout_log = spdlog::stdout_logger_mt("root");
stdout_log->set_level(spdlog::level::trace);
spdlog::register_logger(stdout_log);
root_logger = spdlog::get("root");
}
auto db_log = root_logger->clone("postgresql_connector_logger");
spdlog::register_logger(db_log);
}
FactoryImpl::~FactoryImpl() {}
@ -53,7 +67,8 @@ void FactoryImpl::init() {
auto root = UserImpl{db, std::move(authInfo), std::move(rootIdentity)};
return root.id();
}
}();
}
();
auto rootCategoryExists = (*_connection)( //
sqlpp::select( //
@ -68,61 +83,67 @@ void FactoryImpl::init() {
}
details::session_set_user_id((*_connection), _global_root_uid);
// CategoriesRepositoryImpl repo{(*_connection)};
// CategoriesRepositoryImpl repo{(*_connection)};
// auto rootId = dynamic_cast< CategoryImpl * >(repo.root().get())->id();
// auto rootId = dynamic_cast< CategoryImpl * >(repo.root().get())->id();
// try{
// auto cat1 = (*_connection)(sqlpp::postgresql::insert_into(t_category)
// .set(t_category.owner = app_root_id(),
// t_category.status = 0,
// t_category.parent_id = rootId,
// t_category.name = "cat123",
// t_category.description = "cat123")
// .returning(t_category.id))
// .front()
// .id;
// try{
// auto cat1 = (*_connection)(sqlpp::postgresql::insert_into(t_category)
// .set(t_category.owner = app_root_id(),
// t_category.status = 0,
// t_category.parent_id = rootId,
// t_category.name = "cat123",
// t_category.description = "cat123")
// .returning(t_category.id))
// .front()
// .id;
// auto cat2 = (*_connection)(sqlpp::postgresql::insert_into(t_category)
// .set(t_category.owner = app_root_id(),
// t_category.status = 0,
// t_category.parent_id = rootId,
// t_category.name = "cat2123",
// t_category.description = "cat2123")
// .returning(t_category.id))
// .front()
// .id;
// auto cat2 = (*_connection)(sqlpp::postgresql::insert_into(t_category)
// .set(t_category.owner = app_root_id(),
// t_category.status = 0,
// t_category.parent_id = rootId,
// t_category.name = "cat2123",
// t_category.description = "cat2123")
// .returning(t_category.id))
// .front()
// .id;
// auto cat3 = (*_connection)(sqlpp::postgresql::insert_into(t_category)
// .set(t_category.owner = app_root_id(),
// t_category.status = 0,
// t_category.parent_id = cat2,
// t_category.name = "cat3123",
// t_category.description = "cat3123")
// .returning(t_category.id))
// .front()
// .id;
// } catch (const sqlpp::postgresql::failure &f){
// std::cout << f.what() << '\n';
// }
// auto cat3 = (*_connection)(sqlpp::postgresql::insert_into(t_category)
// .set(t_category.owner = app_root_id(),
// t_category.status = 0,
// t_category.parent_id = cat2,
// t_category.name = "cat3123",
// t_category.description = "cat3123")
// .returning(t_category.id))
// .front()
// .id;
// } catch (const sqlpp::postgresql::failure &f){
// std::cout << f.what() << '\n';
// }
}
std::unique_ptr< Users > FactoryImpl::usersRepository() const {
log().info("FactoryImpl::{}", __FUNCTION__);
return std::make_unique< UsersImpl >(*_connection);
}
std::unique_ptr< CategoriesRepository > FactoryImpl::categoriesRepository() const {
log().info("FactoryImpl::{}", __FUNCTION__);
return std::make_unique< CategoriesRepositoryImpl >(*_connection);
}
std::unique_ptr< ItemsRepository > FactoryImpl::itemsRepository() const {
log().info("FactoryImpl::{}", __FUNCTION__);
return std::make_unique< ItemsRepositoryImpl >(*_connection);
}
std::unique_ptr< Session > FactoryImpl::session() const {
log().info("FactoryImpl::{}", __FUNCTION__);
return std::make_unique< SessionImpl >(*_connection);
}
void FactoryImpl::createRootUser() const {}
void FactoryImpl::createRootUser() const {
log().info("FactoryImpl::{}", __FUNCTION__);
}
} // namespace eedb::pg

View File

@ -66,17 +66,29 @@ TEST_F(PgCategoryTest, addSameCategoryMultipleTimesShouldFail) {
sut->addChild(std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf")), eedb::exceptions::CategoryAddException);
}
// TEST_F(PgCategoryTest, attachToParent) {
// auto cat = std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf");
TEST_F(PgCategoryTest, attachToParent) {
auto cat = std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf");
// cat->attachTo(sut.get());
// EXPECT_TRUE(cat->parent()->parent());
//}
auto childrenbefore = sut->children();
auto count = std::distance(childrenbefore.begin(), childrenbefore.end());
// TEST_F(PgCategoryTest, detachFromParent) {
// auto cat = std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf");
cat->attachTo(sut.get());
// cat->attachTo(sut.get());
// cat->detach();
// EXPECT_FALSE(cat->parent()->parent());
//}
EXPECT_TRUE(cat->parent());
auto children = sut->children();
EXPECT_EQ(std::distance(children.begin(), children.end()), count + 1);
}
TEST_F(PgCategoryTest, detachFromParent) {
auto cat = std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf");
cat->attachTo(sut.get());
auto childrenbefore = sut->children();
auto count = std::distance(childrenbefore.begin(), childrenbefore.end());
cat->detach();
EXPECT_FALSE(cat->parent());
auto children = sut->children();
EXPECT_EQ(std::distance(children.begin(), children.end()), count - 1);
}

View File

@ -50,6 +50,11 @@ namespace exceptions {
private:
std::unique_ptr< Category > _badCategory;
};
class NoRootCategoryException : public std::runtime_error {
public:
NoRootCategoryException(std::string reason) : std::runtime_error(std::move(reason)) {}
};
} // namespace exceptions
/**
* @brief The Categories class

View File

@ -21,30 +21,21 @@ TEST_F(ValueTest, serializeInt) {
EXPECT_CALL(parameter, name()).WillOnce(Return("parameter name"));
eedb::Value _int{4, &parameter};
auto json = nlohmann::json{};
_int.serialize(json);
EXPECT_EQ(json, (nlohmann::json{{"parameter name", 4.0}}));
EXPECT_EQ(_int.serialize(), (nlohmann::json{{"parameter name", 4.0}}));
}
TEST_F(ValueTest, serializeDouble) {
EXPECT_CALL(parameter, name()).WillOnce(Return("parameter name"));
eedb::Value _double{4.0, &parameter};
auto json = nlohmann::json{};
_double.serialize(json);
EXPECT_EQ(json, (nlohmann::json{{"parameter name", 4.0}}));
EXPECT_EQ(_double.serialize(), (nlohmann::json{{"parameter name", 4.0}}));
}
TEST_F(ValueTest, serializeString) {
EXPECT_CALL(parameter, name()).WillOnce(Return("parameter name"));
eedb::Value _string{std::string{"asdfghjkl"}, &parameter};
auto json = nlohmann::json{};
_string.serialize(json);
EXPECT_EQ(json, (nlohmann::json{{"parameter name", "asdfghjkl"}}));
EXPECT_EQ(_string.serialize(), (nlohmann::json{{"parameter name", "asdfghjkl"}}));
}
TEST_F(ValueTest, serializeListOfInts) {
@ -60,19 +51,13 @@ TEST_F(ValueTest, serializeListOfStrings) {
EXPECT_CALL(parameter, name()).WillOnce(Return("parameter name"));
eedb::Value _stringList{std::vector{"a"s, "b"s, "c"s}, &parameter};
auto json = nlohmann::json{};
_stringList.serialize(json);
EXPECT_EQ(json, (nlohmann::json{{"parameter name", {"a"s, "b"s, "c"s}}}));
EXPECT_EQ(_stringList.serialize(), (nlohmann::json{{"parameter name", {"a"s, "b"s, "c"s}}}));
}
TEST_F(ValueTest, serializeListOfRange) {
EXPECT_CALL(parameter, name()).WillOnce(Return("parameter name"));
eedb::Value _range{std::pair{0.001, 1000.0}, &parameter};
auto json = nlohmann::json{};
_range.serialize(json);
EXPECT_EQ(json, (nlohmann::json{{"parameter name", {{"min", 0.001}, {"max", 1000.0}}}}));
EXPECT_EQ(_range.serialize(), (nlohmann::json{{"parameter name", {{"min", 0.001}, {"max", 1000.0}}}}));
}

View File

@ -28,7 +28,7 @@ struct measure {
measure() : _start{std::chrono::steady_clock::now()} {}
~measure() {
auto duration = std::chrono::duration< double, std::milli >(std::chrono::steady_clock::now() - _start);
spdlog::get("default")->info("Request served in: {}ms", duration.count());
spdlog::get("root")->info("Request served in: {}ms", duration.count());
}
std::chrono::steady_clock::time_point _start;