diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-10-15 22:20:05 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-10-15 22:20:05 +0100 |
commit | d340eddd8966689bf20d7749a01e20aacb12c064 (patch) | |
tree | 611011f4e72f58a43c178efb6b766e1eb1caf2be | |
parent | Use rvalue refs for throw wrapper in select tests (diff) | |
download | slicer-d340eddd8966689bf20d7749a01e20aacb12c064.tar.bz2 slicer-d340eddd8966689bf20d7749a01e20aacb12c064.tar.xz slicer-d340eddd8966689bf20d7749a01e20aacb12c064.zip |
Add basic support for insert serialization of objects and sequences of objects
-rw-r--r-- | slicer/db/Jamfile.jam | 21 | ||||
-rw-r--r-- | slicer/db/slicer.sql | 11 | ||||
-rw-r--r-- | slicer/db/sqlBinder.cpp | 70 | ||||
-rw-r--r-- | slicer/db/sqlBinder.h | 36 | ||||
-rw-r--r-- | slicer/db/sqlInsertSerializer.cpp | 76 | ||||
-rw-r--r-- | slicer/db/sqlInsertSerializer.h | 28 | ||||
-rw-r--r-- | slicer/db/testInsert.cpp | 61 | ||||
-rw-r--r-- | slicer/test/preprocessor.cpp | 2 | ||||
-rw-r--r-- | slicer/test/types.ice | 1 |
9 files changed, 305 insertions, 1 deletions
diff --git a/slicer/db/Jamfile.jam b/slicer/db/Jamfile.jam index 9d18558..a6a94e8 100644 --- a/slicer/db/Jamfile.jam +++ b/slicer/db/Jamfile.jam @@ -7,6 +7,7 @@ alias glibmm : : : : lib dbppcore : : : : <include>/usr/include/dbpp ; lib dbpp-postgresql : : : : <include>/usr/include/dbpp-postgresql ; +lib adhocutil : : : : <include>/usr/include/adhocutil ; lib boost_system ; lib boost_filesystem ; lib boost_utf : : <name>boost_unit_test_framework ; @@ -19,6 +20,7 @@ lib slicer-db : <library>IceUtil <library>dbppcore <library>glibmm + <library>adhocutil <library>../slicer//slicer <cflags>-fvisibility=hidden <variant>release:<cflags>-flto @@ -47,3 +49,22 @@ run testSelect.cpp testSelect ; +run testInsert.cpp + : : : + <define>ROOT=\"$(me)\" + <define>BOOST_TEST_DYN_LINK + <library>slicer-db + <library>dbpp-postgresql + <library>boost_system + <library>boost_filesystem + <library>boost_utf + <library>../test//slicer-test + <library>../test//common + <library>../slicer//slicer + <include>.. + <dependency>slicer.sql + <dependency>../test//compilation + : + testInsert + ; + diff --git a/slicer/db/slicer.sql b/slicer/db/slicer.sql index 94807f5..d77c15c 100644 --- a/slicer/db/slicer.sql +++ b/slicer/db/slicer.sql @@ -10,3 +10,14 @@ INSERT INTO test VALUES(1, 1.1, 'text one', true, '2015-01-27 23:06:03', '1 day INSERT INTO test VALUES(2, 12.12, 'text two', true, '2015-02-27 23:06:03', '1 day 12:13:12'); INSERT INTO test VALUES(3, 123.123, 'text three', false, '2015-03-27 23:06:03', '1 day 13:13:12'); INSERT INTO test VALUES(4, 1234.1234, 'text four', false, '2015-04-27 23:06:03', '1 day 14:13:12'); + +CREATE TABLE builtins( + mbool boolean, + mbyte smallint, + mshort smallint, + mint int, + mlong bigint, + mfloat numeric(5, 2), + mdouble numeric(8, 5), + mstring text); + diff --git a/slicer/db/sqlBinder.cpp b/slicer/db/sqlBinder.cpp new file mode 100644 index 0000000..6969749 --- /dev/null +++ b/slicer/db/sqlBinder.cpp @@ -0,0 +1,70 @@ +#include "sqlBinder.h" + +namespace Slicer { + SqlBinder::SqlBinder(DB::Command & c, unsigned int i) : + command(c), + idx(i) + { + } + + void + SqlBinder::get(const boost::posix_time::ptime & b) const + { + command.bindParamT(idx, b); + } + + void + SqlBinder::get(const boost::posix_time::time_duration & b) const + { + command.bindParamT(idx, b); + } + + void + SqlBinder::get(const bool & b) const + { + command.bindParamB(idx, b); + } + + void + SqlBinder::get(const Ice::Byte & b) const + { + command.bindParamI(idx, b); + } + + void + SqlBinder::get(const Ice::Short & b) const + { + command.bindParamI(idx, b); + } + + void + SqlBinder::get(const Ice::Int & b) const + { + command.bindParamI(idx, b); + } + + void + SqlBinder::get(const Ice::Long & b) const + { + command.bindParamI(idx, b); + } + + void + SqlBinder::get(const Ice::Float & b) const + { + command.bindParamF(idx, b); + } + + void + SqlBinder::get(const Ice::Double & b) const + { + command.bindParamF(idx, b); + } + + void + SqlBinder::get(const std::string & b) const + { + command.bindParamS(idx, b); + } +} + diff --git a/slicer/db/sqlBinder.h b/slicer/db/sqlBinder.h new file mode 100644 index 0000000..b4d7ac4 --- /dev/null +++ b/slicer/db/sqlBinder.h @@ -0,0 +1,36 @@ +#ifndef SLICER_DB_SQLBINDER_H +#define SLICER_DB_SQLBINDER_H + +#include <slicer/modelParts.h> +#include <command.h> +#include <boost/date_time/posix_time/ptime.hpp> + +namespace Slicer { + class SqlBinder : public Slicer::ValueTarget, + public Slicer::TValueTarget<boost::posix_time::time_duration>, + public Slicer::TValueTarget<boost::posix_time::ptime> + { + public: + SqlBinder(DB::Command & c, unsigned int idx); + + void get(const boost::posix_time::ptime & b) const override; + void get(const boost::posix_time::time_duration & b) const override; + void get(const bool & b) const override; + void get(const Ice::Byte & b) const override; + void get(const Ice::Short & b) const override; + void get(const Ice::Int & b) const override; + void get(const Ice::Long & b) const override; + void get(const Ice::Float & b) const override; + void get(const Ice::Double & b) const override; + void get(const std::string & b) const override; + + private: + DB::Command & command; + const unsigned int idx; + }; + typedef IceUtil::Handle<SqlBinder> SqlBinderPtr; +} + +#endif + + diff --git a/slicer/db/sqlInsertSerializer.cpp b/slicer/db/sqlInsertSerializer.cpp new file mode 100644 index 0000000..2f8e88d --- /dev/null +++ b/slicer/db/sqlInsertSerializer.cpp @@ -0,0 +1,76 @@ +#include "sqlInsertSerializer.h" +#include "exceptions.h" +#include "sqlBinder.h" +#include <buffer.h> +#include <modifycommand.h> + +namespace Slicer { + SqlInsertSerializer::SqlInsertSerializer(DB::Connection * c, const std::string & t) : + connection(c), + tableName(t) + { + } + + void + SqlInsertSerializer::Serialize(Slicer::ModelPartPtr mp) + { + switch (mp->GetType()) { + case Slicer::mpt_Sequence: + mp->OnEachChild(boost::bind(&SqlInsertSerializer::SerializeSequence, this, _2)); + return; + case Slicer::mpt_Complex: + mp->OnEachChild(boost::bind(&SqlInsertSerializer::SerializeObject, this, _2)); + return; + default: + throw UnsupportedModelType(); + } + } + + void + SqlInsertSerializer::SerializeObject(Slicer::ModelPartPtr mp) const + { + auto ins = createInsert(mp); + int paramNo = 0; + mp->OnEachChild([&ins, ¶mNo](const std::string &, ModelPartPtr cmp, HookCommonPtr) { + cmp->GetValue(new SqlBinder(*ins, paramNo++)); + }); + ins->execute(); + } + + void + SqlInsertSerializer::SerializeSequence(Slicer::ModelPartPtr mp) const + { + ModifyPtr ins; + mp->OnEachChild([&ins, this](const std::string &, ModelPartPtr cmp, HookCommonPtr) { + if (!ins) { + ins = createInsert(cmp); + } + int paramNo = 0; + cmp->OnEachChild([&ins, ¶mNo](const std::string &, ModelPartPtr cmp, HookCommonPtr) { + cmp->GetValue(new SqlBinder(*ins, paramNo++)); + }); + ins->execute(); + }); + } + + SqlInsertSerializer::ModifyPtr + SqlInsertSerializer::createInsert(Slicer::ModelPartPtr mp) const + { + AdHoc::Buffer insert; + insert.appendbf("INSERT INTO %s(", tableName); + int fieldNo = 0; + mp->OnEachChild([&insert, &fieldNo]( const std::string & name, ModelPartPtr, HookCommonPtr) { + if (fieldNo++) { + insert.append(", "); + } + insert.append(name); + }); + insert.append(") VALUES (", AdHoc::Buffer::Use); + for (; fieldNo > 1; --fieldNo) { + insert.append("?, "); + } + insert.append("?)"); + return ModifyPtr(connection->newModifyCommand(insert)); + } +} + diff --git a/slicer/db/sqlInsertSerializer.h b/slicer/db/sqlInsertSerializer.h new file mode 100644 index 0000000..9163f47 --- /dev/null +++ b/slicer/db/sqlInsertSerializer.h @@ -0,0 +1,28 @@ +#ifndef SLICER_DB_SQLINSERTSERIALIZER_H +#define SLICER_DB_SQLINSERTSERIALIZER_H + +#include <slicer/serializer.h> +#include <connection.h> +#include <visibility.h> + +namespace Slicer { + class DLL_PUBLIC SqlInsertSerializer : public Slicer::Serializer { + public: + typedef boost::shared_ptr<DB::ModifyCommand> ModifyPtr; + + SqlInsertSerializer(DB::Connection *, const std::string & tableName); + + virtual void Serialize(Slicer::ModelPartPtr) override; + + protected: + void SerializeObject(Slicer::ModelPartPtr) const; + void SerializeSequence(Slicer::ModelPartPtr) const; + ModifyPtr createInsert(Slicer::ModelPartPtr) const; + + DB::Connection * connection; + const std::string tableName; + }; +} + +#endif + diff --git a/slicer/db/testInsert.cpp b/slicer/db/testInsert.cpp new file mode 100644 index 0000000..9d7bf04 --- /dev/null +++ b/slicer/db/testInsert.cpp @@ -0,0 +1,61 @@ +#define BOOST_TEST_MODULE db_insert +#include <boost/test/unit_test.hpp> +#include <boost/date_time/posix_time/posix_time_io.hpp> +#include <mock.h> +#include <slicer/slicer.h> +#include <definedDirs.h> +#include "sqlInsertSerializer.h" +#include "sqlSelectDeserializer.h" +#include <types.h> + +class StandardMockDatabase : public PQ::Mock { + public: + StandardMockDatabase() : PQ::Mock("user=postgres dbname=postgres", "pqmock", { + rootDir / "slicer.sql" }) + { + } +}; + +BOOST_GLOBAL_FIXTURE( StandardMockDatabase ); + +typedef boost::shared_ptr<DB::Connection> DBPtr; +typedef boost::shared_ptr<DB::SelectCommand> SelectPtr; + +BOOST_AUTO_TEST_CASE( insert_builtins ) +{ + auto db = DBPtr(DB::MockDatabase::openConnectionTo("pqmock")); + TestModule::BuiltInsPtr bi = new TestModule::BuiltIns(true, 4, 16, 64, 128, 1.2, 3.4, "text"); + Slicer::SerializeAny<Slicer::SqlInsertSerializer>(bi, db.get(), "builtins"); + auto sel = SelectPtr(db->newSelectCommand("SELECT * FROM builtins")); + auto bi2 = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, TestModule::BuiltInsPtr>(*sel); + BOOST_REQUIRE_EQUAL(bi->mbool, bi2->mbool); + BOOST_REQUIRE_EQUAL(bi->mbyte, bi2->mbyte); + BOOST_REQUIRE_EQUAL(bi->mshort, bi2->mshort); + BOOST_REQUIRE_EQUAL(bi->mint, bi2->mint); + BOOST_REQUIRE_EQUAL(bi->mlong, bi2->mlong); + BOOST_REQUIRE_EQUAL(bi->mfloat, bi2->mfloat); + BOOST_REQUIRE_EQUAL(bi->mdouble, bi2->mdouble); + BOOST_REQUIRE_EQUAL(bi->mstring, bi2->mstring); +} + +BOOST_AUTO_TEST_CASE( insert_seq_builtins ) +{ + auto db = DBPtr(DB::MockDatabase::openConnectionTo("pqmock")); + TestModule::BuiltInSeq bis = { + TestModule::BuiltInsPtr(new TestModule::BuiltIns(true, 5, 17, 65, 129, 2.3, 4.5, "more text")), + TestModule::BuiltInsPtr(new TestModule::BuiltIns(true, 6, 18, 66, 130, 3.4, 5.6, "even more text")) + }; + Slicer::SerializeAny<Slicer::SqlInsertSerializer>(bis, db.get(), "builtins"); + auto sel = SelectPtr(db->newSelectCommand("SELECT * FROM builtins ORDER BY mint")); + auto bis2 = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, TestModule::BuiltInSeq>(*sel); + BOOST_REQUIRE_EQUAL(3, bis2.size()); + BOOST_REQUIRE_EQUAL(bis.back()->mbool, bis2.back()->mbool); + BOOST_REQUIRE_EQUAL(bis.back()->mbyte, bis2.back()->mbyte); + BOOST_REQUIRE_EQUAL(bis.back()->mshort, bis2.back()->mshort); + BOOST_REQUIRE_EQUAL(bis.back()->mint, bis2.back()->mint); + BOOST_REQUIRE_EQUAL(bis.back()->mlong, bis2.back()->mlong); + BOOST_REQUIRE_EQUAL(bis.back()->mfloat, bis2.back()->mfloat); + BOOST_REQUIRE_EQUAL(bis.back()->mdouble, bis2.back()->mdouble); + BOOST_REQUIRE_EQUAL(bis.back()->mstring, bis2.back()->mstring); +} + diff --git a/slicer/test/preprocessor.cpp b/slicer/test/preprocessor.cpp index bef901e..9a02456 100644 --- a/slicer/test/preprocessor.cpp +++ b/slicer/test/preprocessor.cpp @@ -13,7 +13,7 @@ namespace fs = boost::filesystem; -const unsigned int COMPONENTS_IN_TEST_ICE = 32; +const unsigned int COMPONENTS_IN_TEST_ICE = 33; BOOST_FIXTURE_TEST_SUITE ( preprocessor, FileStructure ); diff --git a/slicer/test/types.ice b/slicer/test/types.ice index 73da2a0..bdb39b2 100644 --- a/slicer/test/types.ice +++ b/slicer/test/types.ice @@ -44,6 +44,7 @@ module TestModule { int a; int b; }; + sequence<BuiltIns> BuiltInSeq; sequence<ClassType> Classes; sequence<StructType> Structs; dictionary<int, ClassType> ClassMap; |