summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slicer/db/Jamfile.jam16
-rw-r--r--slicer/db/sqlTablePatchSerializer.cpp64
-rw-r--r--slicer/db/sqlTablePatchSerializer.h25
-rw-r--r--slicer/db/testPatch.cpp47
4 files changed, 152 insertions, 0 deletions
diff --git a/slicer/db/Jamfile.jam b/slicer/db/Jamfile.jam
index ea394ff..ad15a6c 100644
--- a/slicer/db/Jamfile.jam
+++ b/slicer/db/Jamfile.jam
@@ -67,6 +67,22 @@ run testInsert.cpp
testInsert
;
+run testPatch.cpp
+ : : :
+ <define>BOOST_TEST_DYN_LINK
+ <library>slicer-db
+ <library>dbpp-postgresql
+ <library>boost_system
+ <library>boost_filesystem
+ <library>boost_utf
+ <library>../test//types
+ <library>../test//common
+ <library>../slicer//slicer
+ <implicit-dependency>../slicer//slicer
+ <include>..
+ <dependency>slicer.sql
+ ;
+
run testUpdate.cpp
: : :
<define>BOOST_TEST_DYN_LINK
diff --git a/slicer/db/sqlTablePatchSerializer.cpp b/slicer/db/sqlTablePatchSerializer.cpp
new file mode 100644
index 0000000..20b0d82
--- /dev/null
+++ b/slicer/db/sqlTablePatchSerializer.cpp
@@ -0,0 +1,64 @@
+#include "sqlTablePatchSerializer.h"
+#include "sqlInsertSerializer.h"
+#include <slicer/metadata.h>
+#include <compileTimeFormatter.h>
+#include <scopeExit.h>
+
+namespace Slicer {
+ const std::string md_pkey = "db:pkey";
+ const std::string ignore = "ignore";
+
+ AdHocFormatter(ttname, "slicer_tmp_%?");
+ SqlTablePatchSerializer::SqlTablePatchSerializer(DB::Connection * db, DB::TablePatch & tp) :
+ db(db),
+ tablePatch(tp)
+ {
+ tablePatch.src = ttname::get(this);
+ }
+
+ SqlTablePatchSerializer::~SqlTablePatchSerializer()
+ {
+ }
+
+ void
+ SqlTablePatchSerializer::Serialize(Slicer::ModelPartForRootPtr mpr)
+ {
+ tablePatch.pk.clear();
+ tablePatch.cols.clear();
+
+ createTemporaryTable();
+ AdHoc::ScopeExit tidy(boost::bind(&SqlTablePatchSerializer::dropTemporaryTable, this));
+
+ SqlInsertSerializer ins(db, tablePatch.src);
+ ins.Serialize(mpr);
+
+ auto mp = mpr->GetContainedModelPart();
+ mp->OnEachChild([this](const auto & name, const auto &, const auto & h) {
+ if (metaDataFlagSet(h->GetMetadata(), md_pkey)) {
+ tablePatch.pk.insert(name);
+ }
+ });
+ mp->OnEachChild([this](const auto & name, const auto &, const auto & h) {
+ if (metaDataFlagNotSet(h->GetMetadata(), ignore)) {
+ tablePatch.cols.insert(name);
+ }
+ });
+
+ db->patchTable(&tablePatch);
+ }
+
+ AdHocFormatter(createTmpTable, "CREATE TEMPORARY TABLE %? AS SELECT * FROM %? WHERE 1 = 0");
+ void
+ SqlTablePatchSerializer::createTemporaryTable()
+ {
+ db->execute(createTmpTable::get(tablePatch.src, tablePatch.dest));
+ }
+
+ AdHocFormatter(dropTmpTable, "DROP TABLE %?");
+ void
+ SqlTablePatchSerializer::dropTemporaryTable()
+ {
+ db->execute(dropTmpTable::get(tablePatch.src));
+ }
+}
+
diff --git a/slicer/db/sqlTablePatchSerializer.h b/slicer/db/sqlTablePatchSerializer.h
new file mode 100644
index 0000000..9aad96c
--- /dev/null
+++ b/slicer/db/sqlTablePatchSerializer.h
@@ -0,0 +1,25 @@
+#ifndef SLICER_DB_SQLTABLEPATCHSERIALIZER_H
+#define SLICER_DB_SQLTABLEPATCHSERIALIZER_H
+
+#include <slicer/serializer.h>
+#include <tablepatch.h>
+
+namespace Slicer {
+ class DLL_PUBLIC SqlTablePatchSerializer : public Slicer::Serializer {
+ public:
+ SqlTablePatchSerializer(DB::Connection *, DB::TablePatch &);
+ ~SqlTablePatchSerializer();
+
+ virtual void Serialize(Slicer::ModelPartForRootPtr) override;
+
+ private:
+ void createTemporaryTable();
+ void dropTemporaryTable();
+
+ DB::Connection * db;
+ DB::TablePatch & tablePatch;
+ };
+}
+
+#endif
+
diff --git a/slicer/db/testPatch.cpp b/slicer/db/testPatch.cpp
new file mode 100644
index 0000000..bb7979b
--- /dev/null
+++ b/slicer/db/testPatch.cpp
@@ -0,0 +1,47 @@
+#define BOOST_TEST_MODULE db_patch
+#include <boost/test/unit_test.hpp>
+#include <boost/date_time/posix_time/posix_time_io.hpp>
+#include <pq-mock.h>
+#include <slicer/slicer.h>
+#include <definedDirs.h>
+#include "sqlTablePatchSerializer.h"
+#include "sqlSelectDeserializer.h"
+#include <types.h>
+#include <common.h>
+#include <db.h>
+
+// LCOV_EXCL_START
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestModule::DateTime);
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestModule::IsoDate);
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestDatabase::Timespan);
+// LCOV_EXCL_STOP
+
+class StandardMockDatabase : public PQ::Mock {
+ public:
+ StandardMockDatabase() : PQ::Mock("user=postgres dbname=postgres", "pqmock", {
+ rootDir.parent_path() / "db" / "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::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"))
+ };
+ DB::TablePatch tp;
+ DB::TransactionScope tx(db.get());
+ tp.dest = "builtins";
+ Slicer::SerializeAny<Slicer::SqlTablePatchSerializer>(bis, db.get(), tp);
+ auto cmd = db->select("SELECT COUNT(*) FROM builtins");
+ auto c = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, int>(*cmd);
+ BOOST_REQUIRE_EQUAL(2, c);
+}
+