summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slicer/db/Jamfile.jam21
-rw-r--r--slicer/db/slicer.sql11
-rw-r--r--slicer/db/sqlBinder.cpp70
-rw-r--r--slicer/db/sqlBinder.h36
-rw-r--r--slicer/db/sqlInsertSerializer.cpp76
-rw-r--r--slicer/db/sqlInsertSerializer.h28
-rw-r--r--slicer/db/testInsert.cpp61
-rw-r--r--slicer/test/preprocessor.cpp2
-rw-r--r--slicer/test/types.ice1
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, &paramNo](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, &paramNo](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;