diff options
| -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; | 
