summaryrefslogtreecommitdiff
path: root/odb-tests/common/view/olv
diff options
context:
space:
mode:
Diffstat (limited to 'odb-tests/common/view/olv')
-rw-r--r--odb-tests/common/view/olv/.gitignore46
-rw-r--r--odb-tests/common/view/olv/buildfile50
-rw-r--r--odb-tests/common/view/olv/driver.cxx654
-rw-r--r--odb-tests/common/view/olv/test1.hxx116
-rw-r--r--odb-tests/common/view/olv/test2.hxx122
-rw-r--r--odb-tests/common/view/olv/test3.hxx106
-rw-r--r--odb-tests/common/view/olv/test4.hxx151
-rw-r--r--odb-tests/common/view/olv/test5.hxx86
-rw-r--r--odb-tests/common/view/olv/test6.hxx57
-rw-r--r--odb-tests/common/view/olv/test7.hxx57
-rw-r--r--odb-tests/common/view/olv/test8.hxx54
-rw-r--r--odb-tests/common/view/olv/test9.hxx78
-rw-r--r--odb-tests/common/view/olv/testscript39
13 files changed, 1616 insertions, 0 deletions
diff --git a/odb-tests/common/view/olv/.gitignore b/odb-tests/common/view/olv/.gitignore
new file mode 100644
index 0000000..2b95165
--- /dev/null
+++ b/odb-tests/common/view/olv/.gitignore
@@ -0,0 +1,46 @@
+# ODB-generated files.
+#
+test1-odb.?xx
+test1-odb-*.?xx
+test1.sql
+test1-*.sql
+
+test2-odb.?xx
+test2-odb-*.?xx
+test2.sql
+test2-*.sql
+
+test3-odb.?xx
+test3-odb-*.?xx
+test3.sql
+test3-*.sql
+
+test4-odb.?xx
+test4-odb-*.?xx
+test4.sql
+test4-*.sql
+
+test5-odb.?xx
+test5-odb-*.?xx
+test5.sql
+test5-*.sql
+
+test6-odb.?xx
+test6-odb-*.?xx
+test6.sql
+test6-*.sql
+
+test7-odb.?xx
+test7-odb-*.?xx
+test7.sql
+test7-*.sql
+
+test8-odb.?xx
+test8-odb-*.?xx
+test8.sql
+test8-*.sql
+
+test9-odb.?xx
+test9-odb-*.?xx
+test9.sql
+test9-*.sql
diff --git a/odb-tests/common/view/olv/buildfile b/odb-tests/common/view/olv/buildfile
new file mode 100644
index 0000000..89ecbcf
--- /dev/null
+++ b/odb-tests/common/view/olv/buildfile
@@ -0,0 +1,50 @@
+# file : common/view/olv/buildfile
+# license : GNU GPL v2; see accompanying LICENSE file
+
+import libodb = libodb%lib{odb}
+
+libs =
+
+for db: $databases
+ import libs += libodb-$db%lib{odb-$db}
+
+import libs += lib{common}
+
+hs = test1 test2 test3 test4 test5 test6 test7 test8 test9
+
+exe{driver}: {hxx cxx}{* -*-odb -*-odb-*} testscript
+
+# Introduce the metadata library target to make sure the libodb library is
+# resolved for the odb_compile ad hoc rule (see build/root.build for details).
+#
+libue{test-meta}: $libodb
+
+for h: $hs
+{
+ exe{driver}: {hxx ixx cxx}{$h-odb}
+
+ <{hxx ixx cxx}{$h-odb}>: hxx{$h} libue{test-meta}
+
+ for db: $databases
+ {
+ exe{driver}: {hxx ixx cxx}{$h-odb-$db}: include = $multi
+ <{hxx ixx cxx}{$h-odb-$db}>: hxx{$h} libue{test-meta}
+ }
+}
+
+exe{driver}: libue{test-meta} $libs
+
+# Specify the ODB custom options to be used by the odb_compile ad hoc rule
+# (see build/root.build for details).
+#
+odb_options = --table-prefix t_view_olv_ \
+ --generate-schema \
+ --generate-query
+
+cxx.poptions =+ "-I$out_base" "-I$src_base"
+
+# Testscript's run-time prerequisites.
+#
+exe{driver}: ../../../alias{database-client}: include = adhoc
+
+testscript@./: schemas = $hs
diff --git a/odb-tests/common/view/olv/driver.cxx b/odb-tests/common/view/olv/driver.cxx
new file mode 100644
index 0000000..c08015e
--- /dev/null
+++ b/odb-tests/common/view/olv/driver.cxx
@@ -0,0 +1,654 @@
+// file : common/view/olv/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test object loading views.
+//
+
+#include <memory> // std::unique_ptr
+#include <iostream>
+#include <typeinfo>
+
+#include <odb/session.hxx>
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+
+#include <libcommon/common.hxx>
+
+#include "test1.hxx"
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test4.hxx"
+#include "test5.hxx"
+#include "test6.hxx"
+#include "test7.hxx"
+#include "test8.hxx"
+#include "test9.hxx"
+
+#include "test1-odb.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+#include "test4-odb.hxx"
+#include "test5-odb.hxx"
+#include "test6-odb.hxx"
+#include "test7-odb.hxx"
+#include "test8-odb.hxx"
+#include "test9-odb.hxx"
+
+#undef NDEBUG
+#include <cassert>
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ unique_ptr<database> db (create_database (argc, argv));
+
+ // Test basic object loading functionality.
+ //
+ {
+ using namespace test1;
+
+ {
+ object1 o1a (1, 123);
+ object2 o2 (1, "abc");
+
+ transaction t (db->begin ());
+ db->persist (o1a);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view1> query;
+
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> (query::object1::n == 123));
+ assert (v.o2->s == "abc");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view2 v (db->query_value<view2> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view3 v (db->query_value<view3> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view4 v (db->query_value<view4> ());
+ assert (v.s == "abc" && v.o2->s == "abc" && v.id == 1 &&
+ v.o1->n == 123 && v.n == 123);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view4 v (db->query_value<view4> ());
+ assert (v.s == "abc" && v.o2->s == "abc" && v.id == 1 &&
+ v.o1->n == 123 && v.n == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view5> query;
+
+ object1 o1b (123, 1);
+
+ transaction t (db->begin ());
+ db->persist (o1b);
+ view5 v (db->query_value<view5> (query::o1b::n == 1));
+ assert (v.o1a->n == 123 && v.o2->s == "abc" && v.o1b->n == 1);
+ t.commit ();
+ }
+ }
+
+ // Test loading of object pointers inside objects.
+ //
+ {
+ using namespace test2;
+
+ shared_ptr<object1> o1 (new object1 (123));
+ shared_ptr<object2> o2 (new object2 ("abc", o1));
+
+ {
+
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> ());
+ assert (v.o2->s == "abc" && v.o2->o1->n == 123);
+ t.commit ();
+ }
+
+ {
+ // Check session interaction.
+ //
+ transaction t (db->begin ());
+ session s;
+ shared_ptr<object2> o2a (db->load<object2> (o2->id));
+ view1 v (db->query_value<view1> ());
+ assert (v.o2 == o2a);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view2 v (db->query_value<view2> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1);
+ t.commit ();
+ }
+
+ shared_ptr<object3> o3 (new object3 (o2));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o3);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view3 v (db->query_value<view3> ());
+ assert (v.o1->n == 123 && v.o3->o2->s == "abc" &&
+ v.o3->o2->o1 == v.o1);
+ t.commit ();
+ }
+
+ shared_ptr<object1> o1b (new object1 (234));
+ shared_ptr<object2> o2b (new object2 ("bcd", o1b));
+ shared_ptr<object4> o4 (new object4);
+ o4->o2.push_back (o2);
+ o4->o2.push_back (o2b);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1b);
+ db->persist (o2b);
+ db->persist (o4);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view4 v (db->query_value<view4> ());
+ assert (v.o4->o2[0]->s == "abc" && v.o4->o2[0]->o1->n == 123 &&
+ v.o4->o2[1]->s == "bcd" && v.o4->o2[1]->o1->n == 234);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view5> query;
+ typedef odb::result<view5> result;
+
+ transaction t (db->begin ());
+ session s;
+ result r (db->query<view5> ("ORDER BY" + query::object1::id));
+ result::iterator i (r.begin ());
+
+ assert (i != r.end ());
+ {
+ const view5& v (*i);
+
+ assert (v.o4->o2[0]->s == "abc" && v.o4->o2[0]->o1->n == 123 &&
+ v.o4->o2[1]->s == "bcd" && v.o4->o2[1]->o1->n == 234 &&
+ v.o4->o2[0]->o1 == v.o1);
+ }
+ assert (++i != r.end ());
+ {
+ const view5& v (*i);
+
+ assert (v.o4->o2[0]->s == "abc" && v.o4->o2[0]->o1->n == 123 &&
+ v.o4->o2[1]->s == "bcd" && v.o4->o2[1]->o1->n == 234 &&
+ v.o4->o2[1]->o1 == v.o1);
+ }
+ assert (++i == r.end ());
+ t.commit ();
+ }
+
+ shared_ptr<object5> o5 (new object5 (o1b, o2));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o5);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view6 v (db->query_value<view6> ());
+ assert (v.o1a->n == 123 && v.o1b->n == 234);
+ t.commit ();
+ }
+ }
+
+ // Test JOINs for pointed-to objects, existing and automatically added.
+ //
+ {
+ using namespace test3;
+
+ shared_ptr<object1> o1 (new object1 (123));
+ shared_ptr<object2> o2 (new object2 ("abc"));
+
+ o1->o2 = o2;
+ o2->o1 = o1;
+
+ {
+
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1a v (db->query_value<view1a> ());
+ // VC11
+ assert (v.o1->n == 123 && v.o1->o2.object_id<object2> () == o2->id);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1b v (db->query_value<view1b> ());
+ // VC11
+ assert (v.o1->n == 123 && v.o1->o2.object_id<object2> () == o2->id);
+ t.commit ();
+ }
+
+ // Container case.
+ //
+
+ shared_ptr<object3> o3 (new object3 (123));
+ shared_ptr<object4> o4 (new object4 ("abc"));
+
+ o3->o4 = o4;
+ o4->o3.push_back (o3);
+
+ {
+
+ transaction t (db->begin ());
+ db->persist (o3);
+ db->persist (o4);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view2a v (db->query_value<view2a> ());
+ // VC11
+ assert (v.o3->n == 123 && v.o3->o4.object_id<object4> () == o4->id);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view2b v (db->query_value<view2b> ());
+ // VC11
+ assert (v.o3->n == 123 && v.o3->o4.object_id<object4> () == o4->id);
+ t.commit ();
+ }
+ }
+
+ // Test by-value load.
+ //
+ {
+ using namespace test4;
+
+ {
+ object1 o1 (1, 123);
+ object2 o2 (1, "abc", &o1);
+
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> ());
+ assert (v.o1.n == 123);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1a v (db->query_value<view1a> ());
+ assert (!v.o1_null && v.o1.n == 123);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1b v (db->query_value<view1b> ());
+ assert (/*v.o1_p == &v.o1 && */ v.o1.n == 123); // Copy ctor.
+ t.commit ();
+ }
+
+ {
+ typedef odb::result<view1c> result;
+
+ transaction t (db->begin ());
+ result r (db->query<view1c> ());
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+
+ object1 o1;
+ view1c v (o1);
+ i.load (v);
+
+ assert (v.o1_p == &o1 && o1.n == 123);
+
+ assert (++i == r.end ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view2 v (db->query_value<view2> ());
+
+ // @@ BUILD2 As of cl 19.29.30136 (VS 2019 16.11.5) v.o2.o1 points to
+ // the address of o1 member of the object being returned by
+ // query_value<view2>() which v is a copy of, and thus the
+ // original assertion fails. Note that changing `view2 v` to
+ // `const view2& v` doesn't help.
+ //
+ //assert (v.o1.n == 123 && v.o2.s == "abc" && v.o2.o1 == &v.o1);
+ assert (v.o1.n == 123 && v.o2.s == "abc");
+ t.commit ();
+ }
+
+ object1 o1b (2, 234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1b);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view2a> query;
+
+ transaction t (db->begin ());
+ session s;
+ view2a v (db->query_value<view2a> (query::object1::id == 2));
+ assert (v.o1.n == 234 && v.o2_null);
+ t.commit ();
+ }
+
+ shared_ptr<object3> o3 (new object3 (1, 123));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o3);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ {
+ view3 v (db->query_value<view3> ());
+ assert (v.o3_p == &v.o3 && v.o3.n == 123); // Load into value.
+ }
+ session s; // Load into cache.
+ shared_ptr<object3> o3a (db->load<object3> (o3->id));
+ {
+ view3 v (db->query_value<view3> ());
+ assert (v.o3_p == o3a.get ()); // Load from cache.
+ }
+ t.commit ();
+ }
+ }
+
+ // Test NULL object pointers.
+ //
+ {
+ using namespace test5;
+
+ shared_ptr<object1> o1a (new object1 (123));
+ shared_ptr<object1> o1b (new object1 (234));
+ shared_ptr<object2> o2 (new object2 ("abc", o1a));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1a);
+ db->persist (o1b);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view1> query;
+ typedef odb::result<view1> result;
+
+ transaction t (db->begin ());
+ session s;
+ result r (db->query<view1> ("ORDER BY" + query::object1::id));
+ result::iterator i (r.begin ());
+
+ assert (i != r.end ());
+ {
+ const view1& v (*i);
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1);
+ }
+ assert (++i != r.end ());
+ {
+ const view1& v (*i);
+ assert (v.o1->n == 234 && !v.o2);
+ }
+ assert (++i == r.end ());
+ t.commit ();
+ }
+
+ shared_ptr<object3> o3a (new object3 (make_pair (1, 1), 123));
+ shared_ptr<object3> o3b (new object3 (make_pair (2, 2), 234));
+ shared_ptr<object4> o4 (new object4 ("abc", o3a));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o3a);
+ db->persist (o3b);
+ db->persist (o4);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view2> query;
+ typedef odb::result<view2> result;
+
+ transaction t (db->begin ());
+ session s;
+ result r (db->query<view2> ("ORDER BY" + query::object3::n));
+ result::iterator i (r.begin ());
+
+ assert (i != r.end ());
+ {
+ const view2& v (*i);
+ assert (v.o3->n == 123 && v.o4->s == "abc" && v.o4->o3 == v.o3);
+ }
+ assert (++i != r.end ());
+ {
+ const view2& v (*i);
+ assert (v.o3->n == 234 && !v.o4);
+ }
+ assert (++i == r.end ());
+ t.commit ();
+ }
+ }
+
+ // Test interaction with sections.
+ //
+ {
+ using namespace test6;
+
+ shared_ptr<object1> o1 (new object1 (123));
+ shared_ptr<object2> o2 (new object2 ("abc", o1));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> ());
+
+ assert (v.o1->n == 123 && v.o2->s == "abc" &&
+ !v.o2->r.loaded () && !v.o2->o1);
+
+ db->load (*v.o2, v.o2->r);
+ assert (v.o2->r.loaded () && v.o2->o1 && v.o2->o1->n == 123);
+
+ t.commit ();
+ }
+ }
+
+ // Test explicit conversion to smart pointer member.
+ //
+ {
+ using namespace test7;
+
+ object1 o1 (123);
+ object2 o2 ("abc", &o1);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view1 v (db->query_value<view1> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1.get ());
+ t.commit ();
+ }
+ }
+
+ // Test loading objects without id.
+ //
+ {
+ using namespace test8;
+
+ object1 o1 (123);
+ object2 o2 ("abc", &o1);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view1 v (db->query_value<view1> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1.get ());
+ t.commit ();
+ }
+ }
+
+ // Test loading polymorphic objects.
+ //
+ {
+ using namespace test9;
+
+ root r (1);
+ base b (2, "a");
+ derived d (3, "b", true);
+
+ {
+ transaction t (db->begin ());
+ db->persist (r);
+ db->persist (b);
+ db->persist (d);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+
+ // Load via root.
+ //
+ {
+ view1r r (db->query_value<view1r> (query<view1r>::n == 1));
+ auto& o (*r.o);
+ assert (r.n == 1 && r.o->n == 1 && typeid (o) == typeid (root));
+ }
+
+ {
+ view1r r (db->query_value<view1r> (query<view1r>::n == 2));
+ auto& o (*r.o);
+ assert (r.n == 2 && r.o->n == 2 && typeid (o) == typeid (base));
+ base& b (dynamic_cast<base&> (*r.o));
+ assert (b.s == "a");
+ }
+
+ {
+ view1r r (db->query_value<view1r> (query<view1r>::n == 3));
+ auto& o (*r.o);
+ assert (r.n == 3 && r.o->n == 3 && typeid (o) == typeid (derived));
+ derived& d (dynamic_cast<derived&> (o));
+ assert (d.s == "b" && d.b);
+ }
+
+ // Load via base.
+ //
+ {
+ view1b r (db->query_value<view1b> (query<view1b>::n == 2));
+ assert (r.s == "a" && r.n == 2 && r.o->n == 2 && b.s == "a");
+ }
+
+ {
+ view1b r (db->query_value<view1b> (query<view1b>::n == 3));
+ auto& o (*r.o);
+ assert (r.s == "b" && r.n == 3 && r.o->n == 3 &&
+ typeid (o) == typeid (derived));
+ derived& d (dynamic_cast<derived&> (o));
+ assert (d.s == "b" && d.b);
+ }
+
+ // Load via derived.
+ //
+ {
+ view1d r (db->query_value<view1d> ());
+ assert (r.s == "b" && r.n == 3 &&
+ r.o->n == 3 && r.o->s == "b" && r.o->b);
+ }
+
+ t.commit ();
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/common/view/olv/test1.hxx b/odb-tests/common/view/olv/test1.hxx
new file mode 100644
index 0000000..0de9483
--- /dev/null
+++ b/odb-tests/common/view/olv/test1.hxx
@@ -0,0 +1,116 @@
+// file : common/view/olv/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#include <string>
+#include <memory> // unique_ptr
+#include <utility> // std::move
+
+#include <odb/core.hxx>
+
+// Test basic object loading functionality.
+//
+#pragma db namespace table("t1_") pointer(std::unique_ptr)
+namespace test1
+{
+ #pragma db object
+ struct object1
+ {
+ object1 (int id_ = 0, int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 (int id_ = 0, const char* s_ = ""): id (id_), s (s_) {}
+
+ #pragma db id
+ int id;
+
+ std::string s;
+ };
+
+ #pragma db view object(object1) object(object2: object1::id == object2::id)
+ struct view1
+ {
+ // VC12 workaround (no default move constructor generation).
+ //
+ view1 () {}
+ view1 (view1&& x): o2 (std::move (x.o2)) {}
+
+ std::unique_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1) object(object2: object1::id == object2::id)
+ struct view2
+ {
+ // VC12 workaround (no default move constructor generation).
+ //
+ view2 () {}
+ view2 (view2&& x): o2 (std::move (x.o2)), o1 (std::move (x.o1)) {}
+
+ std::unique_ptr<object2> o2;
+ std::unique_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1 = o1) object(object2 = o2: o1::id == o2::id)
+ struct view3
+ {
+ // VC12 workaround (no default move constructor generation).
+ //
+ view3 () {}
+ view3 (view3&& x): o1 (std::move (x.o1)), o2 (std::move (x.o2)) {}
+
+ std::unique_ptr<object1> o1;
+ std::unique_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1 = o1) object(object2 = o2: o1::id == o2::id)
+ struct view4
+ {
+ // VC12 workaround (no default move constructor generation).
+ //
+ view4 () {}
+ view4 (view4&& x): s (std::move (x.s)),
+ o2 (std::move (x.o2)),
+ id (x.id),
+ o1 (std::move (x.o1)),
+ n (x.n) {}
+
+ std::string s;
+ std::unique_ptr<object2> o2;
+
+ #pragma db column(o1::id)
+ int id;
+
+ std::unique_ptr<object1> o1;
+ int n;
+ };
+
+ #pragma db view \
+ object(object1) \
+ object(object2: object1::id == object2::id) \
+ object(object1 = o1b: object1::id == o1b::n)
+ struct view5
+ {
+ // VC12 workaround (no default move constructor generation).
+ //
+ view5 () {}
+ view5 (view5&& x): o1a (std::move (x.o1a)),
+ o2 (std::move (x.o2)),
+ o1b (std::move (x.o1b)) {}
+
+ std::unique_ptr<object1> o1a;
+ std::unique_ptr<object2> o2;
+ std::unique_ptr<object1> o1b;
+ };
+}
+
+#endif // TEST1_HXX
diff --git a/odb-tests/common/view/olv/test2.hxx b/odb-tests/common/view/olv/test2.hxx
new file mode 100644
index 0000000..a769daa
--- /dev/null
+++ b/odb-tests/common/view/olv/test2.hxx
@@ -0,0 +1,122 @@
+// file : common/view/olv/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#include <string>
+#include <vector>
+#include <memory> // shared_ptr
+
+#include <odb/core.hxx>
+
+// Test loading of object pointers inside objects.
+//
+#pragma db namespace table("t2_") pointer(std::shared_ptr) session
+namespace test2
+{
+ using std::shared_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, shared_ptr<object1> o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ shared_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view2
+ {
+ shared_ptr<object2> o2; // "Unfortunate" order.
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db object
+ struct object3
+ {
+ object3 () {}
+ object3 (shared_ptr<object2> o2_): o2 (o2_) {}
+
+ #pragma db id auto
+ int id;
+
+ shared_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1) object(object2) object(object3)
+ struct view3
+ {
+ shared_ptr<object3> o3; // "Unfortunate" order.
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db object
+ struct object4
+ {
+ #pragma db id auto
+ int id;
+
+ std::vector<shared_ptr<object2>> o2;
+ };
+
+ #pragma db view object(object4)
+ struct view4
+ {
+ shared_ptr<object4> o4;
+ };
+
+ #pragma db view object(object4) object (object2) object(object1)
+ struct view5
+ {
+ shared_ptr<object4> o4; // "Unfortunate" order.
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db object
+ struct object5
+ {
+ object5 () {}
+ object5 (shared_ptr<object1> o1_, shared_ptr<object2> o2_)
+ : o1 (o1_), o2 (o2_) {}
+
+ #pragma db id auto
+ int id;
+
+ shared_ptr<object1> o1;
+ shared_ptr<object2> o2;
+ };
+
+ #pragma db view object(object5) object (object2) \
+ object(object1 = o1a: object2::o1) \
+ object(object1 = o1b: object5::o1)
+ struct view6
+ {
+ shared_ptr<object1> o1a;
+ shared_ptr<object1> o1b;
+ };
+}
+
+#endif // TEST2_HXX
diff --git a/odb-tests/common/view/olv/test3.hxx b/odb-tests/common/view/olv/test3.hxx
new file mode 100644
index 0000000..8cf4344
--- /dev/null
+++ b/odb-tests/common/view/olv/test3.hxx
@@ -0,0 +1,106 @@
+// file : common/view/olv/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#include <string>
+#include <vector>
+#include <memory> // shared_ptr
+
+#include <odb/core.hxx>
+#include <odb/lazy-ptr.hxx>
+
+// Test JOINs for pointed-to objects, existing and automatically added.
+//
+#pragma db namespace table("t3_") pointer(std::shared_ptr) session
+namespace test3
+{
+ using std::shared_ptr;
+
+ struct object2;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+
+ #pragma db inverse(o1)
+ odb::lazy_weak_ptr<object2> o2;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 (const char* s_ = ""): s (s_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1a // Existing JOIN.
+ {
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1)
+ struct view1b // Automatic JOIN.
+ {
+ shared_ptr<object1> o1;
+ };
+
+ // Container case.
+ //
+ struct object4;
+
+ #pragma db object
+ struct object3
+ {
+ object3 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+
+ #pragma db inverse(o3)
+ odb::lazy_weak_ptr<object4> o4;
+ };
+
+ #pragma db object
+ struct object4
+ {
+ object4 (const char* s_ = ""): s (s_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+
+ std::vector<shared_ptr<object3>> o3;
+ };
+
+ #pragma db view object(object3) object(object4 = o4)
+ struct view2a // Existing JOIN.
+ {
+ shared_ptr<object3> o3;
+ };
+
+ #pragma db view object(object3)
+ struct view2b // Automatic JOIN.
+ {
+ shared_ptr<object3> o3;
+ };
+}
+
+#endif // TEST3_HXX
diff --git a/odb-tests/common/view/olv/test4.hxx b/odb-tests/common/view/olv/test4.hxx
new file mode 100644
index 0000000..f2af5fd
--- /dev/null
+++ b/odb-tests/common/view/olv/test4.hxx
@@ -0,0 +1,151 @@
+// file : common/view/olv/test4.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST4_HXX
+#define TEST4_HXX
+
+#include <string>
+#include <memory> // shared_ptr
+
+#include <odb/core.hxx>
+
+// Test by-value load.
+//
+#pragma db namespace table("t4_") session
+namespace test4
+{
+ #pragma db object
+ struct object1
+ {
+ object1 (int id_ = 0, int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 (int id_ = 0, const char* s_ = "", object1* o1_ = 0)
+ : id (id_), s (s_), o1 (o1_) {}
+
+ #pragma db id
+ int id;
+
+ std::string s;
+ object1* o1; // Shallow copy.
+ };
+
+ typedef object1* object1_ptr;
+ typedef object2* object2_ptr;
+
+ #pragma db view object(object1)
+ struct view1
+ {
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) set()
+
+ #pragma db transient
+ object1 o1;
+ };
+
+ #pragma db view object(object1) transient
+ struct view1a
+ {
+ view1a (): o1_null (true) {}
+
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) \
+ set(this.o1_null = !(?))
+
+ object1 o1;
+ bool o1_null;
+ };
+
+ #pragma db view object(object1)
+ struct view1b
+ {
+ view1b (): o1_p (0) {}
+
+ #pragma db transient
+ object1 o1;
+
+ #pragma db get(&this.o1) set(o1_p = (?))
+ object1* o1_p;
+ };
+
+ #pragma db view object(object1)
+ struct view1c
+ {
+ view1c (object1& o1): o1_p (&o1) {}
+
+ object1* o1_p;
+ };
+
+ #pragma db view object(object1) object(object2) transient
+ struct view2
+ {
+ #pragma db member(o2_) virtual(object2_ptr) get(&this.o2) set()
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) set()
+
+ object1 o1;
+ object2 o2;
+ };
+
+ #pragma db view object(object1) object(object2) transient
+ struct view2a
+ {
+ #pragma db member(o2_) virtual(object2_ptr) get(&this.o2) \
+ set(o2_null = !(?))
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) set()
+
+ object1 o1;
+ object2 o2;
+ bool o2_null;
+ };
+
+ // Test loading into raw pointer with non-raw object pointer.
+ //
+ using std::shared_ptr;
+
+ #pragma db object pointer(shared_ptr)
+ struct object3
+ {
+ object3 (int id_ = 0, int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ int id;
+
+ int n;
+ };
+
+ #pragma db view object(object3)
+ struct view3
+ {
+ // This view implements the following slightly twisted logic: if the
+ // object is already in the cache, then set o3_p to that. Otherwise,
+ // load it into the by-value instance. We can also check whether o3_p
+ // points to o3 to distinguish between the two outcomes.
+ //
+
+ // Since we may be getting the pointer as both smart and raw, we
+ // need to create a bit of support code to use in the modifier
+ // expression.
+ //
+ void set_o3 (object3* p) {o3_p = p;} // &o3 or NULL.
+ void set_o3 (shared_ptr<object3> p) {o3_p = p.get ();} // From cache.
+
+ #pragma db get(&this.o3) set(set_o3(?))
+ object3* o3_p;
+
+ #pragma db transient
+ object3 o3;
+
+ // Return-by-value support (query_value()).
+ //
+ view3 (): o3_p (0) {}
+ view3 (const view3& x): o3_p (x.o3_p == &x.o3 ? &o3 : x.o3_p), o3 (x.o3) {}
+ };
+}
+
+#endif // TEST4_HXX
diff --git a/odb-tests/common/view/olv/test5.hxx b/odb-tests/common/view/olv/test5.hxx
new file mode 100644
index 0000000..e3a671b
--- /dev/null
+++ b/odb-tests/common/view/olv/test5.hxx
@@ -0,0 +1,86 @@
+// file : common/view/olv/test5.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST5_HXX
+#define TEST5_HXX
+
+#include <string>
+#include <memory> // shared_ptr
+#include <utility> // pair
+
+#include <odb/core.hxx>
+
+// Test NULL object pointers.
+//
+#pragma db namespace table("t5_") pointer(std::shared_ptr) session
+namespace test5
+{
+ using std::shared_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, shared_ptr<object1> o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ shared_ptr<object1> o1;
+ shared_ptr<object2> o2;
+ };
+
+ typedef std::pair<int, int> comp_id;
+ #pragma db value(comp_id)
+
+ #pragma db object
+ struct object3
+ {
+ object3 (comp_id id_ = comp_id (), int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ comp_id id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object4
+ {
+ object4 () {}
+ object4 (const char* s_, shared_ptr<object3> o3_): s (s_), o3 (o3_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ shared_ptr<object3> o3;
+ };
+
+ #pragma db view object(object3) object(object4)
+ struct view2
+ {
+ shared_ptr<object4> o4;
+ shared_ptr<object3> o3;
+ };
+}
+
+#endif // TEST5_HXX
diff --git a/odb-tests/common/view/olv/test6.hxx b/odb-tests/common/view/olv/test6.hxx
new file mode 100644
index 0000000..5336fa6
--- /dev/null
+++ b/odb-tests/common/view/olv/test6.hxx
@@ -0,0 +1,57 @@
+// file : common/view/olv/test6.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST6_HXX
+#define TEST6_HXX
+
+#include <string>
+#include <memory> // shared_ptr
+
+#include <odb/core.hxx>
+#include <odb/section.hxx>
+
+// Test interaction with sections.
+//
+#pragma db namespace table("t6_") pointer(std::shared_ptr)
+namespace test6
+{
+ using std::shared_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, shared_ptr<object1> o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+
+ #pragma db load(lazy)
+ odb::section r;
+
+ #pragma db section(r)
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ shared_ptr<object1> o1;
+ shared_ptr<object2> o2;
+ };
+}
+
+#endif // TEST6_HXX
diff --git a/odb-tests/common/view/olv/test7.hxx b/odb-tests/common/view/olv/test7.hxx
new file mode 100644
index 0000000..dbdc663
--- /dev/null
+++ b/odb-tests/common/view/olv/test7.hxx
@@ -0,0 +1,57 @@
+// file : common/view/olv/test7.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST7_HXX
+#define TEST7_HXX
+
+#include <string>
+#include <memory> // unique_ptr
+#include <utility> // std::move
+
+#include <odb/core.hxx>
+
+// Test explicit conversion to smart pointer member.
+//
+#pragma db namespace table("t7_") pointer(*) session
+namespace test7
+{
+ using std::unique_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, object1* o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ object1* o1; // Shallow.
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ // VC12 workaround (no default move constructor generation).
+ //
+ view1 () {}
+ view1 (view1&& x): o2 (std::move (x.o2)), o1 (std::move (x.o1)) {}
+
+ unique_ptr<object2> o2;
+ unique_ptr<object1> o1;
+ };
+}
+
+#endif // TEST7_HXX
diff --git a/odb-tests/common/view/olv/test8.hxx b/odb-tests/common/view/olv/test8.hxx
new file mode 100644
index 0000000..607d222
--- /dev/null
+++ b/odb-tests/common/view/olv/test8.hxx
@@ -0,0 +1,54 @@
+// file : common/view/olv/test8.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST8_HXX
+#define TEST8_HXX
+
+#include <string>
+#include <memory> // unique_ptr
+#include <utility> // std::move
+
+#include <odb/core.hxx>
+
+// Test loading objects without id.
+//
+#pragma db namespace table("t8_") pointer(*) session
+namespace test8
+{
+ using std::unique_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object no_id
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, object1* o1_): s (s_), o1 (o1_) {}
+
+ std::string s;
+ object1* o1; // Shallow.
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ // VC12 workaround (no default move constructor generation).
+ //
+ view1 () {}
+ view1 (view1&& x): o2 (std::move (x.o2)), o1 (std::move (x.o1)) {}
+
+ unique_ptr<object2> o2;
+ unique_ptr<object1> o1;
+ };
+}
+
+#endif // TEST8_HXX
diff --git a/odb-tests/common/view/olv/test9.hxx b/odb-tests/common/view/olv/test9.hxx
new file mode 100644
index 0000000..b109de3
--- /dev/null
+++ b/odb-tests/common/view/olv/test9.hxx
@@ -0,0 +1,78 @@
+// file : common/view/olv/test9.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST9_HXX
+#define TEST9_HXX
+
+#include <string>
+#include <memory> // shared_ptr
+
+#include <odb/core.hxx>
+
+// Test loading polymorphic objects.
+//
+#pragma db namespace table("t9_") session
+namespace test9
+{
+ using std::shared_ptr;
+
+ #pragma db object polymorphic pointer(shared_ptr)
+ struct root
+ {
+ virtual ~root () {}
+ root (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct base: root
+ {
+ base (int n_ = 0, const char* s_ = ""): root (n_), s (s_) {}
+
+ std::string s;
+ };
+
+ #pragma db object
+ struct derived: base
+ {
+ derived (int n_ = 0, const char* s_ = "", bool b_ = false)
+ : base (n_, s_), b (b_) {}
+
+ bool b;
+ };
+
+ // Load via root.
+ //
+ #pragma db view object(root)
+ struct view1r
+ {
+ shared_ptr<root> o;
+ int n;
+ };
+
+ // Load via base.
+ //
+ #pragma db view object(base)
+ struct view1b
+ {
+ std::string s;
+ shared_ptr<base> o;
+ int n;
+ };
+
+ // Load via derived.
+ //
+ #pragma db view object(derived)
+ struct view1d
+ {
+ std::string s;
+ shared_ptr<derived> o;
+ int n;
+ };
+}
+
+#endif // TEST9_HXX
diff --git a/odb-tests/common/view/olv/testscript b/odb-tests/common/view/olv/testscript
new file mode 100644
index 0000000..160426d
--- /dev/null
+++ b/odb-tests/common/view/olv/testscript
@@ -0,0 +1,39 @@
+# file : common/view/olv/testscript
+# license : GNU GPL v2; see accompanying LICENSE file
+
+.include ../../../database-options.testscript
+
+: mysql
+:
+if $mysql
+{
+ .include ../../../mysql-schema.testscript
+
+ for s: $schemas
+ cat $out_base/"$s"($multi ? '-mysql' : '').sql | $create_schema_cmd
+ end;
+
+ $* ($multi ? 'mysql' : ) $mysql_options
+}
+
+: sqlite
+:
+if $sqlite
+{
+ .include ../../../sqlite.testscript
+
+ $*
+}
+
+: pgsql
+:
+if $pgsql
+{
+ .include ../../../pgsql-schema.testscript
+
+ for s: $schemas
+ $create_schema_cmd -f $out_base/"$s"($multi ? '-pgsql' : '').sql
+ end;
+
+ $* ($multi ? 'pgsql' : ) $pgsql_options
+}