// file : common/composite-id/driver.cxx // copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file // Test composite object ids. // #include <memory> // std::auto_ptr #include <cassert> #include <iostream> #include <odb/database.hxx> #include <odb/session.hxx> #include <odb/transaction.hxx> #include <common/common.hxx> #include "test.hxx" #include "test-odb.hxx" using namespace std; using namespace odb::core; int main (int argc, char* argv[]) { try { auto_ptr<database> db (create_database (argc, argv)); // Test 1. // { using namespace test1; object o1 (scomp ("aaa", "bbb", "ccc"), 123); o1.vec.push_back (scomp ("xxx", "xxx", "xxx")); o1.vec.push_back (scomp ("yyy", "yyy", "yyy")); object o2 (scomp ("aaa", "bbb", "ccd"), 234); o2.vec.push_back (scomp ("zzz", "", "zzz")); object o3 (scomp ("baa", "bbb", "ccc"), 345); // Persist. // { transaction t (db->begin ()); db->persist (o1); db->persist (o2); db->persist (o3); t.commit (); } // Load. // { transaction t (db->begin ()); auto_ptr<object> p1 (db->load<object> (o1.id)); auto_ptr<object> p2 (db->load<object> (o2.id)); auto_ptr<object> p3 (db->load<object> (o3.id)); t.commit (); assert (*p1 == o1); assert (*p2 == o2); assert (*p3 == o3); } // Update. // { transaction t (db->begin ()); auto_ptr<object> p (db->load<object> (o1.id)); p->num++; db->update (*p); t.commit (); } { transaction t (db->begin ()); auto_ptr<object> p (db->load<object> (o1.id)); t.commit (); assert (p->num == o1.num + 1); } // Erase. // { transaction t (db->begin ()); db->erase<object> (o1.id); t.commit (); } { transaction t (db->begin ()); auto_ptr<object> p (db->find<object> (o1.id)); assert (p.get () == 0); t.commit (); } } // Test 2. // { using namespace test2; object2 o2 (ncomp (2, 0, 1)); o2.o1 = new object1 (scomp ("o1", "o2", "aaa")); object3 o3 (ncomp (3, 0, 1)); o3.o1.push_back (new object1 (scomp ("o1", "o3", "aaa"))); o3.o1.push_back (new object1 (scomp ("o1", "o3", "bbb"))); object4 o4 (ncomp (4, 0, 1)); o4.c.o2 = new object2 (ncomp (2, 4, 1)); o4.c.o2->o1 = new object1 (scomp ("o1", "o2", "ccc")); // Persist. // { transaction t (db->begin ()); db->persist (o2.o1); db->persist (o2); db->persist (o3.o1[0]); db->persist (o3.o1[1]); db->persist (o3); db->persist (o4.c.o2->o1); db->persist (o4.c.o2); db->persist (o4); t.commit (); } // Load. // { transaction t (db->begin ()); auto_ptr<object2> p2 (db->load<object2> (o2.id)); auto_ptr<object3> p3 (db->load<object3> (o3.id)); auto_ptr<object4> p4 (db->load<object4> (o4.id)); t.commit (); assert (p2->o1->id == o2.o1->id); assert (p3->o1.size () == o3.o1.size ()); assert (p3->o1[0]->id == o3.o1[0]->id); assert (p3->o1[1]->id == o3.o1[1]->id); assert (p4->c.o2->id == o4.c.o2->id); assert (p4->c.o2->o1->id == o4.c.o2->o1->id); } // Update. // { scomp id2, id3; { transaction t (db->begin ()); auto_ptr<object2> p2 (db->load<object2> (o2.id)); delete p2->o1; p2->o1 = new object1 (scomp ("o1", "o2", "bbb")); id2 = db->persist (p2->o1); db->update (*p2); auto_ptr<object3> p3 (db->load<object3> (o3.id)); delete p3->o1.back (); p3->o1.pop_back (); p3->o1.push_back (new object1 (scomp ("o1", "o3", "ccc"))); id3 = db->persist (p3->o1.back ()); db->update (*p3); t.commit (); } { transaction t (db->begin ()); auto_ptr<object2> p2 (db->load<object2> (o2.id)); auto_ptr<object3> p3 (db->load<object3> (o3.id)); t.commit (); assert (p2->o1->id == id2); assert (p3->o1.back ()->id == id3); } } // Query. // { { typedef odb::query<object2> query; typedef odb::result<object2> result; transaction t (db->begin ()); { result r (db->query<object2> (query::o1->id.str3 == "bbb")); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->id == o2.id); assert (++i == r.end ()); } { // As id (dual interface). // result r (db->query<object2> (query::o1.str3 == "bbb")); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->id == o2.id); assert (++i == r.end ()); } t.commit (); } // Second level composite object pointer. // { typedef odb::query<object4> query; typedef odb::result<object4> result; transaction t (db->begin ()); result r (db->query<object4> (query::c.o2->o1.str3 == "ccc")); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->id == o4.id); assert (++i == r.end ()); t.commit (); } } // View. // { transaction t (db->begin ()); { typedef odb::query<view2> query; typedef odb::result<view2> result; result r (db->query<view2> (query::object2::id.num2 == 0)); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->num == 1 && i->str == "bbb"); assert (++i == r.end ()); } { typedef odb::query<view3> query; typedef odb::result<view3> result; result r (db->query<view3> ((query::object3::id.num2 == 0) + "ORDER BY" + query::object1::id.str3)); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->num == 1 && i->str == "aaa"); assert (++i != r.end ()); assert (i->num == 1 && i->str == "ccc"); assert (++i == r.end ()); } { typedef odb::query<view4> query; typedef odb::result<view4> result; result r (db->query<view4> (query::object4::id.num2 == 0)); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->num4 == 1 && i->num2 == 1 && i->str == "ccc"); assert (++i == r.end ()); } t.commit (); } } // Test 3. // { using namespace test3; object2 o2 (ncomp (2, 0, 1)); o2.o1 = new object1 (scomp ("o1", "o2", "aaa")); o2.o1->o2 = &o2; // Persist. // { transaction t (db->begin ()); db->persist (o2.o1); db->persist (o2); t.commit (); } // Load. // { session s; transaction t (db->begin ()); auto_ptr<object2> p2 (db->load<object2> (o2.id)); t.commit (); assert (p2->o1->o2->id == o2.id); } // Query. // { typedef odb::query<object1> query; typedef odb::result<object1> result; transaction t (db->begin ()); { session s; result r (db->query<object1> (query::o2->id.num2 == 0)); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->id == o2.o1->id); i->o2->o1 = 0; delete i->o2; assert (++i == r.end ()); } t.commit (); } // View. // { typedef odb::query<view> query; typedef odb::result<view> result; transaction t (db->begin ()); result r (db->query<view> (query::object1::id.str2 == "o2")); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->num == 1 && i->str == "aaa"); assert (++i == r.end ()); t.commit (); } } // Test 4. // { using namespace test4; object2 o2 (ncomp (2, 0, 1)); o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); o2.o1.back ()->o2 = &o2; o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); o2.o1.back ()->o2 = &o2; // Persist. // { transaction t (db->begin ()); db->persist (o2.o1[0]); db->persist (o2.o1[1]); db->persist (o2); t.commit (); } // Load. // { session s; transaction t (db->begin ()); auto_ptr<object2> p2 (db->load<object2> (o2.id)); t.commit (); assert (p2->o1.size () == 2); assert (p2->o1[0]->o2->id == o2.id); assert (p2->o1[1]->o2->id == o2.id); } // Query. // { typedef odb::query<object1> query; typedef odb::result<object1> result; transaction t (db->begin ()); { session s; result r (db->query<object1> (query::o2->id.num2 == 0)); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->id == o2.o1[0]->id); i->o2->o1.clear (); assert (++i != r.end ()); assert (i->id == o2.o1[1]->id); i->o2->o1.clear (); delete i->o2; assert (++i == r.end ()); } t.commit (); } // View. // { typedef odb::query<view> query; typedef odb::result<view> result; transaction t (db->begin ()); result r (db->query<view> (query::object1::id.str3 == "bbb")); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->num == 1 && i->str == "bbb"); assert (++i == r.end ()); t.commit (); } } // Test 5. // { using namespace test5; object2 o2 (ncomp (2, 0, 1)); o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); o2.o1.back ()->o2 = &o2; o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); o2.o1.back ()->o2 = &o2; // Persist. // { transaction t (db->begin ()); db->persist (o2.o1[0]); db->persist (o2.o1[1]); db->persist (o2); t.commit (); } // Load. // { session s; transaction t (db->begin ()); auto_ptr<object2> p2 (db->load<object2> (o2.id)); t.commit (); assert (p2->o1.size () == 2); assert (p2->o1[0]->id == o2.o1[0]->id); assert (p2->o1[0]->o2->id == o2.id); assert (p2->o1[1]->id == o2.o1[1]->id); assert (p2->o1[1]->o2->id == o2.id); } // View. // { typedef odb::query<view> query; typedef odb::result<view> result; transaction t (db->begin ()); result r (db->query<view> ((query::object2::id.num2 == 0) + "ORDER BY" + query::object1::id.str3)); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->num == 1 && i->str == "aaa"); assert (++i != r.end ()); assert (i->num == 1 && i->str == "bbb"); assert (++i == r.end ()); t.commit (); } } // Test 6. // { using namespace test6; object2 o2 (ncomp (2, 0, 1)); o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); o2.o1.back ()->o2.push_back (&o2); o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); o2.o1.back ()->o2.push_back (&o2); // Persist. // { transaction t (db->begin ()); db->persist (o2.o1[0]); db->persist (o2.o1[1]); db->persist (o2); t.commit (); } // Load. // { session s; transaction t (db->begin ()); auto_ptr<object2> p2 (db->load<object2> (o2.id)); t.commit (); assert (p2->o1.size () == 2); assert (p2->o1[0]->id == o2.o1[0]->id); assert (p2->o1[0]->o2[0]->id == o2.id); assert (p2->o1[1]->id == o2.o1[1]->id); assert (p2->o1[1]->o2[0]->id == o2.id); } // View. // { typedef odb::query<view> query; typedef odb::result<view> result; transaction t (db->begin ()); result r (db->query<view> ((query::object2::id.num2 == 0) + "ORDER BY" + query::object1::id.str3)); result::iterator i (r.begin ()); assert (i != r.end ()); assert (i->num == 1 && i->str == "aaa"); assert (++i != r.end ()); assert (i->num == 1 && i->str == "bbb"); assert (++i == r.end ()); t.commit (); } } // Test 7. // { using namespace test7; object o (scomp ("aaa", "bbb", "ccc"), 123); // Persist. // { transaction t (db->begin ()); db->persist (o); t.commit (); } // Load. // { transaction t (db->begin ()); auto_ptr<object> p (db->load<object> (o.id)); t.commit (); assert (*p == o); } // Update. // { transaction t (db->begin ()); auto_ptr<object> p (db->load<object> (o.id)); p->num++; db->update (*p); try { db->update (o); assert (false); } catch (const object_changed&) { } t.commit (); } { transaction t (db->begin ()); auto_ptr<object> p (db->load<object> (o.id)); t.commit (); assert (p->num == o.num + 1); } // Erase. // { transaction t (db->begin ()); try { db->update (o); assert (false); } catch (const object_changed&) { } t.commit (); } } // Test 8. // { using namespace test8; object2 o2a, o2b; object3 o3; o2b.o1 = new object1 (scomp ("222", "aaa", "bbb"), 123); o3.o1.push_back (0); o3.o1.push_back (new object1 (scomp ("333", "aaa", "bbb"), 234)); // Persist. // { transaction t (db->begin ()); db->persist (o2a); db->persist (o2b); db->persist (o2b.o1); db->persist (o3); db->persist (o3.o1[1]); t.commit (); } // Load. // { transaction t (db->begin ()); auto_ptr<object2> p2a (db->load<object2> (o2a.id)); auto_ptr<object2> p2b (db->load<object2> (o2b.id)); auto_ptr<object3> p3 (db->load<object3> (o3.id)); t.commit (); assert (p2a->o1 == 0); assert (p2b->o1 != 0 && *p2b->o1 == *o2b.o1); assert (p3->o1[0] == 0); assert (p3->o1[1] != 0 && *p3->o1[1] == *o3.o1[1]); } // Update. // { object1* o1 (o3.o1[1]); o3.o1.clear (); o3.o1.push_back (o2b.o1); o3.o1.push_back (0); o2a.o1 = o1; o2b.o1 = 0; transaction t (db->begin ()); db->update (o2a); db->update (o2b); db->update (o3); t.commit (); } { transaction t (db->begin ()); auto_ptr<object2> p2a (db->load<object2> (o2a.id)); auto_ptr<object2> p2b (db->load<object2> (o2b.id)); auto_ptr<object3> p3 (db->load<object3> (o3.id)); t.commit (); assert (p2a->o1 != 0 && *p2a->o1 == *o2a.o1); assert (p2b->o1 == 0); assert (p3->o1[0] != 0 && *p3->o1[0] == *o3.o1[0]); assert (p3->o1[1] == 0); } } // Test 9. { using namespace test9; object o (123, "abc"); o.v.push_back (123); // persist // { transaction t (db->begin ()); db->persist (o); t.commit (); } // load & check // { transaction t (db->begin ()); result<object> r (db->query<object> ()); result<object>::iterator i (r.begin ()); assert (i != r.end () && o == *i && ++i == r.end ()); t.commit (); } } } catch (const odb::exception& e) { cerr << e.what () << endl; return 1; } }