From c4918dc201048c558823e6f47d9fa7191249ce64 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 18 Jul 2017 20:46:19 +0100 Subject: Add SQL table patch serializer --- slicer/db/Jamfile.jam | 16 +++++++++ slicer/db/sqlTablePatchSerializer.cpp | 64 +++++++++++++++++++++++++++++++++++ slicer/db/sqlTablePatchSerializer.h | 25 ++++++++++++++ slicer/db/testPatch.cpp | 47 +++++++++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 slicer/db/sqlTablePatchSerializer.cpp create mode 100644 slicer/db/sqlTablePatchSerializer.h create mode 100644 slicer/db/testPatch.cpp 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 + : : : + BOOST_TEST_DYN_LINK + slicer-db + dbpp-postgresql + boost_system + boost_filesystem + boost_utf + ../test//types + ../test//common + ../slicer//slicer + ../slicer//slicer + .. + slicer.sql + ; + run testUpdate.cpp : : : 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 +#include +#include + +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 +#include + +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 +#include +#include +#include +#include +#include "sqlTablePatchSerializer.h" +#include "sqlSelectDeserializer.h" +#include +#include +#include + +// 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 DBPtr; +typedef boost::shared_ptr 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(bis, db.get(), tp); + auto cmd = db->select("SELECT COUNT(*) FROM builtins"); + auto c = Slicer::DeserializeAny(*cmd); + BOOST_REQUIRE_EQUAL(2, c); +} + -- cgit v1.2.3