diff options
| author | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-10-18 01:33:49 +0100 | 
|---|---|---|
| committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-10-18 01:47:47 +0100 | 
| commit | 4c8f043f65a29bbd4ca743398950aea0126343e3 (patch) | |
| tree | 56e52e05f9544915052bad967358f53ef0db8d4f | |
| parent | Restructure alias all list and add missing things (diff) | |
| download | slicer-4c8f043f65a29bbd4ca743398950aea0126343e3.tar.bz2 slicer-4c8f043f65a29bbd4ca743398950aea0126343e3.tar.xz slicer-4c8f043f65a29bbd4ca743398950aea0126343e3.zip | |
Add insert serializers that don't insert fields marked as auto and optionally retrieve the value applied by the database back into the model
| -rw-r--r-- | slicer/db/slicer.sql | 2 | ||||
| -rw-r--r-- | slicer/db/sqlInsertSerializer.cpp | 89 | ||||
| -rw-r--r-- | slicer/db/sqlInsertSerializer.h | 24 | ||||
| -rw-r--r-- | slicer/db/testInsert.cpp | 48 | ||||
| -rw-r--r-- | slicer/test/types.ice | 3 | 
5 files changed, 153 insertions, 13 deletions
| diff --git a/slicer/db/slicer.sql b/slicer/db/slicer.sql index e526db3..9d649bb 100644 --- a/slicer/db/slicer.sql +++ b/slicer/db/slicer.sql @@ -15,7 +15,7 @@ CREATE TABLE builtins(  		mbool boolean,  		mbyte smallint,  		mshort smallint, -		mint int, +		mint serial,  		mlong bigint,  		mfloat numeric(5, 2),  		mdouble numeric(8, 5), diff --git a/slicer/db/sqlInsertSerializer.cpp b/slicer/db/sqlInsertSerializer.cpp index eccc083..e8d44f5 100644 --- a/slicer/db/sqlInsertSerializer.cpp +++ b/slicer/db/sqlInsertSerializer.cpp @@ -3,8 +3,12 @@  #include "sqlBinder.h"  #include <buffer.h>  #include <modifycommand.h> +#include <slicer/metadata.h> +#include <boost/numeric/conversion/cast.hpp>  namespace Slicer { +	const std::string md_auto = "db:auto"; +  	SqlInsertSerializer::SqlInsertSerializer(DB::Connection * c, const std::string & t) :  		connection(c),  		tableName(t) @@ -46,27 +50,72 @@ namespace Slicer {  	}  	void -	SqlInsertSerializer::bindObjectAndExecute(Slicer::ModelPartPtr cmp, DB::ModifyCommand * ins) +	SqlInsertSerializer::bindObjectAndExecute(Slicer::ModelPartPtr cmp, DB::ModifyCommand * ins) const  	{  		int paramNo = 0; -		cmp->OnEachChild([&ins, ¶mNo](const std::string &, ModelPartPtr cmp, HookCommonPtr) { -				cmp->GetValue(new SqlBinder(*ins, paramNo++)); -			}); +		cmp->OnEachChild(boost::bind(&SqlInsertSerializer::bindObjectAndExecuteField, this, boost::ref(paramNo), ins, _2, _3));  		ins->execute();  	} +	class IdSave : public Slicer::ValueSource { +		public: +			IdSave(DB::Connection * c) : +				connection(c) +			{ +			} + +#define NonNumType(T) \ +			void set(T &) const override { throw std::runtime_error("Can't store Id in " #T " type field"); } + +#define NumType(T) \ +			void set(T & v) const override { v = boost::numeric_cast<T>(connection->insertId()); } + +			NonNumType(bool); +			NonNumType(std::string); + +			NumType(Ice::Byte); +			NumType(Ice::Short); +			NumType(Ice::Int); +			NumType(Ice::Long); +			NumType(Ice::Float); +			NumType(Ice::Double); + +		private: +			DB::Connection * connection; +	}; + +	void +	SqlFetchIdInsertSerializer::bindObjectAndExecute(Slicer::ModelPartPtr cmp, DB::ModifyCommand * ins) const +	{ +		SqlAutoIdInsertSerializer::bindObjectAndExecute(cmp, ins); +		cmp->OnEachChild([&ins, this](const std::string &, ModelPartPtr cmp, HookCommonPtr h) { +				if (metaDataFlagSet(h->GetMetadata(), md_auto)) { +					cmp->SetValue(new IdSave(connection)); +				} +			}); +	} + +	void +	SqlInsertSerializer::bindObjectAndExecuteField(int & paramNo, DB::ModifyCommand * ins, Slicer::ModelPartPtr cmp, HookCommonPtr) const +	{ +		cmp->GetValue(new SqlBinder(*ins, paramNo++)); +	} + +	void +	SqlAutoIdInsertSerializer::bindObjectAndExecuteField(int & paramNo, DB::ModifyCommand * ins, Slicer::ModelPartPtr cmp, HookCommonPtr h) const +	{ +		if (metaDataFlagNotSet(h->GetMetadata(), md_auto)) { +			cmp->GetValue(new SqlBinder(*ins, paramNo++)); +		} +	} +  	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); -			}); +		mp->OnEachChild(boost::bind(&SqlInsertSerializer::createInsertField, this, boost::ref(fieldNo), boost::ref(insert), _1, _3));  		insert.append(") VALUES (", AdHoc::Buffer::Use);  		for (; fieldNo > 1; --fieldNo) {  			insert.append("?, "); @@ -74,5 +123,25 @@ namespace Slicer {  		insert.append("?)");  		return ModifyPtr(connection->newModifyCommand(insert));  	} + +	void +	SqlInsertSerializer::createInsertField(int & fieldNo, AdHoc::Buffer & insert, const std::string & name, HookCommonPtr) const +	{ +		if (fieldNo++) { +			insert.append(", "); +		} +		insert.append(name); +	} + +	void +	SqlAutoIdInsertSerializer::createInsertField(int & fieldNo, AdHoc::Buffer & insert, const std::string & name, HookCommonPtr h) const +	{ +		if (metaDataFlagNotSet(h->GetMetadata(), md_auto)) { +			if (fieldNo++) { +				insert.append(", "); +			} +			insert.append(name); +		} +	}  } diff --git a/slicer/db/sqlInsertSerializer.h b/slicer/db/sqlInsertSerializer.h index 843be93..359c655 100644 --- a/slicer/db/sqlInsertSerializer.h +++ b/slicer/db/sqlInsertSerializer.h @@ -4,6 +4,7 @@  #include <slicer/serializer.h>  #include <connection.h>  #include <visibility.h> +#include <buffer.h>  namespace Slicer {  	class DLL_PUBLIC SqlInsertSerializer : public Slicer::Serializer { @@ -18,11 +19,32 @@ namespace Slicer {  			void SerializeObject(Slicer::ModelPartPtr) const;  			void SerializeSequence(Slicer::ModelPartPtr) const;  			ModifyPtr createInsert(Slicer::ModelPartPtr) const; -			static void bindObjectAndExecute(Slicer::ModelPartPtr, DB::ModifyCommand *); +			virtual void createInsertField(int & fieldNo, AdHoc::Buffer & insert, const std::string & name, HookCommonPtr h) const; +			virtual void bindObjectAndExecute(Slicer::ModelPartPtr, DB::ModifyCommand *) const; +			virtual void bindObjectAndExecuteField(int & paramNo, DB::ModifyCommand *, Slicer::ModelPartPtr, HookCommonPtr) const;  			DB::Connection * connection;  			const std::string tableName;  	}; + +	class DLL_PUBLIC SqlAutoIdInsertSerializer : public SqlInsertSerializer { +		public: +			template <typename ... P> +			SqlAutoIdInsertSerializer(const P & ... p) : SqlInsertSerializer(p...) { } + +		protected: +			virtual void createInsertField(int & fieldNo, AdHoc::Buffer & insert, const std::string & name, HookCommonPtr h) const; +			virtual void bindObjectAndExecuteField(int & paramNo, DB::ModifyCommand *, Slicer::ModelPartPtr, HookCommonPtr) const; +	}; + +	class DLL_PUBLIC SqlFetchIdInsertSerializer : public SqlAutoIdInsertSerializer { +		public: +			template <typename ... P> +			SqlFetchIdInsertSerializer(const P & ... p) : SqlAutoIdInsertSerializer(p...) { } + +		protected: +			virtual void bindObjectAndExecute(Slicer::ModelPartPtr, DB::ModifyCommand *) const; +	};  }  #endif diff --git a/slicer/db/testInsert.cpp b/slicer/db/testInsert.cpp index 2a167c0..74ad537 100644 --- a/slicer/db/testInsert.cpp +++ b/slicer/db/testInsert.cpp @@ -66,6 +66,54 @@ BOOST_AUTO_TEST_CASE( insert_seq_builtins )  	BOOST_REQUIRE_EQUAL(bis.back()->mstring, bis2.back()->mstring);  } +BOOST_AUTO_TEST_CASE( autoinsert_seq_builtins ) +{ +	auto db = DBPtr(DB::MockDatabase::openConnectionTo("pqmock")); +	TestModule::BuiltInSeq bis = { +		TestModule::BuiltInsPtr(new TestModule::BuiltIns(true, 5, 17, 0, 129, 2.3, 4.5, "more text")), +		TestModule::BuiltInsPtr(new TestModule::BuiltIns(true, 6, 18, 0, 130, 3.4, 5.6, "even more text")) +	}; +	Slicer::SerializeAny<Slicer::SqlAutoIdInsertSerializer>(bis, db.get(), "builtins"); +	auto sel = SelectPtr(db->newSelectCommand("SELECT * FROM builtins WHERE mint IN (1, 2) ORDER BY mint")); +	auto bis2 = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, TestModule::BuiltInSeq>(*sel); +	BOOST_REQUIRE_EQUAL(2, bis2.size()); +	BOOST_REQUIRE_EQUAL(bis.front()->mint, 0); +	BOOST_REQUIRE_EQUAL(bis.back()->mint, 0); +	BOOST_REQUIRE_EQUAL(bis2.front()->mint, 1); +	BOOST_REQUIRE_EQUAL(bis2.back()->mint, 2); +	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()->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); +} + +BOOST_AUTO_TEST_CASE( fetchinsert_seq_builtins ) +{ +	auto db = DBPtr(DB::MockDatabase::openConnectionTo("pqmock")); +	TestModule::BuiltInSeq bis = { +		TestModule::BuiltInsPtr(new TestModule::BuiltIns(true, 5, 17, 0, 129, 2.3, 4.5, "more text")), +		TestModule::BuiltInsPtr(new TestModule::BuiltIns(true, 6, 18, 0, 130, 3.4, 5.6, "even more text")) +	}; +	Slicer::SerializeAny<Slicer::SqlFetchIdInsertSerializer>(bis, db.get(), "builtins"); +	auto sel = SelectPtr(db->newSelectCommand("SELECT * FROM builtins WHERE mint IN (3, 4) ORDER BY mint")); +	auto bis2 = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, TestModule::BuiltInSeq>(*sel); +	BOOST_REQUIRE_EQUAL(2, bis2.size()); +	BOOST_REQUIRE_EQUAL(bis.front()->mint, 3); +	BOOST_REQUIRE_EQUAL(bis.back()->mint, 4); +	BOOST_REQUIRE_EQUAL(bis2.front()->mint, 3); +	BOOST_REQUIRE_EQUAL(bis2.back()->mint, 4); +	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()->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); +} +  BOOST_AUTO_TEST_CASE( insert_converted )  {  	auto db = DBPtr(DB::MockDatabase::openConnectionTo("pqmock")); diff --git a/slicer/test/types.ice b/slicer/test/types.ice index 4cd6531..41637a0 100644 --- a/slicer/test/types.ice +++ b/slicer/test/types.ice @@ -30,7 +30,8 @@ module TestModule {  		bool mbool;  		byte mbyte;  		short mshort; -		["slicer:db:pkey"] +		["slicer:db:pkey", +		 "slicer:db:auto"]  		int mint;  		["slicer:db:pkey"]  		long mlong; | 
