diff options
-rw-r--r-- | slicer/db/Jamfile.jam | 16 | ||||
-rw-r--r-- | slicer/db/sqlTablePatchSerializer.cpp | 64 | ||||
-rw-r--r-- | slicer/db/sqlTablePatchSerializer.h | 25 | ||||
-rw-r--r-- | slicer/db/testPatch.cpp | 47 |
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); +} + |