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

View File

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

View File

@ -12,12 +12,6 @@ if [ ! -d ${CMAKE_INSTALL_PREFIX} ]; then
fi fi
# clone all # 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 if [ ! -d sqlpp11/.git ]; then
git clone -b develop --depth=1 https://github.com/rbock/sqlpp11.git git clone -b develop --depth=1 https://github.com/rbock/sqlpp11.git
else else
@ -42,37 +36,31 @@ else
cd ChaiScript; git pull; cd ../ cd ChaiScript; git pull; cd ../
fi fi
echo ${CMAKE_PREFIX_PATH}
# install all # install all
mkdir sqlpp11-build -p; cd sqlpp11-build
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
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../sqlpp11\ ${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../sqlpp11\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\ -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\ -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\
-DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}"\ -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}"\ -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}"\
-DENABLE_TESTS=FALSE -DENABLE_TESTS=FALSE
${CMAKE_COMMAND} --build . --target install ${CMAKE_COMMAND} --build . --target install
cd ../ 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\ ${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../wt\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\ -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\ -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}\
@ -100,7 +88,7 @@ ${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../wt\
${CMAKE_COMMAND} --build . --target install ${CMAKE_COMMAND} --build . --target install
cd ../ cd ../
mkdir ChaiScript-build; cd ChaiScript-build mkdir ChaiScript-build -p; cd ChaiScript-build
${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../ChaiScript\ ${CMAKE_COMMAND} -G"${CMAKE_GENERATOR}" ../ChaiScript\
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\ -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\
-DCMAKE_C_COMPILER=${CMAKE_C_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; GRANT ALL ON SCHEMA public TO public;
create extension IF NOT EXISTS "ltree"; 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 ) create OR REPLACE function perm_to_numeric ( m_owner INT, m_group INT, m_other INT )
RETURNS INT AS $$ RETURNS INT AS $$
@ -31,6 +30,15 @@ end $$ --$$
language plpgsql stable cost 1; 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() create or replace function app_current_user_group()
returns int as $$ returns int as $$
begin begin
@ -327,7 +335,7 @@ create table "category"(
constraint "fk_category_stat_owner" foreign key ("owner") references "auth_info"("id") deferrable initially immediate constraint "fk_category_stat_owner" foreign key ("owner") references "auth_info"("id") deferrable initially immediate
) inherits (stat); ) inherits (stat);
create index "ix_category_parent_path" on "category" using GIST ("parent_path"); 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_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(); 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" comment on table "category"

View File

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

@ -4,9 +4,10 @@
#include <utils/spimpl.hpp> #include <utils/spimpl.hpp>
namespace eedb{ namespace eedb {
class User; class User;
} class Category;
} // namespace eedb
namespace eedb::pg { namespace eedb::pg {
class Connection; class Connection;
@ -15,12 +16,14 @@ class CategoriesRepositoryImpl : public CategoriesRepository {
public: public:
// CategoriesRepository interface // CategoriesRepository interface
public: public:
CategoriesRepositoryImpl(Connection &db); CategoriesRepositoryImpl(Connection & db);
std::unique_ptr< Category > root() const override; std::unique_ptr< Category > root() const override;
std::unique_ptr< Category > create(std::string name, std::string description) const override;
private: private:
struct CategoriesRepositoryImplPriv; struct CategoriesRepositoryImplPriv;
spimpl::unique_impl_ptr< CategoriesRepositoryImplPriv > _priv; 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 * @return id of object in database
*/ */
virtual int64_t id() const = 0; virtual int64_t id() const = 0;
virtual void setParent(PgCategory * parent) = 0;
}; };
} // namespace impl } // namespace impl
class Connection; class Connection;
class CategoryImpl : public impl::PgCategory { class CategoryImpl : public impl::PgCategory {
private: public:
/// TODO should be private
struct CategoryImplPrivate; struct CategoryImplPrivate;
spimpl::impl_ptr< CategoryImplPrivate > _priv; spimpl::unique_impl_ptr< CategoryImplPrivate > _priv;
public: public:
// ROOT category
CategoryImpl(Connection & db); 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; string_view displayName() const override;
Category * parent() 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: public:
int64_t id() const override; int64_t id() const override;
void setParent(PgCategory * parent) override;
}; };
} // namespace eedb::pg } // namespace eedb::pg

View File

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

View File

@ -4,15 +4,21 @@
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
namespace eedb::pg::details { #include <eedb/pg/utils.hpp>
inline auto app_current_user_id() { namespace eedb::pg::details {
return sqlpp::verbatim< sqlpp::integer >("app_current_user_id()");
}
template < typename Table > template < typename Table >
auto insert_user_stat(const Table & 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 > 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/postgresql/insert.h>
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#include <eedb/pg/utils.hpp>
namespace eedb::pg { namespace eedb::pg {
class CategoryMock : public impl::PgCategory { class CategoryMock : public impl::PgCategory {
@ -33,9 +35,13 @@ class CategoryMock : public impl::PgCategory {
MOCK_CONST_METHOD0(displayName, std::string_view()); MOCK_CONST_METHOD0(displayName, std::string_view());
MOCK_CONST_METHOD0(path, std::string_view()); MOCK_CONST_METHOD0(path, std::string_view());
MOCK_CONST_METHOD0(parent, Category *()); 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(children, std::unique_ptr< CategoriesChildren >());
MOCK_CONST_METHOD0(id, int64_t()); MOCK_CONST_METHOD0(id, int64_t());
MOCK_METHOD1(setParent, void(impl::PgCategory *));
void _init_simple(std::string name) { void _init_simple(std::string name) {
_root_guard(); _root_guard();
@ -47,7 +53,7 @@ class CategoryMock : public impl::PgCategory {
const auto & row = _db(sqlpp::postgresql::insert_into(t_category) // const auto & row = _db(sqlpp::postgresql::insert_into(t_category) //
.set(t_category.name = "root", // .set(t_category.name = "root", //
t_category.parent_id = sqlpp::null, 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)) .returning(t_category.id, t_category.parent_path))
.front(); .front();

View File

@ -17,6 +17,10 @@
#include <eedb/AuthIdentityConst.hpp> #include <eedb/AuthIdentityConst.hpp>
#include <eedb/pg/utils.hpp>
extern int64_t _global_root_uid;
namespace eedb::pg { namespace eedb::pg {
class UserMock : public ::eedb::pg::impl::UserImplPriv { class UserMock : public ::eedb::pg::impl::UserImplPriv {
@ -34,6 +38,17 @@ class UserMock : public ::eedb::pg::impl::UserImplPriv {
void _init() { void _init() {
using namespace testing; 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) _id = _db(sqlpp::postgresql::insert_into(t_auth_info)
.set( // .set( //
t_auth_info.password_hash = "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q", 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/CategoriesRepository.hpp>
#include <eedb/pg/Category.hpp> #include <eedb/pg/Category.hpp>
#include <eedb/pg/utils.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
namespace eedb::pg { namespace eedb::pg {
struct CategoriesRepositoryImpl::CategoriesRepositoryImplPriv { struct CategoriesRepositoryImpl::CategoriesRepositoryImplPriv {
@ -13,12 +11,20 @@ struct CategoriesRepositoryImpl::CategoriesRepositoryImplPriv {
return std::make_unique< eedb::pg::CategoryImpl >(_db); 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: private:
Connection & _db; Connection & _db;
}; };
CategoriesRepositoryImpl::CategoriesRepositoryImpl(Connection & db) : _priv{spimpl::make_unique_impl< CategoriesRepositoryImplPriv >(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 { // std::unique_ptr< Category > CategoriesRepositoryImpl::root() const { //
return _priv->root(); return _priv->root();
} }

View File

@ -1,18 +1,21 @@
#include <eedb/pg/Category.hpp> #include <eedb/pg/Category.hpp>
#include <eedb/pg/Categories.hpp> #include <spdlog/spdlog.h>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
#include <eedb/User.hpp> #include <eedb/User.hpp>
#include <spdlog/spdlog.h> #include <sqlpp11/postgresql/exception.h>
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#include <eedb/pg/Category.hpp>
#include <eedb/pg/Stats.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 { namespace eedb::pg {
struct CategoryImpl::CategoryImplPrivate { struct CategoryImpl::CategoryImplPrivate {
private: private:
// select // select
@ -28,6 +31,14 @@ struct CategoryImpl::CategoryImplPrivate {
return std::tuple_cat(stat_columns(), category_columns()); 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 // from
auto table_list() const { auto table_list() const {
return t_category; return t_category;
@ -42,55 +53,111 @@ struct CategoryImpl::CategoryImplPrivate {
return t_category.parent_path == "root"; return t_category.parent_path == "root";
} }
public: // set
Category * _self{nullptr}; 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 set_noParent() const {
auto row = _db(select(columns()).from(table_list()).where(root_path_match()).limit(1ul)); return std::tuple{t_category.parent_id = sqlpp::null};
if(row.empty()) { }
// no root category
row = _db(sqlpp::postgresql::insert_into(t_category) auto set_rootCategoryValues() const {
.set( // return std::make_tuple( //
t_category.owner = sqlpp::verbatim< sqlpp::integer >("app_current_user_id()"), t_category.owner = app_root_id(),
t_category.status = 0, t_category.status = 0, /// TODO set status "DETACHED"
t_category.parent_id = sqlpp::null, t_category.parent_id = sqlpp::null,
t_category.name = "root", t_category.name = "root",
t_category.description = "root category") // t_category.description = "root category");
.returning(columns())); }
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()); init_data(row.front());
} }
auto categories() const { CategoryImplPrivate(Connection & db, std::string name, std::string description) : _db{db}, _parent{nullptr} {
auto children = std::make_unique< std::vector< std::unique_ptr< Category > > >(); create(std::move(name), std::move(description));
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)));
} }
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 { bool detached() const {
return _parent == nullptr && _path != "root"; 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 { auto parent() const {
return _parent; return _parent;
} }
@ -107,7 +174,7 @@ struct CategoryImpl::CategoryImplPrivate {
return std::string_view{_path}; return std::string_view{_path};
} }
protected: public:
template < typename Row > template < typename Row >
void init_data(Row & row) { void init_data(Row & row) {
_uid = row.id; _uid = row.id;
@ -118,19 +185,27 @@ struct CategoryImpl::CategoryImplPrivate {
private: private:
Connection & _db; Connection & _db;
impl::PgCategory * _parent{nullptr};
int64_t _uid{}; int64_t _uid{};
Category * _parent{nullptr}; std::vector< std::unique_ptr< Category > > _children;
std::string _name; std::string _name;
std::string _path; std::string _path;
std::string _description; 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; _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; _priv->_self = this;
} }
@ -142,16 +217,19 @@ Category * CategoryImpl::parent() const {
return _priv->parent(); return _priv->parent();
} }
std::unique_ptr< CategoriesChildren > CategoryImpl::children() const { Category * CategoryImpl::addChild(std::unique_ptr< Category > category) noexcept(false) {
return std::make_unique< CategoriesImpl >(_priv->categories()); return _priv->addChild(std::move(category));
} }
std::unique_ptr< Category > CategoryImpl::create(std::string name, std::string description) const { std::unique_ptr< CategoriesChildren > CategoryImpl::children() const {
return _priv->create(std::move(name), std::move(description)); return _priv->categories();
} }
int64_t CategoryImpl::id() const { int64_t CategoryImpl::id() const {
return _priv->id(); return _priv->id();
} }
void CategoryImpl::setParent(impl::PgCategory * parent) {
_priv->setParent(parent);
}
} // namespace eedb::pg } // namespace eedb::pg

View File

@ -5,13 +5,19 @@
#include <eedb/pg/Session.hpp> #include <eedb/pg/Session.hpp>
#include <eedb/pg/Users.hpp> #include <eedb/pg/Users.hpp>
#include <eedb/pg/connection.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 { 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)} {}
FactoryImpl::~FactoryImpl() {} FactoryImpl::~FactoryImpl() {}
std::unique_ptr< Users > FactoryImpl::usersRepository() const { std::unique_ptr< Users > FactoryImpl::usersRepository() const {
createRootUser();
return std::make_unique< UsersImpl >(*_connection); return std::make_unique< UsersImpl >(*_connection);
} }
@ -27,4 +33,17 @@ std::unique_ptr< Session > FactoryImpl::session() const {
return std::make_unique< SessionImpl >(*_connection); 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 } // namespace eedb::pg

View File

@ -117,7 +117,7 @@ class DbTestBase : public testing::Test {
static void SetUpTestCase() { static void SetUpTestCase() {
_test_db = std::make_unique< PgTestDatabasePrepare >(); _test_db = std::make_unique< PgTestDatabasePrepare >();
_test_db->db().execute("SET synchronous_commit=off;"); _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() { 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; using namespace testing;
TEST_F(PgCategoriesRepositoryTest, createMultipleChildren) {
auto child1 = sut->create("child", "desc");
auto child2 = sut->create("child", "desc");
}
TEST_F(PgCategoriesRepositoryTest, rootNotNull) { TEST_F(PgCategoriesRepositoryTest, rootNotNull) {
auto root = sut->root(); auto root = sut->root();
ASSERT_TRUE(root); ASSERT_TRUE(root);

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include <exception>
#include <memory> #include <memory>
#include <string_view> #include <string_view>
@ -19,6 +20,12 @@ class CategoriesRepository {
* @return root category * @return root category
*/ */
virtual std::unique_ptr< Category > root() const = 0; 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 { namespace details {
@ -27,6 +34,24 @@ namespace details {
using CategoryPtrIteratorRange = boost::iterator_range< CategoryPtrIterator >; using CategoryPtrIteratorRange = boost::iterator_range< CategoryPtrIterator >;
} // namespace details } // 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 * @brief The Categories class
*/ */
@ -47,7 +72,7 @@ class Category {
public: public:
virtual ~Category() = default; virtual ~Category() = default;
virtual int foo(){} virtual int foo() {}
/** /**
* @brief displayName * @brief displayName
@ -62,10 +87,12 @@ class Category {
virtual Category * parent() const = 0; virtual Category * parent() const = 0;
/** /**
* @brief create * @brief addChild
* @return category in detached state (not connected to any root category) * @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 * @brief children

View File

@ -4,10 +4,10 @@
#include <eedb/Category.hpp> #include <eedb/Category.hpp>
namespace eedb{ namespace eedb {
class CategoriesRepositoryMock : public CategoriesRepository { class CategoriesRepositoryMock : public CategoriesRepository {
public: public:
MOCK_CONST_METHOD0(root, std::unique_ptr< Category >()); 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

@ -4,15 +4,17 @@
#include <eedb/Category.hpp> #include <eedb/Category.hpp>
namespace eedb{ namespace eedb {
class CategoryMock : public Category { class CategoryMock : public Category {
public: public:
// Category interface // Category interface
public: public:
MOCK_CONST_METHOD0(displayName, string_view()); MOCK_CONST_METHOD0(displayName, string_view());
MOCK_CONST_METHOD0(parent, Category *()); 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 >()); MOCK_CONST_METHOD0(children, std::unique_ptr< CategoriesChildren >());
}; };
} } // namespace eedb