diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-03 18:23:51 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-03 18:23:51 +0200 |
commit | 0d65234bc5c6742721c00360a0e3117d51d89c5f (patch) | |
tree | 000052c43d9676077a7216c28b23683f001be56e /common/id/composite/driver.cxx | |
parent | db1bec04ae8b70281c61ffc468126445a612ae28 (diff) |
Implement nested id support
Now the 'id' specifier can optionally include the data member path
to the id inside the composite value. For example:
#pragma db id(first)
std::pair<int, int> p;
Note that one somewhat counter-intuitive aspect of this new feature
is that the whole member marked with id ('p' in the above example)
and not just the actual id member ('p.first' in the above example)
is treated as readonly.
Such nested id also cannot be automatically assigned (auto specifier).
Diffstat (limited to 'common/id/composite/driver.cxx')
-rw-r--r-- | common/id/composite/driver.cxx | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/common/id/composite/driver.cxx b/common/id/composite/driver.cxx new file mode 100644 index 0000000..0df4c98 --- /dev/null +++ b/common/id/composite/driver.cxx @@ -0,0 +1,730 @@ +// file : common/id/composite/driver.cxx +// copyright : Copyright (c) 2009-2015 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; + } +} |