diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-01-15 20:36:27 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-06-13 17:29:46 +0100 |
commit | d4596cf570dac98e13640d7ff63dba932a5bfd0b (patch) | |
tree | 8e911bb2bfcaa07cbe3976b02bad15bedb43d4a6 | |
parent | A single ycm config that gets its args from b2 (diff) | |
download | p2pvr-d4596cf570dac98e13640d7ff63dba932a5bfd0b.tar.bz2 p2pvr-d4596cf570dac98e13640d7ff63dba932a5bfd0b.tar.xz p2pvr-d4596cf570dac98e13640d7ff63dba932a5bfd0b.zip |
Add the SqlSelectDeserializer for Slicer objects and covering unit tests
-rw-r--r-- | p2pvr/daemon/Jamfile.jam | 3 | ||||
-rw-r--r-- | p2pvr/daemon/sqlSelectDeserializer.cpp | 171 | ||||
-rw-r--r-- | p2pvr/daemon/sqlSelectDeserializer.h | 26 | ||||
-rw-r--r-- | p2pvr/daemon/unittests/Jamfile.jam | 15 | ||||
-rw-r--r-- | p2pvr/daemon/unittests/testSqlSelectDeserializer.cpp | 81 |
5 files changed, 296 insertions, 0 deletions
diff --git a/p2pvr/daemon/Jamfile.jam b/p2pvr/daemon/Jamfile.jam index d9894d3..5913af1 100644 --- a/p2pvr/daemon/Jamfile.jam +++ b/p2pvr/daemon/Jamfile.jam @@ -1,4 +1,5 @@ import testing ; +lib slicer : : <name>slicer : : <include>/usr/include/slicer ; cpp-pch pch : pch.hpp : <library>../ice//p2pvrice @@ -21,9 +22,11 @@ lib p2pvrdaemon : <library>../devices//p2pvrdevices <library>../daemonbase//p2pvrdaemonbase <implicit-dependency>../../libtmdb//tmdb + <library>slicer : : <include>. <library>../ice//p2pvrice + <library>slicer ; unit-test testEmbedding : diff --git a/p2pvr/daemon/sqlSelectDeserializer.cpp b/p2pvr/daemon/sqlSelectDeserializer.cpp new file mode 100644 index 0000000..0e87a64 --- /dev/null +++ b/p2pvr/daemon/sqlSelectDeserializer.cpp @@ -0,0 +1,171 @@ +#include "sqlSelectDeserializer.h" +#include <sqlHandleAsVariableType.h> +#include <logger.h> +#include <boost/algorithm/string/predicate.hpp> +#include <stdexcept> + +VariableType +operator/(DB::SelectCommand & cmd, unsigned int col) +{ + HandleAsVariableType vt; + cmd[col].apply(vt); + return vt.variable; +} + +class SqlSource : public DB::HandleField, public Slicer::ValueSource, + public Slicer::TValueSource<boost::posix_time::time_duration>, + public Slicer::TValueSource<boost::posix_time::ptime> { + public: + bool isNull() const + { + return vt.isNull(); + } + + void interval(const boost::posix_time::time_duration & d) override + { + vt = d; + } + void null() override + { + vt = Null(); + } + void string(const char * s, size_t l) override + { + vt = Glib::ustring(s, l); + } + void integer(int64_t i) override + { + vt = i; + } + void floatingpoint(double fp) override + { + vt = fp; + } + void timestamp(const boost::posix_time::ptime & t) + { + vt = t; + } +#define SET(Type) \ + void set(Type & b) const override { \ + b = vt.as<Type>(); \ + } +#define SETNCONV(Type, CType) \ + void set(Type & b) const override { \ + b = boost::numeric_cast<Type>(vt.as<CType>()); \ + } + SET(bool); + SET(std::string); + SETNCONV(Ice::Byte, int64_t); + SETNCONV(Ice::Short, int64_t); + SET(Ice::Int); + SET(Ice::Long); + SETNCONV(Ice::Float, double); + SET(Ice::Double); + SET(boost::posix_time::ptime); + SET(boost::posix_time::time_duration); + + private: + VariableType vt; +}; +typedef IceUtil::Handle<SqlSource> SqlSourcePtr; + +SqlSelectDeserializer::SqlSelectDeserializer(DB::SelectCommand & c, IceUtil::Optional<std::string> tc) : + cmd(c), + typeIdColName(tc) +{ +} + +void +SqlSelectDeserializer::Deserialize(Slicer::ModelPartPtr mp) +{ + cmd.execute(); + columnCount = cmd.columnCount(); + if (typeIdColName) { + typeIdColIdx = cmd.getOrdinal(*typeIdColName); + } + switch (mp->GetType()) { + case Slicer::mpt_Sequence: + DeserializeSequence(mp); + return; + case Slicer::mpt_Complex: + DeserializeObject(mp); + return; + case Slicer::mpt_Simple: + DeserializeSimple(mp); + return; + default: + throw std::invalid_argument("Unspported model type"); + } +} + +void +SqlSelectDeserializer::DeserializeSimple(Slicer::ModelPartPtr mp) +{ + auto fmp = mp->GetAnonChild(); + if (!cmd.fetch()) { + std::invalid_argument("No rows returned"); + } + SqlSourcePtr h = new SqlSource(); + const DB::Column & c = cmd[0]; + c.apply(*h); + if (!h->isNull()) { + fmp->Create(); + fmp->SetValue(h); + fmp->Complete(); + } + if (cmd.fetch()) { + std::invalid_argument("Too many rows returned"); + } +} + +void +SqlSelectDeserializer::DeserializeSequence(Slicer::ModelPartPtr mp) +{ + mp = mp->GetAnonChild(); + SqlSourcePtr h = new SqlSource(); + while (cmd.fetch()) { + DeserializeRow(mp); + } +} + +void +SqlSelectDeserializer::DeserializeObject(Slicer::ModelPartPtr mp) +{ + if (!cmd.fetch()) { + std::invalid_argument("No rows returned"); + } + DeserializeRow(mp); + if (cmd.fetch()) { + std::invalid_argument("Too many rows returned"); + } +} + +void +SqlSelectDeserializer::DeserializeRow(Slicer::ModelPartPtr mp) +{ + SqlSourcePtr h = new SqlSource(); + auto rmp = mp->GetAnonChild(); + if (rmp) { + if (typeIdColIdx) { + rmp = rmp->GetSubclassModelPart(cmd / *typeIdColIdx); + } + rmp->Create(); + for (auto col = 0u; col < columnCount; col += 1) { + const DB::Column & c = cmd[col]; + auto fmpr = rmp->GetAnonChildRef([&c](Slicer::HookCommonPtr h) { + return boost::iequals(c.name.raw(), h->PartName()); + }); + if (fmpr) { + auto fmp = fmpr->Child(); + c.apply(*h); + if (!h->isNull()) { + fmp->Create(); + fmp->SetValue(h); + fmp->Complete(); + } + } + } + rmp->Complete(); + } +} + diff --git a/p2pvr/daemon/sqlSelectDeserializer.h b/p2pvr/daemon/sqlSelectDeserializer.h new file mode 100644 index 0000000..008a87c --- /dev/null +++ b/p2pvr/daemon/sqlSelectDeserializer.h @@ -0,0 +1,26 @@ +#ifndef P2PVR_SQL_DESERIALIZER_H +#define P2PVR_SQL_DESERIALIZER_H + +#include <slicer/serializer.h> +#include <selectcommand.h> + +class SqlSelectDeserializer : public Slicer::Deserializer { + public: + SqlSelectDeserializer(DB::SelectCommand &, IceUtil::Optional<std::string> typeIdCol = IceUtil::Optional<std::string>()); + + virtual void Deserialize(Slicer::ModelPartPtr) override; + + protected: + void DeserializeSimple(Slicer::ModelPartPtr); + void DeserializeObject(Slicer::ModelPartPtr); + void DeserializeSequence(Slicer::ModelPartPtr); + void DeserializeRow(Slicer::ModelPartPtr); + + DB::SelectCommand & cmd; + unsigned int columnCount; + IceUtil::Optional<std::string> typeIdColName; + IceUtil::Optional<unsigned int> typeIdColIdx; +}; + +#endif + diff --git a/p2pvr/daemon/unittests/Jamfile.jam b/p2pvr/daemon/unittests/Jamfile.jam index f07338f..c9ebc5a 100644 --- a/p2pvr/daemon/unittests/Jamfile.jam +++ b/p2pvr/daemon/unittests/Jamfile.jam @@ -121,3 +121,18 @@ unit-test testStorage : <define>ROOT=\"$(me)\" ; +unit-test testSqlSelectDeserializer : + testSqlSelectDeserializer.cpp + : + <define>BOOST_TEST_DYN_LINK + <library>../..//p2common + <library>../..//p2sql + <library>../..//p2ut + <library>../..//p2xml + <library>..//p2pvrdaemon + <library>IceUtil + <library>Ice + <library>../..//boost_utf + <define>ROOT=\"$(me)\" + ; + diff --git a/p2pvr/daemon/unittests/testSqlSelectDeserializer.cpp b/p2pvr/daemon/unittests/testSqlSelectDeserializer.cpp new file mode 100644 index 0000000..79990cb --- /dev/null +++ b/p2pvr/daemon/unittests/testSqlSelectDeserializer.cpp @@ -0,0 +1,81 @@ +#define BOOST_TEST_MODULE SqlSelectDeserializer +#include <boost/test/unit_test.hpp> +#include <sqlSelectDeserializer.h> +#include <slicer/slicer.h> +#include <connection.h> +#include <p2pvr.h> +#include <rdbmsDataSource.h> +#include <commonObjects.h> +#include <testOptionsSource.h> +#include <boost/filesystem/operations.hpp> +#include <definedDirs.h> +#include <commonHelpers.h> + +typedef boost::shared_ptr<DB::SelectCommand> SelectPtr; + +class TestCommonObjects : public CommonObjects { + public: + TestCommonObjects() + { + TestOptionsSource::LoadTestOptions({ + { "common.datasourceRoot", (RootDir / "datasources").string() }, + }); + } +}; +BOOST_FIXTURE_TEST_SUITE ( Sql, TestCommonObjects ); + +BOOST_AUTO_TEST_CASE( listOfEvents ) +{ + auto db = dataSource<RdbmsDataSource>("postgres")->getReadonly(); + auto sel = SelectPtr(db->newSelectCommand("SELECT * FROM events ORDER BY serviceId, eventId LIMIT 100")); + auto res = Slicer::DeserializeAny<SqlSelectDeserializer, P2PVR::Events>(*sel); + BOOST_REQUIRE_EQUAL(res.size(), 100); + BOOST_REQUIRE_EQUAL(res[0]->ServiceId, 4166); + BOOST_REQUIRE_EQUAL(res[0]->EventId, 49741); + BOOST_REQUIRE_EQUAL(res[0]->Title, "Skiing Weatherview"); + BOOST_REQUIRE(!res[0]->Subtitle); + BOOST_REQUIRE_EQUAL(res[0]->Description, "Detailed weather forecast."); + BOOST_REQUIRE_EQUAL(res[0]->StartTime, Common::DateTime({2014, 12, 19, 0, 25})); + BOOST_REQUIRE_EQUAL(res[0]->StopTime, Common::DateTime({2014, 12, 19, 0, 30})); + BOOST_REQUIRE(res[0]->Current); + BOOST_REQUIRE_EQUAL(res[99]->ServiceId, 4166); + BOOST_REQUIRE_EQUAL(res[99]->EventId, 52448); + BOOST_REQUIRE_EQUAL(res[99]->Title, "East Midlands Today"); +} + +BOOST_AUTO_TEST_CASE( singleField ) +{ + auto db = dataSource<RdbmsDataSource>("postgres")->getReadonly(); + auto sel = SelectPtr(db->newSelectCommand("SELECT EventId FROM events ORDER BY serviceId, eventId LIMIT 1")); + auto res = Slicer::DeserializeAny<SqlSelectDeserializer, int>(*sel); + BOOST_REQUIRE_EQUAL(res, 49741); +} + +BOOST_AUTO_TEST_CASE( singleEvent ) +{ + auto db = dataSource<RdbmsDataSource>("postgres")->getReadonly(); + auto sel = SelectPtr(db->newSelectCommand("SELECT * FROM events ORDER BY serviceId, eventId LIMIT 1")); + auto res = Slicer::DeserializeAny<SqlSelectDeserializer, P2PVR::EventPtr>(*sel); + BOOST_REQUIRE_EQUAL(res->ServiceId, 4166); + BOOST_REQUIRE_EQUAL(res->EventId, 49741); + BOOST_REQUIRE_EQUAL(res->Title, "Skiing Weatherview"); + BOOST_REQUIRE(!res->Subtitle); + BOOST_REQUIRE_EQUAL(res->Description, "Detailed weather forecast."); + BOOST_REQUIRE_EQUAL(res->StartTime, Common::DateTime({2014, 12, 19, 0, 25})); + BOOST_REQUIRE_EQUAL(res->StopTime, Common::DateTime({2014, 12, 19, 0, 30})); +} + +BOOST_AUTO_TEST_CASE( dynamicTypes ) +{ + auto db = dataSource<RdbmsDataSource>("postgres")->getReadonly(); + auto sel = SelectPtr(db->newSelectCommand("SELECT d.*, '::DVBSI::TerrestrialDelivery' \"typeid\" FROM delivery_dvbt d ORDER BY TransportStreamId")); + auto res = Slicer::DeserializeAny<SqlSelectDeserializer, P2PVR::Deliveries>(*sel, "typeid"); + BOOST_REQUIRE_EQUAL(res.size(), 6); + auto dvbt = DVBSI::TerrestrialDeliveryPtr::dynamicCast(res[0]); + BOOST_REQUIRE_EQUAL(dvbt->Frequency, 682000000); + BOOST_REQUIRE_EQUAL(dvbt->TransportStreamId, 4170); + BOOST_REQUIRE_EQUAL(dvbt->CodeRateHP, 2); +} + +BOOST_AUTO_TEST_SUITE_END(); + |