add 'private' interface to category class

This commit is contained in:
Bartosz Wieczorek 2018-03-26 09:50:42 +02:00
parent bd6a6aefe3
commit f689cbd60a
10 changed files with 69 additions and 59 deletions

View File

@ -7,7 +7,7 @@
namespace eedb::pg {
class Connection;
class CategoriesImpl : public Categories {
class CategoriesImpl : public CategoriesChildren {
// Categories interface
public:
CategoriesImpl(std::unique_ptr< std::vector< std::unique_ptr< eedb::Category > > > data);

View File

@ -9,9 +9,24 @@ class User;
}
namespace eedb::pg {
namespace impl {
/**
* @brief The PgCategory class
*
* 'private part' of categories class
*/
class PgCategory : public ::eedb::Category {
/**
* @brief id
* @return id of object in database
*/
virtual int64_t id() const = 0;
};
} // namespace impl
class Connection;
class CategoryImpl : public Category {
class CategoryImpl : public impl::PgCategory {
private:
struct CategoryImplPrivate;
spimpl::impl_ptr< CategoryImplPrivate > _priv;
@ -22,13 +37,14 @@ class CategoryImpl : public Category {
string_view displayName() const override;
string_view path() const override;
Category * parent() const override;
std::unique_ptr< Categories > children() const override;
std::unique_ptr< CategoriesChildren > children() const override;
std::unique_ptr< Category > create(std::string name, std::string description) const override;
public:
int64_t id() const override;
};
} // namespace eedb
} // namespace eedb::pg

View File

@ -2,7 +2,7 @@
#include <gmock/gmock.h>
#include <eedb/mock/db/CategoryMock.hpp>
#include <eedb/pg/Category.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
@ -12,7 +12,8 @@
namespace eedb::pg {
class CategoryMock : public ::eedb::CategoryMock {
class CategoryMock : public impl::PgCategory {
public:
auto _createChild(int64_t parentId, std::string name) {
return _db(sqlpp::postgresql::insert_into(t_category) //
.set(t_category.name = name, t_category.parent_id = parentId)
@ -22,39 +23,46 @@ class CategoryMock : public ::eedb::CategoryMock {
}
void _root_guard() {
if(!_root_id)
if(!_id)
_initRoot();
}
public:
CategoryMock(Connection & db) : _db{db} {}
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_CONST_METHOD0(children, std::unique_ptr< CategoriesChildren >());
MOCK_CONST_METHOD0(id, int64_t());
void _init_simple(std::string name) {
_root_guard();
_createChild(_root_id, name);
_createChild(_id, name);
}
void _initRoot() {
using namespace testing;
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() "))
.returning(t_category.id, t_category.parent_path))
.front();
.set(t_category.name = "root", //
t_category.parent_id = sqlpp::null,
t_category.owner = sqlpp::verbatim< sqlpp::integer >(" app_current_user_id() "))
.returning(t_category.id, t_category.parent_path))
.front();
_root_id = row.id;
_path = row.parent_path;
_id = row.id;
_path = row.parent_path;
}
void _expect_call_path() {
void _expect_call_id() {
using namespace testing;
EXPECT_CALL(*this, path()).WillRepeatedly(Return(_path));
EXPECT_CALL(*this, id()).WillRepeatedly(Return(_id));
}
private:
Connection & _db;
int64_t _root_id{0};
int64_t _id{0};
std::string _path;
};

View File

@ -18,7 +18,7 @@ struct CategoriesImpl::CategoriesImplPriv {
};
CategoriesImpl::CategoriesImpl(std::unique_ptr< std::vector< std::unique_ptr< Category > > > data)
: eedb::Categories(boost::make_transform_iterator(data->begin(), CategoriesImplPriv::getTransform()),
: 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))} {}

View File

@ -126,7 +126,7 @@ struct CategoryImpl::CategoryImplPrivate {
std::string _description;
};
CategoryImpl::CategoryImpl(Connection &db) : _priv{spimpl::make_impl< CategoryImplPrivate >(db, nullptr)} {
CategoryImpl::CategoryImpl(Connection & db) : _priv{spimpl::make_impl< CategoryImplPrivate >(db, nullptr)} {
_priv->_self = this;
}
@ -138,15 +138,11 @@ Category::string_view CategoryImpl::displayName() const {
return _priv->displayName();
}
Category::string_view CategoryImpl::path() const {
return _priv->path();
}
Category * CategoryImpl::parent() const {
return _priv->parent();
}
std::unique_ptr< Categories > CategoryImpl::children() const {
std::unique_ptr< CategoriesChildren > CategoryImpl::children() const {
return std::make_unique< CategoriesImpl >(_priv->categories());
}
@ -154,4 +150,8 @@ std::unique_ptr< Category > CategoryImpl::create(std::string name, std::string d
return _priv->create(std::move(name), std::move(description));
}
int64_t CategoryImpl::id() const {
return _priv->id();
}
} // namespace eedb::pg

View File

@ -1,7 +1,7 @@
#include <eedb/pg/Item.hpp>
#include <eedb/Category.hpp>
#include <eedb/Value.hpp>
#include <eedb/pg/Category.hpp>
#include <eedb/pg/connection.hpp>
#include <eedb/pg/model/all.hpp>
@ -15,16 +15,12 @@ namespace eedb::pg {
struct ItemImpl::ItemPriv {
ItemPriv(Connection & db, int64_t uid, item::Attributes attributes) : _db{db}, _uid{uid}, _attributes{std::move(attributes)} {}
bool attachToCategory(const Category * category) {
bool attachToCategory(const Category * _category) {
auto category = dynamic_cast< const CategoryImpl * >(_category);
assert(category);
auto x = sqlpp::cte(sqlpp::alias::x)
.as(select(t_category.parent_id) //
.from(t_category) //
.where(t_category.parent_path == std::string{category->path()})
.limit(1u));
_db(insert_into(t_category_items) //
.set(t_category_items.category_id = 1, t_category_items.item_id = _uid));
.set(t_category_items.category_id = category->id(), t_category_items.item_id = _uid));
return true;
}

View File

@ -38,10 +38,10 @@ struct ItemsRepositoryImpl::temsRepositoryImplPriv {
return std::tuple_cat(insert(attributes.values()), insert_producer(attributes.producer()));
}
auto insert(const item::Identyfier &id, item::Attributes attributes, const std::optional< item::Foto > & foto) {
auto insert(const item::Identyfier & id, item::Attributes attributes, const std::optional< item::Foto > & foto) {
try {
auto uid = _db(sqlpp::postgresql::insert_into(t_item) //
.set(std::tuple_cat( //
auto uid = _db(sqlpp::postgresql::insert_into(t_item) //
.set(std::tuple_cat( //
insert(id),
insert(attributes))) //
.returning(t_item.id))
@ -84,14 +84,6 @@ struct ItemsRepositoryImpl::temsRepositoryImplPriv {
}
}
auto _cte_categoryIdByPath(const ItemQueryFilters & filer) const {
return sqlpp::cte(sqlpp::alias::x)
.as(select(t_category.parent_id) //
.from(t_category) //
.where(t_category.parent_path == std::string{filer.category() ? filer.category()->path() : std::string_view{""}})
.limit(1u));
}
auto _titem() const {
return t_item.inner_join(t_category_items).on(t_item.id == t_category_items.item_id);
}
@ -120,18 +112,16 @@ struct ItemsRepositoryImpl::temsRepositoryImplPriv {
auto search(const ItemQueryFilters & filer) {
using sqlpp::dynamic_select;
auto x = _cte_categoryIdByPath(filer);
auto s = dynamic_select(_db.native(), all_of(t_item)) //
.dynamic_from(_titem()) //
.dynamic_where()
.limit(100u);
if(filer.category() != nullptr) {
s.where.add(t_category_items.category_id == select(x.parent_id).from(x));
if(auto cat = dynamic_cast< const CategoryImpl * >(filer.category()); cat != nullptr) {
s.where.add(t_category_items.category_id == cat->id());
}
auto rows = _db(with(x)(s));
auto rows = _db(s);
_items.clear();
for(const auto & row : rows) {

View File

@ -27,5 +27,4 @@ TEST_F(PgCategoriesRepositoryTest, rootNotNull) {
auto root = sut->root();
ASSERT_TRUE(root);
EXPECT_FALSE(root->parent());
EXPECT_EQ(root->path(), "root");
}

View File

@ -31,6 +31,11 @@ TEST_F(PgCategoryTest, rootCategoryHasNoParent) {
EXPECT_FALSE(sut->parent());
}
TEST_F(PgCategoryTest, id) {
auto category = sut->create("name", "description");
EXPECT_NE(dynamic_cast< eedb::pg::CategoryImpl * >(category.get())->id(), 0);
}
TEST_F(PgCategoryTest, createChild) {
sut->create("name", "description");
auto children = sut->children();
@ -54,8 +59,3 @@ TEST_F(PgCategoryTest, childHasParent) {
EXPECT_EQ(child->parent(), sut.get());
}
}
TEST_F(PgCategoryTest, path) {
auto path = std::string{sut->create("name", "description")->create("name", "description")->path()};
EXPECT_THAT(path, MatchesRegex(R"(root\.[0-9]*\.[0-9]*)"));
}

View File

@ -37,7 +37,8 @@ class PgItemsRepositoryTest : public DbTestBase< PgItemsRepositoryTest > {
EXPECT_CALL(textParameter, name()).WillRepeatedly(Return(std::string_view{"text parameter"}));
EXPECT_CALL(listParameter, name()).WillRepeatedly(Return(std::string_view{"list parameter"}));
return eedb::Values(eedb::Value{5, &numericParameter},
return eedb::Values( //
eedb::Value{5, &numericParameter},
eedb::Value{"some text"s, &textParameter},
eedb::Value{std::vector{1.2, 3.4, 5.6, 7.8}, &listParameter});
}
@ -68,6 +69,6 @@ TEST_F(PgItemsRepositoryTest, createTwiceThrowsException) {
TEST_F(PgItemsRepositoryTest, createReturnsValidParameter) {
EXPECT_NO_THROW(sut->create(some_id(), some_attributes(), {}));
category._expect_call_path();
category._expect_call_id();
auto items = sut->search(eedb::ItemQueryFilters{&category});
}