update hunter, move creation of category into category class insead of categories repository

This commit is contained in:
Wieczorek Bartosz 2018-07-27 15:46:10 +02:00
parent 43eabfd602
commit 087405ec08
26 changed files with 374 additions and 211 deletions

View File

@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.8)
include(cmake/HunterGate.cmake)
HunterGate(
URL "https://github.com/ruslo/hunter/archive/v0.19.232.tar.gz"
SHA1 "a412c45fe4c5a72fed386f62dd8d753bd4fd3d11"
URL "https://github.com/ruslo/hunter/archive/v0.23.1.tar.gz"
SHA1 "51d2d6be411251c8de18c4ca20ef778880cf4cce"
)
project(eedb)
@ -27,13 +27,13 @@ list(APPEND CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}/local/lib")
link_directories(${CMAKE_BINARY_DIR}/local/lib)
list(APPEND CMAKE_INSTALL_RPATH "${HUNTER_INSTALL_PREFIX}/lib")
link_directories("${HUNTER_INSTALL_PREFIX}/lib")
list(APPEND CMAKE_INSTALL_RPATH "${CMAKE_BINARY_DIR}/local/lib")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(Sqlpp11_DIR "${CMAKE_BINARY_DIR}/local/lib/cmake/Sqlpp11")
set(wt_DIR "${CMAKE_BINARY_DIR}/local/lib/cmake/wt")
set(Sqlpp-connector-postgresql_DIR "${CMAKE_BINARY_DIR}/local/lib/cmake/sqlpp-connector-postgresql")
set(HinnantDate_ROOT_DIR "${CMAKE_BINARY_DIR}/local/include/")
find_program(
CLANG_TIDY_EXE

View File

@ -19,6 +19,8 @@ find_package(spdlog CONFIG REQUIRED)
#hunter_add_package(range-v3)
#find_package(range-v3 CONFIG REQUIRED)
hunter_add_package(date)
find_package(date CONFIG REQUIRED)
hunter_add_package(bison)
hunter_add_package(flex)
@ -32,18 +34,18 @@ execute_process(
COMMAND ${INSTALL_DEPS_SCRIPT}
"${CMAKE_COMMAND}"
"${CMAKE_GENERATOR}"
${CMAKE_CXX_COMPILER}
${CMAKE_C_COMPILER}
${CMAKE_PREFIX_PATH}
${Boost_LIBRARY_DIR_DEBUG}
${CMAKE_BINARY_DIR}/local
${CMAKE_BUILD_TYPE}
"${CMAKE_CXX_COMPILER}"
"${CMAKE_C_COMPILER}"
"${CMAKE_PREFIX_PATH}"
"${Boost_LIBRARY_DIR_DEBUG}"
"${CMAKE_BINARY_DIR}/local"
"${CMAKE_BUILD_TYPE}"
RESULT_VARIABLE rv
OUTPUT_VARIABLE ov
ERROR_VARIABLE ev
ERROR_VARIABLE ov
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_3rdParty
)
message("rv='${rv}'")
message("ov='${ov}'")
message("ev='${ev}'")
#message("ev='${ev}'")

View File

@ -12,12 +12,6 @@ if [ ! -d ${CMAKE_INSTALL_PREFIX} ]; then
fi
# clone all
if [ ! -d date/.git ]; then
git clone --depth=1 https://github.com/HowardHinnant/date.git
else
cd date; git pull; cd ../
fi
if [ ! -d sqlpp11/.git ]; then
git clone -b develop --depth=1 https://github.com/rbock/sqlpp11.git
else
@ -42,37 +36,31 @@ else
cd ChaiScript; git pull; cd ../
fi
echo ${CMAKE_PREFIX_PATH}
# install all
mkdir date-build; cd date-build
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../date\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} \
-DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}"
${CMAKE_COMMAND} --build . --target install
cd ../
mkdir sqlpp11-build; cd sqlpp11-build
mkdir sqlpp11-build -p; cd sqlpp11-build
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../sqlpp11\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\
-DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}"\
-DENABLE_TESTS=FALSE
${CMAKE_COMMAND} --build . --target install
cd ../
mkdir sqlpp11-connector-postgresql-build; cd sqlpp11-connector-postgresql-build
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../sqlpp11-connector-postgresql\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\
-DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}"\
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"\
-DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}"\
-DENABLE_TESTS=FALSE
${CMAKE_COMMAND} --build . --target install
cd ../
mkdir wt-build; cd wt-build
mkdir sqlpp11-connector-postgresql-build -p; cd sqlpp11-connector-postgresql-build
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../sqlpp11-connector-postgresql\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\
-DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}"\
-DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}"\
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"\
-DENABLE_TESTS=FALSE
${CMAKE_COMMAND} --build . --target install
cd ../
mkdir wt-build -p; cd wt-build
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../wt\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\
@ -100,7 +88,7 @@ ${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../wt\
${CMAKE_COMMAND} --build . --target install
cd ../
mkdir ChaiScript-build; cd ChaiScript-build
mkdir ChaiScript-build -p; cd ChaiScript-build
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../ChaiScript\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\

View File

@ -4,7 +4,6 @@ GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
create extension IF NOT EXISTS "ltree";
create extension if not exists "uuid-ossp";
create OR REPLACE function perm_to_numeric ( m_owner INT, m_group INT, m_other INT )
RETURNS INT AS $$
@ -31,6 +30,15 @@ end $$ --$$
language plpgsql stable cost 1;
create or replace function app_root_id()
returns int as $$
begin
-- return current_setting('eedb.root_user.id', TRUE)::int;
return 0;
end $$ --$$
language plpgsql stable cost 1;
create or replace function app_current_user_group()
returns int as $$
begin
@ -327,7 +335,7 @@ create table "category"(
constraint "fk_category_stat_owner" foreign key ("owner") references "auth_info"("id") deferrable initially immediate
) inherits (stat);
create index "ix_category_parent_path" on "category" using GIST ("parent_path");
create unique index "ux_category_name" on "category"("parent_id", "name" );
create unique index "ux_category_name" on "category"("parent_id", "name" ) where ("parent_id" is not null);
create trigger "update_category_last_update" before update on "category" for each row execute procedure last_update_column();
create trigger "update_category_parent_path" before insert or update on "category" for each row execute procedure update_category_parent_path();
comment on table "category"

View File

@ -13,7 +13,7 @@
static auto _createSinks() {
std::vector< spdlog::sink_ptr > sinks;
auto stdout_sink = spdlog::sinks::stdout_sink_mt::instance();
sinks.emplace_back(std::make_shared< spdlog::sinks::ansicolor_sink >(stdout_sink));
// 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));
return sinks;
}

View File

@ -1,19 +0,0 @@
#pragma once
#include <eedb/Category.hpp>
#include <utils/spimpl.hpp>
namespace eedb::pg {
class Connection;
class CategoriesImpl : public CategoriesChildren {
// Categories interface
public:
CategoriesImpl(std::unique_ptr< std::vector< std::unique_ptr< eedb::Category > > > data);
private:
struct CategoriesImplPriv;
spimpl::unique_impl_ptr< CategoriesImplPriv > _priv;
};
} // namespace eedb

View File

@ -6,7 +6,8 @@
namespace eedb {
class User;
}
class Category;
} // namespace eedb
namespace eedb::pg {
class Connection;
@ -19,8 +20,10 @@ class CategoriesRepositoryImpl : public CategoriesRepository {
std::unique_ptr< Category > root() const override;
std::unique_ptr< Category > create(std::string name, std::string description) const override;
private:
struct CategoriesRepositoryImplPriv;
spimpl::unique_impl_ptr< CategoriesRepositoryImplPriv > _priv;
};
} // namespace eedb
} // namespace eedb::pg

View File

@ -21,30 +21,40 @@ namespace impl {
* @return id of object in database
*/
virtual int64_t id() const = 0;
virtual void setParent(PgCategory * parent) = 0;
};
} // namespace impl
class Connection;
class CategoryImpl : public impl::PgCategory {
private:
public:
/// TODO should be private
struct CategoryImplPrivate;
spimpl::impl_ptr< CategoryImplPrivate > _priv;
spimpl::unique_impl_ptr< CategoryImplPrivate > _priv;
public:
// ROOT category
CategoryImpl(Connection & db);
CategoryImpl(spimpl::impl_ptr< CategoryImplPrivate > priv);
// creates new category
CategoryImpl(Connection & db, std::string name, std::string description);
// creates category from private data
CategoryImpl(spimpl::unique_impl_ptr< CategoryImplPrivate > && priv);
string_view displayName() const override;
Category * parent() const override;
std::unique_ptr< CategoriesChildren > children() const override;
Category * addChild(std::unique_ptr< Category > category) noexcept(false) override;
std::unique_ptr< Category > create(std::string name, std::string description) const override;
std::unique_ptr< CategoriesChildren > children() const override;
public:
int64_t id() const override;
void setParent(PgCategory * parent) override;
};
} // namespace eedb::pg

View File

@ -21,5 +21,7 @@ class FactoryImpl : public Factory {
private:
std::unique_ptr< Connection > _connection;
void createRootUser() const;
};
} // namespace eedb::pg

View File

@ -4,15 +4,21 @@
#include <sqlpp11/sqlpp11.h>
namespace eedb::pg::details {
#include <eedb/pg/utils.hpp>
inline auto app_current_user_id() {
return sqlpp::verbatim< sqlpp::integer >("app_current_user_id()");
}
namespace eedb::pg::details {
template < typename Table >
auto insert_user_stat(const Table & table) {
return std::tuple{table.owner = app_current_user_id()};
return std::tuple{//
table.owner = app_current_user_id()};
}
template < typename Table >
inline auto set_stat(){
constexpr Table table;
return std::tuple{//
table.owner = app_current_user_id()};
}
template < typename Table >

View File

@ -0,0 +1,17 @@
#pragma once
#include <sqlpp11/sqlpp11.h>
extern int64_t _global_root_uid;
namespace eedb::pg {
inline auto app_current_user_id() {
return sqlpp::verbatim< sqlpp::integer >("app_current_user_id()");
}
inline auto app_root_id() {
return _global_root_uid;
}
} // namespace eedb::pg

View File

@ -0,0 +1,34 @@
#pragma once
#include <gmock/gmock.h>
#include <eedb/pg/CategoriesRepository.hpp>
#include <eedb/pg/Stats.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
#include <sqlpp11/postgresql/insert.h>
#include <sqlpp11/sqlpp11.h>
namespace eedb::pg {
class CategoriesRepositoryMock : public ::eedb::CategoriesRepository {
public:
/// TODO chenge to transaction
CategoriesRepositoryMock(Connection & db, User & user) : _db{db}, _owner{user} {}
void _init() {}
void _expect_create_category() {}
private:
Connection & _db;
User & _owner;
// CategoriesRepository interface
public:
MOCK_CONST_METHOD0(root, std::unique_ptr< Category >());
MOCK_CONST_METHOD2(create, std::unique_ptr< Category >(std::string name, std::string description));
};
} // namespace eedb::pg

View File

@ -10,6 +10,8 @@
#include <sqlpp11/postgresql/insert.h>
#include <sqlpp11/sqlpp11.h>
#include <eedb/pg/utils.hpp>
namespace eedb::pg {
class CategoryMock : public impl::PgCategory {
@ -33,9 +35,13 @@ class CategoryMock : public impl::PgCategory {
MOCK_CONST_METHOD0(displayName, std::string_view());
MOCK_CONST_METHOD0(path, std::string_view());
MOCK_CONST_METHOD0(parent, Category *());
MOCK_CONST_METHOD2(create, std::unique_ptr< Category >(std::string, std::string));
MOCK_METHOD1(doAddChild, Category *( Category * ) );
Category * addChild(std::unique_ptr< Category > c) {
return doAddChild(c.get());
}
MOCK_CONST_METHOD0(children, std::unique_ptr< CategoriesChildren >());
MOCK_CONST_METHOD0(id, int64_t());
MOCK_METHOD1(setParent, void(impl::PgCategory *));
void _init_simple(std::string name) {
_root_guard();
@ -47,7 +53,7 @@ class CategoryMock : public impl::PgCategory {
const auto & row = _db(sqlpp::postgresql::insert_into(t_category) //
.set(t_category.name = "root", //
t_category.parent_id = sqlpp::null,
t_category.owner = sqlpp::verbatim< sqlpp::integer >(" app_current_user_id() "))
t_category.owner = app_current_user_id())
.returning(t_category.id, t_category.parent_path))
.front();

View File

@ -17,6 +17,10 @@
#include <eedb/AuthIdentityConst.hpp>
#include <eedb/pg/utils.hpp>
extern int64_t _global_root_uid;
namespace eedb::pg {
class UserMock : public ::eedb::pg::impl::UserImplPriv {
@ -34,6 +38,17 @@ class UserMock : public ::eedb::pg::impl::UserImplPriv {
void _init() {
using namespace testing;
_global_root_uid = _db(sqlpp::postgresql::insert_into(t_auth_info)
.set( //
t_auth_info.password_hash = "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q",
t_auth_info.password_method = "bcrypt",
t_auth_info.password_salt = "OM/Z1c4WBFXvwkxh",
t_auth_info.email = "root@eedb.pl", //
t_auth_info.status = 0)
.returning(t_auth_info.id))
.front()
.id;
_id = _db(sqlpp::postgresql::insert_into(t_auth_info)
.set( //
t_auth_info.password_hash = "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q",

View File

@ -1,25 +0,0 @@
#include "eedb/pg/Categories.hpp"
#include <eedb/pg/Category.hpp>
#include <boost/iterator/transform_iterator.hpp>
namespace eedb::pg {
struct CategoriesImpl::CategoriesImplPriv {
public:
static auto getTransform() {
return [](auto & cat) { return cat.get(); };
}
explicit CategoriesImplPriv(std::unique_ptr< std::vector< std::unique_ptr< Category > > > data) : _cache{std::move(data)} {}
private:
std::unique_ptr< std::vector< std::unique_ptr< Category > > > _cache;
};
CategoriesImpl::CategoriesImpl(std::unique_ptr< std::vector< std::unique_ptr< Category > > > data)
: eedb::CategoriesChildren(boost::make_transform_iterator(data->begin(), CategoriesImplPriv::getTransform()),
boost::make_transform_iterator(data->end(), CategoriesImplPriv::getTransform())),
_priv{spimpl::make_unique_impl< CategoriesImplPriv >(std::move(data))} {}
} // namespace eedb::pg

View File

@ -1,9 +1,7 @@
#include <eedb/pg/CategoriesRepository.hpp>
#include <eedb/pg/Category.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
#include <eedb/pg/utils.hpp>
namespace eedb::pg {
struct CategoriesRepositoryImpl::CategoriesRepositoryImplPriv {
@ -13,12 +11,20 @@ struct CategoriesRepositoryImpl::CategoriesRepositoryImplPriv {
return std::make_unique< eedb::pg::CategoryImpl >(_db);
}
auto create(std::string name, std::string description) const {
return std::make_unique< pg::CategoryImpl >(_db, std::move(name), std::move(description));
}
private:
Connection & _db;
};
CategoriesRepositoryImpl::CategoriesRepositoryImpl(Connection & db) : _priv{spimpl::make_unique_impl< CategoriesRepositoryImplPriv >(db)} {}
std::unique_ptr< Category > CategoriesRepositoryImpl::create(std::string name, std::string description) const {
return _priv->create(std::move(name), std::move(description));
}
std::unique_ptr< Category > CategoriesRepositoryImpl::root() const { //
return _priv->root();
}

View File

@ -1,18 +1,21 @@
#include <eedb/pg/Category.hpp>
#include <eedb/pg/Categories.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
#include <spdlog/spdlog.h>
#include <eedb/User.hpp>
#include <spdlog/spdlog.h>
#include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/sqlpp11.h>
#include <eedb/pg/Category.hpp>
#include <eedb/pg/Stats.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
#include <eedb/pg/utils.hpp>
#include <boost/iterator/transform_iterator.hpp>
namespace eedb::pg {
struct CategoryImpl::CategoryImplPrivate {
private:
// select
@ -28,6 +31,14 @@ struct CategoryImpl::CategoryImplPrivate {
return std::tuple_cat(stat_columns(), category_columns());
}
auto cast(Category * category) const {
return dynamic_cast< CategoryImpl * >(category);
}
auto cast(std::unique_ptr< Category > & category) const {
return cast(category.get());
}
// from
auto table_list() const {
return t_category;
@ -42,55 +53,111 @@ struct CategoryImpl::CategoryImplPrivate {
return t_category.parent_path == "root";
}
public:
Category * _self{nullptr};
// set
auto set_nameAndDescription(std::string name, std::string description) const {
return std::tuple{t_category.name = std::move(name), t_category.description = std::move(description)};
}
CategoryImplPrivate(Connection & db, Category * parent) : _db{db}, _parent{parent} {
auto row = _db(select(columns()).from(table_list()).where(root_path_match()).limit(1ul));
if(row.empty()) {
// no root category
row = _db(sqlpp::postgresql::insert_into(t_category)
.set( //
t_category.owner = sqlpp::verbatim< sqlpp::integer >("app_current_user_id()"),
t_category.status = 0,
auto set_noParent() const {
return std::tuple{t_category.parent_id = sqlpp::null};
}
auto set_rootCategoryValues() const {
return std::make_tuple( //
t_category.owner = app_root_id(),
t_category.status = 0, /// TODO set status "DETACHED"
t_category.parent_id = sqlpp::null,
t_category.name = "root",
t_category.description = "root category") //
.returning(columns()));
t_category.description = "root category");
}
auto set_newCategoryValues(std::string name, std::string description) const {
return std::tuple_cat( //
set_nameAndDescription(std::move(name), std::move(description)),
set_noParent(),
details::set_stat< eedb::db::category >());
}
auto create(std::string name, std::string description) {
const auto & row = _db(sqlpp::postgresql::insert_into(t_category)
.set(set_newCategoryValues(std::move(name), std::move(description)))
.returning(columns()))
.front();
init_data(row);
}
public:
impl::PgCategory * _self{nullptr};
CategoryImplPrivate(Connection & db, Category * parent) : _db{db}, _parent{cast(parent)} {
auto row = _db(select(columns()).from(table_list()).where(root_path_match()).limit(1ul));
// no root category if row empty
if(row.empty()) {
row = _db(sqlpp::postgresql::insert_into(t_category).set(set_rootCategoryValues()).returning(columns()));
}
init_data(row.front());
}
auto categories() const {
auto children = std::make_unique< std::vector< std::unique_ptr< Category > > >();
children->reserve(100);
for(auto & category_row : _db(select(columns()).from(table_list()).where(parent_match()))) {
auto priv = spimpl::make_impl< CategoryImplPrivate >(_db, _self);
priv->init_data(category_row);
children->emplace_back(std::make_unique< CategoryImpl >(std::move(priv)));
CategoryImplPrivate(Connection & db, std::string name, std::string description) : _db{db}, _parent{nullptr} {
create(std::move(name), std::move(description));
}
return children;
auto categories() const {
auto getTransform = []() { return [](auto & cat) { return cat.get(); }; };
return std::make_unique< CategoriesChildren >( //
boost::make_transform_iterator(_children.begin(), getTransform()),
boost::make_transform_iterator(_children.end(), getTransform()));
}
void setParent(impl::PgCategory * parent) {
_parent = parent;
}
Category * addChild(std::unique_ptr< Category > category) {
auto pgCategory = cast(category);
// category can be added if
// #1 is detached
// #2 is unique within parent
if(category->parent()) {
/// TODO can't add a category that is already attached to some other category
}
try {
{
auto data = _db(sqlpp::select(t_category.name, t_category.id, t_category.parent_id).from(t_category).unconditionally());
std::cout << "blah1\n";
for(const auto & row : data) {
std::cout << row.name << " " << row.id << " " << row.parent_id << '\n';
}
}
_db(sqlpp::update(table_list()).set(t_category.parent_id = _uid).where(t_category.id == pgCategory->id()));
pgCategory->setParent(_self);
{
auto data = _db(sqlpp::select(t_category.name, t_category.id, t_category.parent_id).from(t_category).unconditionally());
std::cout << "blah2\n";
for(const auto & row : data) {
std::cout << row.name << " " << row.id << " " << row.parent_id << '\n';
}
}
return _children.emplace_back(std::move(category)).get();
} catch(sqlpp::postgresql::unique_violation e) {
throw exceptions::CategoryAddException(std::move(category), e.what());
}
return nullptr;
}
bool detached() const {
return _parent == nullptr && _path != "root";
}
auto create(std::string name, std::string description) const {
const auto & row = _db(sqlpp::postgresql::insert_into(t_category)
.set(t_category.owner = sqlpp::verbatim< sqlpp::integer >("app_current_user_id()"),
t_category.status = 0,
t_category.parent_id = _uid,
t_category.name = std::move(name),
t_category.description = std::move(description)) //
.returning(columns()))
.front();
auto priv = spimpl::make_impl< CategoryImplPrivate >(_db, _self);
priv->init_data(row);
return std::make_unique< CategoryImpl >(std::move(priv));
}
auto parent() const {
return _parent;
}
@ -107,7 +174,7 @@ struct CategoryImpl::CategoryImplPrivate {
return std::string_view{_path};
}
protected:
public:
template < typename Row >
void init_data(Row & row) {
_uid = row.id;
@ -118,19 +185,27 @@ struct CategoryImpl::CategoryImplPrivate {
private:
Connection & _db;
impl::PgCategory * _parent{nullptr};
int64_t _uid{};
Category * _parent{nullptr};
std::vector< std::unique_ptr< Category > > _children;
std::string _name;
std::string _path;
std::string _description;
};
CategoryImpl::CategoryImpl(Connection & db) : _priv{spimpl::make_impl< CategoryImplPrivate >(db, nullptr)} {
CategoryImpl::CategoryImpl(Connection & db) //
: _priv{spimpl::make_unique_impl< CategoryImplPrivate >(db, nullptr)} {
_priv->_self = this;
}
CategoryImpl::CategoryImpl(spimpl::impl_ptr< CategoryImplPrivate > priv) : _priv{std::move(priv)} {
CategoryImpl::CategoryImpl(Connection & db, std::string name, std::string description)
: _priv{spimpl::make_unique_impl< CategoryImplPrivate >(db, std::move(name), std::move(description))} {
_priv->_self = this;
}
CategoryImpl::CategoryImpl(spimpl::unique_impl_ptr< CategoryImplPrivate > && priv) //
: _priv{std::move(priv)} {
_priv->_self = this;
}
@ -142,16 +217,19 @@ Category * CategoryImpl::parent() const {
return _priv->parent();
}
std::unique_ptr< CategoriesChildren > CategoryImpl::children() const {
return std::make_unique< CategoriesImpl >(_priv->categories());
Category * CategoryImpl::addChild(std::unique_ptr< Category > category) noexcept(false) {
return _priv->addChild(std::move(category));
}
std::unique_ptr< Category > CategoryImpl::create(std::string name, std::string description) const {
return _priv->create(std::move(name), std::move(description));
std::unique_ptr< CategoriesChildren > CategoryImpl::children() const {
return _priv->categories();
}
int64_t CategoryImpl::id() const {
return _priv->id();
}
void CategoryImpl::setParent(impl::PgCategory * parent) {
_priv->setParent(parent);
}
} // namespace eedb::pg

View File

@ -5,13 +5,19 @@
#include <eedb/pg/Session.hpp>
#include <eedb/pg/Users.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
#include <eedb/pg/utils.hpp>
int64_t _global_root_uid;
namespace eedb::pg {
FactoryImpl::FactoryImpl(std::unique_ptr< Connection > connection) : _connection{std::move(connection)} {}
FactoryImpl::~FactoryImpl() {}
std::unique_ptr< Users > FactoryImpl::usersRepository() const {
createRootUser();
return std::make_unique< UsersImpl >(*_connection);
}
@ -27,4 +33,17 @@ std::unique_ptr< Session > FactoryImpl::session() const {
return std::make_unique< SessionImpl >(*_connection);
}
void FactoryImpl::createRootUser() const {
_global_root_uid = (*_connection)(sqlpp::postgresql::insert_into(t_auth_info)
.set( //
t_auth_info.password_hash = "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q",
t_auth_info.password_method = "bcrypt",
t_auth_info.password_salt = "OM/Z1c4WBFXvwkxh",
t_auth_info.email = "root@eedb.pl", //
t_auth_info.status = 0)
.returning(t_auth_info.id))
.front()
.id;
}
} // namespace eedb::pg

View File

@ -117,7 +117,7 @@ class DbTestBase : public testing::Test {
static void SetUpTestCase() {
_test_db = std::make_unique< PgTestDatabasePrepare >();
_test_db->db().execute("SET synchronous_commit=off;");
eedb::pg::exec_file(_test_db->db(), "/home/bwieczor/src/eedb/sql/schema.sql");
eedb::pg::exec_file(_test_db->db(), "/home/wieczbar/src/eedb/sql/schema.sql");
}
static void TearDownTestCase() {

View File

@ -1,27 +0,0 @@
#include <eedb/pg/Categories.hpp>
#include "DbTestBase.hpp"
#include <eedb/mock/db/pg/CategoryMock.hpp>
#include <utils/UniquePtrMockWrapper.hpp>
class PgCategoriesTest : public DbTestBase< PgCategoriesTest > {
public:
PgCategoriesTest() {
// sut = std::make_unique< eedb::pg::CategoriesImpl >(_categories);
}
protected:
// std::vector< UniquePtrMockWrapper< eedb::db:: > > _categories;
std::unique_ptr< eedb::pg::CategoriesImpl > sut;
};
template <>
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgCategoriesTest >::_test_db = {};
// TEST_F(PgCategoriesTest, size) {
// EXPECT_EQ(sut->size(), 4);
//}
// TEST_F(PgCategoriesTest, )

View File

@ -23,6 +23,11 @@ std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgCategoriesRepositoryTest
using namespace testing;
TEST_F(PgCategoriesRepositoryTest, createMultipleChildren) {
auto child1 = sut->create("child", "desc");
auto child2 = sut->create("child", "desc");
}
TEST_F(PgCategoriesRepositoryTest, rootNotNull) {
auto root = sut->root();
ASSERT_TRUE(root);

View File

@ -2,11 +2,12 @@
#include "DbTestBase.hpp"
#include <eedb/mock/db/pg/CategoriesRepositoryMock.hpp>
#include <eedb/mock/db/pg/UserMock.hpp>
class PgCategoryTest : public DbTestBase< PgCategoryTest > {
public:
PgCategoryTest() : user{db()} {
PgCategoryTest() : user{db()}, categoriesRepository{db(), user} {
user._init();
sut = std::make_unique< eedb::pg::CategoryImpl >(db());
}
@ -19,6 +20,8 @@ class PgCategoryTest : public DbTestBase< PgCategoryTest > {
protected:
eedb::pg::UserMock user;
eedb::pg::CategoriesRepositoryMock categoriesRepository;
std::unique_ptr< eedb::pg::CategoryImpl > sut;
};
@ -32,30 +35,31 @@ TEST_F(PgCategoryTest, rootCategoryHasNoParent) {
}
TEST_F(PgCategoryTest, id) {
auto category = sut->create("name", "description");
EXPECT_NE(dynamic_cast< eedb::pg::CategoryImpl * >(category.get())->id(), 0);
EXPECT_NE(dynamic_cast< eedb::pg::CategoryImpl * >(sut.get())->id(), 0);
}
TEST_F(PgCategoryTest, createChild) {
sut->create("name", "description");
TEST_F(PgCategoryTest, createCategory) {
auto category = std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf");
EXPECT_NE(dynamic_cast< eedb::pg::CategoryImpl * >(category.get())->id(), 0);
EXPECT_FALSE(category->parent());
}
TEST_F(PgCategoryTest, addCategory) {
auto category = sut->addChild(std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf"));
ASSERT_TRUE(category);
EXPECT_NE(dynamic_cast< eedb::pg::CategoryImpl * >(category)->id(), 0);
EXPECT_TRUE(category->parent());
}
TEST_F(PgCategoryTest, getChildren) {
sut->addChild(std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf"));
auto children = sut->children();
ASSERT_TRUE(children);
EXPECT_EQ(std::distance(children->begin(), children->end()), 1);
}
TEST_F(PgCategoryTest, getChildren) {
auto children = sut->children();
ASSERT_TRUE(children);
EXPECT_EQ(std::distance(children->begin(), children->end()), 0);
}
TEST_F(PgCategoryTest, childHasParent) {
sut->create("name1", "description");
sut->create("name2", "description");
auto children = sut->children();
EXPECT_EQ(std::distance(children->begin(), children->end()), 2);
for(auto child : *children) {
EXPECT_EQ(child->parent(), sut.get());
}
TEST_F(PgCategoryTest, addSameCategoryMultipleTimesShouldFail) {
sut->addChild(std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf"));
EXPECT_THROW(
sut->addChild(std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf")), eedb::exceptions::CategoryAddException);
}

View File

@ -35,4 +35,6 @@ TEST_F(PgParametersRepositoryTest, createWillNotThrow) {
// EXPECT_NO_THROW(sut->create("name", "description"));
}
TEST_F(PgParametersRepositoryTest, createSameThrowsException) {}
TEST_F(PgParametersRepositoryTest, createSameThrowsException) {
//
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <boost/range/iterator_range.hpp>
#include <exception>
#include <memory>
#include <string_view>
@ -19,6 +20,12 @@ class CategoriesRepository {
* @return root category
*/
virtual std::unique_ptr< Category > root() const = 0;
/**
* @brief create
* @return category in detached state (not connected to any parent category)
*/
virtual std::unique_ptr< Category > create(std::string name, std::string description) const = 0;
};
namespace details {
@ -27,6 +34,24 @@ namespace details {
using CategoryPtrIteratorRange = boost::iterator_range< CategoryPtrIterator >;
} // namespace details
namespace exceptions {
/**
* @brief The CategoryAddException class, thrown when a child category cannot be inserted to given category
*/
class CategoryAddException : public std::logic_error {
// exception interface
public:
CategoryAddException(std::unique_ptr< Category > category, std::string reason)
: std::logic_error(std::move(reason)), _badCategory{std::move(category)} {}
std::unique_ptr< Category > get() {
return std::move(_badCategory);
}
private:
std::unique_ptr< Category > _badCategory;
};
} // namespace exceptions
/**
* @brief The Categories class
*/
@ -62,10 +87,12 @@ class Category {
virtual Category * parent() const = 0;
/**
* @brief create
* @return category in detached state (not connected to any root category)
* @brief addChild
* @param category
* @throws
* @return pointer to newely added category
*/
virtual std::unique_ptr< Category > create(std::string name, std::string description) const = 0;
virtual Category * addChild(std::unique_ptr< Category > category) = 0;
/**
* @brief children

View File

@ -8,6 +8,6 @@ namespace eedb{
class CategoriesRepositoryMock : public CategoriesRepository {
public:
MOCK_CONST_METHOD0(root, std::unique_ptr< Category >());
MOCK_CONST_METHOD2(create, std::unique_ptr< Category >(std::string name, std::string description));
};
}
} // namespace eedb

View File

@ -11,8 +11,10 @@ class CategoryMock : public Category {
public:
MOCK_CONST_METHOD0(displayName, string_view());
MOCK_CONST_METHOD0(parent, Category *());
MOCK_CONST_METHOD2(create, std::unique_ptr< Category >(std::string name, std::string description));
MOCK_METHOD1(doAddChild, Category *( Category * ) );
Category * addChild(std::unique_ptr< Category > c) {
return doAddChild(c.get());
}
MOCK_CONST_METHOD0(children, std::unique_ptr< CategoriesChildren >());
};
}
} // namespace eedb