From 43fa55c1b8e389838c83be933bb30a2caaf7468d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 5 Feb 2013 15:50:08 +0200 Subject: Add support for change-tracking containers ODB now supports "smart" ordered containers. Such containers get extra functions for updating and deleting individual elements. Based on this functionality implement two change-tracking containers: odb::vector (equivalent to std::vector) and QOdbList (equivalent to QList). New tests: common/container/change-tracking and qt/common/container/change- tracking. --- qt/common/containers/change-tracking/driver.cxx | 632 ++++++++++++++++++++++++ 1 file changed, 632 insertions(+) create mode 100644 qt/common/containers/change-tracking/driver.cxx (limited to 'qt/common/containers/change-tracking/driver.cxx') diff --git a/qt/common/containers/change-tracking/driver.cxx b/qt/common/containers/change-tracking/driver.cxx new file mode 100644 index 0000000..15dd825 --- /dev/null +++ b/qt/common/containers/change-tracking/driver.cxx @@ -0,0 +1,632 @@ +// file : qt/common/containers/change-tracking/driver.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +// Test change-tracking Qt containers. +// + +#include // HAVE_CXX11 + +#include // std::auto_ptr +#include +#include + +#ifdef HAVE_CXX11 +# include // std::move +#endif + +#include // QT_VERSION, Q_FOREACH +#include + +#include +#include +#include + +#include +#include + +#include + +#include "test.hxx" +#include "test-odb.hxx" + +using namespace std; +using namespace odb::core; + +struct counting_tracer: odb::tracer +{ + void + reset (transaction& tr) {u = i = d = s = t = 0; tr.tracer (*this);} + + virtual void + execute (odb::connection&, const char* stmt) + { + string p (stmt, 6); + if (p == "UPDATE") + u++; + else if (p == "INSERT") + i++; + else if (p == "DELETE") + d++; + else if (p == "SELECT") + s++; + t++; + } + + size_t u, i, d, s, t; +}; + +static counting_tracer tr; + +// Compilation test: instantiate all the functions. Only do this if we +// have a fairly recent version of Qt, otherwise some underlying +// functions will be missing. +// +#if QT_VERSION >= 0x050000 +template class QOdbList; +template class QOdbListIteratorImpl >; +template class QOdbListIterator; +template class QMutableOdbListIterator; +#endif + +void +f (const QList&) {} + +int +main (int argc, char* argv[]) +{ + QCoreApplication app (argc, argv); + + try + { + // Test extended interface. + // + { + typedef QOdbList list; + + list ol; + QList ql; + f (ol); // Implicit conversion to QList. + list ol1 (ql); // Initialization from QList. + ol = ql; // Assignement from QList. + + // Container comparison. + // + if (ol != ol1 || + ol != ql || + ql != ol1) + ol.clear (); + + // Container operators. + // + ol += ol1; + ol += ql; + ol = ol1 + ql; + ol = ql + ol1; + + // Iterator comparison/conversion. + // +#ifndef QT_STRICT_ITERATORS + list::const_iterator i (ol.begin ()); + if (i != ol.end ()) + i = ol.end (); +#endif + + Q_FOREACH (const int& i, ol) + cerr << i; + } + + auto_ptr db (create_database (argc, argv)); + + // Test traits logic. + // + { + object o ("1"); + o.i = 123; + o.s.push_back ("a"); + + assert (!o.s._tracking ()); + + // persist + // + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + assert (o.s._tracking ()); + + // load + // + { + transaction t (db->begin ()); + auto_ptr p (db->load ("1")); + assert (p->s._tracking ()); + t.commit (); + } + + // update + // + { + transaction t (db->begin ()); + db->update (o); + t.commit (); + } + + assert (o.s._tracking ()); + + // erase + // + { + transaction t (db->begin ()); + db->erase (o); + t.commit (); + } + + assert (!o.s._tracking ()); + } + + // Test change tracking. + // + object o ("1"); + o.i = 123; + o.s.push_back ("a"); + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + // push_back/pop_back + // + { + o.s.push_back ("b"); // insert + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.i == 1 && tr.t == 2); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.pop_back (); + o.s.push_back ("c"); // update + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 2 && tr.t == 2); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.pop_back (); // delete + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.d == 1 && tr.t == 2); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.push_back ("b"); + o.s.pop_back (); // no-op + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.t == 1); + assert (*db->load ("1") == o); + t.commit (); + } + + // insert + // + { + o.s.clear (); + o.s.push_back ("a"); + o.s.push_back ("b"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.insert (o.s.begin (), "a1"); // insert front + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 3 && tr.i == 1 && tr.t == 4); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.insert (o.s.begin () + 1, "a2"); // insert middle + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 3 && tr.i == 1 && tr.t == 4); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.insert (o.s.end (), "b1"); // insert back + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.i == 1 && tr.t == 2); + assert (*db->load ("1") == o); + t.commit (); + } + + // erase + // + { + o.s.clear (); + o.s.push_back ("a"); + o.s.push_back ("b"); + o.s.push_back ("c"); + o.s.push_back ("d"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.erase (o.s.begin ()); // erase front + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 4 && tr.d == 1 && tr.t == 5); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.erase (o.s.begin () + 1); // erase middle + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 2 && tr.d == 1 && tr.t == 3); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.erase (o.s.end () - 1); // erase back + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.d == 1 && tr.t == 2); + assert (*db->load ("1") == o); + t.commit (); + } + + // modify + // + { + o.s.clear (); + o.s.push_back ("a"); + o.s.push_back ("b"); + o.s.push_back ("c"); + o.s.push_back ("d"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.modify (1) += 'b'; + o.s.modify_back () += 'd'; + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 3 && tr.t == 3); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.modify_front () += 'a'; + o.s.modify_back () += 'd'; + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 3 && tr.t == 3); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.begin ().modify () += 'a'; + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 2 && tr.t == 2); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.mbegin (); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 5 && tr.t == 5); + assert (*db->load ("1") == o); + t.commit (); + } + + // clear + // + { + o.s.clear (); + o.s.push_back ("a"); + o.s.push_back ("b"); + o.s.push_back ("c"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.clear (); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.d == 1 && tr.t == 2); + assert (*db->load ("1") == o); + t.commit (); + } + + // assign + // + { + o.s.clear (); + o.s.push_back ("a"); + o.s.push_back ("b"); + o.s.push_back ("c"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (*db->load ("1") == o); + t.commit (); + } + + { + QList v; + v.push_back ("1"); + v.push_back ("2"); + v.push_back ("3"); + v.push_back ("4"); + o.s = v; + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 4 && tr.i == 1 && tr.t == 5); + assert (*db->load ("1") == o); + t.commit (); + } + + // removeOne/removeAll + // + { + o.s.clear (); + o.s.push_back ("a"); + o.s.push_back ("a"); + o.s.push_back ("b"); + o.s.push_back ("c"); + o.s.push_back ("a"); + o.s.push_back ("d"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.removeOne ("c"); + assert (o.s.size () == 5 && o.s[3] == "a"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 3 && tr.d == 1 && tr.t == 4); + assert (*db->load ("1") == o); + t.commit (); + } + + { + o.s.removeAll ("a"); + assert (o.s.size () == 2 && o.s[0] == "b" && o.s[1] == "d"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 3 && tr.d == 1 && tr.t == 4); + assert (*db->load ("1") == o); + t.commit (); + } + + // Transaction rollback. + // + { + o.s.clear (); + o.s.push_back ("a"); + o.s.push_back ("b"); + o.s.push_back ("c"); + + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (*db->load ("1") == o); + t.commit (); + } + + { + { + o.s.push_back ("d"); + + transaction t (db->begin ()); + db->update (o); + t.rollback (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.i == 4 && tr.d == 1 && tr.t == 6); + t.commit (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (o); + assert (tr.u == 1 && tr.t == 1); + t.commit (); + } + } + + // Armed copy. + // + { + auto_ptr c; + + { + o.s.pop_back (); + + transaction t (db->begin ()); + db->update (o); + c.reset (new object (o)); + t.rollback (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (c); + assert (tr.u == 1 && tr.i == 3 && tr.d == 1 && tr.t == 5); + t.commit (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (c); + assert (tr.u == 1 && tr.t == 1); + t.commit (); + } + } + + // Armed swap. + // + { + object c (o); + + { + o.s.push_back ("d"); + + transaction t (db->begin ()); + db->update (o); + assert (o.s._tracking () && !c.s._tracking ()); + c.s.swap (o.s); + assert (!o.s._tracking () && c.s._tracking ()); + t.rollback (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (c); + assert (tr.u == 1 && tr.i == 4 && tr.d == 1 && tr.t == 6); + t.commit (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (c); + assert (tr.u == 1 && tr.t == 1); + t.commit (); + } + } + + // Armed move. + // +#ifdef HAVE_CXX11 + { + auto_ptr c; + + { + o.s.pop_back (); + + transaction t (db->begin ()); + db->update (o); + assert (o.s._tracking ()); + c.reset (new object (std::move (o))); + assert (!o.s._tracking () && c->s._tracking ()); + t.rollback (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (c); + assert (tr.u == 1 && tr.i == 2 && tr.d == 1 && tr.t == 4); + t.commit (); + } + + { + transaction t (db->begin ()); + tr.reset (t); + db->update (c); + assert (tr.u == 1 && tr.t == 1); + t.commit (); + } + } +#endif + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} -- cgit v1.1