libinvdb/source/include/dbobject_impl.hh

281 lines
8.7 KiB
C++

#ifndef INVENTORY_DBOBJECT_IMPL_HH_
#define INVENTORY_DBOBJECT_IMPL_HH_
#include <string>
#include "dbfield.hh"
#include "dbfield_impl.hh"
#include "dbobject.hh"
#include "dboperations.hh"
namespace inventory {
namespace datamodel {
template<class Derived>
DBObject<Derived>::DBObject()
: m_record_elements(),
// used in SQL statements, left unregistered
id(NULL, &DBRecordDescTempl<DBObject>::id_desc) {
id = (int)(DBObject<Derived>::Id::UNDEFINED);
}
template<class Derived>
DBNamedObject<Derived>::DBNamedObject()
: name(this, &DBRecordDescTempl<DBNamedObject>::name_desc) {}
template<class Derived>
DBHierarchicalObject<Derived>::DBHierarchicalObject()
: sup(this, &DBRecordDescTempl<DBHierarchicalObject>::sup_desc),
nsub(NULL, &DBRecordDescTempl<DBHierarchicalObject>::nsub_desc) {
sup = (int)(DBHierarchicalObject<Derived>::Id::UNDEFINED);
nsub = -1;
}
template<class Derived>
void DBObject<Derived>::register_element(DBRecordElement<Derived> *el) const {
m_record_elements.insert(
std::make_pair(
std::string(el->element_description()->column_name), el
));
}
template<class Derived>
void DBObject<Derived>::from_query(ResultSet_T r) {
TRY {
id = ResultSet_getIntByName(r,
DBRecordDescTempl<DBObject>::id_desc.column_name);
for (const auto &el : m_record_elements)
(el.second)->from_query(r);
} CATCH(SQLException) {
}
END_TRY;
}
template<class Derived>
void DBHierarchicalObject<Derived>::from_query(ResultSet_T r) {
nsub = ResultSet_getIntByName(r,
DBRecordDescTempl<DBHierarchicalObject>::nsub_desc.column_name);
DBObject<Derived>::from_query(r);
}
template<class Derived>
std::string DBObject<Derived>::prepared_statement_columns() const {
std::string ret;
for (const auto &el : m_record_elements)
ret += el.first + ", ";
ret.pop_back();
ret.pop_back();
return ret;
}
template<class Derived>
std::string DBObject<Derived>::prepared_statement_value_placeholders() const {
std::string ret;
for (const auto &el : m_record_elements)
ret += "?, ";
ret.pop_back();
ret.pop_back();
return ret;
}
template<class Derived>
void DBObject<Derived>::insert(db::DBSession &session) const {
const std::string prepared_stmt =
std::string("INSERT INTO ") +
Derived::sc_table + std::string("(") +
prepared_statement_columns() +
std::string(") VALUES(") +
prepared_statement_value_placeholders() +
std::string(")");
auto stmt_cons =
[this](void *, PreparedStatement_T s) {
insert_values(s);
};
db::DBOperations::execute<void *>(session, NULL, prepared_stmt.c_str(),
stmt_cons);
}
template<class Derived>
void DBObject<Derived>::update(db::DBSession &session) const {
const std::string prepared_stmt =
std::string("UPDATE ") +
Derived::sc_table +
std::string(" SET (") +
prepared_statement_columns() +
std::string(") = (") +
prepared_statement_value_placeholders() +
std::string(") WHERE id = ?");
auto stmt_cons =
[this](void *, PreparedStatement_T s) {
insert_values(s);
};
db::DBOperations::execute<void *>(session, NULL, prepared_stmt.c_str(),
stmt_cons);
}
template<class Derived>
void DBObject<Derived>::remove(db::DBSession &session) const {
const std::string prepared_stmt =
std::string("DELETE FROM ") +
Derived::sc_table +
std::string("WHERE item_id = ?");
auto stmt_cons =
[this](void *, PreparedStatement_T s) {
PreparedStatement_setInt(s, 1, (int)(id));
};
db::DBOperations::execute<void *>(session, NULL, prepared_stmt.c_str(),
stmt_cons);
}
template<class Derived>
void DBObject<Derived>::refresh(db::DBSession &session) {
*this = *DBObject<Derived>::get(session, id);
}
template<class Derived>
void DBObject<Derived>::insert_values(PreparedStatement_T s) const {
int pos = 1;
for (const auto &el : m_record_elements) {
el.second->insert_value(s, pos++);
}
}
template<class Derived>
DBObjectPtr<Derived> DBObject<Derived>::get(db::DBSession &session, int id) {
if (id < 0)
return DBObjectPtr<Derived>(); // TODO
// I want to use underlying database's prepared
// statement system to sanititze inputs, but it's
// not possible to specify tables this way.
const std::string prepared_stmt =
std::string("SELECT * FROM ") +
Derived::sc_view +
std::string(" WHERE id=?");
auto stmt_cons =
[](int id, PreparedStatement_T s) {
PreparedStatement_setInt(s, 1, id);
};
return db::DBOperations::get_single<Derived, int>(session, id,
prepared_stmt.c_str(), stmt_cons);
}
template<class Derived>
DBObjectPtr<Derived> DBNamedObject<Derived>::
get(db::DBSession &session, const char *name) {
const std::string prepared_stmt =
std::string("SELECT * FROM ") +
Derived::sc_view +
std::string(" WHERE name=?");
auto stmt_cons =
[](const char *name, PreparedStatement_T s) {
PreparedStatement_setString(s, 1, name);
};
return db::DBOperations::get_single<Derived, const char *>(session,
name, prepared_stmt.c_str(), stmt_cons);
}
template<class Derived>
template<template<class> class Container>
DBContainerPtr<Derived, Container> DBObject<Derived>::get_all(
db::DBSession &session,
DBObjectInserter<Derived, Container> inserter,
DBContainerPtr<Derived, Container> pcontainer, int offset, int limit) {
const std::string prepared_stmt =
std::string("SELECT * FROM ") +
Derived::sc_view +
std::string(" ORDER BY name ASC LIMIT ? OFFSET ?");
auto stmt_cons =
[](void *, PreparedStatement_T s, int offset, int limit) {
PreparedStatement_setInt(s, 1, limit);
PreparedStatement_setInt(s, 2, offset);
};
return db::DBOperations::get_all<Derived, void *, Container>(session, NULL,
prepared_stmt.c_str(), stmt_cons, inserter, pcontainer, offset, limit);
}
template<class Derived>
template<template<class> class Container>
DBContainerPtr<Derived, Container> DBHierarchicalObject<Derived>::get_children(
db::DBSession &session, int id,
DBObjectInserter<Derived, Container> inserter,
DBContainerPtr<Derived, Container> pcontainer, int offset, int limit) {
const std::string prepared_stmt =
std::string("SELECT * FROM ") +
Derived::sc_view +
std::string(" WHERE parent = ?") +
std::string(" ORDER BY name ASC LIMIT ? OFFSET ?");
auto stmt_cons =
[](int id, PreparedStatement_T s, int offset, int limit) {
PreparedStatement_setInt(s, 1, id);
PreparedStatement_setInt(s, 2, limit);
PreparedStatement_setInt(s, 3, offset);
};
return db::DBOperations::get_all<Derived, int, Container>(session, id,
prepared_stmt.c_str(), stmt_cons, inserter, pcontainer,
offset, limit);
}
template<class Derived>
template<template<class> class Container>
DBContainerPtr<Derived, Container> DBHierarchicalObject<Derived>::get_children(
db::DBSession &session,
DBObjectInserter<Derived, Container> inserter,
DBContainerPtr<Derived, Container> pcontainer, int offset, int limit) {
return get_children<Container>(session, (int)(DBObject<Derived>::id), inserter,
pcontainer, offset, limit);
}
template<class Derived>
DBObjectPtr<Derived> DBHierarchicalObject<Derived>::get_parent(
db::DBSession &session) {
return get(session, sup);
}
template<class Derived>
void DBHierarchicalObject<Derived>::create_sub_view(db::DBSession &session) {
std::string sub_view = std::string("CREATE VIEW ") + Derived::sc_dbclass + "_sub AS \n\
SELECT id, 0 AS sub FROM " + Derived::sc_table + " WHERE id NOT IN (SELECT id FROM " + Derived::sc_dbclass + "_sup) \n\
UNION \n\
SELECT id, sub FROM " + Derived::sc_dbclass + "_sup;";
db::DBOperations::execute<void *>(session, NULL, sub_view.c_str(),
[](void *, PreparedStatement_T s) {});
}
template<class Derived>
void DBHierarchicalObject<Derived>::create_sup_view(db::DBSession &session) {
std::string sup_view = std::string("CREATE VIEW ") + Derived::sc_dbclass + "_sup \
AS SELECT sup AS id, COUNT(*) AS sub FROM " + Derived::sc_table + " GROUP BY sup;";
db::DBOperations::execute<void *>(session, NULL, sup_view.c_str(),
[](void *, PreparedStatement_T s) {});
}
}
}
#endif