281 lines
8.7 KiB
C++
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
|