update hunter, move creation of category into category class insead of categories repository
This commit is contained in:
parent
43eabfd602
commit
087405ec08
@ -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
|
||||
|
||||
@ -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}'")
|
||||
|
||||
@ -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}\
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -4,9 +4,10 @@
|
||||
|
||||
#include <utils/spimpl.hpp>
|
||||
|
||||
namespace eedb{
|
||||
namespace eedb {
|
||||
class User;
|
||||
}
|
||||
class Category;
|
||||
} // namespace eedb
|
||||
|
||||
namespace eedb::pg {
|
||||
class Connection;
|
||||
@ -15,12 +16,14 @@ class CategoriesRepositoryImpl : public CategoriesRepository {
|
||||
public:
|
||||
// CategoriesRepository interface
|
||||
public:
|
||||
CategoriesRepositoryImpl(Connection &db);
|
||||
CategoriesRepositoryImpl(Connection & db);
|
||||
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -21,5 +21,7 @@ class FactoryImpl : public Factory {
|
||||
|
||||
private:
|
||||
std::unique_ptr< Connection > _connection;
|
||||
|
||||
void createRootUser() const;
|
||||
};
|
||||
} // namespace eedb::pg
|
||||
|
||||
@ -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 >
|
||||
|
||||
17
src/libs/db/postgresql_connector/include/eedb/pg/utils.hpp
Normal file
17
src/libs/db/postgresql_connector/include/eedb/pg/utils.hpp
Normal 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
|
||||
@ -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
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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, )
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -35,4 +35,6 @@ TEST_F(PgParametersRepositoryTest, createWillNotThrow) {
|
||||
// EXPECT_NO_THROW(sut->create("name", "description"));
|
||||
}
|
||||
|
||||
TEST_F(PgParametersRepositoryTest, createSameThrowsException) {}
|
||||
TEST_F(PgParametersRepositoryTest, createSameThrowsException) {
|
||||
//
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
@ -47,7 +72,7 @@ class Category {
|
||||
public:
|
||||
virtual ~Category() = default;
|
||||
|
||||
virtual int foo(){}
|
||||
virtual int foo() {}
|
||||
|
||||
/**
|
||||
* @brief displayName
|
||||
@ -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
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
|
||||
#include <eedb/Category.hpp>
|
||||
|
||||
namespace eedb{
|
||||
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
|
||||
|
||||
@ -4,15 +4,17 @@
|
||||
|
||||
#include <eedb/Category.hpp>
|
||||
|
||||
namespace eedb{
|
||||
namespace eedb {
|
||||
class CategoryMock : public Category {
|
||||
public:
|
||||
// Category interface
|
||||
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user