diff --git a/inc/vcf/error-odb.hpp b/inc/vcf/error-odb.hpp index 2773bc32b..0aed96698 100644 --- a/inc/vcf/error-odb.hpp +++ b/inc/vcf/error-odb.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -987,6 +988,48 @@ namespace odb static void callback (database&, const object_type&, callback_event); }; + + // ToolVersion + // + template <> + struct class_traits< ::ebi::vcf::ToolVersion > + { + static const class_kind kind = class_object; + }; + + template <> + class access::object_traits< ::ebi::vcf::ToolVersion > + { + public: + typedef ::ebi::vcf::ToolVersion object_type; + typedef ::ebi::vcf::ToolVersion* pointer_type; + typedef odb::pointer_traits pointer_traits; + + static const bool polymorphic = false; + + typedef long unsigned int id_type; + + static const bool auto_id = true; + + static const bool abstract = false; + + static id_type + id (const object_type&); + + typedef + no_op_pointer_cache_traits + pointer_cache_traits; + + typedef + no_op_reference_cache_traits + reference_cache_traits; + + static void + callback (database&, object_type&, callback_event); + + static void + callback (database&, const object_type&, callback_event); + }; } #include @@ -4810,6 +4853,180 @@ namespace odb { }; + // ToolVersion + // + template + struct query_columns< ::ebi::vcf::ToolVersion, id_sqlite, A > + { + // tool_version + // + typedef + sqlite::query_column< + sqlite::value_traits< + ::std::string, + sqlite::id_text >::query_type, + sqlite::id_text > + tool_version_type_; + + static const tool_version_type_ tool_version; + + // id + // + typedef + sqlite::query_column< + sqlite::value_traits< + long unsigned int, + sqlite::id_integer >::query_type, + sqlite::id_integer > + id_type_; + + static const id_type_ id; + }; + + template + const typename query_columns< ::ebi::vcf::ToolVersion, id_sqlite, A >::tool_version_type_ + query_columns< ::ebi::vcf::ToolVersion, id_sqlite, A >:: + tool_version (A::table_name, "\"tool_version\"", 0); + + template + const typename query_columns< ::ebi::vcf::ToolVersion, id_sqlite, A >::id_type_ + query_columns< ::ebi::vcf::ToolVersion, id_sqlite, A >:: + id (A::table_name, "\"id\"", 0); + + template + struct pointer_query_columns< ::ebi::vcf::ToolVersion, id_sqlite, A >: + query_columns< ::ebi::vcf::ToolVersion, id_sqlite, A > + { + }; + + template <> + class access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >: + public access::object_traits< ::ebi::vcf::ToolVersion > + { + public: + struct id_image_type + { + long long id_value; + bool id_null; + + std::size_t version; + }; + + struct image_type + { + // tool_version + // + details::buffer tool_version_value; + std::size_t tool_version_size; + bool tool_version_null; + + // id_ + // + long long id_value; + bool id_null; + + std::size_t version; + }; + + struct extra_statement_cache_type; + + using object_traits::id; + + static id_type + id (const id_image_type&); + + static id_type + id (const image_type&); + + static bool + grow (image_type&, + bool*); + + static void + bind (sqlite::bind*, + image_type&, + sqlite::statement_kind); + + static void + bind (sqlite::bind*, id_image_type&); + + static bool + init (image_type&, + const object_type&, + sqlite::statement_kind); + + static void + init (object_type&, + const image_type&, + database*); + + static void + init (id_image_type&, const id_type&); + + typedef sqlite::object_statements statements_type; + + typedef sqlite::query_base query_base_type; + + static const std::size_t column_count = 2UL; + static const std::size_t id_column_count = 1UL; + static const std::size_t inverse_column_count = 0UL; + static const std::size_t readonly_column_count = 1UL; + static const std::size_t managed_optimistic_column_count = 0UL; + + static const std::size_t separate_load_column_count = 0UL; + static const std::size_t separate_update_column_count = 0UL; + + static const bool versioned = false; + + static const char persist_statement[]; + static const char find_statement[]; + static const char erase_statement[]; + static const char query_statement[]; + static const char erase_query_statement[]; + + static const char table_name[]; + + static void + persist (database&, object_type&); + + static bool + find (database&, const id_type&, object_type&); + + static bool + reload (database&, object_type&); + + static void + update (database&, const object_type&); + + static void + erase (database&, const id_type&); + + static void + erase (database&, const object_type&); + + static result + query (database&, const query_base_type&); + + static unsigned long long + erase_query (database&, const query_base_type&); + + public: + static bool + find_ (statements_type&, + const id_type*); + + static void + load_ (statements_type&, + object_type&, + bool reload); + }; + + template <> + class access::object_traits_impl< ::ebi::vcf::ToolVersion, id_common >: + public access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite > + { + }; + // Error // // ErrorCount @@ -4858,6 +5075,8 @@ namespace odb // // DuplicationError // + // ToolVersion + // } #include "vcf/error-odb.ipp" diff --git a/inc/vcf/error-odb.ipp b/inc/vcf/error-odb.ipp index 4517897dc..c4e0f347d 100644 --- a/inc/vcf/error-odb.ipp +++ b/inc/vcf/error-odb.ipp @@ -566,6 +566,35 @@ namespace odb ODB_POTENTIALLY_UNUSED (x); ODB_POTENTIALLY_UNUSED (e); } + + // ToolVersion + // + + inline + access::object_traits< ::ebi::vcf::ToolVersion >::id_type + access::object_traits< ::ebi::vcf::ToolVersion >:: + id (const object_type& o) + { + return o.id_; + } + + inline + void access::object_traits< ::ebi::vcf::ToolVersion >:: + callback (database& db, object_type& x, callback_event e) + { + ODB_POTENTIALLY_UNUSED (db); + ODB_POTENTIALLY_UNUSED (x); + ODB_POTENTIALLY_UNUSED (e); + } + + inline + void access::object_traits< ::ebi::vcf::ToolVersion >:: + callback (database& db, const object_type& x, callback_event e) + { + ODB_POTENTIALLY_UNUSED (db); + ODB_POTENTIALLY_UNUSED (x); + ODB_POTENTIALLY_UNUSED (e); + } } #include @@ -1277,5 +1306,27 @@ namespace odb b[1UL].version++; b[2UL].version++; } + + // ToolVersion + // + + inline + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + erase (database& db, const object_type& obj) + { + callback (db, obj, callback_event::pre_erase); + erase (db, id (obj)); + callback (db, obj, callback_event::post_erase); + } + + inline + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + load_ (statements_type& sts, + object_type& obj, + bool) + { + ODB_POTENTIALLY_UNUSED (sts); + ODB_POTENTIALLY_UNUSED (obj); + } } diff --git a/inc/vcf/error.hpp b/inc/vcf/error.hpp index 1fa501434..a7b18594a 100644 --- a/inc/vcf/error.hpp +++ b/inc/vcf/error.hpp @@ -52,6 +52,8 @@ namespace ebi struct NormalizationError; struct DuplicationError; + struct ToolVersion; + /** * * This function allows throwing Error with some polymorphism, without using raw pointers. @@ -365,6 +367,23 @@ namespace ebi virtual ~DuplicationError() override { } virtual void apply_visitor(ErrorVisitor &visitor) override { visitor.visit(*this); } }; + + /** + * class for writing the tool version to db. + */ + #pragma db object + struct ToolVersion + { + ToolVersion(const std::string &tool_version) : tool_version{tool_version} {} + const std::string tool_version; + std::string get_tool_version() const { return tool_version; } + + private: + friend class odb::access; + + #pragma db id auto + unsigned long id_; + }; } } diff --git a/inc/vcf/odb_report.hpp b/inc/vcf/odb_report.hpp index 1001f449e..f3ca7ba63 100644 --- a/inc/vcf/odb_report.hpp +++ b/inc/vcf/odb_report.hpp @@ -37,14 +37,15 @@ namespace ebi { public: - OdbReportRW(const std::string &db_name); + OdbReportRW(const std::string &db_name, const std::string tool_version); virtual ~OdbReportRW(); void flush(); // before reading, make sure you destroy or flush the writer OdbReportRW // ReportWriter implementation virtual void write_error(Error &error) override; virtual void write_warning(Error &error) override; - virtual void write_message(const std::string &report_result) override; + virtual void write_message(const std::string &message) override; + virtual void write_version(ToolVersion tool_version) override; // ReportReader implementation virtual size_t count_warnings() override; @@ -52,10 +53,11 @@ namespace ebi virtual size_t count_errors() override; virtual void for_each_error(std::function)> user_function) override; - virtual std::string get_report_message() override; + virtual std::string get_filename() override; private: std::string db_name; + ToolVersion tool_version; std::unique_ptr db; odb::core::transaction transaction; size_t current_transaction_size; diff --git a/inc/vcf/report_writer.hpp b/inc/vcf/report_writer.hpp index ca548d490..a8fc9ac4a 100644 --- a/inc/vcf/report_writer.hpp +++ b/inc/vcf/report_writer.hpp @@ -33,9 +33,10 @@ namespace ebi virtual ~ReportWriter() {} // needed if using raw pointers, instead of references or shared_ptrs in children virtual void write_error(Error &error) = 0; virtual void write_warning(Error &error) = 0; - virtual void write_message(const std::string &report_result) = 0; + virtual void write_message(const std::string &message) = 0; + virtual void write_version(ToolVersion tool_version) = 0; - virtual std::string get_report_message() = 0; + virtual std::string get_filename() = 0; }; class FileReportWriter : public ReportWriter @@ -61,14 +62,19 @@ namespace ebi file << error.what() << " (warning)" << std::endl; } - virtual void write_message(const std::string &report_result) override + virtual void write_message(const std::string &message) override { - file << report_result << std::endl; + file << message << std::endl; } - virtual std::string get_report_message() override + virtual void write_version(ToolVersion tool_version) override { - return "Text report written to : " + file_name; + file << tool_version.get_tool_version() << std::endl; + } + + virtual std::string get_filename() override + { + return file_name; } private: diff --git a/inc/vcf/summary_report_writer.hpp b/inc/vcf/summary_report_writer.hpp index 1b0c438a2..327c0dae0 100644 --- a/inc/vcf/summary_report_writer.hpp +++ b/inc/vcf/summary_report_writer.hpp @@ -88,26 +88,28 @@ namespace ebi summary.add_to_summary("Warning: " + error.message, error.line); } - virtual void write_message(const std::string &report_result) override + virtual void write_message(const std::string &message) override { - this->report_result = report_result; + file << message << std::endl; } - virtual std::string get_report_message() override + virtual void write_version(ToolVersion tool_version) override { - return "Summary report written to : " + file_name; + file << tool_version.get_tool_version() << std::endl; + } + + virtual std::string get_filename() override + { + return file_name; } private: SummaryTracker summary; - std::string report_result; std::string file_name; std::ofstream file; void write_summary() { - file << report_result << std::endl; - for (auto & error_message : summary.error_order) { file << error_message << ". This occurs " << summary.error_summary_report[error_message].occurrences << " time(s), first time in line " << summary.error_summary_report[error_message].first_occurrence_line << "." << std::endl; diff --git a/src/debugulator_main.cpp b/src/debugulator_main.cpp index 911a9bbd5..81378d5bc 100644 --- a/src/debugulator_main.cpp +++ b/src/debugulator_main.cpp @@ -124,7 +124,7 @@ int main(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << "Writing to standard output..."; } - ebi::vcf::OdbReportRW errorDAO{errors}; + ebi::vcf::OdbReportRW errorDAO{errors, version_info}; auto &input_stream = input_path == ebi::vcf::STDIN ? std::cin : input_file; auto &output_stream = output_path == ebi::vcf::STDOUT ? std::cout : output_file; diff --git a/src/validator_main.cpp b/src/validator_main.cpp index 73cb8b298..033f2c4a4 100644 --- a/src/validator_main.cpp +++ b/src/validator_main.cpp @@ -135,7 +135,7 @@ namespace throw std::runtime_error{"Report file already exists on " + filename + ", please delete it or rename it"}; } if (out == ebi::vcf::DATABASE) { - outputs.emplace_back(new ebi::vcf::OdbReportRW(filename)); + outputs.emplace_back(new ebi::vcf::OdbReportRW(filename, version_info)); } else if (out == ebi::vcf::TEXT) { outputs.emplace_back(new ebi::vcf::FileReportWriter(filename)); } else { @@ -173,6 +173,10 @@ int main(int argc, char** argv) auto outdir = get_output_path(vm[ebi::vcf::OUTDIR].as(), path); auto outputs = get_outputs(vm[ebi::vcf::REPORT].as(), outdir); + for (auto & output : outputs) { + output->write_version(ebi::vcf::ToolVersion{version_info}); + } + if (path == ebi::vcf::STDIN) { BOOST_LOG_TRIVIAL(info) << "Reading from standard input..."; is_valid = ebi::vcf::is_valid_vcf_file(std::cin, path, validationLevel, outputs); @@ -188,7 +192,7 @@ int main(int argc, char** argv) std::string report_result = "According to the VCF specification, the input file is " + std::string(is_valid ? "" : "not ") + "valid"; for (auto & output : outputs) { - BOOST_LOG_TRIVIAL(info) << output->get_report_message(); + BOOST_LOG_TRIVIAL(info) << "Report written to : " << output->get_filename(); output->write_message(report_result); } BOOST_LOG_TRIVIAL(info) << report_result; @@ -198,7 +202,7 @@ int main(int argc, char** argv) BOOST_LOG_TRIVIAL(error) << ex.what(); return 1; } catch (std::runtime_error const & ex) { - BOOST_LOG_TRIVIAL(error) << "The validation could not be completed: " << ex.what(); + BOOST_LOG_TRIVIAL(error) << "The input file is not valid: " << ex.what(); return 1; } catch (std::exception const &ex) { BOOST_LOG_TRIVIAL(error) << ex.what(); diff --git a/src/vcf/error-odb.cpp b/src/vcf/error-odb.cpp index c9f1cd95b..3746dce85 100644 --- a/src/vcf/error-odb.cpp +++ b/src/vcf/error-odb.cpp @@ -19,10 +19,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -14298,6 +14300,554 @@ namespace odb return st.execute (); } + + // ToolVersion + // + + struct access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::extra_statement_cache_type + { + extra_statement_cache_type ( + sqlite::connection&, + image_type&, + id_image_type&, + sqlite::binding&, + sqlite::binding&) + { + } + }; + + access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::id_type + access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + id (const id_image_type& i) + { + sqlite::database* db (0); + ODB_POTENTIALLY_UNUSED (db); + + id_type id; + { + sqlite::value_traits< + long unsigned int, + sqlite::id_integer >::set_value ( + id, + i.id_value, + i.id_null); + } + + return id; + } + + access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::id_type + access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + id (const image_type& i) + { + sqlite::database* db (0); + ODB_POTENTIALLY_UNUSED (db); + + id_type id; + { + sqlite::value_traits< + long unsigned int, + sqlite::id_integer >::set_value ( + id, + i.id_value, + i.id_null); + } + + return id; + } + + bool access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + grow (image_type& i, + bool* t) + { + ODB_POTENTIALLY_UNUSED (i); + ODB_POTENTIALLY_UNUSED (t); + + bool grew (false); + + // tool_version + // + if (t[0UL]) + { + i.tool_version_value.capacity (i.tool_version_size); + grew = true; + } + + // id_ + // + t[1UL] = false; + + return grew; + } + + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + bind (sqlite::bind* b, + image_type& i, + sqlite::statement_kind sk) + { + ODB_POTENTIALLY_UNUSED (sk); + + using namespace sqlite; + + std::size_t n (0); + + // tool_version + // + if (sk != statement_update) + { + b[n].type = sqlite::image_traits< + ::std::string, + sqlite::id_text>::bind_value; + b[n].buffer = i.tool_version_value.data (); + b[n].size = &i.tool_version_size; + b[n].capacity = i.tool_version_value.capacity (); + b[n].is_null = &i.tool_version_null; + n++; + } + + // id_ + // + if (sk != statement_update) + { + b[n].type = sqlite::bind::integer; + b[n].buffer = &i.id_value; + b[n].is_null = &i.id_null; + n++; + } + } + + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + bind (sqlite::bind* b, id_image_type& i) + { + std::size_t n (0); + b[n].type = sqlite::bind::integer; + b[n].buffer = &i.id_value; + b[n].is_null = &i.id_null; + } + + bool access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + init (image_type& i, + const object_type& o, + sqlite::statement_kind sk) + { + ODB_POTENTIALLY_UNUSED (i); + ODB_POTENTIALLY_UNUSED (o); + ODB_POTENTIALLY_UNUSED (sk); + + using namespace sqlite; + + bool grew (false); + + // tool_version + // + if (sk == statement_insert) + { + ::std::string const& v = + o.tool_version; + + bool is_null (false); + std::size_t cap (i.tool_version_value.capacity ()); + sqlite::value_traits< + ::std::string, + sqlite::id_text >::set_image ( + i.tool_version_value, + i.tool_version_size, + is_null, + v); + i.tool_version_null = is_null; + grew = grew || (cap != i.tool_version_value.capacity ()); + } + + // id_ + // + if (sk == statement_insert) + { + long unsigned int const& v = + o.id_; + + bool is_null (false); + sqlite::value_traits< + long unsigned int, + sqlite::id_integer >::set_image ( + i.id_value, + is_null, + v); + i.id_null = is_null; + } + + return grew; + } + + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + init (object_type& o, + const image_type& i, + database* db) + { + ODB_POTENTIALLY_UNUSED (o); + ODB_POTENTIALLY_UNUSED (i); + ODB_POTENTIALLY_UNUSED (db); + + // tool_version + // + { + ::std::string& v = + const_cast< ::std::string& > ( + o.tool_version); + + sqlite::value_traits< + ::std::string, + sqlite::id_text >::set_value ( + v, + i.tool_version_value, + i.tool_version_size, + i.tool_version_null); + } + + // id_ + // + { + long unsigned int& v = + o.id_; + + sqlite::value_traits< + long unsigned int, + sqlite::id_integer >::set_value ( + v, + i.id_value, + i.id_null); + } + } + + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + init (id_image_type& i, const id_type& id) + { + { + bool is_null (false); + sqlite::value_traits< + long unsigned int, + sqlite::id_integer >::set_image ( + i.id_value, + is_null, + id); + i.id_null = is_null; + } + } + + const char access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::persist_statement[] = + "INSERT INTO \"ToolVersion\" " + "(\"tool_version\", " + "\"id\") " + "VALUES " + "(?, ?)"; + + const char access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::find_statement[] = + "SELECT " + "\"ToolVersion\".\"tool_version\", " + "\"ToolVersion\".\"id\" " + "FROM \"ToolVersion\" " + "WHERE \"ToolVersion\".\"id\"=?"; + + const char access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::erase_statement[] = + "DELETE FROM \"ToolVersion\" " + "WHERE \"id\"=?"; + + const char access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::query_statement[] = + "SELECT " + "\"ToolVersion\".\"tool_version\", " + "\"ToolVersion\".\"id\" " + "FROM \"ToolVersion\""; + + const char access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::erase_query_statement[] = + "DELETE FROM \"ToolVersion\""; + + const char access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::table_name[] = + "\"ToolVersion\""; + + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + persist (database& db, object_type& obj) + { + ODB_POTENTIALLY_UNUSED (db); + + using namespace sqlite; + + sqlite::connection& conn ( + sqlite::transaction::current ().connection ()); + statements_type& sts ( + conn.statement_cache ().find_object ()); + + callback (db, + static_cast (obj), + callback_event::pre_persist); + + image_type& im (sts.image ()); + binding& imb (sts.insert_image_binding ()); + + if (init (im, obj, statement_insert)) + im.version++; + + im.id_null = true; + + if (im.version != sts.insert_image_version () || + imb.version == 0) + { + bind (imb.bind, im, statement_insert); + sts.insert_image_version (im.version); + imb.version++; + } + + { + id_image_type& i (sts.id_image ()); + binding& b (sts.id_image_binding ()); + if (i.version != sts.id_image_version () || b.version == 0) + { + bind (b.bind, i); + sts.id_image_version (i.version); + b.version++; + } + } + + insert_statement& st (sts.persist_statement ()); + if (!st.execute ()) + throw object_already_persistent (); + + obj.id_ = id (sts.id_image ()); + + callback (db, + static_cast (obj), + callback_event::post_persist); + } + + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + update (database& db, const object_type& obj) + { + ODB_POTENTIALLY_UNUSED (db); + + using namespace sqlite; + using sqlite::update_statement; + + callback (db, obj, callback_event::pre_update); + + callback (db, obj, callback_event::post_update); + pointer_cache_traits::update (db, obj); + } + + void access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + erase (database& db, const id_type& id) + { + using namespace sqlite; + + ODB_POTENTIALLY_UNUSED (db); + + sqlite::connection& conn ( + sqlite::transaction::current ().connection ()); + statements_type& sts ( + conn.statement_cache ().find_object ()); + + id_image_type& i (sts.id_image ()); + init (i, id); + + binding& idb (sts.id_image_binding ()); + if (i.version != sts.id_image_version () || idb.version == 0) + { + bind (idb.bind, i); + sts.id_image_version (i.version); + idb.version++; + } + + if (sts.erase_statement ().execute () != 1) + throw object_not_persistent (); + + pointer_cache_traits::erase (db, id); + } + + bool access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + find (database& db, const id_type& id, object_type& obj) + { + using namespace sqlite; + + sqlite::connection& conn ( + sqlite::transaction::current ().connection ()); + statements_type& sts ( + conn.statement_cache ().find_object ()); + + statements_type::auto_lock l (sts); + + if (!find_ (sts, &id)) + return false; + + select_statement& st (sts.find_statement ()); + ODB_POTENTIALLY_UNUSED (st); + + reference_cache_traits::position_type pos ( + reference_cache_traits::insert (db, id, obj)); + reference_cache_traits::insert_guard ig (pos); + + callback (db, obj, callback_event::pre_load); + init (obj, sts.image (), &db); + load_ (sts, obj, false); + sts.load_delayed (0); + l.unlock (); + callback (db, obj, callback_event::post_load); + reference_cache_traits::load (pos); + ig.release (); + return true; + } + + bool access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + reload (database& db, object_type& obj) + { + using namespace sqlite; + + sqlite::connection& conn ( + sqlite::transaction::current ().connection ()); + statements_type& sts ( + conn.statement_cache ().find_object ()); + + statements_type::auto_lock l (sts); + + const id_type& id ( + obj.id_); + + if (!find_ (sts, &id)) + return false; + + select_statement& st (sts.find_statement ()); + ODB_POTENTIALLY_UNUSED (st); + + callback (db, obj, callback_event::pre_load); + init (obj, sts.image (), &db); + load_ (sts, obj, true); + sts.load_delayed (0); + l.unlock (); + callback (db, obj, callback_event::post_load); + return true; + } + + bool access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + find_ (statements_type& sts, + const id_type* id) + { + using namespace sqlite; + + id_image_type& i (sts.id_image ()); + init (i, *id); + + binding& idb (sts.id_image_binding ()); + if (i.version != sts.id_image_version () || idb.version == 0) + { + bind (idb.bind, i); + sts.id_image_version (i.version); + idb.version++; + } + + image_type& im (sts.image ()); + binding& imb (sts.select_image_binding ()); + + if (im.version != sts.select_image_version () || + imb.version == 0) + { + bind (imb.bind, im, statement_select); + sts.select_image_version (im.version); + imb.version++; + } + + select_statement& st (sts.find_statement ()); + + st.execute (); + auto_result ar (st); + select_statement::result r (st.fetch ()); + + if (r == select_statement::truncated) + { + if (grow (im, sts.select_image_truncated ())) + im.version++; + + if (im.version != sts.select_image_version ()) + { + bind (imb.bind, im, statement_select); + sts.select_image_version (im.version); + imb.version++; + st.refetch (); + } + } + + return r != select_statement::no_data; + } + + result< access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >::object_type > + access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + query (database&, const query_base_type& q) + { + using namespace sqlite; + using odb::details::shared; + using odb::details::shared_ptr; + + sqlite::connection& conn ( + sqlite::transaction::current ().connection ()); + + statements_type& sts ( + conn.statement_cache ().find_object ()); + + image_type& im (sts.image ()); + binding& imb (sts.select_image_binding ()); + + if (im.version != sts.select_image_version () || + imb.version == 0) + { + bind (imb.bind, im, statement_select); + sts.select_image_version (im.version); + imb.version++; + } + + std::string text (query_statement); + if (!q.empty ()) + { + text += " "; + text += q.clause (); + } + + q.init_parameters (); + shared_ptr st ( + new (shared) select_statement ( + conn, + text, + false, + true, + q.parameters_binding (), + imb)); + + st->execute (); + + shared_ptr< odb::object_result_impl > r ( + new (shared) sqlite::object_result_impl ( + q, st, sts, 0)); + + return result (r); + } + + unsigned long long access::object_traits_impl< ::ebi::vcf::ToolVersion, id_sqlite >:: + erase_query (database&, const query_base_type& q) + { + using namespace sqlite; + + sqlite::connection& conn ( + sqlite::transaction::current ().connection ()); + + std::string text (erase_query_statement); + if (!q.empty ()) + { + text += ' '; + text += q.clause (); + } + + q.init_parameters (); + delete_statement st ( + conn, + text, + q.parameters_binding ()); + + return st.execute (); + } } namespace odb @@ -14319,6 +14869,7 @@ namespace odb } case 2: { + db.execute ("DROP TABLE IF EXISTS \"ToolVersion\""); db.execute ("DROP TABLE IF EXISTS \"DuplicationError\""); db.execute ("DROP TABLE IF EXISTS \"NormalizationError\""); db.execute ("DROP TABLE IF EXISTS \"SamplesFieldBodyError\""); @@ -14475,6 +15026,9 @@ namespace odb " FOREIGN KEY (\"id\")\n" " REFERENCES \"BodySectionError\" (\"id\")\n" " ON DELETE CASCADE)"); + db.execute ("CREATE TABLE \"ToolVersion\" (\n" + " \"tool_version\" TEXT NOT NULL,\n" + " \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT)"); return false; } } diff --git a/src/vcf/odb_report.cpp b/src/vcf/odb_report.cpp index 3191a9111..8db9590a4 100644 --- a/src/vcf/odb_report.cpp +++ b/src/vcf/odb_report.cpp @@ -21,8 +21,8 @@ namespace ebi { namespace vcf { - OdbReportRW::OdbReportRW(const std::string &db_name) : db_name(db_name), current_transaction_size{0}, - transaction_size{1000000} + OdbReportRW::OdbReportRW(const std::string &db_name, const std::string tool_version) : db_name(db_name), tool_version{tool_version}, + current_transaction_size{0}, transaction_size{1000000} { try { boost::filesystem::path db_file{db_name}; @@ -49,6 +49,11 @@ namespace ebi odb::core::schema_catalog::create_schema(*db); t.commit(); + // use class object for writing tool version to db + write_version(tool_version); + + + c->execute("PRAGMA foreign_keys=ON"); } } @@ -86,12 +91,18 @@ namespace ebi error.severity = Severity::ERROR; write(error); } + void OdbReportRW::write_version(ToolVersion tool_version) + { + transaction.reset(db->begin()); + db->persist(tool_version); + ++current_transaction_size; + } void OdbReportRW::write_warning(Error &error) { error.severity = Severity::WARNING; write(error); } - void OdbReportRW::write_message(const std::string &report_result) + void OdbReportRW::write_message(const std::string &message) { // do nothing } @@ -164,9 +175,9 @@ namespace ebi } } - std::string OdbReportRW::get_report_message() + std::string OdbReportRW::get_filename() { - return "Database report written to : " + db_name; + return db_name; } } } diff --git a/test/vcf/debugulator_integration_test.cpp b/test/vcf/debugulator_integration_test.cpp index 3e736e120..c8c5d1ccf 100644 --- a/test/vcf/debugulator_integration_test.cpp +++ b/test/vcf/debugulator_integration_test.cpp @@ -18,6 +18,7 @@ #include "catch/catch.hpp" +#include "cmake_config.hpp" #include "vcf/validator.hpp" #include "vcf/odb_report.hpp" #include "vcf/debugulator.hpp" @@ -27,6 +28,8 @@ namespace ebi { static const std::string BEFORE_TAG = "before"; static const std::string AFTER_TAG = "after"; + const std::string version_info = "vcf-debugulator version " + std::to_string(VERSION_MAJOR) + "." + + std::to_string(VERSION_MINOR); bool validate(std::istream &file, const boost::filesystem::path &path, std::string report_tag) { @@ -34,7 +37,7 @@ namespace ebi db_path += ".debugulator_test." + report_tag + ".db"; boost::filesystem::remove(db_path); // make sure the db doesn't exist from previous runs - auto report = new ebi::vcf::OdbReportRW{db_path.string()}; + auto report = new ebi::vcf::OdbReportRW{db_path.string(), version_info}; std::vector> reports; reports.emplace_back(report); @@ -48,7 +51,7 @@ namespace ebi // report: SqliteReportRW to read the errors. the DB must be flushed before this auto db_path = boost::filesystem::path{"/tmp/"} / path.filename(); db_path += ".debugulator_test." + report_tag + ".db"; - ebi::vcf::OdbReportRW report{db_path.string()}; + ebi::vcf::OdbReportRW report{db_path.string(), version_info}; std::unique_ptr fixed_vcf{new std::stringstream{}}; // writing result vcf to a stringstream in memory diff --git a/test/vcf/debugulator_test.cpp b/test/vcf/debugulator_test.cpp index 84ea4b00e..da955b834 100644 --- a/test/vcf/debugulator_test.cpp +++ b/test/vcf/debugulator_test.cpp @@ -19,12 +19,16 @@ #include "catch/catch.hpp" +#include "cmake_config.hpp" #include "vcf/odb_report.hpp" #include "vcf/debugulator.hpp" #include "vcf/string_constants.hpp" namespace ebi { + const std::string version_info = "vcf-debugulator version " + std::to_string(VERSION_MAJOR) + "." + + std::to_string(VERSION_MINOR); + TEST_CASE("Fixing errors", "[debugulator]") { SECTION("Fix meta definition Type for predefined tags") @@ -509,7 +513,7 @@ namespace ebi std::stringstream ss; SECTION(path.string()) { - vcf::OdbReportRW report{path.string()}; + vcf::OdbReportRW report{path.string(), version_info}; size_t fixed_errors = vcf::debugulator::fix_vcf_file(file, report, ss); CHECK(fixed_errors == 0); } diff --git a/test/vcf/report_writer_test.cpp b/test/vcf/report_writer_test.cpp index cad0394dc..423358e16 100644 --- a/test/vcf/report_writer_test.cpp +++ b/test/vcf/report_writer_test.cpp @@ -22,6 +22,7 @@ #include "catch/catch.hpp" +#include "cmake_config.hpp" #include "vcf/odb_report.hpp" #include "vcf/file_structure.hpp" #include "vcf/validator.hpp" @@ -32,6 +33,9 @@ namespace ebi { + const std::string version_info = "vcf_validator version " + std::to_string(VERSION_MAJOR) + "." + + std::to_string(VERSION_MINOR); + bool is_valid(std::string path, std::unique_ptr output) { std::ifstream input{path}; @@ -48,7 +52,7 @@ namespace ebi { std::string db_name = "test/input_files/sqlite_test.errors.odb.db"; - ebi::vcf::OdbReportRW errorDAO{db_name}; + ebi::vcf::OdbReportRW errorDAO{db_name, version_info}; SECTION("Write and count errors") { ebi::vcf::Error test_error{1, "testing errors"}; @@ -144,7 +148,7 @@ namespace ebi std::string db_name = path.string() + ".errors.db"; { - std::unique_ptr output{new ebi::vcf::OdbReportRW{db_name}}; + std::unique_ptr output{new ebi::vcf::OdbReportRW{db_name, version_info}}; CHECK_FALSE(is_valid(path.string(), std::move(output))); } @@ -154,7 +158,7 @@ namespace ebi size_t count_warnings; { - ebi::vcf::OdbReportRW errorsDAO{db_name}; + ebi::vcf::OdbReportRW errorsDAO{db_name, version_info}; count_errors = errorsDAO.count_errors(); count_warnings = errorsDAO.count_warnings(); } @@ -166,7 +170,7 @@ namespace ebi SECTION(path.string() + " error details") { size_t errors_read = 0; - ebi::vcf::OdbReportRW errorsDAO{db_name}; + ebi::vcf::OdbReportRW errorsDAO{db_name, version_info}; errorsDAO.for_each_error([&errors_read](std::shared_ptr error) { CHECK(error->line == 4); @@ -225,7 +229,7 @@ namespace ebi input.close(); } - CHECK(count_lines(summary_path.string()) == 3); + CHECK(count_lines(summary_path.string()) == 2); } boost::filesystem::remove(summary_path);